1 /* 2 * Copyright (c) 2003 Bruce M. Simpson. 3 * All rights reserved 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "namespace.h" 31 #include <sys/param.h> 32 #include <sys/sysctl.h> 33 #include <sys/ioctl.h> 34 #include <sys/socket.h> 35 #include <net/if.h> 36 #include <net/if_dl.h> 37 #include <net/route.h> 38 39 #include <errno.h> 40 #include <ifaddrs.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include "un-namespace.h" 44 45 #define SALIGN (sizeof(long) - 1) 46 #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ 47 (SALIGN + 1)) 48 #define MAX_SYSCTL_TRY 5 49 #define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) 50 51 int 52 getifmaddrs(struct ifmaddrs **pif) 53 { 54 int icnt = 1; 55 int dcnt = 0; 56 int ntry = 0; 57 size_t len; 58 size_t needed; 59 int mib[6]; 60 int i; 61 char *buf; 62 char *data; 63 char *next; 64 char *p; 65 struct ifma_msghdr *ifmam; 66 struct ifmaddrs *ifa, *ift; 67 struct rt_msghdr *rtm; 68 struct sockaddr *sa; 69 70 mib[0] = CTL_NET; 71 mib[1] = PF_ROUTE; 72 mib[2] = 0; /* protocol */ 73 mib[3] = 0; /* wildcard address family */ 74 mib[4] = NET_RT_IFMALIST; 75 mib[5] = 0; /* no flags */ 76 do { 77 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 78 return (-1); 79 if ((buf = malloc(needed)) == NULL) 80 return (-1); 81 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 82 if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { 83 free(buf); 84 return (-1); 85 } 86 free(buf); 87 buf = NULL; 88 } 89 } while (buf == NULL); 90 91 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 92 rtm = (struct rt_msghdr *)(void *)next; 93 if (rtm->rtm_version != RTM_VERSION) 94 continue; 95 switch (rtm->rtm_type) { 96 case RTM_NEWMADDR: 97 ifmam = (struct ifma_msghdr *)(void *)rtm; 98 if ((ifmam->ifmam_addrs & RTA_IFA) == 0) 99 break; 100 icnt++; 101 p = (char *)(ifmam + 1); 102 for (i = 0; i < RTAX_MAX; i++) { 103 if ((RTA_MASKS & ifmam->ifmam_addrs & 104 (1 << i)) == 0) 105 continue; 106 sa = (struct sockaddr *)(void *)p; 107 len = SA_RLEN(sa); 108 dcnt += len; 109 p += len; 110 } 111 break; 112 } 113 } 114 115 data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt); 116 if (data == NULL) { 117 free(buf); 118 return (-1); 119 } 120 121 ifa = (struct ifmaddrs *)(void *)data; 122 data += sizeof(struct ifmaddrs) * icnt; 123 124 memset(ifa, 0, sizeof(struct ifmaddrs) * icnt); 125 ift = ifa; 126 127 for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { 128 rtm = (struct rt_msghdr *)(void *)next; 129 if (rtm->rtm_version != RTM_VERSION) 130 continue; 131 132 switch (rtm->rtm_type) { 133 case RTM_NEWMADDR: 134 ifmam = (struct ifma_msghdr *)(void *)rtm; 135 if ((ifmam->ifmam_addrs & RTA_IFA) == 0) 136 break; 137 138 p = (char *)(ifmam + 1); 139 for (i = 0; i < RTAX_MAX; i++) { 140 if ((RTA_MASKS & ifmam->ifmam_addrs & 141 (1 << i)) == 0) 142 continue; 143 sa = (struct sockaddr *)(void *)p; 144 len = SA_RLEN(sa); 145 switch (i) { 146 case RTAX_GATEWAY: 147 ift->ifma_lladdr = 148 (struct sockaddr *)(void *)data; 149 memcpy(data, p, len); 150 data += len; 151 break; 152 153 case RTAX_IFP: 154 ift->ifma_name = 155 (struct sockaddr *)(void *)data; 156 memcpy(data, p, len); 157 data += len; 158 break; 159 160 case RTAX_IFA: 161 ift->ifma_addr = 162 (struct sockaddr *)(void *)data; 163 memcpy(data, p, len); 164 data += len; 165 break; 166 167 default: 168 data += len; 169 break; 170 } 171 p += len; 172 } 173 ift->ifma_next = ift + 1; 174 ift = ift->ifma_next; 175 break; 176 } 177 } 178 179 free(buf); 180 181 if (ift > ifa) { 182 ift--; 183 ift->ifma_next = NULL; 184 *pif = ifa; 185 } else { 186 *pif = NULL; 187 free(ifa); 188 } 189 return (0); 190 } 191 192 void 193 freeifmaddrs(struct ifmaddrs *ifmp) 194 { 195 196 free(ifmp); 197 } 198