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 return (ROUNDUP8(ETHER_ADDR_LEN + 2)); 266 default: 267 return (0); 268 } 269 } 270 271 void 272 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) 273 { 274 char *addr; 275 276 ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ 277 278 switch (sdl->sdl_type) { 279 case IFT_ETHER: 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