1/* 2 * $Id: radvd.c,v 1.39 2009/06/19 07:37:11 psavola Exp $ 3 * 4 * Authors: 5 * Pedro Roque <roque@di.fc.ul.pt> 6 * Lars Fenneberg <lf@elemental.net> 7 * 8 * This software is Copyright 1996-2000 by the above mentioned author(s), 9 * All Rights Reserved. 10 * 11 * The license which is distributed with this software in the file COPYRIGHT 12 * applies to this software. If your distribution is missing this file, you 13 * may request it from <pekkas@netcore.fi>. 14 * 15 */ 16 17#include <config.h> 18#include <includes.h> 19#include <radvd.h> 20#include <pathnames.h> 21 22struct Interface *IfaceList = NULL; 23 24char usage_str[] = 25 "[-hsv] [-d level] [-C config_file] [-m log_method] [-l log_file]\n" 26 "\t[-f facility] [-p pid_file] [-u username] [-t chrootdir]"; 27 28#ifdef HAVE_GETOPT_LONG 29struct option prog_opt[] = { 30 {"debug", 1, 0, 'd'}, 31 {"config", 1, 0, 'C'}, 32 {"pidfile", 1, 0, 'p'}, 33 {"logfile", 1, 0, 'l'}, 34 {"logmethod", 1, 0, 'm'}, 35 {"facility", 1, 0, 'f'}, 36 {"username", 1, 0, 'u'}, 37 {"chrootdir", 1, 0, 't'}, 38 {"version", 0, 0, 'v'}, 39 {"help", 0, 0, 'h'}, 40 {"singleprocess", 0, 0, 's'}, 41 {NULL, 0, 0, 0} 42}; 43#endif 44 45extern FILE *yyin; 46 47char *conf_file = NULL; 48char *pname; 49int sock = -1; 50 51volatile int sighup_received = 0; 52volatile int sigterm_received = 0; 53volatile int sigint_received = 0; 54 55void sighup_handler(int sig); 56void sigterm_handler(int sig); 57void sigint_handler(int sig); 58void timer_handler(void *data); 59void config_interface(void); 60void kickoff_adverts(void); 61void stop_adverts(void); 62void version(void); 63void usage(void); 64int drop_root_privileges(const char *); 65int readin_config(char *); 66int check_conffile_perm(const char *, const char *); 67 68/* Foxconn added start pling 12/22/2011 */ 69/* WNDR3400v2 Defect#135: Sync radvd prefix lifetime with IAPD lifetime */ 70#include <sys/sysinfo.h> 71 72/* Signal handlers SIGUSR1: to reset prefix lifetime 73 * after a sucessful IAPD renew */ 74int sigusr1_received = 0; 75void sigusr1_handler(int sig); 76 77/* Functions to record initial advertise time */ 78int use_dynamic_lifetime = 0; 79unsigned long initial_advert_time = 0; 80 81void set_initial_advert_time(void) 82{ 83 struct sysinfo info; 84 sysinfo(&info); 85 initial_advert_time = (unsigned long)(info.uptime); 86} 87 88unsigned long get_current_time(void) 89{ 90 struct sysinfo info; 91 sysinfo(&info); 92 return (unsigned long)(info.uptime); 93} 94/* Foxconn added end pling 12/22/2011 */ 95int 96main(int argc, char *argv[]) 97{ 98 unsigned char msg[MSG_SIZE]; 99 char pidstr[16]; 100 ssize_t ret; 101 int c, log_method; 102 char *logfile, *pidfile; 103 sigset_t oset, nset; 104 int facility, fd; 105 char *username = NULL; 106 char *chrootdir = NULL; 107 int singleprocess = 0; 108#ifdef HAVE_GETOPT_LONG 109 int opt_idx; 110#endif 111 112 pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; 113 114 srand((unsigned int)time(NULL)); 115 116 log_method = L_STDERR_SYSLOG; 117 logfile = PATH_RADVD_LOG; 118 conf_file = PATH_RADVD_CONF; 119 facility = LOG_FACILITY; 120 pidfile = PATH_RADVD_PID; 121 122 /* parse args */ 123#ifdef HAVE_GETOPT_LONG 124 /* Foxconn modified start pling 12/22/2011 */ 125 /* Add option to show advertise real lifetime */ 126 /* while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) */ 127 while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhsD", prog_opt, &opt_idx)) > 0) 128 /* Foxconn modified end pling 12/22/2011 */ 129#else 130 /* Foxconn modified start pling 12/22/2011 */ 131 /* Add option to show advertise real lifetime */ 132 /* while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) */ 133 while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhsD")) > 0) 134 /* Foxconn modified end pling 12/22/2011 */ 135#endif 136 { 137 switch (c) { 138 case 'C': 139 conf_file = optarg; 140 break; 141 case 'd': 142 set_debuglevel(atoi(optarg)); 143 break; 144 case 'f': 145 facility = atoi(optarg); 146 break; 147 case 'l': 148 logfile = optarg; 149 break; 150 case 'p': 151 pidfile = optarg; 152 break; 153 case 'm': 154 if (!strcmp(optarg, "syslog")) 155 { 156 log_method = L_SYSLOG; 157 } 158 else if (!strcmp(optarg, "stderr_syslog")) 159 { 160 log_method = L_STDERR_SYSLOG; 161 } 162 else if (!strcmp(optarg, "stderr")) 163 { 164 log_method = L_STDERR; 165 } 166 else if (!strcmp(optarg, "logfile")) 167 { 168 log_method = L_LOGFILE; 169 } 170 else if (!strcmp(optarg, "none")) 171 { 172 log_method = L_NONE; 173 } 174 else 175 { 176 fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); 177 exit(1); 178 } 179 break; 180 case 't': 181 chrootdir = strdup(optarg); 182 break; 183 case 'u': 184 username = strdup(optarg); 185 break; 186 case 'v': 187 version(); 188 break; 189 case 's': 190 singleprocess = 1; 191 break; 192 /* Foxconn added start pling 12/22/2011 */ 193 /* Add option to show advertise dynamic lifetime */ 194 case 'D': 195 use_dynamic_lifetime = 1; 196 break; 197 /* Foxconn added end pling 12/22/2011 */ 198 case 'h': 199 usage(); 200#ifdef HAVE_GETOPT_LONG 201 case ':': 202 fprintf(stderr, "%s: option %s: parameter expected\n", pname, 203 prog_opt[opt_idx].name); 204 exit(1); 205#endif 206 case '?': 207 exit(1); 208 } 209 } 210 211 if (chrootdir) { 212 if (!username) { 213 fprintf(stderr, "Chroot as root is not safe, exiting\n"); 214 exit(1); 215 } 216 217 if (chroot(chrootdir) == -1) { 218 perror("chroot"); 219 exit (1); 220 } 221 222 if (chdir("/") == -1) { 223 perror("chdir"); 224 exit (1); 225 } 226 /* username will be switched later */ 227 } 228 229 if (log_open(log_method, pname, logfile, facility) < 0) 230 exit(1); 231 232 flog(LOG_INFO, "version %s started", VERSION); 233 234 /* get a raw socket for sending and receiving ICMPv6 messages */ 235 sock = open_icmpv6_socket(); 236 if (sock < 0) 237 exit(1); 238 239 /* check that 'other' cannot write the file 240 * for non-root, also that self/own group can't either 241 */ 242 if (check_conffile_perm(username, conf_file) < 0) { 243 if (get_debuglevel() == 0) 244 exit(1); 245 else 246 flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); 247 } 248 249 /* if we know how to do it, check whether forwarding is enabled */ 250 if (check_ip6_forwarding()) { 251 if (get_debuglevel() == 0) { 252 flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting"); 253 exit(1); 254 } 255 else 256 flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway."); 257 } 258 259 /* parse config file */ 260 if (readin_config(conf_file) < 0) 261 exit(1); 262 263 /* drop root privileges if requested. */ 264 if (username) { 265 if (!singleprocess) { 266 dlog(LOG_DEBUG, 3, "Initializing privsep"); 267 if (privsep_init() < 0) 268 flog(LOG_WARNING, "Failed to initialize privsep."); 269 } 270 271 if (drop_root_privileges(username) < 0) 272 exit(1); 273 } 274 275 if ((fd = open(pidfile, O_RDONLY, 0)) > 0) 276 { 277 ret = read(fd, pidstr, sizeof(pidstr) - 1); 278 if (ret < 0) 279 { 280 flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno)); 281 exit(1); 282 } 283 pidstr[ret] = '\0'; 284 if (!kill((pid_t)atol(pidstr), 0)) 285 { 286 flog(LOG_ERR, "radvd already running, terminating."); 287 exit(1); 288 } 289 close(fd); 290 fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644); 291 } 292 else /* FIXME: not atomic if pidfile is on an NFS mounted volume */ 293 fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); 294 295 if (fd < 0) 296 { 297 flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno)); 298 exit(1); 299 } 300 301 /* 302 * okay, config file is read in, socket and stuff is setup, so 303 * lets fork now... 304 */ 305 306 if (get_debuglevel() == 0) { 307 308 /* Detach from controlling terminal */ 309 if (daemon(0, 0) < 0) 310 perror("daemon"); 311 312 /* close old logfiles, including stderr */ 313 log_close(); 314 315 /* reopen logfiles, but don't log to stderr unless explicitly requested */ 316 if (log_method == L_STDERR_SYSLOG) 317 log_method = L_SYSLOG; 318 if (log_open(log_method, pname, logfile, facility) < 0) 319 exit(1); 320 321 } 322 323 /* 324 * config signal handlers, also make sure ALRM isn't blocked and raise a warning if so 325 * (some stupid scripts/pppd appears to do this...) 326 */ 327 sigemptyset(&nset); 328 sigaddset(&nset, SIGALRM); 329 sigprocmask(SIG_UNBLOCK, &nset, &oset); 330 if (sigismember(&oset, SIGALRM)) 331 flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); 332 333 signal(SIGHUP, sighup_handler); 334 signal(SIGTERM, sigterm_handler); 335 signal(SIGINT, sigint_handler); 336 signal(SIGUSR1, sigusr1_handler); /* Foxconn added pling 12/22/2011 */ 337 338 snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid()); 339 340 write(fd, pidstr, strlen(pidstr)); 341 342 close(fd); 343 344 config_interface(); 345 /* Foxconn added start pling 12/22/2011 */ 346 /* Record the time for first advertisement */ 347 set_initial_advert_time(); 348 /* Foxconn added end pling 12/22/2011 */ 349 kickoff_adverts(); 350 351 /* enter loop */ 352 353 for (;;) 354 { 355 int len, hoplimit; 356 struct sockaddr_in6 rcv_addr; 357 struct in6_pktinfo *pkt_info = NULL; 358 359 len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit); 360 if (len > 0) 361 process(sock, IfaceList, msg, len, 362 &rcv_addr, pkt_info, hoplimit); 363 364 if (sigterm_received || sigint_received) { 365 stop_adverts(); 366 367 /* Foxconn added start pling 11/30/2010 */ 368 /* WNR3500L TD192, Per Netgear spec, 369 * need to send RA for 3 times before termination. 370 */ 371 usleep(200000); 372 stop_adverts(); 373 usleep(200000); 374 stop_adverts(); 375 /* Foxconn added end pling 11/30/2010 */ 376 377 break; 378 } 379 380 if (sighup_received) 381 { 382 reload_config(); 383 sighup_received = 0; 384 } 385 /* Foxconn added start pling 12/22/2011 */ 386 /* Reset the initial advertisement time to now */ 387 /* This should happen after a successful IADP renew */ 388 if (sigusr1_received) 389 { 390 set_initial_advert_time(); 391 sigusr1_received = 0; 392 } 393 /* Foxconn added end pling 12/22/2011 */ 394 } 395 396 unlink(pidfile); 397 exit(0); 398} 399 400void 401timer_handler(void *data) 402{ 403 struct Interface *iface = (struct Interface *) data; 404 double next; 405 406 dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name); 407 408 send_ra_forall(sock, iface, NULL); 409 410 next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); 411 412 if (iface->init_racount < MAX_INITIAL_RTR_ADVERTISEMENTS - 1) 413 { 414 iface->init_racount++; 415 next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, next); 416 } 417 /* Foxconn Perry added start, 2011/05/13, for IPv6 obsolete prefix information */ 418 else 419 { 420 iface->init_racount++; 421 } 422 /* Foxconn Perry added end, 2011/05/13, for IPv6 obsolete prefix information */ 423 424 set_timer(&iface->tm, next); 425} 426 427void 428config_interface(void) 429{ 430 struct Interface *iface; 431 for(iface=IfaceList; iface; iface=iface->next) 432 { 433 if (iface->AdvLinkMTU) 434 set_interface_linkmtu(iface->Name, iface->AdvLinkMTU); 435 if (iface->AdvCurHopLimit) 436 set_interface_curhlim(iface->Name, iface->AdvCurHopLimit); 437 if (iface->AdvReachableTime) 438 set_interface_reachtime(iface->Name, iface->AdvReachableTime); 439 if (iface->AdvRetransTimer) 440 set_interface_retranstimer(iface->Name, iface->AdvRetransTimer); 441 } 442} 443 444void 445kickoff_adverts(void) 446{ 447 struct Interface *iface; 448 449 /* 450 * send initial advertisement and set timers 451 */ 452 453 for(iface=IfaceList; iface; iface=iface->next) 454 { 455 if( iface->UnicastOnly ) 456 break; 457 458 init_timer(&iface->tm, timer_handler, (void *) iface); 459 460 if (!iface->AdvSendAdvert) 461 break; 462 463 /* send an initial advertisement */ 464 send_ra_forall(sock, iface, NULL); 465 466 iface->init_racount++; 467 468 set_timer(&iface->tm, 469 min(MAX_INITIAL_RTR_ADVERT_INTERVAL, 470 iface->MaxRtrAdvInterval)); 471 } 472} 473 474void 475stop_adverts(void) 476{ 477 struct Interface *iface; 478 479 /* 480 * send final RA (a SHOULD in RFC4861 section 6.2.5) 481 */ 482 483 for (iface=IfaceList; iface; iface=iface->next) { 484 if( ! iface->UnicastOnly ) { 485 if (iface->AdvSendAdvert) { 486 /* send a final advertisement with zero Router Lifetime */ 487 iface->AdvDefaultLifetime = 0; 488 /* Foxconn Perry added start, 2011/05/13, for IPv6 obsolete prefix information */ 489 iface->init_racount = 0; 490 /* Foxconn Perry added end, 2011/05/13, for IPv6 obsolete prefix information */ 491 send_ra_forall(sock, iface, NULL); 492 } 493 } 494 } 495} 496 497void reload_config(void) 498{ 499 struct Interface *iface; 500 501 flog(LOG_INFO, "attempting to reread config file"); 502 503 dlog(LOG_DEBUG, 4, "reopening log"); 504 if (log_reopen() < 0) 505 exit(1); 506 507 /* disable timers, free interface and prefix structures */ 508 for(iface=IfaceList; iface; iface=iface->next) 509 { 510 /* check that iface->tm was set in the first place */ 511 if (iface->tm.next && iface->tm.prev) 512 { 513 dlog(LOG_DEBUG, 4, "disabling timer for %s", iface->Name); 514 clear_timer(&iface->tm); 515 } 516 } 517 518 iface=IfaceList; 519 while(iface) 520 { 521 struct Interface *next_iface = iface->next; 522 struct AdvPrefix *prefix; 523 struct AdvRoute *route; 524 struct AdvRDNSS *rdnss; 525 526 dlog(LOG_DEBUG, 4, "freeing interface %s", iface->Name); 527 528 prefix = iface->AdvPrefixList; 529 while (prefix) 530 { 531 struct AdvPrefix *next_prefix = prefix->next; 532 533 free(prefix); 534 prefix = next_prefix; 535 } 536 537 route = iface->AdvRouteList; 538 while (route) 539 { 540 struct AdvRoute *next_route = route->next; 541 542 free(route); 543 route = next_route; 544 } 545 546 rdnss = iface->AdvRDNSSList; 547 while (rdnss) 548 { 549 struct AdvRDNSS *next_rdnss = rdnss->next; 550 551 free(rdnss); 552 rdnss = next_rdnss; 553 } 554 555 free(iface); 556 iface = next_iface; 557 } 558 559 IfaceList = NULL; 560 561 /* reread config file */ 562 if (readin_config(conf_file) < 0) 563 exit(1); 564 565 /* XXX: fails due to lack of permissions with non-root user */ 566 config_interface(); 567 kickoff_adverts(); 568 569 flog(LOG_INFO, "resuming normal operation"); 570} 571 572void 573sighup_handler(int sig) 574{ 575 /* Linux has "one-shot" signals, reinstall the signal handler */ 576 signal(SIGHUP, sighup_handler); 577 578 dlog(LOG_DEBUG, 4, "sighup_handler called"); 579 580 sighup_received = 1; 581} 582 583void 584sigterm_handler(int sig) 585{ 586 /* Linux has "one-shot" signals, reinstall the signal handler */ 587 signal(SIGTERM, sigterm_handler); 588 589 dlog(LOG_DEBUG, 4, "sigterm_handler called"); 590 591 sigterm_received = 1; 592} 593 594void 595sigint_handler(int sig) 596{ 597 /* Linux has "one-shot" signals, reinstall the signal handler */ 598 signal(SIGINT, sigint_handler); 599 600 dlog(LOG_DEBUG, 4, "sigint_handler called"); 601 602 sigint_received = 1; 603} 604 605/* Foxconn added start pling 12/22/2011 */ 606/* Add signal handler for SIGUSR1, to handle 607 * signal after a successful IAPD renew */ 608void sigusr1_handler(int sig) 609{ 610 signal(SIGUSR1, sigusr1_handler); 611 sigusr1_received = 1; 612} 613/* Foxconn added end pling 12/22/2011 */ 614int 615drop_root_privileges(const char *username) 616{ 617 struct passwd *pw = NULL; 618 pw = getpwnam(username); 619 if (pw) { 620 if (initgroups(username, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { 621 flog(LOG_ERR, "Couldn't change to '%.32s' uid=%d gid=%d", 622 username, pw->pw_uid, pw->pw_gid); 623 return (-1); 624 } 625 } 626 else { 627 flog(LOG_ERR, "Couldn't find user '%.32s'", username); 628 return (-1); 629 } 630 return 0; 631} 632 633int 634check_conffile_perm(const char *username, const char *conf_file) 635{ 636 struct stat *st = NULL; 637 struct passwd *pw = NULL; 638 FILE *fp = fopen(conf_file, "r"); 639 640 if (fp == NULL) { 641 flog(LOG_ERR, "can't open %s: %s", conf_file, strerror(errno)); 642 return (-1); 643 } 644 fclose(fp); 645 646 st = malloc(sizeof(struct stat)); 647 if (st == NULL) 648 goto errorout; 649 650 if (!username) 651 username = "root"; 652 653 pw = getpwnam(username); 654 655 if (stat(conf_file, st) || pw == NULL) 656 goto errorout; 657 658 if (st->st_mode & S_IWOTH) { 659 flog(LOG_ERR, "Insecure file permissions (writable by others): %s", conf_file); 660 goto errorout; 661 } 662 663 /* for non-root: must not be writable by self/own group */ 664 if (strncmp(username, "root", 5) != 0 && 665 ((st->st_mode & S_IWGRP && pw->pw_gid == st->st_gid) || 666 (st->st_mode & S_IWUSR && pw->pw_uid == st->st_uid))) { 667 flog(LOG_ERR, "Insecure file permissions (writable by self/group): %s", conf_file); 668 goto errorout; 669 } 670 671 free(st); 672 return 0; 673 674errorout: 675 if (st) 676 free(st); 677 return(-1); 678} 679 680int 681check_ip6_forwarding(void) 682{ 683 int forw_sysctl[] = { SYSCTL_IP6_FORWARDING }; 684 int value; 685 size_t size = sizeof(value); 686 FILE *fp = NULL; 687 688#ifdef __linux__ 689 fp = fopen(PROC_SYS_IP6_FORWARDING, "r"); 690 if (fp) { 691 fscanf(fp, "%d", &value); 692 fclose(fp); 693 } 694 else 695 flog(LOG_DEBUG, "Correct IPv6 forwarding procfs entry not found, " 696 "perhaps the procfs is disabled, " 697 "or the kernel interface has changed?"); 698#endif /* __linux__ */ 699 700 if (!fp && sysctl(forw_sysctl, sizeof(forw_sysctl)/sizeof(forw_sysctl[0]), 701 &value, &size, NULL, 0) < 0) { 702 flog(LOG_DEBUG, "Correct IPv6 forwarding sysctl branch not found, " 703 "perhaps the kernel interface has changed?"); 704 return(0); /* this is of advisory value only */ 705 } 706 707 if (value != 1) { 708 flog(LOG_DEBUG, "IPv6 forwarding setting is: %u, should be 1", value); 709 return(-1); 710 } 711 712 return(0); 713} 714 715int 716readin_config(char *fname) 717{ 718 if ((yyin = fopen(fname, "r")) == NULL) 719 { 720 flog(LOG_ERR, "can't open %s: %s", fname, strerror(errno)); 721 return (-1); 722 } 723 724 if (yyparse() != 0) 725 { 726 flog(LOG_ERR, "error parsing or activating the config file: %s", fname); 727 return (-1); 728 } 729 730 fclose(yyin); 731 return 0; 732} 733 734void 735version(void) 736{ 737 fprintf(stderr, "Version: %s\n\n", VERSION); 738 fprintf(stderr, "Compiled in settings:\n"); 739 fprintf(stderr, " default config file \"%s\"\n", PATH_RADVD_CONF); 740 fprintf(stderr, " default pidfile \"%s\"\n", PATH_RADVD_PID); 741 fprintf(stderr, " default logfile \"%s\"\n", PATH_RADVD_LOG); 742 fprintf(stderr, " default syslog facililty %d\n", LOG_FACILITY); 743 fprintf(stderr, "Please send bug reports or suggestions to %s.\n", 744 CONTACT_EMAIL); 745 746 exit(1); 747} 748 749void 750usage(void) 751{ 752 fprintf(stderr, "usage: %s %s\n", pname, usage_str); 753 exit(1); 754} 755 756