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 {sizeof(sin6_allrouters), AF_INET6}; 77 78 static void call_script(char *, char *); 79 static int safefile(const char *); 80 81 int 82 sockopen(void) 83 { 84 static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL; 85 int sndcmsglen, on; 86 static u_char answer[1500]; 87 struct icmp6_filter filt; 88 89 sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 90 CMSG_SPACE(sizeof(int)); 91 if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 92 warnmsg(LOG_ERR, __func__, 93 "malloc for receive msghdr failed"); 94 return(-1); 95 } 96 if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) { 97 warnmsg(LOG_ERR, __func__, 98 "malloc for send msghdr failed"); 99 return(-1); 100 } 101 memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6)); 102 sin6_allrouters.sin6_family = AF_INET6; 103 sin6_allrouters.sin6_len = sizeof(sin6_allrouters); 104 if (inet_pton(AF_INET6, ALLROUTER, 105 &sin6_allrouters.sin6_addr.s6_addr) != 1) { 106 warnmsg(LOG_ERR, __func__, "inet_pton failed for %s", 107 ALLROUTER); 108 return(-1); 109 } 110 111 if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 112 warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno)); 113 return(-1); 114 } 115 116 /* specify to tell receiving interface */ 117 on = 1; 118 #ifdef IPV6_RECVPKTINFO 119 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 120 sizeof(on)) < 0) { 121 warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s", 122 strerror(errno)); 123 exit(1); 124 } 125 #else /* old adv. API */ 126 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 127 sizeof(on)) < 0) { 128 warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s", 129 strerror(errno)); 130 exit(1); 131 } 132 #endif 133 134 on = 1; 135 /* specify to tell value of hoplimit field of received IP6 hdr */ 136 #ifdef IPV6_RECVHOPLIMIT 137 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 138 sizeof(on)) < 0) { 139 warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s", 140 strerror(errno)); 141 exit(1); 142 } 143 #else /* old adv. API */ 144 if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 145 sizeof(on)) < 0) { 146 warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s", 147 strerror(errno)); 148 exit(1); 149 } 150 #endif 151 152 /* specfiy to accept only router advertisements on the socket */ 153 ICMP6_FILTER_SETBLOCKALL(&filt); 154 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); 155 if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 156 sizeof(filt)) == -1) { 157 warnmsg(LOG_ERR, __func__, "setsockopt(ICMP6_FILTER): %s", 158 strerror(errno)); 159 return(-1); 160 } 161 162 /* initialize msghdr for receiving packets */ 163 rcviov[0].iov_base = (caddr_t)answer; 164 rcviov[0].iov_len = sizeof(answer); 165 rcvmhdr.msg_name = (caddr_t)&from; 166 rcvmhdr.msg_iov = rcviov; 167 rcvmhdr.msg_iovlen = 1; 168 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 169 170 /* initialize msghdr for sending packets */ 171 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 172 sndmhdr.msg_iov = sndiov; 173 sndmhdr.msg_iovlen = 1; 174 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 175 sndmhdr.msg_controllen = sndcmsglen; 176 177 return(rssock); 178 } 179 180 void 181 sendpacket(struct ifinfo *ifinfo) 182 { 183 struct in6_pktinfo *pi; 184 struct cmsghdr *cm; 185 int hoplimit = 255; 186 int i; 187 struct sockaddr_in6 dst; 188 189 dst = sin6_allrouters; 190 dst.sin6_scope_id = ifinfo->linkid; 191 192 sndmhdr.msg_name = (caddr_t)&dst; 193 sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data; 194 sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen; 195 196 cm = CMSG_FIRSTHDR(&sndmhdr); 197 /* specify the outgoing interface */ 198 cm->cmsg_level = IPPROTO_IPV6; 199 cm->cmsg_type = IPV6_PKTINFO; 200 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 201 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 202 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 203 pi->ipi6_ifindex = ifinfo->sdl->sdl_index; 204 205 /* specify the hop limit of the packet */ 206 cm = CMSG_NXTHDR(&sndmhdr, cm); 207 cm->cmsg_level = IPPROTO_IPV6; 208 cm->cmsg_type = IPV6_HOPLIMIT; 209 cm->cmsg_len = CMSG_LEN(sizeof(int)); 210 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 211 212 warnmsg(LOG_DEBUG, __func__, 213 "send RS on %s, whose state is %d", 214 ifinfo->ifname, ifinfo->state); 215 i = sendmsg(rssock, &sndmhdr, 0); 216 if (i < 0 || i != ifinfo->rs_datalen) { 217 /* 218 * ENETDOWN is not so serious, especially when using several 219 * network cards on a mobile node. We ignore it. 220 */ 221 if (errno != ENETDOWN || dflag > 0) 222 warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s", 223 ifinfo->ifname, strerror(errno)); 224 } 225 226 /* update counter */ 227 ifinfo->probes++; 228 } 229 230 void 231 rtsol_input(int s) 232 { 233 u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 234 int ifindex = 0, i, *hlimp = NULL; 235 struct in6_pktinfo *pi = NULL; 236 struct ifinfo *ifi = NULL; 237 struct icmp6_hdr *icp; 238 struct nd_router_advert *nd_ra; 239 struct cmsghdr *cm; 240 241 /* get message. namelen and controllen must always be initialized. */ 242 rcvmhdr.msg_namelen = sizeof(from); 243 rcvmhdr.msg_controllen = rcvcmsglen; 244 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 245 warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno)); 246 return; 247 } 248 249 /* extract optional information via Advanced API */ 250 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); cm; 251 cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { 252 if (cm->cmsg_level == IPPROTO_IPV6 && 253 cm->cmsg_type == IPV6_PKTINFO && 254 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 255 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 256 ifindex = pi->ipi6_ifindex; 257 } 258 if (cm->cmsg_level == IPPROTO_IPV6 && 259 cm->cmsg_type == IPV6_HOPLIMIT && 260 cm->cmsg_len == CMSG_LEN(sizeof(int))) 261 hlimp = (int *)CMSG_DATA(cm); 262 } 263 264 if (ifindex == 0) { 265 warnmsg(LOG_ERR, __func__, 266 "failed to get receiving interface"); 267 return; 268 } 269 if (hlimp == NULL) { 270 warnmsg(LOG_ERR, __func__, 271 "failed to get receiving hop limit"); 272 return; 273 } 274 275 if (i < sizeof(struct nd_router_advert)) { 276 warnmsg(LOG_INFO, __func__, 277 "packet size(%d) is too short", i); 278 return; 279 } 280 281 icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; 282 283 if (icp->icmp6_type != ND_ROUTER_ADVERT) { 284 /* 285 * this should not happen because we configured a filter 286 * that only passes RAs on the receiving socket. 287 */ 288 warnmsg(LOG_ERR, __func__, 289 "invalid icmp type(%d) from %s on %s", icp->icmp6_type, 290 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 291 INET6_ADDRSTRLEN), 292 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 293 return; 294 } 295 296 if (icp->icmp6_code != 0) { 297 warnmsg(LOG_INFO, __func__, 298 "invalid icmp code(%d) from %s on %s", icp->icmp6_code, 299 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 300 INET6_ADDRSTRLEN), 301 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 302 return; 303 } 304 305 if (*hlimp != 255) { 306 warnmsg(LOG_INFO, __func__, 307 "invalid RA with hop limit(%d) from %s on %s", 308 *hlimp, 309 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 310 INET6_ADDRSTRLEN), 311 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 312 return; 313 } 314 315 if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 316 warnmsg(LOG_INFO, __func__, 317 "invalid RA with non link-local source from %s on %s", 318 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 319 INET6_ADDRSTRLEN), 320 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 321 return; 322 } 323 324 /* xxx: more validation? */ 325 326 if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) { 327 warnmsg(LOG_INFO, __func__, 328 "received RA from %s on an unexpected IF(%s)", 329 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, 330 INET6_ADDRSTRLEN), 331 if_indextoname(pi->ipi6_ifindex, ifnamebuf)); 332 return; 333 } 334 335 warnmsg(LOG_DEBUG, __func__, 336 "received RA from %s on %s, state is %d", 337 inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), 338 ifi->ifname, ifi->state); 339 340 nd_ra = (struct nd_router_advert *)icp; 341 342 /* 343 * Process the "O bit." 344 * If the value of OtherConfigFlag changes from FALSE to TRUE, the 345 * host should invoke the stateful autoconfiguration protocol, 346 * requesting information. 347 * [RFC 2462 Section 5.5.3] 348 */ 349 if (((nd_ra->nd_ra_flags_reserved) & ND_RA_FLAG_OTHER) && 350 !ifi->otherconfig) { 351 warnmsg(LOG_DEBUG, __func__, 352 "OtherConfigFlag on %s is turned on", ifi->ifname); 353 ifi->otherconfig = 1; 354 call_script(otherconf_script, ifi->ifname); 355 } 356 357 ifi->racnt++; 358 359 switch (ifi->state) { 360 case IFS_IDLE: /* should be ignored */ 361 case IFS_DELAY: /* right? */ 362 break; 363 case IFS_PROBE: 364 ifi->state = IFS_IDLE; 365 ifi->probes = 0; 366 rtsol_timer_update(ifi); 367 break; 368 } 369 } 370 371 static void 372 call_script(char *scriptpath, char *ifname) 373 { 374 pid_t pid, wpid; 375 376 if (scriptpath == NULL) 377 return; 378 379 /* launch the script */ 380 pid = fork(); 381 if (pid < 0) { 382 warnmsg(LOG_ERR, __func__, 383 "failed to fork: %s", strerror(errno)); 384 return; 385 } else if (pid) { 386 int wstatus; 387 388 do { 389 wpid = wait(&wstatus); 390 } while (wpid != pid && wpid > 0); 391 392 if (wpid < 0) 393 warnmsg(LOG_ERR, __func__, 394 "wait: %s", strerror(errno)); 395 else { 396 warnmsg(LOG_DEBUG, __func__, 397 "script \"%s\" terminated", scriptpath); 398 } 399 } else { 400 char *argv[3]; 401 int fd; 402 403 argv[0] = scriptpath; 404 argv[1] = ifname; 405 argv[2] = NULL; 406 407 if (safefile(scriptpath)) { 408 warnmsg(LOG_ERR, __func__, 409 "script \"%s\" cannot be executed safely", 410 scriptpath); 411 exit(1); 412 } 413 414 if ((fd = open("/dev/null", O_RDWR)) != -1) { 415 dup2(fd, STDIN_FILENO); 416 dup2(fd, STDOUT_FILENO); 417 dup2(fd, STDERR_FILENO); 418 if (fd > STDERR_FILENO) 419 close(fd); 420 } 421 422 execv(scriptpath, argv); 423 424 warnmsg(LOG_ERR, __func__, "child: exec failed: %s", 425 strerror(errno)); 426 exit(0); 427 } 428 429 return; 430 } 431 432 static int 433 safefile(const char *path) 434 { 435 struct stat s; 436 uid_t myuid; 437 438 /* no setuid */ 439 if (getuid() != geteuid()) { 440 warnmsg(LOG_NOTICE, __func__, 441 "setuid'ed execution not allowed\n"); 442 return (-1); 443 } 444 445 if (lstat(path, &s) != 0) { 446 warnmsg(LOG_NOTICE, __func__, "lstat failed: %s", 447 strerror(errno)); 448 return (-1); 449 } 450 451 /* the file must be owned by the running uid */ 452 myuid = getuid(); 453 if (s.st_uid != myuid) { 454 warnmsg(LOG_NOTICE, __func__, 455 "%s has invalid owner uid\n", path); 456 return (-1); 457 } 458 459 switch (s.st_mode & S_IFMT) { 460 case S_IFREG: 461 break; 462 default: 463 warnmsg(LOG_NOTICE, __func__, 464 "%s is an invalid file type 0x%o\n", 465 path, (s.st_mode & S_IFMT)); 466 return (-1); 467 } 468 469 return (0); 470 } 471