FreeBSD: network interface information - c

I am trying to programmingly find network interfaces info in FreeBSD. In linux, the interfaces are listed at /etc/network/interfaces file.
Is there any such file in FreeBSD? How can I extract that info?

you can always use getifaddrs(3) here is an exmaple:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
int main(void) {
struct ifaddrs *ifap,*ifa;
getifaddrs(&ifap);
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
printf("%s\n",ifa->ifa_name);
}
freeifaddrs(ifap);
}
EDIT: on linux if you need to fetch the link layer address of the interface you need to look for AF_PACKET sa_family, which is found in netpacket/packet.h
on linux, *bsd its called AF_LINK and its in net/if_dl.h
#ifdef AF_LINK
# include <net/if_dl.h>
#endif
#ifdef AF_PACKET
# include <netpacket/packet.h>
#endif
#ifdef AF_LINK
#define SDL ((struct sockaddr_dl *)ifa->ifa_addr)
if (SDL->sdl_family == AF_LINK) {
bcopy(SDL->sdl_data + SDL->sdl_nlen,....,SDL->sdl_alen
}
#undef SDL
#endif
#ifdef AF_PACKET
if (ifa->ifa_addr->sa_family == AF_PACKET) {
struct sockaddr_ll *sl =
(struct sockaddr_ll*) ifa->ifa_addr;
bcopy(sl->sll_addr,....,sl->sll_halen
}
#endif

Related

how I can enforce OpenSSL to use my system's root CA if I make my application for linux or for windows 10 or later?

I am making the following piece of code:
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <shlwapi.h>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <shlwapi.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
//#pragma comment (lib, "Mswsock.lib")
//#pragma comment (lib, "AdvApi32.lib")
#define WIN32_LEAN_AND_MEAN
int verifyCerts( SSL_CTX* ctx )
{
// directory where executable is
char path[MAX_PATH] = "";
memset(path, 0, MAX_PATH);
GetModuleFileName(0, path, MAX_PATH);
PathRemoveFileSpec(path);
sprintf(path,"%s\\%s",path,"certificates");
printf("\nCert path %s\n",path);
sprintf(path,"%s\\%s",path,"certificates");
printf("\nCert path %s\n",path);
int value = SSL_CTX_load_verify_locations(ctx,NULL,path);
}
#else // By default use system's CA root
int verifyCerts( SSL_CTX* ctx )
{
}
#endif
SSL_CTX* InitCTX(void)
{
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
const SSL_METHOD* method = SSLv23_method();
SSL_CTX* ctx = SSL_CTX_new(method);
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1);
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
int value = verifyCerts( ctx );
if(value == 0) {
printf("Certificate error\n");
exit(1);
}
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
return ctx;
}
In my case I want to do the following:
For windows XP (legacy application) to provide certificates alongside to my application so I can mame my application as sacure as possible.
At any other case (for linux systems or windows 10 or above) I'll use the OS's default CA certs (no hussle to provide my own).
So how I can ensure that the latter case is applicable as well?
At #else section just place the following code:
int verifyCerts( SSL_CTX* ctx )
{
const char *path = getenv(X509_get_default_cert_dir_env());
if (!path){
path = X509_get_default_cert_dir();
}
return SSL_CTX_load_verify_locations(ctx,NULL,path);
}
That will allow for linux systems to verify using default certs path. So for windows XP only we can use custom mingw flags.

Kernel module to filter NFS requests

I'm working on a proof-of-concept kernel module to filter NFS requests based on some criteria (client IP address, type of operation performed, etc.)
I used a hacky method described in this question but I couldn't retrieve the client IP address inside this method.
My current thinking is to have a Netfilter hook to intercept the network packets, parse them to identify the operations and apply the filtering there.
He're is a sample of what I'm talking about.. It's for kernel version 4.15.0
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module, */
#include <linux/moduleparam.h> /* which will have params */
#include <linux/unistd.h> /* The list of system calls */
#include <linux/dirent.h>
#include <linux/cred.h>
#include <linux/syscalls.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/tcp.h>
static struct nf_hook_ops nfin;
static unsigned int hook_func_in(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct ethhdr *eth;
struct iphdr *ip_header;
struct tcphdr *tcph;
char *data;
eth = eth_hdr(skb);
ip_header = ip_hdr(skb);
tcph = tcp_hdr(skb);
data = (char *)((unsigned char *)tcph + (tcph->doff * 4));
/* Skip if it's not TCP packet */
if (ip_header->protocol != IPPROTO_TCP)
return NF_ACCEPT;
printk("src mac %pM --- src IP addr:%pI4 --- protocol: %u\n", eth->h_source, &ip_header->saddr, ip_header->protocol);
printk("TCP source : %hu, TCP dest : %hu\n", ntohs(tcph->source), ntohs(tcph->dest));
// Parse data pointer here..
return NF_ACCEPT;
}
int init_module()
{
nfin.hook = hook_func_in;
nfin.hooknum = NF_INET_LOCAL_IN;
nfin.pf = PF_INET;
nfin.priority = 0;
nf_register_net_hook(&init_net, &nfin);
return 0;
}
void cleanup_module()
{
nf_unregister_net_hook(&init_net, &nfin);
}
How can I parse the data pointer to be able to identify the type of request I'm handling? or how to parse the RPC request from the sk_buff object?
Is this the right approach to go about this task?

Why can't I access uname struct's domainname member even if I defined _GNU_SOURCE

I am trying to some get Linux kernel version information by calling uname system call, but I am getting a compiler error saying ‘struct utsname’ has no member named ‘domainname’
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>
#define _GNU_SOURCE
int main(void) {
struct utsname buffer;
errno = 0;
if (uname(&buffer) != 0) {
perror("uname");
exit(EXIT_FAILURE);
}
printf("system name = %s\n", buffer.sysname);
printf("node name = %s\n", buffer.nodename);
printf("release = %s\n", buffer.release);
printf("version = %s\n", buffer.version);
printf("machine = %s\n", buffer.machine);
#ifdef _GNU_SOURCE
printf("domain name = %s\n", buffer.domainname);
#endif
return EXIT_SUCCESS;
}
according to https://linux.die.net/man/2/uname struct utsname is
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined
network" */
char release[]; /* Operating system release (e.g., "2.6.28") */
char version[]; /* Operating system version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
I am not sure what I missed here
From man feature_test_macros:
NOTE: In order to be effective, a feature test macro must be defined
before including any header files
It's:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/utsname.h>

Connection refused on wpa_ctrl_open

I am trying to use C code to access wpa_supplicant in an ARM embedded system running linux. After searching, I realise that I could use wpa_supplicant control interface. I try to open a connection using wpa_ctrl_open(), and resulted in "Connection refused" error:
Failed to connect to wpa_supplicant global interface: /var/run/wpa_supplicant error: Connection refused
The code I am using to test:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "includes.h"
#ifdef CONFIG_CTRL_IFACE_UNIX
#include <dirent.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
#include "wpa_ctrl.h"
#include "common.h"
struct wpa_ctrl {
int s;
#ifdef CONFIG_CTRL_IFACE_UDP
struct sockaddr_in local;
struct sockaddr_in dest;
#else // CONFIG_CTRL_IFACE_UDP
struct sockaddr_un local;
struct sockaddr_un dest;
#endif // CONFIG_CTRL_IFACE_UDP
};
static struct wpa_ctrl *ctrl_conn;
int main(int argc,char **argv)
{
const char *global = "/var/run/wpa_supplicant";
ctrl_conn = wpa_ctrl_open(global);
if (ctrl_conn == NULL)
{
fprintf(stderr, "Failed to connect to wpa_supplicant "
"global interface: %s error: %s\n",global,strerror(errno));
return -1;
}
else
{
printf("Success\n");
}
return 0;
}
After tracing the code in wpa_ctrl.c, I found the problem is on the following IF condition, inside wpa_ctrl_open2() function:
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,sizeof(ctrl->dest)) < 0)
I do not know what is the problem and how I can solve it.
On the same machine, I tried to run wpa_cli and it can access wpa_supplicant perfectly.
I used the following command to compile:
gcc -o test_wpa main.c wpa_ctrl.c os_unix.c -DCONFIG_BACKEND_FILE -DCONFIG_IEEE80211W -DCONFIG_DRIVER_WEXT -DCONFIG_WIRELESS_EXTENSION -DCONFIG_DRIVER_NL80211 -DCONFIG_LIBNL20 -DEAP_PSK -DIEEE8021X_EAPOL -DCONFIG_SHA256 -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX -DCONFIG_SME -lrt
wpa_supplicant code (including wpa_ctrl.c & os_unix.c) can be download at here:
http://w1.fi/releases/wpa_supplicant-2.5.tar.gz
Many thanks in advance!
I found the way to solve the problem, add "wlan0" after the path:
const char *global = "/var/run/wpa_supplicant/wlan0";
ctrl_conn = wpa_ctrl_open(global);

Get IP address of an interface on Linux

How can I get the IPv4 address of an interface on Linux from C code?
For example, I'd like to get the IP address (if any) assigned to eth0.
Try this:
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int
main()
{
int fd;
struct ifreq ifr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
ifr.ifr_addr.sa_family = AF_INET;
/* I want IP address attached to "eth0" */
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);
ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
/* display result */
printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
return 0;
}
The code sample is taken from here.
In addition to the ioctl() method Filip demonstrated you can use getifaddrs(). There is an example program at the bottom of the man page.
If you're looking for an address (IPv4) of the specific interface say wlan0 then
try this code which uses getifaddrs():
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
You can replace wlan0 with eth0 for ethernet and lo for local loopback.
The structure and detailed explanations of the data structures
used could be found here.
To know more about linked list in C this page will be a good starting point.
My 2 cents: the same code works even if iOS:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
showIP();
}
void showIP()
{
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1)
{
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
{
if (s != 0)
{
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("\tInterface : <%s>\n",ifa->ifa_name );
printf("\t Address : <%s>\n", host);
}
}
freeifaddrs(ifaddr);
}
#end
I simply removed the test against wlan0 to see data.
ps You can remove "family"
I have been in the same issue recently, and this is the code I made up and it works. Make sure to use the name of the network interface, exactly as you have it (could be "eth0" or else).
gotta check if ifconfigcommand beforehand to get the interface name and use it in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void extract_ipaddress()
{
//create an ifreq struct for passing data in and out of ioctl
struct ifreq my_struct;
//declare and define the variable containing the name of the interface
char *interface_name="enp0s3"; //a very frequent interface name is "eth0";
//the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
//Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
size_t interface_name_len=strlen(interface_name);
if(interface_name_len<sizeof(my_struct.ifr_name))
{
memcpy(my_struct.ifr_name,interface_name,interface_name_len);
my_struct.ifr_name[interface_name_len]=0;
}
else
{
perror("Copy name of interface to ifreq struct");
printf("The name you provided for the interface is too long...\n");
}
//provide an open socket descriptor with the address family AF_INET
/* ***************************************************************
* All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
* ***************************************************************
*/
int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
if(file_descriptor==-1)
{
perror("Socket file descriptor");
printf("The construction of the socket file descriptor was unsuccessful.\n");
return -1;
}
//invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
if (myioctl_call==-1)
{
perror("ioctl");
printf("Ooops, error when invoking ioctl() system call.\n");
close(file_descriptor);
return -1;
}
close(file_descriptor);
/* **********************************************************************
* If this completes without error , then the hardware address of the interface should have been returned in the 'my_struct.ifr_addr' which is types as struct sockaddr_in.
* ***********************************************************************/
//extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
/* *** Cast the returned address to a struct 'sockaddr_in' *** */
struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
/* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
printf("IP Address is %s.\n", inet_ntoa(ipaddress->sin_addr));
}
If you don't mind the binary size, you can use iproute2 as library.
iproute2-as-lib
Pros:
No need to write the socket layer code.
More or even more information about network interfaces can be got. Same functionality with the iproute2 tools.
Simple API interface.
Cons:
iproute2-as-lib library size is big. ~500kb.
I found a quite easy way to get ip, by take advantage of using bash command:
hostname -I
but use "hostname -I" natively will print the result on screen, we need to use "popen()" to read result out and save it into a string, here is c code:
#include <stdio.h> // popen
#include "ip_common_def.h"
const char * get_ip()
{
// Read out "hostname -I" command output
FILE *fd = popen("hostname -I", "r");
if(fd == NULL) {
fprintf(stderr, "Could not open pipe.\n");
return NULL;
}
// Put output into a string (static memory)
static char buffer[IP_BUFFER_LEN];
fgets(buffer, IP_BUFFER_LEN, fd);
// Only keep the first ip.
for (int i = 0; i < IP_BUFFER_LEN; ++i)
{
if (buffer[i] == ' ')
{
buffer[i] = '\0';
break;
}
}
char *ret = malloc(strlen(buffer) + 1);
memcpy(ret, buffer, strlen(buffer));
ret[strlen(buffer)] = '\0';
printf("%s\n", ret);
return ret;
}

Resources