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 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/capsicum.h> 38 #include <sys/ioctl.h> 39 #include <sys/queue.h> 40 #include <sys/socket.h> 41 #include <sys/sysctl.h> 42 43 #include <net/if.h> 44 #include <net/if_types.h> 45 #include <net/route.h> 46 #include <net/if_dl.h> 47 #include <net/if_media.h> 48 #include <net/ethernet.h> 49 #include <netinet/in.h> 50 #include <netinet/icmp6.h> 51 52 #include <netinet6/in6_var.h> 53 #include <netinet6/nd6.h> 54 55 #include <capsicum_helpers.h> 56 #include <stdio.h> 57 #include <unistd.h> 58 #include <stdlib.h> 59 #include <syslog.h> 60 #include <string.h> 61 #include <fcntl.h> 62 #include <errno.h> 63 #include <limits.h> 64 #include <ifaddrs.h> 65 #include "rtsold.h" 66 67 static int ifsock; 68 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 69 70 int 71 ifinit(void) 72 { 73 cap_rights_t rights; 74 int sock; 75 76 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 77 if (sock < 0) { 78 warnmsg(LOG_ERR, __func__, "socket(): %s", 79 strerror(errno)); 80 return (-1); 81 } 82 if (caph_rights_limit(sock, cap_rights_init(&rights, CAP_IOCTL)) < 0) { 83 warnmsg(LOG_ERR, __func__, "caph_rights_limit(): %s", 84 strerror(errno)); 85 (void)close(sock); 86 return (-1); 87 } 88 ifsock = sock; 89 return (0); 90 } 91 92 int 93 interface_up(char *name) 94 { 95 struct ifreq ifr; 96 struct in6_ndireq nd; 97 int llflag; 98 int s; 99 100 memset(&ifr, 0, sizeof(ifr)); 101 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 102 memset(&nd, 0, sizeof(nd)); 103 strlcpy(nd.ifname, name, sizeof(nd.ifname)); 104 105 if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 106 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s", 107 strerror(errno)); 108 return (-1); 109 } 110 if (!(ifr.ifr_flags & IFF_UP)) { 111 ifr.ifr_flags |= IFF_UP; 112 if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) 113 warnmsg(LOG_ERR, __func__, 114 "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); 115 return (-1); 116 } 117 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 118 warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s", 119 strerror(errno)); 120 return (-1); 121 } 122 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 123 warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s", 124 strerror(errno)); 125 close(s); 126 return (-1); 127 } 128 129 warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name); 130 131 if (nd.ndi.flags & ND6_IFF_IFDISABLED) { 132 if (Fflag) { 133 nd.ndi.flags &= ~ND6_IFF_IFDISABLED; 134 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 135 warnmsg(LOG_WARNING, __func__, 136 "ioctl(SIOCSIFINFO_IN6): %s", 137 strerror(errno)); 138 close(s); 139 return (-1); 140 } 141 } else { 142 warnmsg(LOG_WARNING, __func__, 143 "%s is disabled.", name); 144 close(s); 145 return (-1); 146 } 147 } 148 if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) { 149 if (Fflag) { 150 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV; 151 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd)) { 152 warnmsg(LOG_WARNING, __func__, 153 "ioctl(SIOCSIFINFO_IN6): %s", 154 strerror(errno)); 155 close(s); 156 return (-1); 157 } 158 } else { 159 warnmsg(LOG_WARNING, __func__, 160 "%s does not accept Router Advertisement.", name); 161 close(s); 162 return (-1); 163 } 164 } 165 close(s); 166 167 if (cap_llflags_get(capllflags, name, &llflag) != 0) { 168 warnmsg(LOG_WARNING, __func__, 169 "cap_llflags_get() failed, anyway I'll try"); 170 return (0); 171 } 172 173 if (!(llflag & IN6_IFF_NOTREADY)) { 174 warnmsg(LOG_DEBUG, __func__, "%s is ready", name); 175 return (0); 176 } else { 177 if (llflag & IN6_IFF_TENTATIVE) { 178 warnmsg(LOG_DEBUG, __func__, "%s is tentative", 179 name); 180 return (IFS_TENTATIVE); 181 } 182 if (llflag & IN6_IFF_DUPLICATED) 183 warnmsg(LOG_DEBUG, __func__, "%s is duplicated", 184 name); 185 return (-1); 186 } 187 } 188 189 int 190 interface_status(struct ifinfo *ifinfo) 191 { 192 char *ifname = ifinfo->ifname; 193 struct ifreq ifr; 194 struct ifmediareq ifmr; 195 196 /* get interface flags */ 197 memset(&ifr, 0, sizeof(ifr)); 198 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 199 if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { 200 warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s", 201 ifname, strerror(errno)); 202 return (-1); 203 } 204 /* 205 * if one of UP and RUNNING flags is dropped, 206 * the interface is not active. 207 */ 208 if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 209 goto inactive; 210 /* Next, check carrier on the interface, if possible */ 211 if (!ifinfo->mediareqok) 212 goto active; 213 memset(&ifmr, 0, sizeof(ifmr)); 214 strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); 215 216 if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { 217 if (errno != EINVAL) { 218 warnmsg(LOG_DEBUG, __func__, 219 "ioctl(SIOCGIFMEDIA) on %s: %s", 220 ifname, strerror(errno)); 221 return(-1); 222 } 223 /* 224 * EINVAL simply means that the interface does not support 225 * the SIOCGIFMEDIA ioctl. We regard it alive. 226 */ 227 ifinfo->mediareqok = 0; 228 goto active; 229 } 230 231 if (ifmr.ifm_status & IFM_AVALID) { 232 switch (ifmr.ifm_active & IFM_NMASK) { 233 case IFM_ETHER: 234 case IFM_IEEE80211: 235 if (ifmr.ifm_status & IFM_ACTIVE) 236 goto active; 237 else 238 goto inactive; 239 break; 240 default: 241 goto inactive; 242 } 243 } 244 245 inactive: 246 return (0); 247 248 active: 249 return (1); 250 } 251 252 #define ROUNDUP(a, size) \ 253 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) 254 255 #define NEXT_SA(ap) (ap) = (struct sockaddr *) \ 256 ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ 257 sizeof(u_long)) : sizeof(u_long))) 258 #define ROUNDUP8(a) (1 + (((a) - 1) | 7)) 259 260 int 261 lladdropt_length(struct sockaddr_dl *sdl) 262 { 263 switch (sdl->sdl_type) { 264 case IFT_ETHER: 265 case IFT_L2VLAN: 266 return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 267 default: 268 return (0); 269 } 270 } 271 272 void 273 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 274 { 275 char *addr; 276 277 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 278 279 switch (sdl->sdl_type) { 280 case IFT_ETHER: 281 case IFT_L2VLAN: 282 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; 283 addr = (char *)(ndopt + 1); 284 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); 285 break; 286 default: 287 warnmsg(LOG_ERR, __func__, 288 "unsupported link type(%d)", sdl->sdl_type); 289 exit(1); 290 } 291 } 292 293 struct sockaddr_dl * 294 if_nametosdl(char *name) 295 { 296 int mib[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; 297 char *buf, *next, *lim; 298 size_t len; 299 struct if_msghdr *ifm; 300 struct sockaddr *sa, *rti_info[RTAX_MAX]; 301 struct sockaddr_dl *sdl = NULL, *ret_sdl; 302 303 if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) 304 return(NULL); 305 if ((buf = malloc(len)) == NULL) 306 return(NULL); 307 if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) < 0) { 308 free(buf); 309 return (NULL); 310 } 311 312 lim = buf + len; 313 for (next = buf; next < lim; next += ifm->ifm_msglen) { 314 ifm = (struct if_msghdr *)(void *)next; 315 if (ifm->ifm_type == RTM_IFINFO) { 316 sa = (struct sockaddr *)(ifm + 1); 317 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 318 if ((sa = rti_info[RTAX_IFP]) != NULL) { 319 if (sa->sa_family == AF_LINK) { 320 sdl = (struct sockaddr_dl *)(void *)sa; 321 if (strlen(name) != sdl->sdl_nlen) 322 continue; /* not same len */ 323 if (strncmp(&sdl->sdl_data[0], 324 name, 325 sdl->sdl_nlen) == 0) { 326 break; 327 } 328 } 329 } 330 } 331 } 332 if (next >= lim) { 333 /* search failed */ 334 free(buf); 335 return (NULL); 336 } 337 338 if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) { 339 free(buf); 340 return (NULL); 341 } 342 memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); 343 344 free(buf); 345 return (ret_sdl); 346 } 347 348 static void 349 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 350 { 351 int i; 352 353 for (i = 0; i < RTAX_MAX; i++) { 354 if (addrs & (1 << i)) { 355 rti_info[i] = sa; 356 NEXT_SA(sa); 357 } else 358 rti_info[i] = NULL; 359 } 360 } 361