1 /*
2 *
3 * Authors:
4 * Pedro Roque <roque@di.fc.ul.pt>
5 * Lars Fenneberg <lf@elemental.net>
6 *
7 * This software is Copyright 1996-2000 by the above mentioned author(s),
8 * All Rights Reserved.
9 *
10 * The license which is distributed with this software in the file COPYRIGHT
11 * applies to this software. If your distribution is missing this file, you
12 * may request it from <reubenhwk@gmail.com>.
13 *
14 */
15
16 #include "radvd.h"
17 #include "config.h"
18 #include "includes.h"
19 #include "pathnames.h"
20
21 #ifdef HAVE_NETLINK
22 #include "netlink.h"
23 #endif
24
25 #include <libgen.h>
26 #include <poll.h>
27 #include <sys/file.h>
28
29 #ifdef HAVE_GETOPT_LONG
30
31 /* clang-format off */
32 static char usage_str[] = {
33 "\n"
34 " -C, --config=PATH Set the config file. Default is /etc/radvd.d.\n"
35 " -c, --configtest Parse the config file and exit.\n"
36 " -d, --debug=NUM Set the debug level. Values can be 1, 2, 3, 4 or 5.\n"
37 " -f, --facility=NUM Set the logging facility.\n"
38 " -h, --help Show this help screen.\n"
39 " -l, --logfile=PATH Set the log file.\n"
40 " -m, --logmethod=X Set method to: syslog, stderr, stderr_syslog, logfile,\n"
41 " stderr_clean, or none.\n"
42 " -n, --nodaemon Prevent the daemonizing.\n"
43 " -p, --pidfile=PATH Set the pid file.\n"
44 " -t, --chrootdir=PATH Chroot to the specified path.\n"
45 " -u, --username=USER Switch to the specified user.\n"
46 " -v, --version Print the version and quit.\n"
47 };
48
49 static struct option prog_opt[] = {
50 {"chrootdir", 1, 0, 't'},
51 {"config", 1, 0, 'C'},
52 {"configtest", 0, 0, 'c'},
53 {"debug", 1, 0, 'd'},
54 {"facility", 1, 0, 'f'},
55 {"help", 0, 0, 'h'},
56 {"logfile", 1, 0, 'l'},
57 {"logmethod", 1, 0, 'm'},
58 {"nodaemon", 0, 0, 'n'},
59 {"pidfile", 1, 0, 'p'},
60 {"username", 1, 0, 'u'},
61 {"version", 0, 0, 'v'},
62 {NULL, 0, 0, 0}
63 };
64
65 #else
66
67 static char usage_str[] = {
68 "[-hvcn] [-d level] [-C config_path] [-m log_method] [-l log_file]\n"
69 "\t[-f facility] [-p pid_file] [-u username] [-t chrootdir]"
70
71 };
72 /* clang-format on */
73
74 #endif
75
76 static volatile int sighup_received = 0;
77 static volatile int sigint_received = 0;
78 static volatile int sigterm_received = 0;
79 static volatile int sigusr1_received = 0;
80
81 static int check_conffile_perm(const char *, const char *);
82 static int drop_root_privileges(const char *);
83 static int open_and_lock_pid_file(char const *daemon_pid_file_ident);
84 static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid);
85 static pid_t daemonp(char const *daemon_pid_file_ident);
86 static pid_t do_daemonize(int log_method, char const *daemon_pid_file_ident);
87 static struct Interface *main_loop(int sock, struct Interface *ifaces, char const *conf_path);
88 static struct Interface *reload_config(int sock, struct Interface *ifaces, char const *conf_path);
89 static void check_pid_file(char const *daemon_pid_file_ident);
90 static void config_interface(struct Interface *iface);
91 static void kickoff_adverts(int sock, struct Interface *iface);
92 static void reset_prefix_lifetimes(struct Interface *ifaces);
93 static void reset_prefix_lifetimes_foo(struct Interface *iface, void *data);
94 static void setup_iface_foo(struct Interface *iface, void *data);
95 static void setup_ifaces(int sock, struct Interface *ifaces);
96 static void sighup_handler(int sig);
97 static void sigint_handler(int sig);
98 static void sigterm_handler(int sig);
99 static void sigusr1_handler(int sig);
100 static void stop_advert_foo(struct Interface *iface, void *data);
101 static void stop_adverts(int sock, struct Interface *ifaces);
102 static void timer_handler(int sock, struct Interface *iface);
103 static void usage(char const *pname);
104 static void version(void);
105
106 /* daemonize and write pid file. The pid of the daemon child process
107 * will be written to the pid file from the *parent* process. This
108 * insures there is no race condition as described in redhat bug 664783. */
daemonp(char const * daemon_pid_file_ident)109 static pid_t daemonp(char const *daemon_pid_file_ident)
110 {
111 int pipe_ends[2];
112
113 if (0 != pipe(pipe_ends)) {
114 flog(LOG_ERR, "unable to create pipe: %s", strerror(errno));
115 exit(-1);
116 }
117
118 pid_t pid = fork();
119
120 if (-1 == pid) {
121 flog(LOG_ERR, "unable to fork in daemonp");
122 exit(-1);
123 } else if (0 == pid) {
124 /* Child process, detached.. */
125 pid = getpid();
126 close(pipe_ends[0]);
127 if (0 != write_pid_file(daemon_pid_file_ident, pid)) {
128 flog(LOG_ERR, "failure writing pid file");
129 exit(-1);
130 }
131 if (sizeof(pid) != write(pipe_ends[1], &pid, sizeof(pid))) {
132 flog(LOG_ERR, "failure piping pid to parent process");
133 }
134
135 umask(0);
136 if (-1 == setsid()) {
137 flog(LOG_ERR, "unable to become a session leader: %s", strerror(errno));
138 exit(-1);
139 }
140
141 if (chdir("/") == -1) {
142 perror("chdir");
143 exit(1);
144 }
145 close(STDIN_FILENO);
146 close(STDOUT_FILENO);
147 close(STDERR_FILENO);
148 if (open("/dev/null", O_RDONLY) == -1) {
149 flog(LOG_ERR, "unable to redirect stdin to /dev/null");
150 exit(-1);
151 }
152 if (open("/dev/null", O_WRONLY) == -1) {
153 flog(LOG_ERR, "unable to redirect stdout to /dev/null");
154 exit(-1);
155 }
156 if (open("/dev/null", O_RDWR) == -1) {
157 flog(LOG_ERR, "unable to redirect stderr to /dev/null");
158 exit(-1);
159 }
160 } else {
161 /* Parent. Make sure the pid file is written before exiting. */
162 close(pipe_ends[1]);
163 pid_t msg = -1;
164 ssize_t rc = read(pipe_ends[0], &msg, sizeof(msg));
165 if (rc != sizeof(msg)) {
166 flog(LOG_ERR, "child failed to signal pid file written: %s", strerror(errno));
167 exit(-1);
168 } else if (msg != pid) {
169 flog(LOG_ERR, "child wrote wrong pid to pid file: %d", msg);
170 exit(-1);
171 } else {
172 dlog(LOG_DEBUG, 5, "child signaled pid file written: %d", msg);
173 }
174 close(pipe_ends[0]);
175
176 return pid;
177 }
178 return 0;
179 }
180
main(int argc,char * argv[])181 int main(int argc, char *argv[])
182 {
183 int c;
184 int log_method = L_UNSPEC;
185 char *logfile = PATH_RADVD_LOG;
186 int facility = LOG_FACILITY;
187 char *username = NULL;
188 char *chrootdir = NULL;
189 int configtest = 0;
190 int daemonize = 1;
191
192 char const *pname = ((pname = strrchr(argv[0], '/')) != NULL) ? pname + 1 : argv[0];
193
194 srand((unsigned int)time(NULL));
195
196 char const *conf_path = PATH_RADVD_CONF;
197 char const *daemon_pid_file_ident = PATH_RADVD_PID;
198
199 /* parse args */
200 #define OPTIONS_STR "d:C:l:m:p:t:u:vhcn"
201 #ifdef HAVE_GETOPT_LONG
202 int opt_idx;
203 while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0)
204 #else
205 while ((c = getopt(argc, argv, OPTIONS_STR)) > 0)
206 #endif
207 {
208 switch (c) {
209 case 'C':
210 conf_path = optarg;
211 break;
212 case 'd':
213 set_debuglevel(atoi(optarg));
214 break;
215 case 'f':
216 facility = atoi(optarg);
217 break;
218 case 'l':
219 logfile = optarg;
220 break;
221 case 'p':
222 daemon_pid_file_ident = optarg;
223 break;
224 case 'm':
225 if (!strcmp(optarg, "syslog")) {
226 log_method = L_SYSLOG;
227 } else if (!strcmp(optarg, "stderr_syslog")) {
228 log_method = L_STDERR_SYSLOG;
229 } else if (!strcmp(optarg, "stderr")) {
230 log_method = L_STDERR;
231 } else if (!strcmp(optarg, "stderr_clean")) {
232 log_method = L_STDERR_CLEAN;
233 } else if (!strcmp(optarg, "logfile")) {
234 log_method = L_LOGFILE;
235 } else if (!strcmp(optarg, "none")) {
236 log_method = L_NONE;
237 } else {
238 fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
239 exit(1);
240 }
241 break;
242 case 't':
243 chrootdir = strdup(optarg);
244 break;
245 case 'u':
246 username = strdup(optarg);
247 break;
248 case 'v':
249 version();
250 break;
251 case 'c':
252 configtest = 1;
253 break;
254 case 'n':
255 daemonize = 0;
256 break;
257 case 'h':
258 usage(pname);
259 #ifdef HAVE_GETOPT_LONG
260 case ':':
261 fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name);
262 exit(1);
263 #endif
264 case '?':
265 exit(1);
266 }
267 }
268
269 /* TODO: Seems like this chroot'ing should happen *after* daemonizing for
270 * the sake of the PID file. */
271 if (chrootdir) {
272 if (!username) {
273 fprintf(stderr, "Chroot as root is not safe, exiting\n");
274 exit(1);
275 }
276
277 if (chroot(chrootdir) == -1) {
278 perror("chroot");
279 exit(1);
280 }
281
282 if (chdir("/") == -1) {
283 perror("chdir");
284 exit(1);
285 }
286 /* username will be switched later */
287 }
288
289 if (configtest) {
290 set_debuglevel(1);
291 switch (log_method) {
292 case L_STDERR:
293 case L_STDERR_CLEAN:
294 break;
295 case L_STDERR_SYSLOG:
296 case L_NONE:
297 case L_UNSPEC:
298 case L_SYSLOG:
299 case L_LOGFILE:
300 default:
301 log_method = L_STDERR;
302 break;
303 }
304 }
305 if (log_method == L_UNSPEC)
306 log_method = daemonize ? L_STDERR_SYSLOG : L_STDERR;
307 if (log_open(log_method, pname, logfile, facility) < 0) {
308 perror("log_open");
309 exit(1);
310 }
311
312 if (!configtest) {
313 flog(LOG_INFO, "version %s started", VERSION);
314 }
315
316 /* check that 'other' cannot write the file
317 * for non-root, also that self/own group can't either
318 */
319 if (check_conffile_perm(username, conf_path) != 0) {
320 if (get_debuglevel() == 0) {
321 flog(LOG_ERR, "exiting, permissions on conf_file invalid");
322 exit(1);
323 } else
324 flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
325 }
326
327 /* parse config file */
328 struct Interface *ifaces = NULL;
329 if ((ifaces = readin_config(conf_path)) == 0) {
330 flog(LOG_ERR, "exiting, failed to read config file");
331 exit(1);
332 }
333
334 if (configtest) {
335 free_ifaces(ifaces);
336 exit(0);
337 }
338
339 /* get a raw socket for sending and receiving ICMPv6 messages */
340 int sock = open_icmpv6_socket();
341 if (sock < 0) {
342 perror("open_icmpv6_socket");
343 exit(1);
344 }
345
346 /* if we know how to do it, check whether forwarding is enabled */
347 if (check_ip6_forwarding()) {
348 flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway");
349 }
350
351 int const pidfd = open_and_lock_pid_file(daemon_pid_file_ident);
352
353 /*
354 * okay, config file is read in, socket and stuff is setup, so
355 * lets fork now...
356 */
357 if (daemonize) {
358 pid_t pid = do_daemonize(log_method, daemon_pid_file_ident);
359 if (pid != 0 && pid != -1) {
360 /* We want to see clean output from valgrind, so free username, chrootdir,
361 * and ifaces in the child process. */
362 if (ifaces)
363 free_ifaces(ifaces);
364
365 if (username)
366 free(username);
367
368 if (chrootdir)
369 free(chrootdir);
370
371 exit(0);
372 }
373 } else {
374 if (0 != write_pid_file(daemon_pid_file_ident, getpid())) {
375 flog(LOG_ERR, "failure writing pid file detected");
376 exit(-1);
377 }
378 }
379
380 check_pid_file(daemon_pid_file_ident);
381
382 #ifdef __linux__
383 /* for privsep */ {
384 dlog(LOG_DEBUG, 3, "initializing privsep");
385
386 int pipefds[2];
387
388 if (pipe(pipefds) != 0) {
389 flog(LOG_ERR, "Couldn't create privsep pipe.");
390 return -1;
391 }
392
393 pid_t pid = fork();
394
395 if (pid == -1) {
396 flog(LOG_ERR, "Couldn't fork for privsep.");
397 return -1;
398 }
399
400 if (pid == 0) {
401 /* We want to see clean output from valgrind, so free username, chrootdir,
402 * and ifaces in the child process. */
403 if (ifaces)
404 free_ifaces(ifaces);
405
406 if (username)
407 free(username);
408
409 if (chrootdir)
410 free(chrootdir);
411
412 close(pipefds[1]);
413
414 privsep_init(pipefds[0]);
415 _exit(0);
416 }
417
418 dlog(LOG_DEBUG, 3, "radvd privsep PID is %d", pid);
419
420 /* Continue execution (will drop privileges soon) */
421 close(pipefds[0]);
422 privsep_set_write_fd(pipefds[1]);
423 }
424 #endif
425
426 if (username) {
427 if (drop_root_privileges(username) < 0) {
428 perror("drop_root_privileges");
429 flog(LOG_ERR, "unable to drop root privileges");
430 exit(1);
431 }
432 dlog(LOG_DEBUG, 3, "running as user: %s", username);
433 }
434
435 setup_ifaces(sock, ifaces);
436 ifaces = main_loop(sock, ifaces, conf_path);
437 stop_adverts(sock, ifaces);
438
439 flog(LOG_INFO, "removing %s", daemon_pid_file_ident);
440 unlink(daemon_pid_file_ident);
441 close(pidfd);
442
443 if (ifaces)
444 free_ifaces(ifaces);
445
446 if (chrootdir)
447 free(chrootdir);
448
449 if (username)
450 free(username);
451
452 flog(LOG_INFO, "returning from radvd main");
453 log_close();
454
455 return 0;
456 }
457
main_loop(int sock,struct Interface * ifaces,char const * conf_path)458 static struct Interface *main_loop(int sock, struct Interface *ifaces, char const *conf_path)
459 {
460 struct pollfd fds[2];
461 sigset_t sigmask;
462 sigset_t sigempty;
463 struct sigaction sa;
464
465 sigemptyset(&sigempty);
466
467 sigemptyset(&sigmask);
468 sigaddset(&sigmask, SIGHUP);
469 sigaddset(&sigmask, SIGTERM);
470 sigaddset(&sigmask, SIGINT);
471 sigaddset(&sigmask, SIGUSR1);
472 sigprocmask(SIG_BLOCK, &sigmask, NULL);
473
474 sa.sa_handler = sighup_handler;
475 sigemptyset(&sa.sa_mask);
476 sa.sa_flags = 0;
477 sigaction(SIGHUP, &sa, 0);
478
479 sa.sa_handler = sigterm_handler;
480 sigemptyset(&sa.sa_mask);
481 sa.sa_flags = 0;
482 sigaction(SIGTERM, &sa, 0);
483
484 sa.sa_handler = sigint_handler;
485 sigemptyset(&sa.sa_mask);
486 sa.sa_flags = 0;
487 sigaction(SIGINT, &sa, 0);
488
489 sa.sa_handler = sigusr1_handler;
490 sigemptyset(&sa.sa_mask);
491 sa.sa_flags = 0;
492 sigaction(SIGUSR1, &sa, 0);
493
494 memset(fds, 0, sizeof(fds));
495
496 fds[0].fd = sock;
497 fds[0].events = POLLIN;
498
499 #if HAVE_NETLINK
500 fds[1].fd = netlink_socket();
501 fds[1].events = POLLIN;
502 #else
503 fds[1].fd = -1;
504 #endif
505
506 for (;;) {
507 struct timespec *tsp = 0;
508
509 struct Interface *next_iface_to_expire = find_iface_by_time(ifaces);
510 if (next_iface_to_expire) {
511 static struct timespec ts;
512 int timeout = next_time_msec(next_iface_to_expire);
513 ts.tv_sec = timeout / 1000;
514 ts.tv_nsec = (timeout - 1000 * ts.tv_sec) * 1000000;
515 tsp = &ts;
516 dlog(LOG_DEBUG, 1, "polling for %g second(s), next iface is %s", timeout / 1000.0,
517 next_iface_to_expire->props.name);
518 } else {
519 dlog(LOG_DEBUG, 1, "no iface is next. Polling indefinitely");
520 }
521 #ifdef HAVE_PPOLL
522 int rc = ppoll(fds, sizeof(fds) / sizeof(fds[0]), tsp, &sigempty);
523 #else
524 int rc = poll(fds, sizeof(fds) / sizeof(fds[0]), 1000 * tsp->tv_sec);
525 #endif
526
527 if (rc > 0) {
528 #ifdef HAVE_NETLINK
529 if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
530 flog(LOG_WARNING, "socket error on fds[1].fd");
531 } else if (fds[1].revents & POLLIN) {
532 process_netlink_msg(fds[1].fd, ifaces);
533 }
534 #endif
535
536 if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
537 flog(LOG_WARNING, "socket error on fds[0].fd");
538 } else if (fds[0].revents & POLLIN) {
539 int len, hoplimit;
540 struct sockaddr_in6 rcv_addr;
541 struct in6_pktinfo *pkt_info = NULL;
542 unsigned char msg[MSG_SIZE_RECV];
543 unsigned char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))];
544
545 len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit, chdr);
546 if (len > 0 && pkt_info) {
547 process(sock, ifaces, msg, len, &rcv_addr, pkt_info, hoplimit);
548 } else if (!pkt_info) {
549 dlog(LOG_INFO, 4, "recv_rs_ra returned null pkt_info");
550 } else if (len <= 0) {
551 dlog(LOG_INFO, 4, "recv_rs_ra returned len <= 0: %d", len);
552 }
553 }
554 } else if (rc == 0) {
555 if (next_iface_to_expire)
556 timer_handler(sock, next_iface_to_expire);
557 } else if (rc == -1) {
558 dlog(LOG_INFO, 3, "poll returned early: %s", strerror(errno));
559 }
560
561 if (sigint_received) {
562 flog(LOG_WARNING, "exiting, %d sigint(s) received", sigint_received);
563 break;
564 }
565
566 if (sigterm_received) {
567 flog(LOG_WARNING, "exiting, %d sigterm(s) received", sigterm_received);
568 break;
569 }
570
571 if (sighup_received) {
572 dlog(LOG_INFO, 3, "sig hup received");
573 ifaces = reload_config(sock, ifaces, conf_path);
574 sighup_received = 0;
575 }
576
577 if (sigusr1_received) {
578 dlog(LOG_INFO, 3, "sig usr1 received");
579 reset_prefix_lifetimes(ifaces);
580 sigusr1_received = 0;
581 }
582 }
583
584 return ifaces;
585 }
586
do_daemonize(int log_method,char const * daemon_pid_file_ident)587 static pid_t do_daemonize(int log_method, char const *daemon_pid_file_ident)
588 {
589 pid_t pid = -1;
590
591 pid = daemonp(daemon_pid_file_ident);
592
593 if (-1 == pid) {
594 flog(LOG_ERR, "unable to daemonize: %s", strerror(errno));
595 exit(-1);
596 }
597 return pid;
598 }
599
open_pid_file(char const * daemon_pid_file_ident)600 static int open_pid_file(char const *daemon_pid_file_ident)
601 {
602 int pidfd = open(daemon_pid_file_ident, O_SYNC | O_CREAT | O_RDWR, 0644);
603 if (-1 == pidfd) {
604 flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
605 exit(-1);
606 } else {
607 dlog(LOG_DEBUG, 5, "opened pid file %s", daemon_pid_file_ident);
608 }
609 return pidfd;
610 }
611
open_and_lock_pid_file(char const * daemon_pid_file_ident)612 static int open_and_lock_pid_file(char const *daemon_pid_file_ident)
613 {
614 dlog(LOG_DEBUG, 3, "radvd startup PID is %d", getpid());
615
616 int pidfd = open_pid_file(daemon_pid_file_ident);
617
618 int lock = flock(pidfd, LOCK_EX | LOCK_NB);
619 if (0 != lock) {
620 flog(LOG_ERR, "unable to lock pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
621 exit(-1);
622 } else {
623 dlog(LOG_DEBUG, 4, "locked pid file %s", daemon_pid_file_ident);
624 }
625
626 return pidfd;
627 }
628
write_pid_file(char const * daemon_pid_file_ident,pid_t pid)629 static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid)
630 {
631 int pidfd = open_pid_file(daemon_pid_file_ident);
632 char pid_str[20] = {""};
633 sprintf(pid_str, "%d", pid);
634 dlog(LOG_DEBUG, 3, "radvd PID is %s", pid_str);
635 size_t len = strlen(pid_str);
636 int rc = write(pidfd, pid_str, len);
637 if (rc != (int)len) {
638 return -1;
639 }
640 char newline[] = {"\n"};
641 len = strlen(newline);
642 rc = write(pidfd, newline, len);
643 if (rc != (int)len) {
644 return -1;
645 }
646 rc = fsync(pidfd);
647 if (rc != 0) {
648 dlog(LOG_DEBUG, 4, "failed to fsync pid file: %s", daemon_pid_file_ident);
649 }
650 rc = close(pidfd);
651 if (rc != 0) {
652 dlog(LOG_DEBUG, 4, "failed to close pid file: %s", daemon_pid_file_ident);
653 }
654 char *dirstrcopy = strdup(daemon_pid_file_ident);
655 char *dirstr = dirname(dirstrcopy);
656 int dirfd = open(dirstr, O_RDONLY);
657 rc = fsync(dirfd);
658 if (rc != 0) {
659 dlog(LOG_DEBUG, 4, "failed to fsync pid dir: %s", dirstr);
660 }
661 rc = close(dirfd);
662 if (rc != 0) {
663 dlog(LOG_DEBUG, 4, "failed to close pid dir: %s", dirstr);
664 }
665 free(dirstrcopy);
666 dlog(LOG_DEBUG, 4, "wrote pid %d to pid file: %s", pid, daemon_pid_file_ident);
667 return rc;
668 }
669
check_pid_file(char const * daemon_pid_file_ident)670 static void check_pid_file(char const *daemon_pid_file_ident)
671 {
672 FILE *pidfile = fopen(daemon_pid_file_ident, "r");
673
674 if (!pidfile) {
675 flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
676 exit(-1);
677 }
678
679 pid_t pid = -1;
680
681 int rc = fscanf(pidfile, "%d", &pid);
682 fclose(pidfile);
683
684 if (rc != 1) {
685 flog(LOG_ERR, "unable to read pid from pid file: %s", daemon_pid_file_ident);
686 exit(-1);
687 }
688
689 if (pid != getpid()) {
690 flog(LOG_ERR, "pid in file, %s, doesn't match getpid(): %d != %d", daemon_pid_file_ident, pid, getpid());
691 exit(-1);
692 }
693 dlog(LOG_DEBUG, 4, "validated pid file, %s: %d", daemon_pid_file_ident, pid);
694 }
695
timer_handler(int sock,struct Interface * iface)696 static void timer_handler(int sock, struct Interface *iface)
697 {
698 dlog(LOG_DEBUG, 1, "timer_handler called for %s", iface->props.name);
699
700 if (send_ra_forall(sock, iface, NULL) != 0) {
701 dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name);
702 }
703
704 double next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval);
705
706 reschedule_iface(iface, next);
707 }
708
config_interface(struct Interface * iface)709 static void config_interface(struct Interface *iface)
710 {
711 if (iface->AdvLinkMTU)
712 set_interface_linkmtu(iface->props.name, iface->AdvLinkMTU);
713 if (iface->ra_header_info.AdvCurHopLimit)
714 set_interface_curhlim(iface->props.name, iface->ra_header_info.AdvCurHopLimit);
715 if (iface->ra_header_info.AdvReachableTime)
716 set_interface_reachtime(iface->props.name, iface->ra_header_info.AdvReachableTime);
717 if (iface->ra_header_info.AdvRetransTimer)
718 set_interface_retranstimer(iface->props.name, iface->ra_header_info.AdvRetransTimer);
719 }
720
721 /*
722 * send initial advertisement and set timers
723 */
kickoff_adverts(int sock,struct Interface * iface)724 static void kickoff_adverts(int sock, struct Interface *iface)
725 {
726 clock_gettime(CLOCK_MONOTONIC, &iface->times.last_ra_time);
727
728 if (iface->UnicastOnly)
729 return;
730
731 clock_gettime(CLOCK_MONOTONIC, &iface->times.last_multicast);
732
733 /* send an initial advertisement */
734 if (send_ra_forall(sock, iface, NULL) != 0) {
735 dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name);
736 }
737
738 double next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval);
739 reschedule_iface(iface, next);
740 }
741
stop_advert_foo(struct Interface * iface,void * data)742 static void stop_advert_foo(struct Interface *iface, void *data)
743 {
744 if (!iface->UnicastOnly) {
745 /* send a final advertisement with zero Router Lifetime */
746 dlog(LOG_DEBUG, 4, "stopping all adverts on %s", iface->props.name);
747 iface->state_info.cease_adv = 1;
748 int sock = *(int *)data;
749 send_ra_forall(sock, iface, NULL);
750 }
751 }
752
stop_adverts(int sock,struct Interface * ifaces)753 static void stop_adverts(int sock, struct Interface *ifaces)
754 {
755 flog(LOG_INFO, "sending stop adverts");
756 /*
757 * send final RA (a SHOULD in RFC4861 section 6.2.5)
758 */
759 for_each_iface(ifaces, stop_advert_foo, &sock);
760 }
761
setup_iface_foo(struct Interface * iface,void * data)762 static void setup_iface_foo(struct Interface *iface, void *data)
763 {
764 int sock = *(int *)data;
765
766 if (setup_iface(sock, iface) < 0) {
767 if (iface->IgnoreIfMissing) {
768 dlog(LOG_DEBUG, 4, "interface %s does not exist or is not set up properly, ignoring the interface",
769 iface->props.name);
770 return;
771 } else {
772 flog(LOG_ERR, "interface %s does not exist or is not set up properly", iface->props.name);
773 exit(1);
774 }
775 }
776
777 config_interface(iface);
778 kickoff_adverts(sock, iface);
779 }
780
setup_ifaces(int sock,struct Interface * ifaces)781 static void setup_ifaces(int sock, struct Interface *ifaces) { for_each_iface(ifaces, setup_iface_foo, &sock); }
782
reload_config(int sock,struct Interface * ifaces,char const * conf_path)783 static struct Interface *reload_config(int sock, struct Interface *ifaces, char const *conf_path)
784 {
785 free_ifaces(ifaces);
786
787 flog(LOG_INFO, "attempting to reread config file");
788
789 /* reread config file */
790 ifaces = readin_config(conf_path);
791 if (!ifaces) {
792 flog(LOG_ERR, "exiting, failed to read config file");
793 exit(1);
794 }
795 setup_ifaces(sock, ifaces);
796
797 flog(LOG_INFO, "resuming normal operation");
798
799 return ifaces;
800 }
801
sighup_handler(int sig)802 static void sighup_handler(int sig) { sighup_received = 1; }
803
sigterm_handler(int sig)804 static void sigterm_handler(int sig)
805 {
806 ++sigterm_received;
807
808 if (sigterm_received > 2) {
809 abort();
810 }
811 }
812
sigint_handler(int sig)813 static void sigint_handler(int sig)
814 {
815 ++sigint_received;
816
817 if (sigint_received > 2) {
818 abort();
819 }
820 }
821
sigusr1_handler(int sig)822 static void sigusr1_handler(int sig) { sigusr1_received = 1; }
823
reset_prefix_lifetimes_foo(struct Interface * iface,void * data)824 static void reset_prefix_lifetimes_foo(struct Interface *iface, void *data)
825 {
826 flog(LOG_INFO, "Resetting prefix lifetimes on %s", iface->props.name);
827
828 for (struct AdvPrefix *prefix = iface->AdvPrefixList; prefix; prefix = prefix->next) {
829 if (prefix->DecrementLifetimesFlag) {
830 char pfx_str[INET6_ADDRSTRLEN];
831 addrtostr(&prefix->Prefix, pfx_str, sizeof(pfx_str));
832 dlog(LOG_DEBUG, 4, "%s/%u%%%s plft reset from %u to %u secs", pfx_str, prefix->PrefixLen,
833 iface->props.name, prefix->curr_preferredlft, prefix->AdvPreferredLifetime);
834 dlog(LOG_DEBUG, 4, "%s/%u%%%s vlft reset from %u to %u secs", pfx_str, prefix->PrefixLen,
835 iface->props.name, prefix->curr_validlft, prefix->AdvValidLifetime);
836 prefix->curr_validlft = prefix->AdvValidLifetime;
837 prefix->curr_preferredlft = prefix->AdvPreferredLifetime;
838 }
839 }
840 }
841
reset_prefix_lifetimes(struct Interface * ifaces)842 static void reset_prefix_lifetimes(struct Interface *ifaces) { for_each_iface(ifaces, reset_prefix_lifetimes_foo, 0); }
843
drop_root_privileges(const char * username)844 static int drop_root_privileges(const char *username)
845 {
846 struct passwd *pw = getpwnam(username);
847 if (pw) {
848 if (initgroups(username, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
849 flog(LOG_ERR, "Couldn't change to '%.32s' uid=%d gid=%d", username, pw->pw_uid, pw->pw_gid);
850 return -1;
851 }
852 } else {
853 flog(LOG_ERR, "Couldn't find user '%.32s'", username);
854 return -1;
855 }
856 return 0;
857 }
858
check_conffile_perm(const char * username,const char * conf_file)859 static int check_conffile_perm(const char *username, const char *conf_file)
860 {
861 FILE *fp = fopen(conf_file, "r");
862 if (fp == NULL) {
863 flog(LOG_ERR, "can't open %s: %s", conf_file, strerror(errno));
864 return -1;
865 }
866 fclose(fp);
867
868 if (!username)
869 username = "root";
870
871 struct passwd *pw = getpwnam(username);
872 if (!pw) {
873 return -1;
874 }
875
876 struct stat stbuf;
877 if (0 != stat(conf_file, &stbuf)) {
878 return -1;
879 }
880
881 if (stbuf.st_mode & S_IWOTH) {
882 flog(LOG_ERR, "Insecure file permissions (writable by others): %s", conf_file);
883 return -1;
884 }
885
886 /* for non-root: must not be writable by self/own group */
887 if (strncmp(username, "root", 5) != 0 && ((stbuf.st_mode & S_IWGRP && pw->pw_gid == stbuf.st_gid) ||
888 (stbuf.st_mode & S_IWUSR && pw->pw_uid == stbuf.st_uid))) {
889 flog(LOG_ERR, "Insecure file permissions (writable by self/group): %s", conf_file);
890 return -1;
891 }
892
893 return 0;
894 }
895
version(void)896 static void version(void)
897 {
898 fprintf(stderr, "Version: %s\n\n", VERSION);
899 fprintf(stderr, "Compiled in settings:\n");
900 fprintf(stderr, " default config file \"%s\"\n", PATH_RADVD_CONF);
901 fprintf(stderr, " default pidfile \"%s\"\n", PATH_RADVD_PID);
902 fprintf(stderr, " default logfile \"%s\"\n", PATH_RADVD_LOG);
903 fprintf(stderr, " default syslog facility %d\n", LOG_FACILITY);
904 fprintf(stderr, "Please send bug reports or suggestions to %s.\n", CONTACT_EMAIL);
905
906 exit(1);
907 }
908
usage(char const * pname)909 static void usage(char const *pname)
910 {
911 fprintf(stderr, "usage: %s %s\n", pname, usage_str);
912 exit(1);
913 }
914