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
;
42 void freeifaddrs(struct ifaddrs
*ifp
)
44 stor
*head
= (stor
*) ifp
;
47 head
= (stor
*) head
->next
;
52 static void ipv6netmask(unsigned prefix_length
, struct sockaddr_in6
*sa
)
54 unsigned char* hb
= sa
->sin6_addr
.s6_addr
;
55 unsigned onebytes
= prefix_length
/ 8;
56 unsigned bits
= prefix_length
% 8;
57 unsigned nullbytes
= 16 - onebytes
;
58 memset(hb
, -1, onebytes
);
59 memset(hb
+onebytes
, 0, nullbytes
);
67 static void dealwithipv6(stor
**list
, stor
** head
)
69 FILE* f
= fopen("/proc/net/if_inet6", "r");
70 /* 00000000000000000000000000000001 01 80 10 80 lo
73 A = addr B=netlink device#, C=prefix length,
74 D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c)
76 char v6conv
[32 + 7 + 1], *v6
;
77 char *line
, linebuf
[512];
79 while((line
= fgets(linebuf
, sizeof linebuf
, f
))) {
91 char name
[IFNAMSIZ
+1];
92 if(5 == sscanf(line
, "%x %x %x %x %s", &b
, &c
, &d
, &e
, name
)) {
93 struct sockaddr_in6 sa
= {0};
94 if(1 == inet_pton(AF_INET6
, v6conv
, &sa
.sin6_addr
)) {
95 sa
.sin6_family
= AF_INET6
;
96 stor
* curr
= list_add(list
, head
, name
);
99 curr
->ifa
.ifa_addr
= (struct sockaddr
*) &curr
->addr
;
101 curr
->netmask
.v6
= sa
;
102 curr
->ifa
.ifa_netmask
= (struct sockaddr
*) &curr
->netmask
;
103 /* find ipv4 struct with the same interface name to copy flags */
105 for(;scan
&& strcmp(name
, scan
->name
);scan
=(stor
*)scan
->next
);
106 if(scan
) curr
->ifa
.ifa_flags
= scan
->ifa
.ifa_flags
;
107 else curr
->ifa
.ifa_flags
= 0;
115 int getifaddrs(struct ifaddrs
**ifap
)
117 stor
*list
= 0, *head
= 0;
118 struct if_nameindex
* ii
= if_nameindex();
121 for(i
= 0; ii
[i
].if_index
|| ii
[i
].if_name
; i
++) {
122 stor
* curr
= list_add(&list
, &head
, ii
[i
].if_name
);
124 if_freenameindex(ii
);
128 if_freenameindex(ii
);
130 int sock
= socket(PF_INET
, SOCK_DGRAM
|SOCK_CLOEXEC
, IPPROTO_IP
);
131 if(sock
== -1) goto err2
;
132 struct ifreq reqs
[32]; /* arbitrary chosen boundary */
133 struct ifconf conf
= {.ifc_len
= sizeof reqs
, .ifc_req
= reqs
};
134 if(-1 == ioctl(sock
, SIOCGIFCONF
, &conf
)) goto err
;
135 size_t reqitems
= conf
.ifc_len
/ sizeof(struct ifreq
);
136 for(head
= list
; head
; head
= (stor
*)head
->next
) {
137 for(i
= 0; i
< reqitems
; i
++) {
138 // get SIOCGIFADDR of active interfaces.
139 if(!strcmp(reqs
[i
].ifr_name
, head
->name
)) {
140 head
->addr
.v4
= *(struct sockaddr_in
*)&reqs
[i
].ifr_addr
;
141 head
->ifa
.ifa_addr
= (struct sockaddr
*) &head
->addr
;
146 snprintf(req
.ifr_name
, sizeof req
.ifr_name
, "%s", head
->name
);
147 if(-1 == ioctl(sock
, SIOCGIFFLAGS
, &req
)) goto err
;
149 head
->ifa
.ifa_flags
= req
.ifr_flags
;
150 if(head
->ifa
.ifa_addr
) {
151 /* or'ing flags with IFF_LOWER_UP on active interfaces to mimic glibc */
152 head
->ifa
.ifa_flags
|= IFF_LOWER_UP
;
153 if(-1 == ioctl(sock
, SIOCGIFNETMASK
, &req
)) goto err
;
154 head
->netmask
.v4
= *(struct sockaddr_in
*)&req
.ifr_netmask
;
155 head
->ifa
.ifa_netmask
= (struct sockaddr
*) &head
->netmask
;
157 if(head
->ifa
.ifa_flags
& IFF_POINTOPOINT
) {
158 if(-1 == ioctl(sock
, SIOCGIFDSTADDR
, &req
)) goto err
;
159 head
->dst
.v4
= *(struct sockaddr_in
*)&req
.ifr_dstaddr
;
161 if(-1 == ioctl(sock
, SIOCGIFBRDADDR
, &req
)) goto err
;
162 head
->dst
.v4
= *(struct sockaddr_in
*)&req
.ifr_broadaddr
;
164 head
->ifa
.ifa_ifu
.ifu_dstaddr
= (struct sockaddr
*) &head
->dst
;
169 for(head
= list
; head
; head
=(stor
*)head
->next
) last
=head
;
171 dealwithipv6(&list
, &head
);
172 *ifap
= (struct ifaddrs
*) list
;
177 freeifaddrs((struct ifaddrs
*) list
);