1 1.28 christos /* $NetBSD: if.c,v 1.29 2021/03/23 18:16:53 christos Exp $ */ 2 1.18 rpaulo /* $KAME: if.c,v 1.36 2004/11/30 22:32:01 suz Exp $ */ 3 1.2 itojun 4 1.1 itojun /* 5 1.1 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 1.1 itojun * All rights reserved. 7 1.26 roy * 8 1.1 itojun * Redistribution and use in source and binary forms, with or without 9 1.1 itojun * modification, are permitted provided that the following conditions 10 1.1 itojun * are met: 11 1.1 itojun * 1. Redistributions of source code must retain the above copyright 12 1.1 itojun * notice, this list of conditions and the following disclaimer. 13 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 itojun * notice, this list of conditions and the following disclaimer in the 15 1.1 itojun * documentation and/or other materials provided with the distribution. 16 1.1 itojun * 3. Neither the name of the project nor the names of its contributors 17 1.1 itojun * may be used to endorse or promote products derived from this software 18 1.1 itojun * without specific prior written permission. 19 1.26 roy * 20 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 itojun * SUCH DAMAGE. 31 1.1 itojun */ 32 1.1 itojun 33 1.27 christos #define RTM_NAMES 34 1.1 itojun #include <sys/param.h> 35 1.22 roy #include <sys/queue.h> 36 1.1 itojun #include <sys/socket.h> 37 1.1 itojun #include <sys/sysctl.h> 38 1.1 itojun #include <sys/ioctl.h> 39 1.1 itojun #include <net/if.h> 40 1.1 itojun #include <net/if_types.h> 41 1.6 itojun #include <ifaddrs.h> 42 1.22 roy #ifdef __FreeBSD__ 43 1.22 roy #include <net/ethernet.h> 44 1.22 roy #else 45 1.1 itojun #include <net/if_ether.h> 46 1.22 roy #endif 47 1.1 itojun #include <net/route.h> 48 1.1 itojun #include <net/if_dl.h> 49 1.1 itojun #include <netinet/in.h> 50 1.1 itojun #include <netinet/icmp6.h> 51 1.1 itojun #include <unistd.h> 52 1.1 itojun #include <errno.h> 53 1.1 itojun #include <stdlib.h> 54 1.1 itojun #include <string.h> 55 1.1 itojun #include <syslog.h> 56 1.22 roy 57 1.1 itojun #include "rtadvd.h" 58 1.1 itojun #include "if.h" 59 1.25 christos #include "logit.h" 60 1.24 ozaki #include "prog_ops.h" 61 1.1 itojun 62 1.21 roy #ifndef RT_ROUNDUP 63 1.21 roy #define RT_ROUNDUP(a) \ 64 1.21 roy ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 65 1.21 roy #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len)) 66 1.21 roy #endif 67 1.1 itojun 68 1.1 itojun static void 69 1.27 christos get_rtaddrs(int addrs, const struct sockaddr *sa, 70 1.27 christos const struct sockaddr **rti_info) 71 1.1 itojun { 72 1.1 itojun int i; 73 1.26 roy 74 1.1 itojun for (i = 0; i < RTAX_MAX; i++) { 75 1.1 itojun if (addrs & (1 << i)) { 76 1.1 itojun rti_info[i] = sa; 77 1.21 roy RT_ADVANCE(sa, sa); 78 1.1 itojun } 79 1.1 itojun else 80 1.1 itojun rti_info[i] = NULL; 81 1.1 itojun } 82 1.1 itojun } 83 1.1 itojun 84 1.1 itojun struct sockaddr_dl * 85 1.20 christos if_nametosdl(const char *name) 86 1.1 itojun { 87 1.16 itojun struct ifaddrs *ifap, *ifa; 88 1.17 itojun struct sockaddr_dl *sdl; 89 1.1 itojun 90 1.16 itojun if (getifaddrs(&ifap) != 0) 91 1.15 itojun return (NULL); 92 1.1 itojun 93 1.16 itojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 94 1.16 itojun if (strcmp(ifa->ifa_name, name) != 0) 95 1.16 itojun continue; 96 1.16 itojun if (ifa->ifa_addr->sa_family != AF_LINK) 97 1.16 itojun continue; 98 1.16 itojun 99 1.16 itojun sdl = malloc(ifa->ifa_addr->sa_len); 100 1.16 itojun if (!sdl) 101 1.16 itojun continue; /*XXX*/ 102 1.16 itojun 103 1.16 itojun memcpy(sdl, ifa->ifa_addr, ifa->ifa_addr->sa_len); 104 1.16 itojun freeifaddrs(ifap); 105 1.16 itojun return (sdl); 106 1.1 itojun } 107 1.1 itojun 108 1.16 itojun freeifaddrs(ifap); 109 1.16 itojun return (NULL); 110 1.1 itojun } 111 1.1 itojun 112 1.1 itojun int 113 1.20 christos if_getmtu(const char *name) 114 1.1 itojun { 115 1.22 roy struct ifreq ifr; 116 1.22 roy int s, mtu; 117 1.8 itojun 118 1.24 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 119 1.22 roy return 0; 120 1.8 itojun 121 1.22 roy memset(&ifr, 0, sizeof(ifr)); 122 1.22 roy ifr.ifr_addr.sa_family = AF_INET6; 123 1.22 roy strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 124 1.24 ozaki if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1) 125 1.8 itojun mtu = ifr.ifr_mtu; 126 1.22 roy else 127 1.22 roy mtu = 0; 128 1.24 ozaki prog_close(s); 129 1.8 itojun 130 1.22 roy return mtu; 131 1.1 itojun } 132 1.1 itojun 133 1.1 itojun /* give interface index and its old flags, then new flags returned */ 134 1.1 itojun int 135 1.28 christos if_getflags(unsigned int ifindex, int oifflags) 136 1.1 itojun { 137 1.1 itojun struct ifreq ifr; 138 1.1 itojun int s; 139 1.1 itojun 140 1.24 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 141 1.29 christos logit(LOG_ERR, "%s: socket: %m", __func__); 142 1.1 itojun return (oifflags & ~IFF_UP); 143 1.1 itojun } 144 1.1 itojun 145 1.22 roy memset(&ifr, 0, sizeof(ifr)); 146 1.1 itojun if_indextoname(ifindex, ifr.ifr_name); 147 1.24 ozaki if (prog_ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { 148 1.29 christos logit(LOG_ERR, "%s: ioctl:SIOCGIFFLAGS: failed for %s", 149 1.14 itojun __func__, ifr.ifr_name); 150 1.24 ozaki prog_close(s); 151 1.1 itojun return (oifflags & ~IFF_UP); 152 1.1 itojun } 153 1.24 ozaki prog_close(s); 154 1.1 itojun return (ifr.ifr_flags); 155 1.1 itojun } 156 1.1 itojun 157 1.1 itojun #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 158 1.1 itojun int 159 1.1 itojun lladdropt_length(struct sockaddr_dl *sdl) 160 1.1 itojun { 161 1.12 itojun switch (sdl->sdl_type) { 162 1.11 itojun case IFT_ETHER: 163 1.13 itojun case IFT_FDDI: 164 1.11 itojun return(ROUNDUP8(ETHER_ADDR_LEN + 2)); 165 1.11 itojun default: 166 1.11 itojun return(0); 167 1.1 itojun } 168 1.1 itojun } 169 1.1 itojun 170 1.1 itojun void 171 1.1 itojun lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 172 1.1 itojun { 173 1.1 itojun char *addr; 174 1.1 itojun 175 1.1 itojun ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 176 1.1 itojun 177 1.12 itojun switch (sdl->sdl_type) { 178 1.11 itojun case IFT_ETHER: 179 1.13 itojun case IFT_FDDI: 180 1.11 itojun ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 181 1.11 itojun addr = (char *)(ndopt + 1); 182 1.11 itojun memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 183 1.11 itojun break; 184 1.11 itojun default: 185 1.29 christos logit(LOG_ERR, "%s: unsupported link type(%d)", 186 1.14 itojun __func__, sdl->sdl_type); 187 1.11 itojun exit(1); 188 1.1 itojun } 189 1.1 itojun 190 1.1 itojun return; 191 1.1 itojun } 192 1.1 itojun 193 1.1 itojun #define FILTER_MATCH(type, filter) ((0x1 << type) & filter) 194 1.27 christos #define SIN6(s) ((const struct sockaddr_in6 *)(s)) 195 1.27 christos #define SDL(s) ((const struct sockaddr_dl *)(s)) 196 1.1 itojun char * 197 1.28 christos get_next_msg(char *buf, char *lim, unsigned int ifindex, size_t *lenp, 198 1.28 christos int filter) 199 1.1 itojun { 200 1.1 itojun struct rt_msghdr *rtm; 201 1.1 itojun struct ifa_msghdr *ifam; 202 1.27 christos const struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; 203 1.1 itojun 204 1.1 itojun *lenp = 0; 205 1.1 itojun for (rtm = (struct rt_msghdr *)buf; 206 1.1 itojun rtm < (struct rt_msghdr *)lim; 207 1.1 itojun rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { 208 1.1 itojun /* just for safety */ 209 1.1 itojun if (!rtm->rtm_msglen) { 210 1.29 christos logit(LOG_WARNING, "%s: rtm_msglen is 0 " 211 1.14 itojun "(buf=%p lim=%p rtm=%p)", __func__, 212 1.1 itojun buf, lim, rtm); 213 1.1 itojun break; 214 1.1 itojun } 215 1.1 itojun if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { 216 1.1 itojun continue; 217 1.1 itojun } 218 1.1 itojun 219 1.1 itojun switch (rtm->rtm_type) { 220 1.1 itojun case RTM_GET: 221 1.1 itojun case RTM_ADD: 222 1.1 itojun case RTM_DELETE: 223 1.1 itojun /* address related checks */ 224 1.1 itojun sa = (struct sockaddr *)(rtm + 1); 225 1.1 itojun get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 226 1.1 itojun if ((dst = rti_info[RTAX_DST]) == NULL || 227 1.1 itojun dst->sa_family != AF_INET6) 228 1.1 itojun continue; 229 1.1 itojun 230 1.1 itojun if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || 231 1.1 itojun IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) 232 1.1 itojun continue; 233 1.1 itojun 234 1.1 itojun if ((gw = rti_info[RTAX_GATEWAY]) == NULL || 235 1.1 itojun gw->sa_family != AF_LINK) 236 1.1 itojun continue; 237 1.1 itojun if (ifindex && SDL(gw)->sdl_index != ifindex) 238 1.1 itojun continue; 239 1.1 itojun 240 1.1 itojun if (rti_info[RTAX_NETMASK] == NULL) 241 1.1 itojun continue; 242 1.1 itojun 243 1.1 itojun /* found */ 244 1.1 itojun *lenp = rtm->rtm_msglen; 245 1.1 itojun return (char *)rtm; 246 1.1 itojun /* NOTREACHED */ 247 1.1 itojun case RTM_NEWADDR: 248 1.1 itojun case RTM_DELADDR: 249 1.1 itojun ifam = (struct ifa_msghdr *)rtm; 250 1.1 itojun 251 1.1 itojun /* address related checks */ 252 1.1 itojun sa = (struct sockaddr *)(ifam + 1); 253 1.1 itojun get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 254 1.1 itojun if ((ifa = rti_info[RTAX_IFA]) == NULL || 255 1.1 itojun (ifa->sa_family != AF_INET && 256 1.1 itojun ifa->sa_family != AF_INET6)) 257 1.1 itojun continue; 258 1.1 itojun 259 1.1 itojun if (ifa->sa_family == AF_INET6 && 260 1.1 itojun (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || 261 1.1 itojun IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) 262 1.1 itojun continue; 263 1.1 itojun 264 1.1 itojun if (ifindex && ifam->ifam_index != ifindex) 265 1.1 itojun continue; 266 1.1 itojun 267 1.1 itojun /* found */ 268 1.1 itojun *lenp = ifam->ifam_msglen; 269 1.1 itojun return (char *)rtm; 270 1.1 itojun /* NOTREACHED */ 271 1.22 roy #ifdef RTM_IFANNOUNCE 272 1.22 roy case RTM_IFANNOUNCE: 273 1.22 roy #endif 274 1.1 itojun case RTM_IFINFO: 275 1.1 itojun /* found */ 276 1.1 itojun *lenp = rtm->rtm_msglen; 277 1.1 itojun return (char *)rtm; 278 1.1 itojun /* NOTREACHED */ 279 1.1 itojun } 280 1.1 itojun } 281 1.1 itojun 282 1.1 itojun return (char *)rtm; 283 1.1 itojun } 284 1.9 cgd #undef FILTER_MATCH 285 1.1 itojun 286 1.27 christos const struct in6_addr * 287 1.27 christos get_addr(const void *buf) 288 1.1 itojun { 289 1.27 christos const struct rt_msghdr *rtm = buf; 290 1.27 christos const struct sockaddr *sa, *rti_info[RTAX_MAX]; 291 1.1 itojun 292 1.27 christos sa = (const struct sockaddr *)(rtm + 1); 293 1.1 itojun get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 294 1.1 itojun 295 1.27 christos return &SIN6(rti_info[RTAX_DST])->sin6_addr; 296 1.1 itojun } 297 1.1 itojun 298 1.28 christos unsigned int 299 1.27 christos get_rtm_ifindex(const void *buf) 300 1.1 itojun { 301 1.27 christos const struct rt_msghdr *rtm = buf; 302 1.27 christos const struct sockaddr *sa, *rti_info[RTAX_MAX]; 303 1.1 itojun 304 1.27 christos sa = (const struct sockaddr *)(rtm + 1); 305 1.1 itojun get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 306 1.1 itojun 307 1.27 christos return SDL(rti_info[RTAX_GATEWAY])->sdl_index; 308 1.1 itojun } 309 1.1 itojun 310 1.28 christos unsigned int 311 1.27 christos get_ifm_ifindex(const void *buf) 312 1.1 itojun { 313 1.27 christos const struct if_msghdr *ifm = buf; 314 1.1 itojun 315 1.28 christos return ifm->ifm_index; 316 1.1 itojun } 317 1.1 itojun 318 1.28 christos unsigned int 319 1.27 christos get_ifam_ifindex(const void *buf) 320 1.1 itojun { 321 1.27 christos const struct ifa_msghdr *ifam = buf; 322 1.1 itojun 323 1.28 christos return ifam->ifam_index; 324 1.1 itojun } 325 1.1 itojun 326 1.1 itojun int 327 1.27 christos get_ifm_flags(const void *buf) 328 1.1 itojun { 329 1.27 christos const struct if_msghdr *ifm = buf; 330 1.1 itojun 331 1.27 christos return ifm->ifm_flags; 332 1.1 itojun } 333 1.1 itojun 334 1.22 roy #ifdef RTM_IFANNOUNCE 335 1.28 christos unsigned int 336 1.27 christos get_ifan_ifindex(const void *buf) 337 1.22 roy { 338 1.27 christos const struct if_announcemsghdr *ifan = buf; 339 1.22 roy 340 1.28 christos return ifan->ifan_index; 341 1.22 roy } 342 1.22 roy 343 1.22 roy int 344 1.27 christos get_ifan_what(const void *buf) 345 1.22 roy { 346 1.27 christos const struct if_announcemsghdr *ifan = buf; 347 1.22 roy 348 1.27 christos return (int)ifan->ifan_what; 349 1.22 roy } 350 1.22 roy #endif 351 1.22 roy 352 1.1 itojun int 353 1.27 christos get_prefixlen(const void *buf) 354 1.1 itojun { 355 1.27 christos const struct rt_msghdr *rtm = buf; 356 1.27 christos const struct sockaddr *sa, *rti_info[RTAX_MAX]; 357 1.27 christos const unsigned char *p, *lim; 358 1.26 roy 359 1.27 christos sa = (const struct sockaddr *)(rtm + 1); 360 1.1 itojun get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 361 1.1 itojun sa = rti_info[RTAX_NETMASK]; 362 1.1 itojun 363 1.27 christos p = (const unsigned char *)(&SIN6(sa)->sin6_addr); 364 1.27 christos lim = (const unsigned char *)sa + sa->sa_len; 365 1.8 itojun return prefixlen(p, lim); 366 1.8 itojun } 367 1.8 itojun 368 1.8 itojun int 369 1.19 roy prefixlen(const unsigned char *p, const unsigned char *lim) 370 1.8 itojun { 371 1.8 itojun int masklen; 372 1.8 itojun 373 1.1 itojun for (masklen = 0; p < lim; p++) { 374 1.1 itojun switch (*p) { 375 1.1 itojun case 0xff: 376 1.1 itojun masklen += 8; 377 1.1 itojun break; 378 1.1 itojun case 0xfe: 379 1.1 itojun masklen += 7; 380 1.1 itojun break; 381 1.1 itojun case 0xfc: 382 1.1 itojun masklen += 6; 383 1.1 itojun break; 384 1.1 itojun case 0xf8: 385 1.1 itojun masklen += 5; 386 1.1 itojun break; 387 1.1 itojun case 0xf0: 388 1.1 itojun masklen += 4; 389 1.1 itojun break; 390 1.1 itojun case 0xe0: 391 1.1 itojun masklen += 3; 392 1.1 itojun break; 393 1.1 itojun case 0xc0: 394 1.1 itojun masklen += 2; 395 1.1 itojun break; 396 1.1 itojun case 0x80: 397 1.1 itojun masklen += 1; 398 1.1 itojun break; 399 1.1 itojun case 0x00: 400 1.1 itojun break; 401 1.1 itojun default: 402 1.27 christos return -1; 403 1.1 itojun } 404 1.1 itojun } 405 1.1 itojun 406 1.27 christos return masklen; 407 1.1 itojun } 408 1.1 itojun 409 1.1 itojun int 410 1.27 christos rtmsg_type(const void *buf) 411 1.1 itojun { 412 1.27 christos const struct rt_msghdr *rtm = buf; 413 1.1 itojun 414 1.27 christos return rtm->rtm_type; 415 1.27 christos } 416 1.27 christos 417 1.27 christos const char * 418 1.27 christos rtmsg_typestr(const void *buf) 419 1.27 christos { 420 1.27 christos const struct rt_msghdr *rtm = buf; 421 1.27 christos 422 1.27 christos return rtm->rtm_type < __arraycount(rtm_names) 423 1.27 christos ? rtm_names[rtm->rtm_type] : "*unknown*"; 424 1.1 itojun } 425 1.1 itojun 426 1.1 itojun int 427 1.27 christos rtmsg_len(const void *buf) 428 1.1 itojun { 429 1.27 christos const struct rt_msghdr *rtm = buf; 430 1.1 itojun 431 1.27 christos return rtm->rtm_msglen; 432 1.1 itojun } 433