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 #include -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; }