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>
14 #include <sys/socket.h>
17 struct sockaddr_in6 v6
;
18 struct sockaddr_in v4
;
21 typedef struct ifaddrs_storage
{
26 char name
[IFNAMSIZ
+1];
28 #define next ifa.ifa_next
30 static stor
* list_add(stor
** list
, stor
** head
, char* ifname
)
32 stor
* curr
= calloc(1, sizeof(stor
));
34 strcpy(curr
->name
, ifname
);
35 curr
->ifa
.ifa_name
= curr
->name
;
36 if(*head
) (*head
)->next
= (struct ifaddrs
*) curr
;
38 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 unsigned char* hb
= sa
->sin6_addr
.s6_addr
;
56 unsigned onebytes
= prefix_length
/ 8;
57 unsigned bits
= prefix_length
% 8;
58 unsigned nullbytes
= 16 - onebytes
;
59 memset(hb
, -1, onebytes
);
60 memset(hb
+onebytes
, 0, nullbytes
);
68 static void dealwithipv6(stor
**list
, stor
** head
)
70 FILE* f
= fopen("/proc/net/if_inet6", "rbe");
71 /* 00000000000000000000000000000001 01 80 10 80 lo
74 A = addr B=netlink device#, C=prefix length,
75 D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c)
77 char v6conv
[32 + 7 + 1], *v6
;
78 char *line
, linebuf
[512];
80 while((line
= fgets(linebuf
, sizeof linebuf
, f
))) {
92 char name
[IFNAMSIZ
+1];
93 if(5 == sscanf(line
, "%x %x %x %x %s", &b
, &c
, &d
, &e
, name
)) {
94 struct sockaddr_in6 sa
= {0};
95 if(1 == inet_pton(AF_INET6
, v6conv
, &sa
.sin6_addr
)) {
96 sa
.sin6_family
= AF_INET6
;
97 stor
* curr
= list_add(list
, head
, name
);
100 curr
->ifa
.ifa_addr
= (struct sockaddr
*) &curr
->addr
;
102 curr
->netmask
.v6
= sa
;
103 curr
->ifa
.ifa_netmask
= (struct sockaddr
*) &curr
->netmask
;
104 /* find ipv4 struct with the same interface name to copy flags */
106 for(;scan
&& strcmp(name
, scan
->name
);scan
=(stor
*)scan
->next
);
107 if(scan
) curr
->ifa
.ifa_flags
= scan
->ifa
.ifa_flags
;
108 else curr
->ifa
.ifa_flags
= 0;
116 int getifaddrs(struct ifaddrs
**ifap
)
118 stor
*list
= 0, *head
= 0;
119 struct if_nameindex
* ii
= if_nameindex();
122 for(i
= 0; ii
[i
].if_index
|| ii
[i
].if_name
; i
++) {
123 stor
* curr
= list_add(&list
, &head
, ii
[i
].if_name
);
125 if_freenameindex(ii
);
129 if_freenameindex(ii
);
131 int sock
= socket(PF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
, IPPROTO_IP
);
132 if(sock
== -1) goto err2
;
133 struct ifreq reqs
[32]; /* arbitrary chosen boundary */
134 struct ifconf conf
= {.ifc_len
= sizeof reqs
, .ifc_req
= reqs
};
135 if(-1 == ioctl(sock
, SIOCGIFCONF
, &conf
)) goto err
;
136 size_t reqitems
= conf
.ifc_len
/ sizeof(struct ifreq
);
137 for(head
= list
; head
; head
= (stor
*)head
->next
) {
138 for(i
= 0; i
< reqitems
; i
++) {
139 // get SIOCGIFADDR of active interfaces.
140 if(!strcmp(reqs
[i
].ifr_name
, head
->name
)) {
141 head
->addr
.v4
= *(struct sockaddr_in
*)&reqs
[i
].ifr_addr
;
142 head
->ifa
.ifa_addr
= (struct sockaddr
*) &head
->addr
;
147 snprintf(req
.ifr_name
, sizeof req
.ifr_name
, "%s", head
->name
);
148 if(-1 == ioctl(sock
, SIOCGIFFLAGS
, &req
)) goto err
;
150 head
->ifa
.ifa_flags
= req
.ifr_flags
;
151 if(head
->ifa
.ifa_addr
) {
152 /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
153 head
->ifa
.ifa_flags
|= IFF_LOWER_UP
;
154 if(-1 == ioctl(sock
, SIOCGIFNETMASK
, &req
)) goto err
;
155 head
->netmask
.v4
= *(struct sockaddr_in
*)&req
.ifr_netmask
;
156 head
->ifa
.ifa_netmask
= (struct sockaddr
*) &head
->netmask
;
158 if(head
->ifa
.ifa_flags
& IFF_POINTOPOINT
) {
159 if(-1 == ioctl(sock
, SIOCGIFDSTADDR
, &req
)) goto err
;
160 head
->dst
.v4
= *(struct sockaddr_in
*)&req
.ifr_dstaddr
;
162 if(-1 == ioctl(sock
, SIOCGIFBRDADDR
, &req
)) goto err
;
163 head
->dst
.v4
= *(struct sockaddr_in
*)&req
.ifr_broadaddr
;
165 head
->ifa
.ifa_ifu
.ifu_dstaddr
= (struct sockaddr
*) &head
->dst
;
170 for(head
= list
; head
; head
=(stor
*)head
->next
) last
=head
;
172 dealwithipv6(&list
, &head
);
173 *ifap
= (struct ifaddrs
*) list
;
178 freeifaddrs((struct ifaddrs
*) list
);