diff options
| -rw-r--r-- | src/network/getifaddrs.c | 107 | 
1 files changed, 52 insertions, 55 deletions
| diff --git a/src/network/getifaddrs.c b/src/network/getifaddrs.c index d96d1094..50eaee80 100644 --- a/src/network/getifaddrs.c +++ b/src/network/getifaddrs.c @@ -12,17 +12,27 @@  #include <unistd.h>  #include <sys/ioctl.h> -static struct ifaddrs* list_add(struct ifaddrs** list, struct ifaddrs** head, char* ifname) +typedef union { +	struct sockaddr_in6 v6; +	struct sockaddr_in v4; +} soa; + +typedef struct ifaddrs_storage { +	struct ifaddrs ifa; +	soa addr; +	soa netmask; +	soa dst; +	char name[IFNAMSIZ+1]; +} stor; +#define next ifa.ifa_next + +static stor* list_add(stor** list, stor** head, char* ifname)  { -	struct ifaddrs* curr = calloc(1, sizeof(struct ifaddrs)); +	stor* curr = calloc(1, sizeof(stor));  	if(curr) { -		curr->ifa_name = strdup(ifname); -		if(!curr->ifa_name) { -			free(curr); -			curr = 0; -			goto out; -		} -		if(*head) (*head)->ifa_next = curr; +		strcpy(curr->name, ifname); +		curr->ifa.ifa_name = curr->name; +		if(*head) (*head)->next = (struct ifaddrs*) curr;  		*head = curr;  		if(!*list) *list = curr;  	} @@ -32,40 +42,21 @@ static struct ifaddrs* list_add(struct ifaddrs** list, struct ifaddrs** head, ch  void freeifaddrs(struct ifaddrs *ifp)  { -	struct ifaddrs *head = ifp; +	stor *head = (stor *) ifp;  	while(head) { -		free(head->ifa_name); -		free(head->ifa_addr); -		free(head->ifa_netmask); -		free(head->ifa_ifu.ifu_dstaddr); -		free(head->ifa_data);  		void *p = head; -		head = head->ifa_next; +		head = (stor *) head->next;  		free(p);  	}  } -static struct sockaddr *sockaddr_in_dup(struct sockaddr_in *src) -{ -	struct sockaddr_in *nu = malloc(sizeof(struct sockaddr_in)); -	if(nu) *nu = *src; -	return (struct sockaddr*) nu; -} - -static struct sockaddr *sockaddr_in6_dup(struct sockaddr_in6 *src) -{ -	struct sockaddr_in6 *nu = malloc(sizeof(struct sockaddr_in6)); -	if(nu) *nu = *src; -	return (struct sockaddr*) nu; -} -  static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)  {  	// FIXME: left for bit-wizard rich  	memset(&sa->sin6_addr, -1, sizeof(sa->sin6_addr));  } -static void dealwithipv6(struct ifaddrs **list, struct ifaddrs** head) +static void dealwithipv6(stor **list, stor** head)  {  	FILE* f = fopen("/proc/net/if_inet6", "r");  	/* 00000000000000000000000000000001 01 80 10 80 lo @@ -94,16 +85,18 @@ static void dealwithipv6(struct ifaddrs **list, struct ifaddrs** head)  			struct sockaddr_in6 sa = {0};  			if(1 == inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) {  				sa.sin6_family = AF_INET6; -				struct ifaddrs* curr = list_add(list, head, name); +				stor* curr = list_add(list, head, name);  				if(!curr) goto out; -				curr->ifa_addr = sockaddr_in6_dup(&sa); +				curr->addr.v6 = sa; +				curr->ifa.ifa_addr = (struct sockaddr*) &curr->addr;  				ipv6netmask(c, &sa); -				curr->ifa_netmask = sockaddr_in6_dup(&sa); +				curr->netmask.v6 = sa; +				curr->ifa.ifa_netmask = (struct sockaddr*) &curr->netmask;  				/* find ipv4 struct with the same interface name to copy flags */ -				struct ifaddrs* scan = *list; -				for(;scan && strcmp(name, scan->ifa_name);scan=scan->ifa_next); -				if(scan) curr->ifa_flags=scan->ifa_flags; -				else curr->ifa_flags = 0; +				stor* scan = *list; +				for(;scan && strcmp(name, scan->name);scan=(stor*)scan->next); +				if(scan) curr->ifa.ifa_flags = scan->ifa.ifa_flags; +				else curr->ifa.ifa_flags = 0;  			} else errno = 0;  		}  	} @@ -114,12 +107,13 @@ static void dealwithipv6(struct ifaddrs **list, struct ifaddrs** head)  int getifaddrs(struct ifaddrs **ifap)  {  	FILE* f = fopen("/proc/net/dev", "r"); +	if(!f) return -1; +  	/* the alternative to parsing /proc.. seems to be iterating  	   through the interfaces using an index number in ifreq.ifr_ifindex  	   until we get some error code back. the kernel will fill ifr_name field  	   for valid ifindices (SIOCGIFINDEX) */ -	if(!f) return -1; -	struct ifaddrs *list = 0, *head = 0; +	stor *list = 0, *head = 0;  	char* line; char linebuf[512];  	while((line = fgets(linebuf, sizeof linebuf, f))) { @@ -129,7 +123,7 @@ int getifaddrs(struct ifaddrs **ifap)  		if(line > start && *line == ':') {  			// found interface  			*line = 0; -			struct ifaddrs* curr = list_add(&list, &head, start); +			stor* curr = list_add(&list, &head, start);  			if(!curr) {  				fclose(f);  				goto err2; @@ -145,47 +139,50 @@ int getifaddrs(struct ifaddrs **ifap)  	if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;  	else {  		size_t reqitems = conf.ifc_len / sizeof(struct ifreq); -		for(head = list; head; head=head->ifa_next) { +		for(head = list; head; head = (stor*)head->next) {  			size_t i;  			for(i = 0; i < reqitems; i++) {  				// get SIOCGIFADDR of active interfaces. -				if(!strcmp(reqs[i].ifr_name, head->ifa_name)) { -					head->ifa_addr = sockaddr_in_dup((struct sockaddr_in*) &reqs[i].ifr_addr); +				if(!strcmp(reqs[i].ifr_name, head->name)) { +					head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr; +					head->ifa.ifa_addr = (struct sockaddr*) &head->addr;  					break;  				}  			}  			struct ifreq req; -			snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->ifa_name); +			snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);  			if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err; -			head->ifa_flags = req.ifr_flags; -			if(head->ifa_addr) { +			head->ifa.ifa_flags = req.ifr_flags; +			if(head->ifa.ifa_addr) {  				/* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */ -				head->ifa_flags |= IFF_LOWER_UP;  +				head->ifa.ifa_flags |= IFF_LOWER_UP;   				if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err; -				head->ifa_netmask = sockaddr_in_dup((struct sockaddr_in*) &req.ifr_netmask); +				head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask; +				head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask; -				if(head->ifa_flags & IFF_POINTOPOINT) { +				if(head->ifa.ifa_flags & IFF_POINTOPOINT) {  					if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err; -					head->ifa_ifu.ifu_dstaddr = sockaddr_in_dup((struct sockaddr_in*) &req.ifr_dstaddr); +					head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr;  				} else {  					if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err; -					head->ifa_ifu.ifu_broadaddr = sockaddr_in_dup((struct sockaddr_in*) &req.ifr_broadaddr); +					head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr;  				} +				head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;  			}  		}  	}  	close(sock);  	void* last = 0; -	for(head = list; head; head=head->ifa_next) last=head; +	for(head = list; head; head=(stor*)head->next) last=head;  	head = last;  	dealwithipv6(&list, &head); -	*ifap = list; +	*ifap = (struct ifaddrs*) list;  	return 0;  	err:  	close(sock);  	err2: -	freeifaddrs(list); +	freeifaddrs((struct ifaddrs*) list);  	return -1;  } | 
