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