1818╚─────────────────────────────────────────────────────────────────────────────*/
1919#include "libc/sock/ifaddrs.h"
2020#include "libc/calls/calls.h"
21+ #include "libc/calls/syscall-sysv.internal.h"
22+ #include "libc/dce.h"
23+ #include "libc/limits.h"
2124#include "libc/mem/mem.h"
2225#include "libc/sock/sock.h"
2326#include "libc/sock/struct/ifconf.h"
2427#include "libc/sock/struct/ifreq.h"
28+ #include "libc/sock/struct/sockaddr6.h"
29+ #include "libc/stdio/stdio.h"
2530#include "libc/str/str.h"
2631#include "libc/sysv/consts/af.h"
2732#include "libc/sysv/consts/iff.h"
33+ #include "libc/sysv/consts/o.h"
2834#include "libc/sysv/consts/sio.h"
2935#include "libc/sysv/consts/sock.h"
3036
@@ -36,6 +42,20 @@ struct IfAddr {
3642 struct sockaddr_in bstaddr ;
3743};
3844
45+ struct IfAddr6Info {
46+ int addr_scope ;
47+ int addr_flags ;
48+ };
49+
50+ struct IfAddr6 {
51+ struct ifaddrs ifaddrs ;
52+ char name [IFNAMSIZ ];
53+ struct sockaddr_in6 addr ;
54+ struct sockaddr_in6 netmask ;
55+ struct sockaddr_in6 bstaddr ; // unused
56+ struct IfAddr6Info info ;
57+ };
58+
3959/**
4060 * Frees network interface address list.
4161 */
@@ -48,13 +68,81 @@ void freeifaddrs(struct ifaddrs *ifp) {
4868 }
4969}
5070
71+ // hex repr to network order int
72+ static uint128_t hex2no (const char * str ) {
73+ uint128_t res = 0 ;
74+ const int max_quads = sizeof (uint128_t ) * 2 ;
75+ int i = 0 ;
76+ while ((i < max_quads ) && str [i ]) {
77+ uint8_t acc = (((str [i ] & 0xF ) + (str [i ] >> 6 )) | ((str [i ] >> 3 ) & 0x8 ));
78+ acc = acc << 4 ;
79+ i += 1 ;
80+ if (str [i ]) {
81+ acc = acc | (((str [i ] & 0xF ) + (str [i ] >> 6 )) | ((str [i ] >> 3 ) & 0x8 ));
82+ i += 1 ;
83+ }
84+ res = (res >> 8 ) | (((uint128_t )acc ) << ((sizeof (uint128_t ) - 1 ) * 8 ));
85+ }
86+ res = res >> ((max_quads - i ) * 4 );
87+ return res ;
88+ }
89+
90+ /**
91+ * Gets network interface IPv6 address list on linux.
92+ *
93+ * @return 0 on success, or -1 w/ errno
94+ */
95+ static int getifaddrs_linux_ip6 (struct ifconf * conf ) {
96+ int fd ;
97+ int n = 0 ;
98+ struct ifreq * ifreq = conf -> ifc_req ;
99+ const int bufsz = 44 + IFNAMSIZ + 1 ;
100+ char buf [bufsz + 1 ]; // one line max size
101+ if ((fd = sys_openat (0 , "/proc/net/if_inet6" , O_RDONLY , 0 )) == -1 ) {
102+ return -1 ;
103+ }
104+
105+ while ((n = sys_read (fd , & buf [n ], bufsz - n )) &&
106+ ((char * )ifreq < (conf -> ifc_buf + conf -> ifc_len ))) {
107+ // flags linux include/uapi/linux/if_addr.h:44
108+ // scope linux include/net/ipv6.h:L99
109+
110+ // *addr, *index, *plen, *scope, *flags, *ifname
111+ char * s [] = {& buf [0 ], & buf [33 ], & buf [36 ], & buf [39 ], & buf [42 ], & buf [45 ]};
112+ int ifnamelen = 0 ;
113+ while (* s [5 ] == ' ' ) {
114+ ++ s [5 ];
115+ }
116+ while (s [5 ][ifnamelen ] > '\n' ) {
117+ ++ ifnamelen ;
118+ }
119+ buf [32 ] = buf [35 ] = buf [38 ] = buf [41 ] = buf [44 ] = s [5 ][ifnamelen ] = '\0' ;
120+ bzero (ifreq , sizeof (* ifreq ));
121+ ifreq -> ifr_addr .sa_family = AF_INET6 ;
122+ memcpy (& ifreq -> ifr_name , s [5 ], ifnamelen );
123+ * ((uint128_t * )& ifreq -> ifr6_addr ) = hex2no (s [0 ]);
124+ ifreq -> ifr6_ifindex = hex2no (s [1 ]);
125+ ifreq -> ifr6_prefixlen = hex2no (s [2 ]);
126+ ifreq -> ifr6_scope = hex2no (s [3 ]);
127+ ifreq -> ifr6_flags = hex2no (s [4 ]);
128+ ++ ifreq ;
129+ int tlen = & s [5 ][ifnamelen ] - & buf [0 ] + 1 ;
130+ n = bufsz - tlen ;
131+ memcpy (& buf , & buf [tlen ], n );
132+ }
133+
134+ conf -> ifc_len = (char * )ifreq - conf -> ifc_buf ;
135+ return sys_close (fd );
136+ }
137+
51138/**
52139 * Gets network interface address list.
53140 *
54141 * @return 0 on success, or -1 w/ errno
55142 * @see tool/viz/getifaddrs.c for example code
56143 */
57144int getifaddrs (struct ifaddrs * * out_ifpp ) {
145+ // printf("%d\n", sizeof(struct ifreq));
58146 int rc = -1 ;
59147 int fd ;
60148 if ((fd = socket (AF_INET , SOCK_DGRAM | SOCK_CLOEXEC , 0 )) != -1 ) {
@@ -65,42 +153,88 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
65153 conf .ifc_buf = data ;
66154 conf .ifc_len = size ;
67155 if (!ioctl (fd , SIOCGIFCONF , & conf )) {
156+ if (IsLinux ()) {
157+ struct ifconf confl6 ;
158+ confl6 .ifc_buf = data + conf .ifc_len ;
159+ confl6 .ifc_len = size - conf .ifc_len ;
160+ if ((rc = getifaddrs_linux_ip6 (& confl6 )))
161+ return rc ;
162+ conf .ifc_len += confl6 .ifc_len ;
163+ }
164+
68165 struct ifaddrs * res = 0 ;
69166 for (struct ifreq * ifr = (struct ifreq * )data ;
70167 (char * )ifr < data + conf .ifc_len ; ++ ifr ) {
71- if (ifr -> ifr_addr .sa_family != AF_INET ) {
72- continue ; // TODO(jart): IPv6 support
73- }
74- struct IfAddr * addr ;
75- if ((addr = calloc (1 , sizeof (struct IfAddr )))) {
76- memcpy (addr -> name , ifr -> ifr_name , IFNAMSIZ );
77- addr -> ifaddrs .ifa_name = addr -> name ;
78- memcpy (& addr -> addr , & ifr -> ifr_addr , sizeof (struct sockaddr_in ));
79- addr -> ifaddrs .ifa_addr = (struct sockaddr * )& addr -> addr ;
80- addr -> ifaddrs .ifa_netmask = (struct sockaddr * )& addr -> netmask ;
81- if (!ioctl (fd , SIOCGIFFLAGS , ifr )) {
82- addr -> ifaddrs .ifa_flags = ifr -> ifr_flags ;
83- }
84- if (!ioctl (fd , SIOCGIFNETMASK , ifr )) {
85- memcpy (& addr -> netmask , & ifr -> ifr_addr ,
86- sizeof (struct sockaddr_in ));
168+ uint16_t family = ifr -> ifr_addr .sa_family ;
169+ if (family == AF_INET ) {
170+ struct IfAddr * addr ;
171+ if ((addr = calloc (1 , sizeof (struct IfAddr )))) {
172+ memcpy (addr -> name , ifr -> ifr_name , IFNAMSIZ );
173+ addr -> ifaddrs .ifa_name = addr -> name ;
174+ memcpy (& addr -> addr , & ifr -> ifr_addr , sizeof (struct sockaddr_in ));
175+ addr -> ifaddrs .ifa_addr = (struct sockaddr * )& addr -> addr ;
176+ addr -> ifaddrs .ifa_netmask = (struct sockaddr * )& addr -> netmask ;
177+ if (!ioctl (fd , SIOCGIFFLAGS , ifr )) {
178+ addr -> ifaddrs .ifa_flags = ifr -> ifr_flags ;
179+ }
180+ if (!ioctl (fd , SIOCGIFNETMASK , ifr )) {
181+ memcpy (& addr -> netmask , & ifr -> ifr_addr ,
182+ sizeof (struct sockaddr_in ));
183+ }
184+ unsigned long op ;
185+ if (addr -> ifaddrs .ifa_flags & IFF_BROADCAST ) {
186+ op = SIOCGIFBRDADDR ;
187+ } else if (addr -> ifaddrs .ifa_flags & IFF_POINTOPOINT ) {
188+ op = SIOCGIFDSTADDR ;
189+ } else {
190+ op = 0 ;
191+ }
192+ if (op && !ioctl (fd , op , ifr )) {
193+ memcpy (& addr -> bstaddr , & ifr -> ifr_addr ,
194+ sizeof (struct sockaddr_in ));
195+ addr -> ifaddrs .ifa_broadaddr = // is union'd w/ ifu_dstaddr
196+ (struct sockaddr * )& addr -> bstaddr ;
197+ }
198+ addr -> ifaddrs .ifa_next = res ;
199+ res = (struct ifaddrs * )addr ;
87200 }
88- unsigned long op ;
89- if (addr -> ifaddrs .ifa_flags & IFF_BROADCAST ) {
90- op = SIOCGIFBRDADDR ;
91- } else if (addr -> ifaddrs .ifa_flags & IFF_POINTOPOINT ) {
92- op = SIOCGIFDSTADDR ;
93- } else {
94- op = 0 ;
95- }
96- if (op && !ioctl (fd , op , ifr )) {
97- memcpy (& addr -> bstaddr , & ifr -> ifr_addr ,
98- sizeof (struct sockaddr_in ));
99- addr -> ifaddrs .ifa_broadaddr = // is union'd w/ ifu_dstaddr
100- (struct sockaddr * )& addr -> bstaddr ;
201+ } else if (family == AF_INET6 ) {
202+ struct IfAddr6 * addr6 ;
203+ if ((addr6 = calloc (1 , sizeof (struct IfAddr6 )))) {
204+ addr6 -> ifaddrs .ifa_name = addr6 -> name ;
205+ addr6 -> ifaddrs .ifa_addr = (struct sockaddr * )& addr6 -> addr ;
206+ addr6 -> ifaddrs .ifa_netmask = (struct sockaddr * )& addr6 -> netmask ;
207+ addr6 -> ifaddrs .ifa_broadaddr = (struct sockaddr * )& addr6 -> bstaddr ;
208+ addr6 -> ifaddrs .ifa_data = (void * )& addr6 -> info ;
209+
210+ memcpy (& addr6 -> name , & ifr -> ifr_name , IFNAMSIZ );
211+ addr6 -> info .addr_flags = ifr -> ifr6_flags ;
212+ addr6 -> info .addr_scope = ifr -> ifr6_scope ;
213+
214+ addr6 -> addr .sin6_family = AF_INET6 ;
215+ addr6 -> addr .sin6_port = 0 ;
216+ addr6 -> addr .sin6_flowinfo = 0 ;
217+ addr6 -> addr .sin6_scope_id = ifr -> ifr6_ifindex ;
218+ memcpy (& addr6 -> addr .sin6_addr , & ifr -> ifr6_addr ,
219+ sizeof (struct in6_addr ));
220+
221+ addr6 -> netmask .sin6_family = AF_INET6 ;
222+ addr6 -> netmask .sin6_port = 0 ;
223+ addr6 -> netmask .sin6_flowinfo = 0 ;
224+ addr6 -> addr .sin6_scope_id = ifr -> ifr6_ifindex ;
225+ memcpy (& addr6 -> netmask .sin6_addr , & ifr -> ifr6_addr ,
226+ sizeof (struct in6_addr ));
227+ * ((uint128_t * )& (addr6 -> netmask .sin6_addr )) &=
228+ (UINT128_MAX >> ifr -> ifr6_prefixlen );
229+
230+ if (!ioctl (fd , SIOCGIFFLAGS , ifr )) {
231+ addr6 -> ifaddrs .ifa_flags = ifr -> ifr_flags ;
232+ }
233+
234+ bzero (& addr6 -> bstaddr , sizeof (struct sockaddr_in6 ));
235+ addr6 -> ifaddrs .ifa_next = res ;
236+ res = (struct ifaddrs * )addr6 ;
101237 }
102- addr -> ifaddrs .ifa_next = res ;
103- res = (struct ifaddrs * )addr ;
104238 }
105239 }
106240 * out_ifpp = res ;
0 commit comments