2 * $Id: radvd.c,v 1.61.2.1 2011/08/22 12:28:46 reubenhwk Exp $
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Lars Fenneberg <lf@elemental.net>
8 * This software is Copyright 1996-2000 by the above mentioned author(s),
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>.
20 #include "pathnames.h"
28 struct Interface
*IfaceList
= NULL
;
30 #ifdef HAVE_GETOPT_LONG
34 " -c, --configtest Parse the config file and exit.\n"
35 " -C, --config=PATH Sets the config file. Default is /etc/radvd.conf.\n"
36 " -d, --debug=NUM Sets the debug level. Values can be 1, 2, 3, 4 or 5.\n"
37 " -f, --facility=NUM Sets the logging facility.\n"
38 " -h, --help Show this help screen.\n"
39 " -l, --logfile=PATH Sets the log file.\n"
40 " -m, --logmethod=X Sets the log method to one of: syslog, stderr, stderr_syslog, logfile, or none.\n"
41 " -p, --pidfile=PATH Sets the pid file.\n"
42 " -s, --singleprocess Use privsep.\n"
43 " -t, --chrootdir=PATH Chroot to the specified path.\n"
44 " -u, --username=USER Switch to the specified user.\n"
45 " -v, --version Print the version and quit.\n"
48 struct option prog_opt
[] = {
50 {"configtest", 0, 0, 'c'},
51 {"config", 1, 0, 'C'},
52 {"pidfile", 1, 0, 'p'},
53 {"logfile", 1, 0, 'l'},
54 {"logmethod", 1, 0, 'm'},
55 {"facility", 1, 0, 'f'},
56 {"username", 1, 0, 'u'},
57 {"chrootdir", 1, 0, 't'},
58 {"version", 0, 0, 'v'},
60 {"singleprocess", 0, 0, 's'},
67 "[-hsvc] [-d level] [-C config_file] [-m log_method] [-l log_file]\n"
68 "\t[-f facility] [-p pid_file] [-u username] [-t chrootdir]";
74 char *conf_file
= NULL
;
78 volatile int sighup_received
= 0;
79 volatile int sigterm_received
= 0;
80 volatile int sigint_received
= 0;
81 volatile int sigusr1_received
= 0;
83 void sighup_handler(int sig
);
84 void sigterm_handler(int sig
);
85 void sigint_handler(int sig
);
86 void sigusr1_handler(int sig
);
87 void timer_handler(void *data
);
88 void config_interface(void);
89 void kickoff_adverts(void);
90 void stop_adverts(void);
93 int drop_root_privileges(const char *);
94 int readin_config(char *);
95 int check_conffile_perm(const char *, const char *);
99 main(int argc
, char *argv
[])
104 char *logfile
, *pidfile
;
106 char *username
= NULL
;
107 char *chrootdir
= NULL
;
109 int singleprocess
= 0;
110 #ifdef HAVE_GETOPT_LONG
114 pname
= ((pname
=strrchr(argv
[0],'/')) != NULL
)?pname
+1:argv
[0];
116 srand((unsigned int)time(NULL
));
118 log_method
= L_STDERR_SYSLOG
;
119 logfile
= PATH_RADVD_LOG
;
120 conf_file
= PATH_RADVD_CONF
;
121 facility
= LOG_FACILITY
;
122 pidfile
= PATH_RADVD_PID
;
125 #define OPTIONS_STR "d:C:l:m:p:t:u:vhcs"
126 #ifdef HAVE_GETOPT_LONG
127 while ((c
= getopt_long(argc
, argv
, OPTIONS_STR
, prog_opt
, &opt_idx
)) > 0)
129 while ((c
= getopt(argc
, argv
, OPTIONS_STR
)) > 0)
137 set_debuglevel(atoi(optarg
));
140 facility
= atoi(optarg
);
149 if (!strcmp(optarg
, "syslog"))
151 log_method
= L_SYSLOG
;
153 else if (!strcmp(optarg
, "stderr_syslog"))
155 log_method
= L_STDERR_SYSLOG
;
157 else if (!strcmp(optarg
, "stderr"))
159 log_method
= L_STDERR
;
161 else if (!strcmp(optarg
, "logfile"))
163 log_method
= L_LOGFILE
;
165 else if (!strcmp(optarg
, "none"))
171 fprintf(stderr
, "%s: unknown log method: %s\n", pname
, optarg
);
176 chrootdir
= strdup(optarg
);
179 username
= strdup(optarg
);
192 #ifdef HAVE_GETOPT_LONG
194 fprintf(stderr
, "%s: option %s: parameter expected\n", pname
,
195 prog_opt
[opt_idx
].name
);
205 fprintf(stderr
, "Chroot as root is not safe, exiting\n");
209 if (chroot(chrootdir
) == -1) {
214 if (chdir("/") == -1) {
218 /* username will be switched later */
222 log_method
= L_STDERR
;
225 if (log_open(log_method
, pname
, logfile
, facility
) < 0) {
231 flog(LOG_INFO
, "version %s started", VERSION
);
234 /* get a raw socket for sending and receiving ICMPv6 messages */
235 sock
= open_icmpv6_socket();
237 perror("open_icmpv6_socket");
241 /* check that 'other' cannot write the file
242 * for non-root, also that self/own group can't either
244 if (check_conffile_perm(username
, conf_file
) < 0) {
245 if (get_debuglevel() == 0) {
246 flog(LOG_ERR
, "Exiting, permissions on conf_file invalid.\n");
250 flog(LOG_WARNING
, "Insecure file permissions, but continuing anyway");
253 /* if we know how to do it, check whether forwarding is enabled */
254 if (check_ip6_forwarding()) {
255 flog(LOG_WARNING
, "IPv6 forwarding seems to be disabled, but continuing anyway.");
258 /* parse config file */
259 if (readin_config(conf_file
) < 0) {
260 flog(LOG_ERR
, "Exiting, failed to read config file.\n");
265 fprintf(stderr
, "Syntax OK\n");
269 /* drop root privileges if requested. */
271 if (!singleprocess
) {
272 dlog(LOG_DEBUG
, 3, "Initializing privsep");
273 if (privsep_init() < 0)
274 flog(LOG_WARNING
, "Failed to initialize privsep.");
277 if (drop_root_privileges(username
) < 0) {
278 perror("drop_root_privileges");
283 if ((fd
= open(pidfile
, O_RDONLY
, 0)) > 0)
285 ret
= read(fd
, pidstr
, sizeof(pidstr
) - 1);
288 flog(LOG_ERR
, "cannot read radvd pid file, terminating: %s", strerror(errno
));
292 if (!kill((pid_t
)atol(pidstr
), 0))
294 flog(LOG_ERR
, "radvd already running, terminating.");
298 fd
= open(pidfile
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0644);
300 else /* FIXME: not atomic if pidfile is on an NFS mounted volume */
301 fd
= open(pidfile
, O_CREAT
|O_EXCL
|O_WRONLY
, 0644);
305 flog(LOG_ERR
, "cannot create radvd pid file, terminating: %s", strerror(errno
));
310 * okay, config file is read in, socket and stuff is setup, so
314 if (get_debuglevel() == 0) {
316 /* Detach from controlling terminal */
317 if (daemon(0, 0) < 0)
320 /* close old logfiles, including stderr */
323 /* reopen logfiles, but don't log to stderr unless explicitly requested */
324 if (log_method
== L_STDERR_SYSLOG
)
325 log_method
= L_SYSLOG
;
326 if (log_open(log_method
, pname
, logfile
, facility
) < 0) {
334 * config signal handlers
336 signal(SIGHUP
, sighup_handler
);
337 signal(SIGTERM
, sigterm_handler
);
338 signal(SIGINT
, sigint_handler
);
339 signal(SIGUSR1
, sigusr1_handler
);
341 snprintf(pidstr
, sizeof(pidstr
), "%ld\n", (long)getpid());
343 ret
= write(fd
, pidstr
, strlen(pidstr
));
344 if (ret
!= strlen(pidstr
))
346 flog(LOG_ERR
, "cannot write radvd pid file, terminating: %s", strerror(errno
));
363 struct pollfd fds
[2];
365 memset(fds
, 0, sizeof(fds
));
368 fds
[0].events
= POLLIN
;
372 fds
[1].fd
= netlink_socket();
373 fds
[1].events
= POLLIN
;
382 struct Interface
*next
= NULL
;
383 struct Interface
*iface
;
388 timeout
= next_time_msec(IfaceList
);
390 for (iface
= IfaceList
; iface
; iface
= iface
->next
) {
392 t
= next_time_msec(iface
);
400 dlog(LOG_DEBUG
, 5, "polling for %g seconds.", timeout
/1000.0);
402 rc
= poll(fds
, sizeof(fds
)/sizeof(fds
[0]), timeout
);
405 if (fds
[0].revents
& (POLLERR
| POLLHUP
| POLLNVAL
)) {
406 flog(LOG_WARNING
, "socket error on fds[0].fd");
408 else if (fds
[0].revents
& POLLIN
) {
410 struct sockaddr_in6 rcv_addr
;
411 struct in6_pktinfo
*pkt_info
= NULL
;
412 unsigned char msg
[MSG_SIZE_RECV
];
414 len
= recv_rs_ra(msg
, &rcv_addr
, &pkt_info
, &hoplimit
);
416 process(IfaceList
, msg
, len
,
417 &rcv_addr
, pkt_info
, hoplimit
);
421 if (fds
[1].revents
& (POLLERR
| POLLHUP
| POLLNVAL
)) {
422 flog(LOG_WARNING
, "socket error on fds[1].fd");
424 else if (fds
[1].revents
& POLLIN
) {
425 process_netlink_msg(fds
[1].fd
);
429 else if ( rc
== 0 ) {
433 else if ( rc
== -1 && errno
!= EINTR
) {
434 flog(LOG_ERR
, "poll error: %s", strerror(errno
));
437 if (sigterm_received
|| sigint_received
) {
438 flog(LOG_WARNING
, "Exiting, sigterm or sigint received.\n");
448 if (sigusr1_received
)
450 reset_prefix_lifetimes();
451 sigusr1_received
= 0;
458 timer_handler(void *data
)
460 struct Interface
*iface
= (struct Interface
*) data
;
463 dlog(LOG_DEBUG
, 4, "timer_handler called for %s", iface
->Name
);
465 if (send_ra_forall(iface
, NULL
) != 0) {
469 next
= rand_between(iface
->MinRtrAdvInterval
, iface
->MaxRtrAdvInterval
);
471 if (iface
->init_racount
< MAX_INITIAL_RTR_ADVERTISEMENTS
)
473 iface
->init_racount
++;
474 next
= min(MAX_INITIAL_RTR_ADVERT_INTERVAL
, next
);
477 iface
->next_multicast
= next_timeval(next
);
481 config_interface(void)
483 struct Interface
*iface
;
484 for(iface
=IfaceList
; iface
; iface
=iface
->next
)
486 if (iface
->AdvLinkMTU
)
487 set_interface_linkmtu(iface
->Name
, iface
->AdvLinkMTU
);
488 if (iface
->AdvCurHopLimit
)
489 set_interface_curhlim(iface
->Name
, iface
->AdvCurHopLimit
);
490 if (iface
->AdvReachableTime
)
491 set_interface_reachtime(iface
->Name
, iface
->AdvReachableTime
);
492 if (iface
->AdvRetransTimer
)
493 set_interface_retranstimer(iface
->Name
, iface
->AdvRetransTimer
);
498 kickoff_adverts(void)
500 struct Interface
*iface
;
503 * send initial advertisement and set timers
506 for(iface
=IfaceList
; iface
; iface
=iface
->next
)
511 gettimeofday(&iface
->last_ra_time
, NULL
);
513 if( iface
->UnicastOnly
)
516 gettimeofday(&iface
->last_multicast
, NULL
);
518 if (!iface
->AdvSendAdvert
)
521 /* send an initial advertisement */
522 if (send_ra_forall(iface
, NULL
) == 0) {
524 iface
->init_racount
++;
526 next
= min(MAX_INITIAL_RTR_ADVERT_INTERVAL
, iface
->MaxRtrAdvInterval
);
527 iface
->next_multicast
= next_timeval(next
);
535 struct Interface
*iface
;
538 * send final RA (a SHOULD in RFC4861 section 6.2.5)
541 for (iface
=IfaceList
; iface
; iface
=iface
->next
) {
542 if( ! iface
->UnicastOnly
) {
543 if (iface
->AdvSendAdvert
) {
544 /* send a final advertisement with zero Router Lifetime */
545 iface
->cease_adv
= 1;
546 send_ra_forall(iface
, NULL
);
552 void reload_config(void)
554 struct Interface
*iface
;
556 flog(LOG_INFO
, "attempting to reread config file");
558 dlog(LOG_DEBUG
, 4, "reopening log");
559 if (log_reopen() < 0) {
560 perror("log_reopen");
567 struct Interface
*next_iface
= iface
->next
;
568 struct AdvPrefix
*prefix
;
569 struct AdvRoute
*route
;
570 struct AdvRDNSS
*rdnss
;
571 struct AdvDNSSL
*dnssl
;
573 dlog(LOG_DEBUG
, 4, "freeing interface %s", iface
->Name
);
575 prefix
= iface
->AdvPrefixList
;
578 struct AdvPrefix
*next_prefix
= prefix
->next
;
581 prefix
= next_prefix
;
584 route
= iface
->AdvRouteList
;
587 struct AdvRoute
*next_route
= route
->next
;
593 rdnss
= iface
->AdvRDNSSList
;
596 struct AdvRDNSS
*next_rdnss
= rdnss
->next
;
602 dnssl
= iface
->AdvDNSSLList
;
605 struct AdvDNSSL
*next_dnssl
= dnssl
->next
;
608 for (i
= 0; i
< dnssl
->AdvDNSSLNumber
; i
++)
609 free(dnssl
->AdvDNSSLSuffixes
[i
]);
610 free(dnssl
->AdvDNSSLSuffixes
);
622 /* reread config file */
623 if (readin_config(conf_file
) < 0) {
624 perror("readin_config failed.");
628 /* XXX: fails due to lack of permissions with non-root user */
632 flog(LOG_INFO
, "resuming normal operation");
636 sighup_handler(int sig
)
638 /* Linux has "one-shot" signals, reinstall the signal handler */
639 signal(SIGHUP
, sighup_handler
);
641 dlog(LOG_DEBUG
, 4, "sighup_handler called");
647 sigterm_handler(int sig
)
649 /* Linux has "one-shot" signals, reinstall the signal handler */
650 signal(SIGTERM
, sigterm_handler
);
652 dlog(LOG_DEBUG
, 4, "sigterm_handler called");
656 if(sigterm_received
> 1){
657 dlog(LOG_ERR
, 1, "sigterm_handler called %d times...aborting...", sigterm_received
);
663 sigint_handler(int sig
)
665 /* Linux has "one-shot" signals, reinstall the signal handler */
666 signal(SIGINT
, sigint_handler
);
668 dlog(LOG_DEBUG
, 4, "sigint_handler called");
672 if(sigint_received
> 1){
673 dlog(LOG_ERR
, 1, "sigint_handler called %d times...aborting...", sigint_received
);
679 void reset_prefix_lifetimes(void)
681 struct Interface
*iface
;
682 struct AdvPrefix
*prefix
;
683 char pfx_str
[INET6_ADDRSTRLEN
];
686 flog(LOG_INFO
, "Resetting prefix lifetimes");
688 for (iface
= IfaceList
; iface
; iface
= iface
->next
)
690 for (prefix
= iface
->AdvPrefixList
; prefix
;
691 prefix
= prefix
->next
)
693 if (prefix
->DecrementLifetimesFlag
)
695 print_addr(&prefix
->Prefix
, pfx_str
);
696 dlog(LOG_DEBUG
, 4, "%s/%u%%%s plft reset from %u to %u secs", pfx_str
, prefix
->PrefixLen
, iface
->Name
, prefix
->curr_preferredlft
, prefix
->AdvPreferredLifetime
);
697 dlog(LOG_DEBUG
, 4, "%s/%u%%%s vlft reset from %u to %u secs", pfx_str
, prefix
->PrefixLen
, iface
->Name
, prefix
->curr_validlft
, prefix
->AdvValidLifetime
);
698 prefix
->curr_validlft
=
699 prefix
->AdvValidLifetime
;
700 prefix
->curr_preferredlft
=
701 prefix
->AdvPreferredLifetime
;
709 void sigusr1_handler(int sig
)
712 /* Linux has "one-shot" signals, reinstall the signal handler */
713 signal(SIGUSR1
, sigusr1_handler
);
715 dlog(LOG_DEBUG
, 4, "sigusr1_handler called");
717 sigusr1_received
= 1;
722 drop_root_privileges(const char *username
)
724 struct passwd
*pw
= NULL
;
725 pw
= getpwnam(username
);
727 if (initgroups(username
, pw
->pw_gid
) != 0 || setgid(pw
->pw_gid
) != 0 || setuid(pw
->pw_uid
) != 0) {
728 flog(LOG_ERR
, "Couldn't change to '%.32s' uid=%d gid=%d",
729 username
, pw
->pw_uid
, pw
->pw_gid
);
734 flog(LOG_ERR
, "Couldn't find user '%.32s'", username
);
741 check_conffile_perm(const char *username
, const char *conf_file
)
745 struct passwd
*pw
= NULL
;
746 FILE *fp
= fopen(conf_file
, "r");
749 flog(LOG_ERR
, "can't open %s: %s", conf_file
, strerror(errno
));
757 pw
= getpwnam(username
);
759 if (stat(conf_file
, &stbuf
) || pw
== NULL
)
762 if (stbuf
.st_mode
& S_IWOTH
) {
763 flog(LOG_ERR
, "Insecure file permissions (writable by others): %s", conf_file
);
767 /* for non-root: must not be writable by self/own group */
768 if (strncmp(username
, "root", 5) != 0 &&
769 ((stbuf
.st_mode
& S_IWGRP
&& pw
->pw_gid
== stbuf
.st_gid
) ||
770 (stbuf
.st_mode
& S_IWUSR
&& pw
->pw_uid
== stbuf
.st_uid
))) {
771 flog(LOG_ERR
, "Insecure file permissions (writable by self/group): %s", conf_file
);
782 check_ip6_forwarding(void)
784 int forw_sysctl
[] = { SYSCTL_IP6_FORWARDING
};
786 size_t size
= sizeof(value
);
788 static int warned
= 0;
791 fp
= fopen(PROC_SYS_IP6_FORWARDING
, "r");
793 int rc
= fscanf(fp
, "%d", &value
);
795 flog(LOG_ERR
, "cannot read value from %s: %s", PROC_SYS_IP6_FORWARDING
, strerror(errno
));
801 flog(LOG_DEBUG
, "Correct IPv6 forwarding procfs entry not found, "
802 "perhaps the procfs is disabled, "
803 "or the kernel interface has changed?");
804 #endif /* __linux__ */
806 if (!fp
&& sysctl(forw_sysctl
, sizeof(forw_sysctl
)/sizeof(forw_sysctl
[0]),
807 &value
, &size
, NULL
, 0) < 0) {
808 flog(LOG_DEBUG
, "Correct IPv6 forwarding sysctl branch not found, "
809 "perhaps the kernel interface has changed?");
810 return(0); /* this is of advisory value only */
813 if (value
!= 1 && !warned
) {
815 flog(LOG_DEBUG
, "IPv6 forwarding setting is: %u, should be 1", value
);
823 readin_config(char *fname
)
825 if ((yyin
= fopen(fname
, "r")) == NULL
)
827 flog(LOG_ERR
, "can't open %s: %s", fname
, strerror(errno
));
833 flog(LOG_ERR
, "error parsing or activating the config file: %s", fname
);
844 fprintf(stderr
, "Version: %s\n\n", VERSION
);
845 fprintf(stderr
, "Compiled in settings:\n");
846 fprintf(stderr
, " default config file \"%s\"\n", PATH_RADVD_CONF
);
847 fprintf(stderr
, " default pidfile \"%s\"\n", PATH_RADVD_PID
);
848 fprintf(stderr
, " default logfile \"%s\"\n", PATH_RADVD_LOG
);
849 fprintf(stderr
, " default syslog facility %d\n", LOG_FACILITY
);
850 fprintf(stderr
, "Please send bug reports or suggestions to %s.\n",
859 fprintf(stderr
, "usage: %s %s\n", pname
, usage_str
);