1 /* $OpenBSD: getifaddrs.c,v 1.14 2021/11/29 03:20:37 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1999 5 * Berkeley Software Design, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp 26 */ 27 28 #include <sys/param.h> /* ALIGN ALIGNBYTES */ 29 #include <sys/types.h> 30 #include <sys/ioctl.h> 31 #include <sys/socket.h> 32 #include <net/if.h> 33 #include <net/route.h> 34 #include <sys/sysctl.h> 35 #include <net/if_dl.h> 36 37 #include <errno.h> 38 #include <ifaddrs.h> 39 #include <stddef.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #define SALIGN (sizeof(long) - 1) 45 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) 46 47 int 48 getifaddrs(struct ifaddrs **pif) 49 { 50 int icnt = 1; 51 int dcnt = 0; 52 int ncnt = 0; 53 int mib[6]; 54 size_t needed; 55 char *buf = NULL, *bufp; 56 char *next; 57 struct ifaddrs *cif = 0; 58 char *p, *p0; 59 struct rt_msghdr *rtm; 60 struct if_msghdr *ifm; 61 struct ifa_msghdr *ifam; 62 struct sockaddr_dl *dl; 63 struct sockaddr *sa; 64 u_short index = 0; 65 size_t len, alen, dlen; 66 struct ifaddrs *ifa, *ift; 67 int i; 68 char *data; 69 char *names; 70 71 mib[0] = CTL_NET; 72 mib[1] = PF_ROUTE; 73 mib[2] = 0; /* protocol */ 74 mib[3] = 0; /* wildcard address family */ 75 mib[4] = NET_RT_IFLIST; 76 mib[5] = 0; /* no flags */ 77 while (1) { 78 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) { 79 free(buf); 80 return (-1); 81 } 82 if (needed == 0) 83 break; 84 if ((bufp = realloc(buf, needed)) == NULL) { 85 free(buf); 86 return (-1); 87 } 88 buf = bufp; 89 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { 90 if (errno == ENOMEM) 91 continue; 92 free(buf); 93 return (-1); 94 } 95 break; 96 } 97 98 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 99 rtm = (struct rt_msghdr *)next; 100 if (rtm->rtm_version != RTM_VERSION) 101 continue; 102 switch (rtm->rtm_type) { 103 case RTM_IFINFO: 104 ifm = (struct if_msghdr *)rtm; 105 if (ifm->ifm_addrs & RTA_IFP) { 106 index = ifm->ifm_index; 107 ++icnt; 108 dl = (struct sockaddr_dl *)(next + 109 rtm->rtm_hdrlen); 110 dcnt += SA_RLEN((struct sockaddr *)dl) + 111 ALIGNBYTES; 112 dcnt += sizeof(ifm->ifm_data); 113 ncnt += dl->sdl_nlen + 1; 114 } else 115 index = 0; 116 break; 117 118 case RTM_NEWADDR: 119 ifam = (struct ifa_msghdr *)rtm; 120 if (index && ifam->ifam_index != index) 121 abort(); /* XXX abort illegal in library */ 122 123 #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) 124 if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) 125 break; 126 p = next + rtm->rtm_hdrlen; 127 ++icnt; 128 /* Scan to look for length of address */ 129 alen = 0; 130 for (p0 = p, i = 0; i < RTAX_MAX; i++) { 131 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 132 == 0) 133 continue; 134 sa = (struct sockaddr *)p; 135 len = SA_RLEN(sa); 136 if (i == RTAX_IFA) { 137 alen = len; 138 break; 139 } 140 p += len; 141 } 142 for (p = p0, i = 0; i < RTAX_MAX; i++) { 143 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 144 == 0) 145 continue; 146 sa = (struct sockaddr *)p; 147 len = SA_RLEN(sa); 148 if (i == RTAX_NETMASK && sa->sa_len == 0) 149 dcnt += alen; 150 else 151 dcnt += len; 152 p += len; 153 } 154 break; 155 } 156 } 157 158 if (icnt + dcnt + ncnt == 1) { 159 *pif = NULL; 160 free(buf); 161 return (0); 162 } 163 data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); 164 if (data == NULL) { 165 free(buf); 166 return(-1); 167 } 168 169 ifa = (struct ifaddrs *)data; 170 data += sizeof(struct ifaddrs) * icnt; 171 names = data + dcnt; 172 173 memset(ifa, 0, sizeof(struct ifaddrs) * icnt); 174 ift = ifa; 175 176 index = 0; 177 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 178 rtm = (struct rt_msghdr *)next; 179 if (rtm->rtm_version != RTM_VERSION) 180 continue; 181 switch (rtm->rtm_type) { 182 case RTM_IFINFO: 183 ifm = (struct if_msghdr *)rtm; 184 if (ifm->ifm_addrs & RTA_IFP) { 185 index = ifm->ifm_index; 186 dl = (struct sockaddr_dl *)(next + 187 rtm->rtm_hdrlen); 188 189 cif = ift; 190 ift->ifa_name = names; 191 ift->ifa_flags = (int)ifm->ifm_flags; 192 memcpy(names, dl->sdl_data, dl->sdl_nlen); 193 names[dl->sdl_nlen] = 0; 194 names += dl->sdl_nlen + 1; 195 196 ift->ifa_addr = (struct sockaddr *)data; 197 memcpy(data, dl, 198 ((struct sockaddr *)dl)->sa_len); 199 data += SA_RLEN((struct sockaddr *)dl); 200 201 /* ifm_data needs to be aligned */ 202 ift->ifa_data = data = (void *)ALIGN(data); 203 dlen = rtm->rtm_hdrlen - 204 offsetof(struct if_msghdr, ifm_data); 205 if (dlen > sizeof(ifm->ifm_data)) 206 dlen = sizeof(ifm->ifm_data); 207 memcpy(data, &ifm->ifm_data, dlen); 208 data += sizeof(ifm->ifm_data); 209 210 ift = (ift->ifa_next = ift + 1); 211 } else 212 index = 0; 213 break; 214 215 case RTM_NEWADDR: 216 ifam = (struct ifa_msghdr *)rtm; 217 if (index && ifam->ifam_index != index) 218 abort(); /* XXX abort illegal in library */ 219 220 if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) 221 break; 222 ift->ifa_name = cif->ifa_name; 223 ift->ifa_flags = cif->ifa_flags; 224 ift->ifa_data = NULL; 225 p = next + rtm->rtm_hdrlen; 226 /* Scan to look for length of address */ 227 alen = 0; 228 for (p0 = p, i = 0; i < RTAX_MAX; i++) { 229 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 230 == 0) 231 continue; 232 sa = (struct sockaddr *)p; 233 len = SA_RLEN(sa); 234 if (i == RTAX_IFA) { 235 alen = len; 236 break; 237 } 238 p += len; 239 } 240 for (p = p0, i = 0; i < RTAX_MAX; i++) { 241 if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) 242 == 0) 243 continue; 244 sa = (struct sockaddr *)p; 245 len = SA_RLEN(sa); 246 switch (i) { 247 case RTAX_IFA: 248 ift->ifa_addr = (struct sockaddr *)data; 249 memcpy(data, p, len); 250 data += len; 251 break; 252 253 case RTAX_NETMASK: 254 ift->ifa_netmask = 255 (struct sockaddr *)data; 256 if (sa->sa_len == 0) { 257 memset(data, 0, alen); 258 data += alen; 259 break; 260 } 261 memcpy(data, p, len); 262 data += len; 263 break; 264 265 case RTAX_BRD: 266 ift->ifa_broadaddr = 267 (struct sockaddr *)data; 268 memcpy(data, p, len); 269 data += len; 270 break; 271 } 272 p += len; 273 } 274 275 276 ift = (ift->ifa_next = ift + 1); 277 break; 278 } 279 } 280 281 free(buf); 282 if (--ift >= ifa) { 283 ift->ifa_next = NULL; 284 *pif = ifa; 285 } else { 286 *pif = NULL; 287 free(ifa); 288 } 289 return (0); 290 } 291 DEF_WEAK(getifaddrs); 292 293 void 294 freeifaddrs(struct ifaddrs *ifp) 295 { 296 free(ifp); 297 } 298 DEF_WEAK(freeifaddrs); 299