/* BEGIN: Added by z67728, 2009/11/3 */ void sigdebug_handler(int sig) { static int iLogSwitch = 0; signal(SIGUSR1, sigdebug_handler); iLogSwitch = !iLogSwitch; if ( iLogSwitch ) { set_debuglevel(LOG_DEBUG); printf("\r\n Radvd open log ! \r\n"); } else { set_debuglevel(LOG_EMERG); printf("\r\n Radvd close log ! \r\n"); } dlog(LOG_DEBUG, 4, "\r\n Open log ! \r\n"); return; }
int main() { set_debuglevel(DL_INFO); set_abortlevel(DL_WARN); /* FIXME: wrapper testing (but may not be necessary...) */ DO_ASSERT(get_eventlog_monitor_thread_handle() == NULL); CHECKED_OPERATION(clear_policy()); DO_ASSERT(!is_any_process_pending_restart()); printf("All Test Passed\n"); return 0; }
int main(int argc, char *argv[]) { unsigned char msg[MSG_SIZE]; char pidstr[16]; ssize_t ret; int c, log_method; char *logfile, *pidfile; sigset_t oset, nset; int facility, fd; char *username = NULL; char *chrootdir = NULL; int singleprocess = 0; #ifdef HAVE_GETOPT_LONG int opt_idx; #endif /* BEGIN: Added by z67728, 2009/10/19 */ FILE * pidfp = NULL; int pid = 0; /* END: Added by z67728, 2009/10/19 */ /*start: 用于查询组件版本号(dns atpv),请不要修改或删除*/ /*if ((argc == 2) && (NULL != argv[1]) && (0 == strcmp(argv[1],ATP_VERSION_CMD_KEY))) { printf("\r\n%s.\n", RADVD_MODULE_VERSION); exit(0); }*/ /*end */ pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; srand((unsigned int)time(NULL)); log_method = L_STDERR_SYSLOG; /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */ #define RADVD_LOG (ROUTER_VARPATH_PREFIX "/radvd/radvd.log") #define RADVD_CONF (ROUTER_VARPATH_PREFIX "/radvd/radvd.conf") #define RADVD_PID (ROUTER_VARPATH_PREFIX "/radvd/radvd.pid") logfile = RADVD_LOG; conf_file = RADVD_CONF; facility = LOG_FACILITY; pidfile = RADVD_PID; /*END PN:2071008409 l00170266 for var problem modify 20120725 */ /* parse args */ #ifdef HAVE_GETOPT_LONG while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) #else while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) #endif { switch (c) { case 'C': conf_file = optarg; break; case 'd': set_debuglevel(atoi(optarg)); break; case 'f': facility = atoi(optarg); break; case 'l': logfile = optarg; break; case 'p': pidfile = optarg; break; case 'm': if (!strcmp(optarg, "syslog")) { log_method = L_SYSLOG; } else if (!strcmp(optarg, "stderr_syslog")) { log_method = L_STDERR_SYSLOG; } else if (!strcmp(optarg, "stderr")) { log_method = L_STDERR; } else if (!strcmp(optarg, "logfile")) { log_method = L_LOGFILE; } else if (!strcmp(optarg, "none")) { log_method = L_NONE; } else { fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); exit(1); } break; case 't': chrootdir = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'v': /* BEGIN 3061302357 y00188255 2013-6-28 Modified */ //version(); printf("%s\n", RADVD_MODULE_VERSION); printf("BUILTTIME is: %s %s\n",__DATE__,__TIME__); exit(1); /* END 3061302357 y00188255 2013-6-28 Modified */ break; case 's': singleprocess = 1; break; case 'h': usage(); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } if (chrootdir) { if (!username) { fprintf(stderr, "Chroot as root is not safe, exiting\n"); exit(1); } if (chroot(chrootdir) == -1) { perror("chroot"); exit (1); } if (chdir("/") == -1) { perror("chdir"); exit (1); } /* username will be switched later */ } if (log_open(log_method, pname, logfile, facility) < 0) exit(1); flog(LOG_INFO, "version %s started", VERSION); /* get a raw socket for sending and receiving ICMPv6 messages */ sock = open_icmpv6_socket(); if (sock < 0) exit(1); #if 0 /* check that 'other' cannot write the file * for non-root, also that self/own group can't either */ if (check_conffile_perm(username, conf_file) < 0) { if (get_debuglevel() == 0) exit(1); else flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); } /* if we know how to do it, check whether forwarding is enabled */ if (check_ip6_forwarding()) { if (get_debuglevel() == 0) { flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting"); exit(1); } else flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway."); } #endif /* parse config file */ if (readin_config(conf_file) < 0){ if ( 0 != unlink(pidfile) ){ printf("\r\n Delete %s meet error. error : %s .",pidfile,strerror(errno)); } exit(1); } /* drop root privileges if requested. */ if (username) { if (!singleprocess) { dlog(LOG_DEBUG, 3, "Initializing privsep"); if (privsep_init() < 0) flog(LOG_WARNING, "Failed to initialize privsep."); } if (drop_root_privileges(username) < 0) exit(1); } #if 0 if ((fd = open(pidfile, O_RDONLY, 0)) > 0) { ret = read(fd, pidstr, sizeof(pidstr) - 1); if (ret < 0) { flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno)); exit(1); } pidstr[ret] = '\0'; if (!kill((pid_t)atol(pidstr), 0)) { flog(LOG_ERR, "radvd already running, terminating."); exit(1); } close(fd); fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644); } else /* FIXME: not atomic if pidfile is on an NFS mounted volume */ fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); if (fd < 0) { flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno)); exit(1); } #endif /* * okay, config file is read in, socket and stuff is setup, so * lets fork now... */ #if 0 if (get_debuglevel() == 0) { /* Detach from controlling terminal */ if (daemon(0, 0) < 0) perror("daemon"); /* close old logfiles, including stderr */ log_close(); /* reopen logfiles, but don't log to stderr unless explicitly requested */ if (log_method == L_STDERR_SYSLOG) log_method = L_SYSLOG; if (log_open(log_method, pname, logfile, facility) < 0) exit(1); } #endif /* * config signal handlers, also make sure ALRM isn't blocked and raise a warning if so * (some stupid scripts/pppd appears to do this...) */ sigemptyset(&nset); sigaddset(&nset, SIGALRM); sigprocmask(SIG_UNBLOCK, &nset, &oset); if (sigismember(&oset, SIGALRM)) flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); signal(SIGINT, sigint_handler); /* BEGIN: Added by z67728, 2009/11/3 */ signal(SIGUSR1, sigdebug_handler); signal(SIGUSR2, sigprefixchg_handler); /* END: Added by z67728, 2009/11/3 */ #if 0 snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid()); write(fd, pidstr, strlen(pidstr)); close(fd); #endif /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */ #define RADVD_READTEST (ROUTER_VARPATH_PREFIX "/radvd/readtest") if ( 0 == access(RADVD_READTEST,F_OK) ) /*END PN:2071008409 l00170266 for var problem modify 20120725 */ { /* Ready test */ g_iReadTestFlag = 1; } pid = getpid(); if ((pidfp = fopen(pidfile, "w")) != NULL) { fwrite(&pid,1,4,pidfp); fclose(pidfp); } config_interface(); kickoff_adverts(); /* enter loop */ for (;;) { int len = 0, hoplimit = 0; struct sockaddr_in6 rcv_addr; struct in6_pktinfo *pkt_info = NULL; len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit); if (len > 0) { process(sock, IfaceList, msg, len, &rcv_addr, pkt_info, hoplimit); } if (sigterm_received || sigint_received) { stop_adverts(); break; } if (sighup_received) { if ( 1 == g_iPrefixChgeFlag ) { disable_oldprefix(); } reload_config(); sighup_received = 0; g_iPrefixChgeFlag = 0; } } unlink(pidfile); exit(0); }
int main(int argc, char *argv[]) { unsigned char msg[MSG_SIZE]; char pidstr[16]; ssize_t ret; int c, log_method; char *logfile, *pidfile; sigset_t oset, nset; int facility, fd; char *username = NULL; char *chrootdir = NULL; int singleprocess = 0; #ifdef HAVE_GETOPT_LONG int opt_idx; #endif pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; srand((unsigned int)time(NULL)); log_method = L_STDERR_SYSLOG; logfile = PATH_RADVD_LOG; conf_file = PATH_RADVD_CONF; facility = LOG_FACILITY; pidfile = PATH_RADVD_PID; /* parse args */ #ifdef HAVE_GETOPT_LONG /* Add option to show advertise real lifetime */ /* while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) */ while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhsD", prog_opt, &opt_idx)) > 0) #else /* Add option to show advertise real lifetime */ /* while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) */ while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhsD")) > 0) #endif { switch (c) { case 'C': conf_file = optarg; break; case 'd': set_debuglevel(atoi(optarg)); break; case 'f': facility = atoi(optarg); break; case 'l': logfile = optarg; break; case 'p': pidfile = optarg; break; case 'm': if (!strcmp(optarg, "syslog")) { log_method = L_SYSLOG; } else if (!strcmp(optarg, "stderr_syslog")) { log_method = L_STDERR_SYSLOG; } else if (!strcmp(optarg, "stderr")) { log_method = L_STDERR; } else if (!strcmp(optarg, "logfile")) { log_method = L_LOGFILE; } else if (!strcmp(optarg, "none")) { log_method = L_NONE; } else { fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); exit(1); } break; case 't': chrootdir = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'v': version(); break; case 's': singleprocess = 1; break; /* Add option to show advertise dynamic lifetime */ case 'D': use_dynamic_lifetime = 1; break; case 'h': usage(); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } if (chrootdir) { if (!username) { fprintf(stderr, "Chroot as root is not safe, exiting\n"); exit(1); } if (chroot(chrootdir) == -1) { perror("chroot"); exit (1); } if (chdir("/") == -1) { perror("chdir"); exit (1); } /* username will be switched later */ } if (log_open(log_method, pname, logfile, facility) < 0) exit(1); flog(LOG_INFO, "version %s started", VERSION); /* get a raw socket for sending and receiving ICMPv6 messages */ sock = open_icmpv6_socket(); if (sock < 0) exit(1); /* check that 'other' cannot write the file * for non-root, also that self/own group can't either */ if (check_conffile_perm(username, conf_file) < 0) { if (get_debuglevel() == 0) exit(1); else flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); } /* if we know how to do it, check whether forwarding is enabled */ if (check_ip6_forwarding()) { if (get_debuglevel() == 0) { flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting"); exit(1); } else flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway."); } /* parse config file */ if (readin_config(conf_file) < 0) exit(1); /* drop root privileges if requested. */ if (username) { if (!singleprocess) { dlog(LOG_DEBUG, 3, "Initializing privsep"); if (privsep_init() < 0) flog(LOG_WARNING, "Failed to initialize privsep."); } if (drop_root_privileges(username) < 0) exit(1); } if ((fd = open(pidfile, O_RDONLY, 0)) > 0) { ret = read(fd, pidstr, sizeof(pidstr) - 1); if (ret < 0) { flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno)); exit(1); } pidstr[ret] = '\0'; if (!kill((pid_t)atol(pidstr), 0)) { flog(LOG_ERR, "radvd already running, terminating."); exit(1); } close(fd); fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644); } else /* FIXME: not atomic if pidfile is on an NFS mounted volume */ fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); if (fd < 0) { flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno)); exit(1); } /* * okay, config file is read in, socket and stuff is setup, so * lets fork now... */ if (get_debuglevel() == 0) { /* Detach from controlling terminal */ if (daemon(0, 0) < 0) perror("daemon"); /* close old logfiles, including stderr */ log_close(); /* reopen logfiles, but don't log to stderr unless explicitly requested */ if (log_method == L_STDERR_SYSLOG) log_method = L_SYSLOG; if (log_open(log_method, pname, logfile, facility) < 0) exit(1); } /* * config signal handlers, also make sure ALRM isn't blocked and raise a warning if so * (some stupid scripts/pppd appears to do this...) */ sigemptyset(&nset); sigaddset(&nset, SIGALRM); sigprocmask(SIG_UNBLOCK, &nset, &oset); if (sigismember(&oset, SIGALRM)) flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); signal(SIGINT, sigint_handler); signal(SIGUSR1, sigusr1_handler); snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid()); write(fd, pidstr, strlen(pidstr)); close(fd); config_interface(); /* Record the time for first advertisement */ set_initial_advert_time(); kickoff_adverts(); /* enter loop */ for (;;) { int len, hoplimit; struct sockaddr_in6 rcv_addr; struct in6_pktinfo *pkt_info = NULL; len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit); if (len > 0) process(sock, IfaceList, msg, len, &rcv_addr, pkt_info, hoplimit); if (sigterm_received || sigint_received) { stop_adverts(); /* WNR3500L TD192, Per Netgear spec, * need to send RA for 3 times before termination. */ usleep(200000); stop_adverts(); usleep(200000); stop_adverts(); break; } if (sighup_received) { reload_config(); sighup_received = 0; } /* Reset the initial advertisement time to now */ /* This should happen after a successful IADP renew */ if (sigusr1_received) { set_initial_advert_time(); sigusr1_received = 0; } } unlink(pidfile); exit(0); }
int main(int argc, char *argv[]) { char pidstr[16]; ssize_t ret; int c, log_method; char *logfile, *pidfile; int facility, fd; char *username = NULL; char *chrootdir = NULL; int configtest = 0; int singleprocess = 0; #ifdef HAVE_GETOPT_LONG int opt_idx; #endif pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; srand((unsigned int)time(NULL)); log_method = L_STDERR_SYSLOG; logfile = PATH_RADVD_LOG; conf_file = PATH_RADVD_CONF; facility = LOG_FACILITY; pidfile = PATH_RADVD_PID; /* parse args */ #define OPTIONS_STR "d:C:l:m:p:t:u:vhcs" #ifdef HAVE_GETOPT_LONG while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0) #else while ((c = getopt(argc, argv, OPTIONS_STR)) > 0) #endif { switch (c) { case 'C': conf_file = optarg; break; case 'd': set_debuglevel(atoi(optarg)); break; case 'f': facility = atoi(optarg); break; case 'l': logfile = optarg; break; case 'p': pidfile = optarg; break; case 'm': if (!strcmp(optarg, "syslog")) { log_method = L_SYSLOG; } else if (!strcmp(optarg, "stderr_syslog")) { log_method = L_STDERR_SYSLOG; } else if (!strcmp(optarg, "stderr")) { log_method = L_STDERR; } else if (!strcmp(optarg, "logfile")) { log_method = L_LOGFILE; } else if (!strcmp(optarg, "none")) { log_method = L_NONE; } else { fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); exit(1); } break; case 't': chrootdir = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'v': version(); break; case 'c': configtest = 1; break; case 's': singleprocess = 1; break; case 'h': usage(); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } if (chrootdir) { if (!username) { fprintf(stderr, "Chroot as root is not safe, exiting\n"); exit(1); } if (chroot(chrootdir) == -1) { perror("chroot"); exit (1); } if (chdir("/") == -1) { perror("chdir"); exit (1); } /* username will be switched later */ } if (configtest) { log_method = L_STDERR; } if (log_open(log_method, pname, logfile, facility) < 0) { perror("log_open"); exit(1); } if (!configtest) { flog(LOG_INFO, "version %s started", VERSION); } /* get a raw socket for sending and receiving ICMPv6 messages */ sock = open_icmpv6_socket(); if (sock < 0) { perror("open_icmpv6_socket"); exit(1); } /* check that 'other' cannot write the file * for non-root, also that self/own group can't either */ if (check_conffile_perm(username, conf_file) < 0) { if (get_debuglevel() == 0) { flog(LOG_ERR, "Exiting, permissions on conf_file invalid.\n"); exit(1); } else flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); } /* if we know how to do it, check whether forwarding is enabled */ if (check_ip6_forwarding()) { flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway."); } /* parse config file */ if (readin_config(conf_file) < 0) { flog(LOG_ERR, "Exiting, failed to read config file.\n"); exit(1); } if (configtest) { fprintf(stderr, "Syntax OK\n"); exit(0); } /* drop root privileges if requested. */ if (username) { if (!singleprocess) { dlog(LOG_DEBUG, 3, "Initializing privsep"); if (privsep_init() < 0) flog(LOG_WARNING, "Failed to initialize privsep."); } if (drop_root_privileges(username) < 0) { perror("drop_root_privileges"); exit(1); } } if ((fd = open(pidfile, O_RDONLY, 0)) > 0) { ret = read(fd, pidstr, sizeof(pidstr) - 1); if (ret < 0) { flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno)); exit(1); } pidstr[ret] = '\0'; if (!kill((pid_t)atol(pidstr), 0)) { flog(LOG_ERR, "radvd already running, terminating."); exit(1); } close(fd); fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644); } else /* FIXME: not atomic if pidfile is on an NFS mounted volume */ fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644); if (fd < 0) { flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno)); exit(1); } /* * okay, config file is read in, socket and stuff is setup, so * lets fork now... */ if (get_debuglevel() == 0) { /* Detach from controlling terminal */ if (daemon(0, 0) < 0) perror("daemon"); /* close old logfiles, including stderr */ log_close(); /* reopen logfiles, but don't log to stderr unless explicitly requested */ if (log_method == L_STDERR_SYSLOG) log_method = L_SYSLOG; if (log_open(log_method, pname, logfile, facility) < 0) { perror("log_open"); exit(1); } } /* * config signal handlers */ signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); signal(SIGINT, sigint_handler); signal(SIGUSR1, sigusr1_handler); snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid()); ret = write(fd, pidstr, strlen(pidstr)); if (ret != strlen(pidstr)) { flog(LOG_ERR, "cannot write radvd pid file, terminating: %s", strerror(errno)); exit(1); } close(fd); config_interface(); kickoff_adverts(); main_loop(); stop_adverts(); unlink(pidfile); return 0; }
int main(int argc, char *argv[]) { unsigned char msg[MSG_SIZE]; int c, len, hoplimit; int fform = 0; int edefs = 0; struct sockaddr_in6 rcv_addr; struct in6_pktinfo *pkt_info = NULL; #ifdef HAVE_GETOPT_LONG int opt_idx; #endif pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0]; /* parse args */ #ifdef HAVE_GETOPT_LONG while ((c = getopt_long(argc, argv, "d:fehv", prog_opt, &opt_idx)) > 0) #else while ((c = getopt(argc, argv, "d:fehv")) > 0) #endif { switch (c) { case 'd': set_debuglevel(atoi(optarg)); break; case 'f': fform = 1; break; case 'e': edefs = 1; break; case 'v': version(); break; case 'h': usage(); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } if (log_open(L_STDERR, pname, NULL, 0) < 0) exit(1); /* get a raw socket for sending and receiving ICMPv6 messages */ sock = open_icmpv6_socket(); if (sock < 0) exit(1); for(;;) { len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit); if (len > 0) { struct icmp6_hdr *icmph; /* * can this happen? */ if (len < sizeof(struct icmp6_hdr)) { log(LOG_WARNING, "received icmpv6 packet with invalid length: %d", len); exit(1); } icmph = (struct icmp6_hdr *) msg; if (icmph->icmp6_type != ND_ROUTER_SOLICIT && icmph->icmp6_type != ND_ROUTER_ADVERT) { /* * We just want to listen to RSs and RAs */ log(LOG_ERR, "icmpv6 filter failed"); exit(1); } dlog(LOG_DEBUG, 4, "receiver if_index: %d", pkt_info->ipi6_ifindex); if (icmph->icmp6_type == ND_ROUTER_SOLICIT) { /* not yet */ } else if (icmph->icmp6_type == ND_ROUTER_ADVERT) { if (!fform) print_ra(msg, len, &rcv_addr, hoplimit, pkt_info->ipi6_ifindex); else print_ff(msg, len, &rcv_addr, hoplimit, pkt_info->ipi6_ifindex, edefs); } } else if (len == 0) { log(LOG_ERR, "received zero lenght packet"); exit(1); } else { log(LOG_ERR, "recv_rs_ra: %s", strerror(errno)); exit(1); } } exit(0); }
int main(int argc, char *argv[]) { int c; int log_method = L_STDERR_SYSLOG; char *logfile = PATH_RADVD_LOG; int facility = LOG_FACILITY; char *username = NULL; char *chrootdir = NULL; int configtest = 0; int daemonize = 1; char const *pname = ((pname = strrchr(argv[0], '/')) != NULL) ? pname + 1 : argv[0]; srand((unsigned int)time(NULL)); char const *conf_path = PATH_RADVD_CONF; char const *daemon_pid_file_ident = PATH_RADVD_PID; /* parse args */ #define OPTIONS_STR "d:C:l:m:p:t:u:vhcn" #ifdef HAVE_GETOPT_LONG int opt_idx; while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0) #else while ((c = getopt(argc, argv, OPTIONS_STR)) > 0) #endif { switch (c) { case 'C': conf_path = optarg; break; case 'd': set_debuglevel(atoi(optarg)); break; case 'f': facility = atoi(optarg); break; case 'l': logfile = optarg; break; case 'p': daemon_pid_file_ident = optarg; break; case 'm': if (!strcmp(optarg, "syslog")) { log_method = L_SYSLOG; } else if (!strcmp(optarg, "stderr_syslog")) { log_method = L_STDERR_SYSLOG; } else if (!strcmp(optarg, "stderr")) { log_method = L_STDERR; } else if (!strcmp(optarg, "logfile")) { log_method = L_LOGFILE; } else if (!strcmp(optarg, "none")) { log_method = L_NONE; } else { fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg); exit(1); } break; case 't': chrootdir = strdup(optarg); break; case 'u': username = strdup(optarg); break; case 'v': version(); break; case 'c': configtest = 1; break; case 'n': daemonize = 0; break; case 'h': usage(pname); #ifdef HAVE_GETOPT_LONG case ':': fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name); exit(1); #endif case '?': exit(1); } } /* TODO: Seems like this chroot'ing should happen *after* daemonizing for * the sake of the PID file. */ if (chrootdir) { if (!username) { fprintf(stderr, "Chroot as root is not safe, exiting\n"); exit(1); } if (chroot(chrootdir) == -1) { perror("chroot"); exit(1); } if (chdir("/") == -1) { perror("chdir"); exit(1); } /* username will be switched later */ } if (configtest) { set_debuglevel(1); log_method = L_STDERR; } if (log_open(log_method, pname, logfile, facility) < 0) { perror("log_open"); exit(1); } if (!configtest) { flog(LOG_INFO, "version %s started", VERSION); } /* check that 'other' cannot write the file * for non-root, also that self/own group can't either */ if (check_conffile_perm(username, conf_path) != 0) { if (get_debuglevel() == 0) { flog(LOG_ERR, "exiting, permissions on conf_file invalid"); exit(1); } else flog(LOG_WARNING, "Insecure file permissions, but continuing anyway"); } /* parse config file */ struct Interface *ifaces = NULL; if ((ifaces = readin_config(conf_path)) == 0) { flog(LOG_ERR, "exiting, failed to read config file"); exit(1); } if (configtest) { free_ifaces(ifaces); exit(0); } /* get a raw socket for sending and receiving ICMPv6 messages */ int sock = open_icmpv6_socket(); if (sock < 0) { perror("open_icmpv6_socket"); exit(1); } /* if we know how to do it, check whether forwarding is enabled */ if (check_ip6_forwarding()) { flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway"); } int const pidfd = open_and_lock_pid_file(daemon_pid_file_ident); /* * okay, config file is read in, socket and stuff is setup, so * lets fork now... */ if (daemonize) { pid_t pid = do_daemonize(log_method, daemon_pid_file_ident); if (pid != 0 && pid != -1) { /* We want to see clean output from valgrind, so free username, chrootdir, * and ifaces in the child process. */ if (ifaces) free_ifaces(ifaces); if (username) free(username); if (chrootdir) free(chrootdir); exit(0); } } else { if (0 != write_pid_file(daemon_pid_file_ident, getpid())) { flog(LOG_ERR, "failure writing pid file detected"); exit(-1); } } check_pid_file(daemon_pid_file_ident); #ifdef __linux__ /* for privsep */ { dlog(LOG_DEBUG, 3, "initializing privsep"); int pipefds[2]; if (pipe(pipefds) != 0) { flog(LOG_ERR, "Couldn't create privsep pipe."); return -1; } pid_t pid = fork(); if (pid == -1) { flog(LOG_ERR, "Couldn't fork for privsep."); return -1; } if (pid == 0) { /* We want to see clean output from valgrind, so free username, chrootdir, * and ifaces in the child process. */ if (ifaces) free_ifaces(ifaces); if (username) free(username); if (chrootdir) free(chrootdir); close(pipefds[1]); privsep_init(pipefds[0]); _exit(0); } dlog(LOG_DEBUG, 3, "radvd privsep PID is %d", pid); /* Continue execution (will drop privileges soon) */ close(pipefds[0]); privsep_set_write_fd(pipefds[1]); } #endif if (username) { if (drop_root_privileges(username) < 0) { perror("drop_root_privileges"); flog(LOG_ERR, "unable to drop root privileges"); exit(1); } dlog(LOG_DEBUG, 3, "running as user: %s", username); } setup_ifaces(sock, ifaces); ifaces = main_loop(sock, ifaces, conf_path); stop_adverts(sock, ifaces); flog(LOG_INFO, "removing %s", daemon_pid_file_ident); unlink(daemon_pid_file_ident); close(pidfd); if (ifaces) free_ifaces(ifaces); if (chrootdir) free(chrootdir); if (username) free(username); flog(LOG_INFO, "returning from radvd main"); log_close(); return 0; }
/* Set up all the radvd internal stuff from our own configuration */ int radvd_init(char *ifname, struct config *c) { struct AdvPrefix *prefix; sigset_t oset, nset; if (log_open(L_STDERR, "radvd", NULL, -1) < 0) { error("log_open\n"); return -1; } srand((unsigned int)time(NULL)); info("starting radvd on device %s\n", ifname); sock = open_icmpv6_socket(); if (sock < 0) { error("open_icmpv6_socket\n"); return -1; } sigemptyset(&nset); sigaddset(&nset, SIGALRM); sigprocmask(SIG_UNBLOCK, &nset, &oset); if (sigismember(&oset, SIGALRM)) flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong."); /* setup the radvd struct Interface to know about all our defaults */ iface = malloc(sizeof(struct Interface)); if (iface == NULL) return -1; iface_init_defaults(iface); strncpy(iface->Name, ifname, IFNAMSIZ-1); iface->Name[IFNAMSIZ-1] = '\0'; iface->next = NULL; iface->AdvSendAdvert = 1; /* check the interface exists... this probably shouldn't fail */ if (check_device(sock, iface) < 0) { error("check_device!\n"); return -1; } if (setup_deviceinfo(sock, iface) < 0) { error("setup_deviceinfo\n"); return -1; } if (check_iface(iface) < 0) { error("check_iface\n"); return -1; } if (setup_linklocal_addr(sock, iface) < 0) { error("setup_linklocal_addr\n"); return -1; } if (setup_allrouters_membership(sock, iface) < 0) { error("setup_allrouters_membership\n"); return -1; } /* set up the prefix we're advertising from the config struct we get passed in. */ prefix = malloc(sizeof(struct AdvPrefix)); if (prefix == NULL) return -1; prefix_init_defaults(prefix); prefix->PrefixLen = 64; memcpy(&prefix->Prefix, c->router_addr.s6_addr, sizeof(struct in6_addr)); prefix->next = NULL; iface->AdvPrefixList = prefix; // config_interface(); radvd_kickoff_adverts(); set_debuglevel(0); return sock; }