2020#include "libc/calls/calls.h"
2121#include "libc/calls/syscall-sysv.internal.h"
2222#include "libc/dce.h"
23+ #include "libc/intrin/newbie.h"
2324#include "libc/limits.h"
2425#include "libc/mem/mem.h"
2526#include "libc/sock/sock.h"
3435#include "libc/sysv/consts/sio.h"
3536#include "libc/sysv/consts/sock.h"
3637
38+ #define SIOCGIFAFLAG_IN6 3240126793 // bsd
39+ #define SIOCGIFNETMASK_IN6 3240126757 // bsd
40+
3741struct IfAddr {
3842 struct ifaddrs ifaddrs ;
3943 char name [IFNAMSIZ ];
@@ -142,27 +146,27 @@ static int getifaddrs_linux_ip6(struct ifconf *conf) {
142146 * @see tool/viz/getifaddrs.c for example code
143147 */
144148int getifaddrs (struct ifaddrs * * out_ifpp ) {
145- // printf("%d\n", sizeof(struct ifreq));
146- int rc = -1 ;
147- int fd ;
149+ int rc = 0 ;
150+ int fd , fd6 = -1 ;
148151 if ((fd = socket (AF_INET , SOCK_DGRAM | SOCK_CLOEXEC , 0 )) != -1 ) {
149152 char * data ;
150153 size_t size ;
151154 if ((data = malloc ((size = 16384 )))) {
152- struct ifconf conf ;
155+ struct ifconf conf , confl6 ;
153156 conf .ifc_buf = data ;
154157 conf .ifc_len = size ;
155158 if (!ioctl (fd , SIOCGIFCONF , & conf )) {
159+ confl6 .ifc_buf = data + conf .ifc_len ;
160+ confl6 .ifc_len = size - conf .ifc_len ;
156161 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 ;
162+ rc = getifaddrs_linux_ip6 (& confl6 );
163163 }
164+ if (rc )
165+ return rc ;
166+ conf .ifc_len += confl6 .ifc_len ;
164167
165168 struct ifaddrs * res = 0 ;
169+ rc = -1 ;
166170 for (struct ifreq * ifr = (struct ifreq * )data ;
167171 (char * )ifr < data + conf .ifc_len ; ++ ifr ) {
168172 uint16_t family = ifr -> ifr_addr .sa_family ;
@@ -207,9 +211,10 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
207211 addr6 -> ifaddrs .ifa_broadaddr = (struct sockaddr * )& addr6 -> bstaddr ;
208212 addr6 -> ifaddrs .ifa_data = (void * )& addr6 -> info ;
209213
210- memcpy (& addr6 -> name , & ifr -> ifr_name , IFNAMSIZ );
211- addr6 -> info .addr_flags = ifr -> ifr6_flags ;
212214 addr6 -> info .addr_scope = ifr -> ifr6_scope ;
215+ addr6 -> info .addr_flags = ifr -> ifr6_flags ;
216+
217+ memcpy (& addr6 -> name , & ifr -> ifr_name , IFNAMSIZ );
213218
214219 addr6 -> addr .sin6_family = AF_INET6 ;
215220 addr6 -> addr .sin6_port = 0 ;
@@ -222,10 +227,33 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
222227 addr6 -> netmask .sin6_port = 0 ;
223228 addr6 -> netmask .sin6_flowinfo = 0 ;
224229 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 );
230+
231+ if (IsBsd ()) { // on bsd we miss prefixlen and addr flags
232+ if (fd6 == -1 ) {
233+ fd6 = socket (AF_INET6 , SOCK_DGRAM | SOCK_CLOEXEC , 0 );
234+ }
235+ uint8_t in6req [288 ]; // BSD struct in6_ifreq
236+ bzero (& in6req , sizeof (in6req ));
237+ memcpy (& in6req , & ifr -> ifr_name , IFNAMSIZ );
238+ in6req [16 ] = 28 ; // sin6_len sizeof(struct sockaddr_in6_bsd)
239+ in6req [17 ] = AF_INET6 ; // sin6_family
240+ memcpy (& in6req [24 ], & addr6 -> addr .sin6_addr ,
241+ sizeof (struct in6_addr )); // sin6_addr
242+ if (!ioctl (fd6 , SIOCGIFAFLAG_IN6 , & in6req )) {
243+ addr6 -> info .addr_flags =
244+ * (int * )(& in6req [16 ]); // ifru_flags6
245+ }
246+ in6req [16 ] = 28 ; // sin6_len
247+ in6req [17 ] = AF_INET6 ; // sin6_family
248+ if (!ioctl (fd6 , SIOCGIFNETMASK_IN6 , & in6req )) {
249+ memcpy (& (addr6 -> netmask .sin6_addr ), & in6req [24 ],
250+ sizeof (struct in6_addr ));
251+ }
252+ } else {
253+ int prefixlen = ifr -> ifr6_prefixlen ;
254+ * ((uint128_t * )& (addr6 -> netmask .sin6_addr )) = htobe128 (
255+ prefixlen == 0 ? 0 : (UINT128_MAX << (128 - prefixlen )));
256+ }
229257
230258 if (!ioctl (fd , SIOCGIFFLAGS , ifr )) {
231259 addr6 -> ifaddrs .ifa_flags = ifr -> ifr_flags ;
@@ -243,6 +271,9 @@ int getifaddrs(struct ifaddrs **out_ifpp) {
243271 free (data );
244272 }
245273 close (fd );
274+ if (fd6 != -1 ) {
275+ close (fd6 );
276+ }
246277 }
247278 return rc ;
248279}
0 commit comments