1 /* $KAME: rtsol.c,v 1.27 2003/10/05 00:09:36 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/uio.h> 37 #include <sys/time.h> 38 #include <sys/queue.h> 39 #include <sys/wait.h> 40 #include <sys/stat.h> 41 42 #include <net/if.h> 43 #include <net/route.h> 44 #include <net/if_dl.h> 45 46 #include <netinet/in.h> 47 #include <netinet/ip6.h> 48 #include <netinet6/ip6_var.h> 49 #include <netinet/icmp6.h> 50 51 #include <arpa/inet.h> 52 53 #include <time.h> 54 #include <fcntl.h> 55 #include <unistd.h> 56 #include <stdio.h> 57 #include <err.h> 58 #include <errno.h> 59 #include <string.h> 60 #include <stdlib.h> 61 #include <syslog.h> 62 #include "rtsold.h" 63 64 #define ALLROUTER "ff02::2" 65 66 static struct msghdr rcvmhdr; 67 static struct msghdr sndmhdr; 68 static struct iovec rcviov[2]; 69 static struct iovec sndiov[2]; 70 static struct sockaddr_in6 from; 71 static int rcvcmsglen; 72 73 int rssock; 74 75 static struct sockaddr_in6 sin6_allrouters = { 76 .sin6_len = sizeof(sin6_allrouters), 77 .sin6_family = AF_INET6, 78 }; 79 80 static void call_script(char *, char *); 81 static int safefile(const char *); 82 83 int 84 sockopen(void) 85 { 86 static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL; 87 int sndcmsglen, on; 88 static u_char answer[1500]; 89 struct icmp6_filter filt; 90 91 sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 92 CMSG_SPACE(sizeof(int)); 93 if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 94 warnmsg(LOG_ERR, __func__, 95 "malloc for receive msghdr failed"); 96 return(-1); 97 } 98 if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) { 99 warnmsg(LOG_ERR, __func__, 100 "malloc for send msghdr failed"); 101 return(-1); 102 } 103 memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6)); 104 sin6_allrouters.sin6_family = AF_INET6; 105 sin6_allrouters.sin6_len = sizeof(sin6_allrouters); 106 if (inet_pton(AF_INET6, ALLROUTER, 107 &sin6_allrouters.sin6_addr.s6_addr) != 1) { 108 warnmsg(LOG_ERR, __func__, "inet_pton failed for %s", 109 ALLROUTER); 110 return(-1); 111 } 112 113 if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 114 warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 115 return(-1); 116 } 117 118 /* specify to tell receiving interface */ 119 on = 1; 120 #ifdef IPV6_RECVPKTINFO 121 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 122 sizeof(on)) < 0) { 123 warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s", 124 strerror(errno)); 125 exit(1); 126 } 127 #else /* old adv. API */ 128 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 129 sizeof(on)) < 0) { 130 warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s", 131 strerror(errno)); 132 exit(1); 133 } 134 #endif 135 136 on = 1; 137 /* specify to tell value of hoplimit field of received IP6 hdr */ 138 #ifdef IPV6_RECVHOPLIMIT 139 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 140 sizeof(on)) < 0) { 141 warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s", 142 strerror(errno)); 143 exit(1); 144 } 145 #else /* old adv. API */ 146 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 147 sizeof(on)) < 0) { 148 warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s", 149 strerror(errno)); 150 exit(1); 151 } 152 #endif 153 154 /* specfiy to accept only router advertisements on the socket */ 155 ICMP6_FILTER_SETBLOCKALL(&filt); 156 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 157 if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 158 sizeof(filt)) == -1) { 159 warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s", 160 strerror(errno)); 161 return(-1); 162 } 163 164 /* initialize msghdr for receiving packets */ 165 rcviov[0].iov_base = (caddr_t)answer; 166 rcviov[0].iov_len = sizeof(answer); 167 rcvmhdr.msg_name = (caddr_t)&from; 168 rcvmhdr.msg_iov = rcviov; 169 rcvmhdr.msg_iovlen = 1; 170 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 171 172 /* initialize msghdr for sending packets */ 173 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 174 sndmhdr.msg_iov = sndiov; 175 sndmhdr.msg_iovlen = 1; 176 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 177 sndmhdr.msg_controllen = sndcmsglen; 178 179 return(rssock); 180 } 181 182 void 183 sendpacket(struct ifinfo *ifinfo) 184 { 185 struct in6_pktinfo *pi; 186 struct cmsghdr *cm; 187 int hoplimit = 255; 188 ssize_t i; 189 struct sockaddr_in6 dst; 190 191 dst = sin6_allrouters; 192 dst.sin6_scope_id = ifinfo->linkid; 193 194 sndmhdr.msg_name = (caddr_t)&dst; 195 sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data; 196 sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen; 197 198 cm = CMSG_FIRSTHDR(&sndmhdr); 199 /* specify the outgoing interface */ 200 cm->cmsg_level = IPPROTO_IPV6; 201 cm->cmsg_type = IPV6_PKTINFO; 202 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 203 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 204 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 205 pi->ipi6_ifindex = ifinfo->sdl->sdl_index; 206 207 /* specify the hop limit of the packet */ 208 cm = CMSG_NXTHDR(&sndmhdr, cm); 209 cm->cmsg_level = IPPROTO_IPV6; 210 cm->cmsg_type = IPV6_HOPLIMIT; 211 cm->cmsg_len = CMSG_LEN(sizeof(int)); 212 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 213 214 warnmsg(LOG_DEBUG, __func__, 215 "send RS on %s, whose state is %d", 216 ifinfo->ifname, ifinfo->state); 217 i = sendmsg(rssock, &sndmhdr, 0); 218 if (i < 0 || (size_t)i != ifinfo->rs_datalen) { 219 /* 220 * ENETDOWN is not so serious, especially when using several 221 * network cards on a mobile node. We ignore it. 222 */ 223 if (errno != ENETDOWN || dflag > 0) 224 warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s", 225 ifinfo->ifname, strerror(errno)); 226 } 227 228 /* update counter */ 229 ifinfo->probes++; 230 } 231 232 void 233 rtsol_input(int s) 234 { 235 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 236 int ifindex = 0, *hlimp = NULL; 237 ssize_t i; 238 struct in6_pktinfo *pi = NULL; 239 struct ifinfo *ifi = NULL; 240 struct icmp6_hdr *icp; 241 struct nd_router_advert *nd_ra; 242 struct cmsghdr *cm; 243 244 /* get message. namelen and controllen must always be initialized. */ 245 rcvmhdr.msg_namelen = sizeof(from); 246 rcvmhdr.msg_controllen = rcvcmsglen; 247 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 248 warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno)); 249 return; 250 } 251 252 /* extract optional information via Advanced API */ 253 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); cm; 254 cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { 255 if (cm->cmsg_level == IPPROTO_IPV6 && 256 cm->cmsg_type == IPV6_PKTINFO && 257 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 258 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 259 ifindex = pi->ipi6_ifindex; 260 } 261 if (cm->cmsg_level == IPPROTO_IPV6 && 262 cm->cmsg_type == IPV6_HOPLIMIT && 263 cm->cmsg_len == CMSG_LEN(sizeof(int))) 264 hlimp = (int *)CMSG_DATA(cm); 265 } 266 267 if (ifindex == 0) { 268 warnmsg(LOG_ERR, __func__, 269 "failed to get receiving interface"); 270 return; 271 } 272 if (hlimp == NULL) { 273 warnmsg(LOG_ERR, __func__, 274 "failed to get receiving hop limit"); 275 return; 276 } 277 278 if ((size_t)i < sizeof(struct nd_router_advert)) { 279 warnmsg(LOG_INFO, __func__, 280 "packet size(%zd) is too short", i); 281 return; 282 } 283 284 icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; 285 286 if (icp->icmp6_type != ND_ROUTER_ADVERT) { 287 /* 288 * this should not happen because we configured a filter 289 * that only passes RAs on the receiving socket. 290 */ 291 warnmsg(LOG_ERR, __func__, 292 "invalid icmp type(%d) from %s on %s", icp->icmp6_type, 293 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 294 INET6_ADDRSTRLEN), 295 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 296 return; 297 } 298 299 if (icp->icmp6_code != 0) { 300 warnmsg(LOG_INFO, __func__, 301 "invalid icmp code(%d) from %s on %s", icp->icmp6_code, 302 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 303 INET6_ADDRSTRLEN), 304 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 305 return; 306 } 307 308 if (*hlimp != 255) { 309 warnmsg(LOG_INFO, __func__, 310 "invalid RA with hop limit(%d) from %s on %s", 311 *hlimp, 312 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 313 INET6_ADDRSTRLEN), 314 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 315 return; 316 } 317 318 if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 319 warnmsg(LOG_INFO, __func__, 320 "invalid RA with non link-local source from %s on %s", 321 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 322 INET6_ADDRSTRLEN), 323 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 324 return; 325 } 326 327 /* xxx: more validation? */ 328 329 if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) { 330 warnmsg(LOG_INFO, __func__, 331 "received RA from %s on an unexpected IF(%s)", 332 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 333 INET6_ADDRSTRLEN), 334 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 335 return; 336 } 337 338 warnmsg(LOG_DEBUG, __func__, 339 "received RA from %s on %s, state is %d", 340 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), 341 ifi->ifname, ifi->state); 342 343 nd_ra = (struct nd_router_advert *)icp; 344 345 /* 346 * Process the "O bit." 347 * If the value of OtherConfigFlag changes from FALSE to TRUE, the 348 * host should invoke the stateful autoconfiguration protocol, 349 * requesting information. 350 * [RFC 2462 Section 5.5.3] 351 */ 352 if (((nd_ra->nd_ra_flags_reserved) & ND_RA_FLAG_OTHER) && 353 !ifi->otherconfig) { 354 warnmsg(LOG_DEBUG, __func__, 355 "OtherConfigFlag on %s is turned on", ifi->ifname); 356 ifi->otherconfig = 1; 357 call_script(otherconf_script, ifi->ifname); 358 } 359 360 ifi->racnt++; 361 362 switch (ifi->state) { 363 case IFS_IDLE: /* should be ignored */ 364 case IFS_DELAY: /* right? */ 365 break; 366 case IFS_PROBE: 367 ifi->state = IFS_IDLE; 368 ifi->probes = 0; 369 rtsol_timer_update(ifi); 370 break; 371 } 372 } 373 374 static void 375 call_script(char *scriptpath, char *ifname) 376 { 377 pid_t pid, wpid; 378 379 if (scriptpath == NULL) 380 return; 381 382 /* launch the script */ 383 pid = fork(); 384 if (pid < 0) { 385 warnmsg(LOG_ERR, __func__, 386 "failed to fork: %s", strerror(errno)); 387 return; 388 } else if (pid) { 389 int wstatus; 390 391 do { 392 wpid = wait(&wstatus); 393 } while (wpid != pid && wpid > 0); 394 395 if (wpid < 0) 396 warnmsg(LOG_ERR, __func__, 397 "wait: %s", strerror(errno)); 398 else { 399 warnmsg(LOG_DEBUG, __func__, 400 "script \"%s\" terminated", scriptpath); 401 } 402 } else { 403 char *argv[3]; 404 int fd; 405 406 argv[0] = scriptpath; 407 argv[1] = ifname; 408 argv[2] = NULL; 409 410 if (safefile(scriptpath)) { 411 warnmsg(LOG_ERR, __func__, 412 "script \"%s\" cannot be executed safely", 413 scriptpath); 414 exit(1); 415 } 416 417 if ((fd = open("/dev/null", O_RDWR)) != -1) { 418 dup2(fd, STDIN_FILENO); 419 dup2(fd, STDOUT_FILENO); 420 dup2(fd, STDERR_FILENO); 421 if (fd > STDERR_FILENO) 422 close(fd); 423 } 424 425 execv(scriptpath, argv); 426 427 warnmsg(LOG_ERR, __func__, "child: exec failed: %s", 428 strerror(errno)); 429 exit(0); 430 } 431 432 return; 433 } 434 435 static int 436 safefile(const char *path) 437 { 438 struct stat s; 439 uid_t myuid; 440 441 /* no setuid */ 442 if (getuid() != geteuid()) { 443 warnmsg(LOG_NOTICE, __func__, 444 "setuid'ed execution not allowed\n"); 445 return (-1); 446 } 447 448 if (lstat(path, &s) != 0) { 449 warnmsg(LOG_NOTICE, __func__, "lstat failed: %s", 450 strerror(errno)); 451 return (-1); 452 } 453 454 /* the file must be owned by the running uid */ 455 myuid = getuid(); 456 if (s.st_uid != myuid) { 457 warnmsg(LOG_NOTICE, __func__, 458 "%s has invalid owner uid\n", path); 459 return (-1); 460 } 461 462 switch (s.st_mode & S_IFMT) { 463 case S_IFREG: 464 break; 465 default: 466 warnmsg(LOG_NOTICE, __func__, 467 "%s is an invalid file type 0x%o\n", 468 path, (s.st_mode & S_IFMT)); 469 return (-1); 470 } 471 472 return (0); 473 } 474