1 /* $KAME: if.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/capsicum.h> 36 #include <sys/ioctl.h> 37 #include <sys/queue.h> 38 #include <sys/socket.h> 39 #include <sys/sysctl.h> 40 41 #include <net/if.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 #include <net/if_dl.h> 45 #include <net/if_media.h> 46 #include <net/ethernet.h> 47 #include <netinet/in.h> 48 #include <netinet/icmp6.h> 49 50 #include <netinet6/in6_var.h> 51 #include <netinet6/nd6.h> 52 53 #include <capsicum_helpers.h> 54 #include <stdio.h> 55 #include <unistd.h> 56 #include <stdlib.h> 57 #include <syslog.h> 58 #include <string.h> 59 #include <fcntl.h> 60 #include <errno.h> 61 #include <limits.h> 62 #include <ifaddrs.h> 63 #include "rtsold.h" 64 65 static int ifsock; 66 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 67 68 int 69 ifinit(void) 70 { 71 cap_rights_t rights; 72 int sock; 73 74 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 75 if (sock < 0) { 76 warnmsg(LOG_ERR, __func__, "socket(): %s", 77 strerror(errno)); 78 return (-1); 79 } 80 if (caph_rights_limit(sock, cap_rights_init(&rights, CAP_IOCTL)) < 0) { 81 warnmsg(LOG_ERR, __func__, "caph_rights_limit(): %s", 82 strerror(errno)); 83 (void)close(sock); 84 return (-1); 85 } 86 ifsock = sock; 87 return (0); 88 } 89 90 int 91 interface_up(char *name) 92 { 93 struct ifreq ifr; 94 struct in6_ndireq nd; 95 int llflag; 96 int s; 97 98 memset(&ifr, 0, sizeof(ifr)); 99 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 100 memset(&nd, 0, sizeof(nd)); 101 strlcpy(nd.ifname, name, sizeof(nd.ifname)); 102 103 if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 104 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 105 strerror(errno)); 106 return (-1); 107 } 108 if (!(ifr.ifr_flags & IFF_UP)) { 109 ifr.ifr_flags |= IFF_UP; 110 if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 111 warnmsg(LOG_ERR, __func__, 112 "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 113 return (-1); 114 } 115 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 116 warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", 117 strerror(errno)); 118 return (-1); 119 } 120 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 121 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", 122 strerror(errno)); 123 close(s); 124 return (-1); 125 } 126 127 warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 128 129 if (nd.ndi.flags & ND6_IFF_IFDISABLED) { 130 if (Fflag) { 131 nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 132 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 133 warnmsg(LOG_WARNING, __func__, 134 "ioctl(SIOCSIFINFO_IN6): %s", 135 strerror(errno)); 136 close(s); 137 return (-1); 138 } 139 } else { 140 warnmsg(LOG_WARNING, __func__, 141 "%s is disabled.", name); 142 close(s); 143 return (-1); 144 } 145 } 146 if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { 147 if (Fflag) { 148 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 149 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 150 warnmsg(LOG_WARNING, __func__, 151 "ioctl(SIOCSIFINFO_IN6): %s", 152 strerror(errno)); 153 close(s); 154 return (-1); 155 } 156 } else { 157 warnmsg(LOG_WARNING, __func__, 158 "%s does not accept Router Advertisement.", name); 159 close(s); 160 return (-1); 161 } 162 } 163 close(s); 164 165 if (cap_llflags_get(capllflags, name, &llflag) != 0) { 166 warnmsg(LOG_WARNING, __func__, 167 "cap_llflags_get() failed, anyway I'll try"); 168 return (0); 169 } 170 171 if (!(llflag & IN6_IFF_NOTREADY)) { 172 warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 173 return (0); 174 } else { 175 if (llflag & IN6_IFF_TENTATIVE) { 176 warnmsg(LOG_DEBUG, __func__, "%s is tentative", 177 name); 178 return (IFS_TENTATIVE); 179 } 180 if (llflag & IN6_IFF_DUPLICATED) 181 warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 182 name); 183 return (-1); 184 } 185 } 186 187 int 188 interface_status(struct ifinfo *ifinfo) 189 { 190 char *ifname = ifinfo->ifname; 191 struct ifreq ifr; 192 struct ifmediareq ifmr; 193 194 /* get interface flags */ 195 memset(&ifr, 0, sizeof(ifr)); 196 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 197 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 198 warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 199 ifname, strerror(errno)); 200 return (-1); 201 } 202 /* 203 * if one of UP and RUNNING flags is dropped, 204 * the interface is not active. 205 */ 206 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 207 goto inactive; 208 /* Next, check carrier on the interface, if possible */ 209 if (!ifinfo->mediareqok) 210 goto active; 211 memset(&ifmr, 0, sizeof(ifmr)); 212 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 213 214 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 215 if (errno != EINVAL) { 216 warnmsg(LOG_DEBUG, __func__, 217 "ioctl(SIOCGIFMEDIA) on %s: %s", 218 ifname, strerror(errno)); 219 return(-1); 220 } 221 /* 222 * EINVAL simply means that the interface does not support 223 * the SIOCGIFMEDIA ioctl. We regard it alive. 224 */ 225 ifinfo->mediareqok = 0; 226 goto active; 227 } 228 229 if (ifmr.ifm_status & IFM_AVALID) { 230 switch (ifmr.ifm_active & IFM_NMASK) { 231 case IFM_ETHER: 232 case IFM_IEEE80211: 233 if (ifmr.ifm_status & IFM_ACTIVE) 234 goto active; 235 else 236 goto inactive; 237 break; 238 default: 239 goto inactive; 240 } 241 } 242 243 inactive: 244 return (0); 245 246 active: 247 return (1); 248 } 249 250 #define ROUNDUP(a, size) \ 251 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 252 253 #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 254 ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 255 sizeof(u_long)) : sizeof(u_long))) 256 #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 257 258 int 259 lladdropt_length(struct sockaddr_dl *sdl) 260 { 261 switch (sdl->sdl_type) { 262 case IFT_ETHER: 263 case IFT_L2VLAN: 264 return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 265 default: 266 return (0); 267 } 268 } 269 270 void 271 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 272 { 273 char *addr; 274 275 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 276 277 switch (sdl->sdl_type) { 278 case IFT_ETHER: 279 case IFT_L2VLAN: 280 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 281 addr = (char *)(ndopt + 1); 282 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 283 break; 284 default: 285 warnmsg(LOG_ERR, __func__, 286 "unsupported link type(%d)", sdl->sdl_type); 287 exit(1); 288 } 289 } 290 291 struct sockaddr_dl * 292 if_nametosdl(char *name) 293 { 294 int mib[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 295 char *buf, *next, *lim; 296 size_t len; 297 struct if_msghdr *ifm; 298 struct sockaddr *sa, *rti_info[RTAX_MAX]; 299 struct sockaddr_dl *sdl = NULL, *ret_sdl; 300 301 if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) 302 return(NULL); 303 if ((buf = malloc(len)) == NULL) 304 return(NULL); 305 if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) < 0) { 306 free(buf); 307 return (NULL); 308 } 309 310 lim = buf + len; 311 for (next = buf; next < lim; next += ifm->ifm_msglen) { 312 ifm = (struct if_msghdr *)(void *)next; 313 if (ifm->ifm_type == RTM_IFINFO) { 314 sa = (struct sockaddr *)(ifm + 1); 315 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 316 if ((sa = rti_info[RTAX_IFP]) != NULL) { 317 if (sa->sa_family == AF_LINK) { 318 sdl = (struct sockaddr_dl *)(void *)sa; 319 if (strlen(name) != sdl->sdl_nlen) 320 continue; /* not same len */ 321 if (strncmp(&sdl->sdl_data[0], 322 name, 323 sdl->sdl_nlen) == 0) { 324 break; 325 } 326 } 327 } 328 } 329 } 330 if (next >= lim) { 331 /* search failed */ 332 free(buf); 333 return (NULL); 334 } 335 336 if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 337 free(buf); 338 return (NULL); 339 } 340 memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 341 342 free(buf); 343 return (ret_sdl); 344 } 345 346 static void 347 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 348 { 349 int i; 350 351 for (i = 0; i < RTAX_MAX; i++) { 352 if (addrs & (1 << i)) { 353 rti_info[i] = sa; 354 NEXT_SA(sa); 355 } else 356 rti_info[i] = NULL; 357 } 358 } 359