1 /* (C) 2013 John Spencer. released under musl's standard MIT license. */
6 #include <net/if.h> /* IFNAMSIZ, ifreq, ifconf */
11 #include <arpa/inet.h> /* inet_pton */
13 #include <sys/ioctl.h>
16 struct sockaddr_in6 v6;
17 struct sockaddr_in v4;
20 typedef struct ifaddrs_storage {
25 char name[IFNAMSIZ+1];
27 #define next ifa.ifa_next
29 static stor* list_add(stor** list, stor** head, char* ifname)
31 stor* curr = calloc(1, sizeof(stor));
33 strcpy(curr->name, ifname);
34 curr->ifa.ifa_name = curr->name;
35 if(*head) (*head)->next = (struct ifaddrs*) curr;
37 if(!*list) *list = curr;
43 void freeifaddrs(struct ifaddrs *ifp)
45 stor *head = (stor *) ifp;
48 head = (stor *) head->next;
53 static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
55 // FIXME: left for bit-wizard rich
56 memset(&sa->sin6_addr, -1, sizeof(sa->sin6_addr));
59 static void dealwithipv6(stor **list, stor** head)
61 FILE* f = fopen("/proc/net/if_inet6", "r");
62 /* 00000000000000000000000000000001 01 80 10 80 lo
65 A = addr B=netlink device#, C=prefix length,
66 D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c)
68 char v6conv[32 + 7 + 1], *v6;
69 char *line, linebuf[512];
71 while((line = fgets(linebuf, sizeof linebuf, f))) {
83 char name[IFNAMSIZ+1];
84 if(5 == sscanf(line, "%x %x %x %x %s", &b, &c, &d, &e, name)) {
85 struct sockaddr_in6 sa = {0};
86 if(1 == inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) {
87 sa.sin6_family = AF_INET6;
88 stor* curr = list_add(list, head, name);
91 curr->ifa.ifa_addr = (struct sockaddr*) &curr->addr;
93 curr->netmask.v6 = sa;
94 curr->ifa.ifa_netmask = (struct sockaddr*) &curr->netmask;
95 /* find ipv4 struct with the same interface name to copy flags */
97 for(;scan && strcmp(name, scan->name);scan=(stor*)scan->next);
98 if(scan) curr->ifa.ifa_flags = scan->ifa.ifa_flags;
99 else curr->ifa.ifa_flags = 0;
107 int getifaddrs(struct ifaddrs **ifap)
109 FILE* f = fopen("/proc/net/dev", "r");
112 /* the alternative to parsing /proc.. seems to be iterating
113 through the interfaces using an index number in ifreq.ifr_ifindex
114 until we get some error code back. the kernel will fill ifr_name field
115 for valid ifindices (SIOCGIFINDEX) */
116 stor *list = 0, *head = 0;
118 char* line; char linebuf[512];
119 while((line = fgets(linebuf, sizeof linebuf, f))) {
120 while(isspace(*line) && *line) line++;
122 while(*line && isalnum(*line)) line++;
123 if(line > start && *line == ':') {
126 stor* curr = list_add(&list, &head, start);
135 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
136 if(sock == -1) goto err2;
137 struct ifreq reqs[32]; /* arbitrary chosen boundary */
138 struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs};
139 if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;
141 size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
142 for(head = list; head; head = (stor*)head->next) {
144 for(i = 0; i < reqitems; i++) {
145 // get SIOCGIFADDR of active interfaces.
146 if(!strcmp(reqs[i].ifr_name, head->name)) {
147 head->addr.v4 = *(struct sockaddr_in*)&reqs[i].ifr_addr;
148 head->ifa.ifa_addr = (struct sockaddr*) &head->addr;
153 snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);
154 if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err;
156 head->ifa.ifa_flags = req.ifr_flags;
157 if(head->ifa.ifa_addr) {
158 /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
159 head->ifa.ifa_flags |= IFF_LOWER_UP;
160 if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err;
161 head->netmask.v4 = *(struct sockaddr_in*)&req.ifr_netmask;
162 head->ifa.ifa_netmask = (struct sockaddr*) &head->netmask;
164 if(head->ifa.ifa_flags & IFF_POINTOPOINT) {
165 if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) goto err;
166 head->dst.v4 = *(struct sockaddr_in*)&req.ifr_dstaddr;
168 if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) goto err;
169 head->dst.v4 = *(struct sockaddr_in*)&req.ifr_broadaddr;
171 head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) &head->dst;
177 for(head = list; head; head=(stor*)head->next) last=head;
179 dealwithipv6(&list, &head);
180 *ifap = (struct ifaddrs*) list;
185 freeifaddrs((struct ifaddrs*) list);