]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/main.c
Adds krt_source route attribute.
[thirdparty/bird.git] / sysdep / unix / main.c
CommitLineData
25697773
MM
1/*
2 * BIRD Internet Routing Daemon -- Unix Entry Point
3 *
50fe90ed 4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
25697773
MM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9a220cab 9#undef LOCAL_DEBUG
6b9fa320 10
1bc26957
OZ
11#define _GNU_SOURCE 1
12
25697773 13#include <stdio.h>
7a2105be 14#include <stdlib.h>
70591fa0
MM
15#include <fcntl.h>
16#include <unistd.h>
b1a1faba 17#include <signal.h>
1bc26957
OZ
18#include <pwd.h>
19#include <grp.h>
b1b19433 20#include <sys/stat.h>
48ec367a 21#include <libgen.h>
25697773
MM
22
23#include "nest/bird.h"
24#include "lib/lists.h"
25#include "lib/resource.h"
b5d9ee5c 26#include "lib/socket.h"
14dea0ed 27#include "lib/event.h"
221135d6 28#include "lib/string.h"
25697773 29#include "nest/route.h"
b5d9ee5c 30#include "nest/protocol.h"
8a48ecb8 31#include "nest/iface.h"
7d3aab1c 32#include "nest/cli.h"
f545d387 33#include "nest/locks.h"
70591fa0 34#include "conf/conf.h"
b9d70dc8 35#include "filter/filter.h"
b5d9ee5c
MM
36
37#include "unix.h"
7e7790c6 38#include "krt.h"
b5d9ee5c
MM
39
40/*
41 * Debugging
42 */
43
f9eb8f7e
MM
44#ifdef DEBUGGING
45static int debug_flag = 1;
46#else
47static int debug_flag = 0;
48#endif
49
4c9dd1e4
MM
50void
51async_dump(void)
b5d9ee5c 52{
4c9dd1e4 53 debug("INTERNAL STATE DUMP\n\n");
b5d9ee5c 54
5bc512aa 55 rdump(&root_pool);
b5d9ee5c
MM
56 sk_dump_all();
57 tm_dump_all();
8a48ecb8 58 if_dump_all();
869c6959 59 neigh_dump_all();
b5d9ee5c
MM
60 rta_dump_all();
61 rt_dump_all();
86b00230 62 protos_dump_all();
b5d9ee5c
MM
63
64 debug("\n");
65}
66
1bc26957
OZ
67/*
68 * Dropping privileges
69 */
70
71#ifdef CONFIG_RESTRICTED_PRIVILEGES
72#include "lib/syspriv.h"
73#else
74
75static inline void
76drop_uid(uid_t uid)
77{
78 die("Cannot change user on this platform");
79}
80
81#endif
82
83static inline void
84drop_gid(gid_t gid)
85{
86 if (setgid(gid) < 0)
87 die("setgid: %m");
88}
89
b5d9ee5c 90/*
70591fa0 91 * Reading the Configuration
b5d9ee5c
MM
92 */
93
acc93efd
OZ
94#ifdef PATH_IPROUTE_DIR
95
96static inline void
97add_num_const(char *name, int val)
98{
99 struct symbol *s = cf_find_symbol(name);
100 s->class = SYM_NUMBER;
101 s->def = NULL;
102 s->aux = val;
103}
104
105/* the code of read_iproute_table() is based on
106 rtnl_tab_initialize() from iproute2 package */
107static void
108read_iproute_table(char *file, char *prefix, int max)
109{
110 char buf[512], namebuf[512];
111 char *name;
112 int val;
113 FILE *fp;
114
115 strcpy(namebuf, prefix);
116 name = namebuf + strlen(prefix);
117
118 fp = fopen(file, "r");
119 if (!fp)
120 return;
121
122 while (fgets(buf, sizeof(buf), fp))
123 {
124 char *p = buf;
125
126 while (*p == ' ' || *p == '\t')
127 p++;
128
129 if (*p == '#' || *p == '\n' || *p == 0)
130 continue;
131
132 if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
133 sscanf(p, "0x%x %s #", &val, name) != 2 &&
134 sscanf(p, "%d %s\n", &val, name) != 2 &&
135 sscanf(p, "%d %s #", &val, name) != 2)
136 continue;
137
138 if (val < 0 || val > max)
139 continue;
140
141 for(p = name; *p; p++)
142 if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
143 *p = '_';
144
145 add_num_const(namebuf, val);
146 }
147
148 fclose(fp);
149}
150
151#endif // PATH_IPROUTE_DIR
152
153
4c9dd1e4 154static char *config_name = PATH_CONFIG;
70591fa0
MM
155
156static int
48ec367a 157cf_read(byte *dest, unsigned int len, int fd)
70591fa0 158{
48ec367a 159 int l = read(fd, dest, len);
70591fa0
MM
160 if (l < 0)
161 cf_error("Read error");
162 return l;
163}
164
48ec367a
OF
165static int
166cf_open(char *filename)
167{
168 char full_name[BIRD_FNAME_MAX];
169 char *cur = filename;
170 int ret;
171
172 if (*filename != '/') {
df279118
OZ
173 char dir[BIRD_FNAME_MAX];
174 strncpy(dir, config_name, sizeof(dir));
175 dir[sizeof(dir)-1] = 0;
176 snprintf(full_name, sizeof(full_name), "%s/%s", dirname(dir), filename);
9b7fdfc8 177 full_name[sizeof(full_name)-1] = 0;
48ec367a
OF
178 cur = full_name;
179 }
180
181 if ((ret = open(cur, O_RDONLY)) == -1)
182 cf_error("Unable to open included configuration file: %s", cur);
9b7fdfc8
OZ
183
184 return ret;
48ec367a
OF
185}
186
187
a0c37b45
MM
188void
189sysdep_preconfig(struct config *c)
190{
191 init_list(&c->logfiles);
acc93efd
OZ
192
193#ifdef PATH_IPROUTE_DIR
72aed1a0 194 read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
acc93efd
OZ
195 read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
196 read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
197 read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
198#endif
a0c37b45
MM
199}
200
50fe90ed 201int
6578a604 202sysdep_commit(struct config *new, struct config *old UNUSED)
a0c37b45 203{
44d4ab7a 204 log_switch(debug_flag, &new->logfiles, new->syslog_name);
50fe90ed 205 return 0;
a0c37b45
MM
206}
207
50fe90ed
MM
208static int
209unix_read_config(struct config **cp, char *name)
70591fa0 210{
50fe90ed 211 struct config *conf = config_alloc(name);
3c3271d9 212 int ret;
31b3e1bb 213
50fe90ed 214 *cp = conf;
48ec367a
OF
215 conf->file_fd = open(name, O_RDONLY);
216 if (conf->file_fd < 0)
50fe90ed 217 return 0;
70591fa0 218 cf_read_hook = cf_read;
48ec367a 219 cf_open_hook = cf_open;
3c3271d9 220 ret = config_parse(conf);
48ec367a 221 close(conf->file_fd);
3c3271d9 222 return ret;
50fe90ed
MM
223}
224
225static void
226read_config(void)
227{
228 struct config *conf;
229
230 if (!unix_read_config(&conf, config_name))
231 {
232 if (conf->err_msg)
48ec367a 233 die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
50fe90ed
MM
234 else
235 die("Unable to open configuration file %s: %m", config_name);
236 }
bf1aec97 237 config_commit(conf, RECONFIG_HARD);
70591fa0 238}
31b3e1bb 239
4c9dd1e4
MM
240void
241async_config(void)
242{
50fe90ed
MM
243 struct config *conf;
244
245 log(L_INFO "Reconfiguration requested by SIGHUP");
246 if (!unix_read_config(&conf, config_name))
247 {
248 if (conf->err_msg)
48ec367a 249 log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
50fe90ed
MM
250 else
251 log(L_ERR "Unable to open configuration file %s: %m", config_name);
252 config_free(conf);
253 }
254 else
bf1aec97 255 config_commit(conf, RECONFIG_HARD);
50fe90ed
MM
256}
257
258void
bf1aec97 259cmd_reconfig(char *name, int type)
50fe90ed
MM
260{
261 struct config *conf;
262
e0a45fb4
OZ
263 if (cli_access_restricted())
264 return;
265
50fe90ed
MM
266 if (!name)
267 name = config_name;
268 cli_msg(-2, "Reading configuration from %s", name);
269 if (!unix_read_config(&conf, name))
270 {
271 if (conf->err_msg)
272 cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
273 else
274 cli_msg(8002, "%s: %m", name);
275 config_free(conf);
276 }
277 else
278 {
bf1aec97 279 switch (config_commit(conf, type))
50fe90ed
MM
280 {
281 case CONF_DONE:
282 cli_msg(3, "Reconfigured.");
283 break;
284 case CONF_PROGRESS:
285 cli_msg(4, "Reconfiguration in progress.");
286 break;
bf8558bc
MM
287 case CONF_SHUTDOWN:
288 cli_msg(6, "Reconfiguration ignored, shutting down.");
289 break;
50fe90ed
MM
290 default:
291 cli_msg(5, "Reconfiguration already in progress, queueing new config");
292 }
293 }
4c9dd1e4
MM
294}
295
7d3aab1c
MM
296/*
297 * Command-Line Interface
298 */
299
300static sock *cli_sk;
dc82daaa 301static char *path_control_socket = PATH_CONTROL_SOCKET;
7d3aab1c 302
6baef17e
OZ
303
304static void
7d3aab1c
MM
305cli_write(cli *c)
306{
307 sock *s = c->priv;
308
6baef17e 309 while (c->tx_pos)
7d3aab1c
MM
310 {
311 struct cli_out *o = c->tx_pos;
6baef17e
OZ
312
313 int len = o->wpos - o->outpos;
7d3aab1c 314 s->tbuf = o->outpos;
6baef17e
OZ
315 o->outpos = o->wpos;
316
317 if (sk_send(s, len) <= 0)
318 return;
319
320 c->tx_pos = o->next;
7d3aab1c 321 }
6baef17e
OZ
322
323 /* Everything is written */
324 s->tbuf = NULL;
325 cli_written(c);
326}
327
328void
329cli_write_trigger(cli *c)
330{
331 sock *s = c->priv;
332
333 if (s->tbuf == NULL)
334 cli_write(c);
335}
336
337static void
338cli_tx(sock *s)
339{
340 cli_write(s->data);
7d3aab1c
MM
341}
342
343int
344cli_get_command(cli *c)
345{
346 sock *s = c->priv;
347 byte *t = c->rx_aux ? : s->rbuf;
348 byte *tend = s->rpos;
349 byte *d = c->rx_pos;
350 byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
351
352 while (t < tend)
353 {
354 if (*t == '\r')
355 t++;
356 else if (*t == '\n')
357 {
358 t++;
359 c->rx_pos = c->rx_buf;
360 c->rx_aux = t;
361 *d = 0;
362 return (d < dend) ? 1 : -1;
363 }
364 else if (d < dend)
365 *d++ = *t++;
366 }
367 c->rx_aux = s->rpos = s->rbuf;
368 c->rx_pos = d;
369 return 0;
370}
371
372static int
6578a604 373cli_rx(sock *s, int size UNUSED)
7d3aab1c 374{
7d3aab1c
MM
375 cli_kick(s->data);
376 return 0;
377}
378
7d3aab1c
MM
379static void
380cli_err(sock *s, int err)
381{
4761efdb
MM
382 if (config->cli_debug)
383 {
384 if (err)
385 log(L_INFO "CLI connection dropped: %s", strerror(err));
386 else
387 log(L_INFO "CLI connection closed");
388 }
7d3aab1c
MM
389 cli_free(s->data);
390}
391
392static int
6578a604 393cli_connect(sock *s, int size UNUSED)
7d3aab1c
MM
394{
395 cli *c;
396
4761efdb
MM
397 if (config->cli_debug)
398 log(L_INFO "CLI connect");
7d3aab1c
MM
399 s->rx_hook = cli_rx;
400 s->tx_hook = cli_tx;
401 s->err_hook = cli_err;
7d3aab1c 402 s->data = c = cli_new(s);
dc82daaa 403 s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
7d3aab1c
MM
404 c->rx_pos = c->rx_buf;
405 c->rx_aux = NULL;
ea0ac8f6 406 rmove(s, c->pool);
7d3aab1c
MM
407 return 1;
408}
409
410static void
e8b89a61 411cli_init_unix(uid_t use_uid, gid_t use_gid)
7d3aab1c
MM
412{
413 sock *s;
414
415 cli_init();
416 s = cli_sk = sk_new(cli_pool);
417 s->type = SK_UNIX_PASSIVE;
418 s->rx_hook = cli_connect;
e1ddd993 419 s->rbsize = 1024;
97e46d28 420 sk_open_unix(s, path_control_socket);
e8b89a61
OZ
421
422 if (use_uid || use_gid)
423 if (chown(path_control_socket, use_uid, use_gid) < 0)
424 die("chown: %m");
425
426 if (chmod(path_control_socket, 0660) < 0)
427 die("chmod: %m");
7d3aab1c
MM
428}
429
f4aabcee
MM
430/*
431 * Shutdown
432 */
433
e0a45fb4
OZ
434void
435cmd_shutdown(void)
436{
437 if (cli_access_restricted())
438 return;
439
440 cli_msg(7, "Shutdown requested");
441 order_shutdown();
442}
443
f4aabcee
MM
444void
445async_shutdown(void)
446{
6b9fa320 447 DBG("Shutting down...\n");
bf8558bc 448 order_shutdown();
f4aabcee
MM
449}
450
451void
bf8558bc 452sysdep_shutdown_done(void)
f4aabcee 453{
d3f36e59 454 unlink(path_control_socket);
76b53a4e 455 log_msg(L_FATAL "Shutdown completed");
653b4015 456 exit(0);
f4aabcee
MM
457}
458
4c9dd1e4
MM
459/*
460 * Signals
461 */
462
463static void
6578a604 464handle_sighup(int sig UNUSED)
4c9dd1e4 465{
6b9fa320 466 DBG("Caught SIGHUP...\n");
4c9dd1e4
MM
467 async_config_flag = 1;
468}
469
470static void
6578a604 471handle_sigusr(int sig UNUSED)
4c9dd1e4 472{
6b9fa320 473 DBG("Caught SIGUSR...\n");
4c9dd1e4
MM
474 async_dump_flag = 1;
475}
476
f4aabcee 477static void
6578a604 478handle_sigterm(int sig UNUSED)
f4aabcee 479{
6b9fa320 480 DBG("Caught SIGTERM...\n");
f4aabcee
MM
481 async_shutdown_flag = 1;
482}
483
4c9dd1e4
MM
484static void
485signal_init(void)
486{
487 struct sigaction sa;
488
489 bzero(&sa, sizeof(sa));
490 sa.sa_handler = handle_sigusr;
491 sa.sa_flags = SA_RESTART;
492 sigaction(SIGUSR1, &sa, NULL);
493 sa.sa_handler = handle_sighup;
494 sa.sa_flags = SA_RESTART;
495 sigaction(SIGHUP, &sa, NULL);
f4aabcee
MM
496 sa.sa_handler = handle_sigterm;
497 sa.sa_flags = SA_RESTART;
498 sigaction(SIGTERM, &sa, NULL);
4c9dd1e4
MM
499 signal(SIGPIPE, SIG_IGN);
500}
501
502/*
503 * Parsing of command-line arguments
504 */
505
1bc26957 506static char *opt_list = "c:dD:ps:u:g:";
44d4ab7a
OZ
507static int parse_and_exit;
508char *bird_name;
1bc26957
OZ
509static char *use_user;
510static char *use_group;
0bcba21e 511
4c9dd1e4
MM
512static void
513usage(void)
514{
1bc26957 515 fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
4c9dd1e4
MM
516 exit(1);
517}
518
44d4ab7a
OZ
519static inline char *
520get_bird_name(char *s, char *def)
521{
522 char *t;
523 if (!s)
524 return def;
525 t = strrchr(s, '/');
526 if (!t)
527 return s;
528 if (!t[1])
529 return def;
530 return t+1;
531}
a4644ed6 532
1bc26957
OZ
533static inline uid_t
534get_uid(const char *s)
535{
536 struct passwd *pw;
537 char *endptr;
e8b89a61
OZ
538 long int rv;
539
540 if (!s)
541 return 0;
542
1bc26957 543 errno = 0;
e8b89a61 544 rv = strtol(s, &endptr, 10);
1bc26957
OZ
545
546 if (!errno && !*endptr)
547 return rv;
548
549 pw = getpwnam(s);
550 if (!pw)
551 die("Cannot find user '%s'", s);
552
553 return pw->pw_uid;
554}
555
556static inline gid_t
557get_gid(const char *s)
558{
559 struct group *gr;
560 char *endptr;
e8b89a61
OZ
561 long int rv;
562
563 if (!s)
564 return 0;
1bc26957
OZ
565
566 errno = 0;
e8b89a61 567 rv = strtol(s, &endptr, 10);
1bc26957
OZ
568
569 if (!errno && !*endptr)
570 return rv;
571
572 gr = getgrnam(s);
573 if (!gr)
574 die("Cannot find group '%s'", s);
575
576 return gr->gr_gid;
577}
578
4c9dd1e4
MM
579static void
580parse_args(int argc, char **argv)
581{
582 int c;
583
44d4ab7a 584 bird_name = get_bird_name(argv[0], "bird");
e67af428
MM
585 if (argc == 2)
586 {
587 if (!strcmp(argv[1], "--version"))
588 {
589 fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
590 exit(0);
591 }
592 if (!strcmp(argv[1], "--help"))
593 usage();
594 }
4c9dd1e4
MM
595 while ((c = getopt(argc, argv, opt_list)) >= 0)
596 switch (c)
597 {
598 case 'c':
599 config_name = optarg;
600 break;
601 case 'd':
a0c37b45
MM
602 debug_flag |= 1;
603 break;
604 case 'D':
4c9dd1e4 605 log_init_debug(optarg);
a0c37b45 606 debug_flag |= 2;
4c9dd1e4 607 break;
a4644ed6
OZ
608 case 'p':
609 parse_and_exit = 1;
610 break;
dc82daaa
MM
611 case 's':
612 path_control_socket = optarg;
613 break;
1bc26957
OZ
614 case 'u':
615 use_user = optarg;
616 break;
617 case 'g':
618 use_group = optarg;
619 break;
4c9dd1e4
MM
620 default:
621 usage();
622 }
623 if (optind < argc)
624 usage();
625}
626
fd50083d
MM
627/*
628 * Hic Est main()
629 */
25697773
MM
630
631int
4c9dd1e4 632main(int argc, char **argv)
25697773 633{
7a2105be
MM
634#ifdef HAVE_LIBDMALLOC
635 if (!getenv("DMALLOC_OPTIONS"))
636 dmalloc_debug(0x2f03d00);
637#endif
638
4c9dd1e4 639 parse_args(argc, argv);
a0c37b45
MM
640 if (debug_flag == 1)
641 log_init_debug("");
44d4ab7a 642 log_switch(debug_flag, NULL, NULL);
4c9dd1e4 643
c74c0e3c 644 resource_init();
f545d387 645 olock_init();
b5d9ee5c 646 io_init();
2326b001 647 rt_init();
8a48ecb8 648 if_init();
af582c48 649 roa_init();
c74c0e3c 650
e8b89a61
OZ
651 uid_t use_uid = get_uid(use_user);
652 gid_t use_gid = get_gid(use_group);
653
97e46d28 654 if (!parse_and_exit)
e8b89a61
OZ
655 {
656 test_old_bird(path_control_socket);
657 cli_init_unix(use_uid, use_gid);
658 }
659
660 if (use_gid)
661 drop_gid(use_gid);
662
663 if (use_uid)
664 drop_uid(use_uid);
97e46d28 665
0432c017 666 protos_build();
3991d84e
MM
667 proto_build(&proto_unix_kernel);
668 proto_build(&proto_unix_iface);
c74c0e3c 669
c74c0e3c 670 read_config();
8a48ecb8 671
a4644ed6
OZ
672 if (parse_and_exit)
673 exit(0);
674
0bcba21e
MM
675 if (!debug_flag)
676 {
677 pid_t pid = fork();
678 if (pid < 0)
679 die("fork: %m");
4524331a 680 if (pid)
0bcba21e
MM
681 return 0;
682 setsid();
8411a37e
MM
683 close(0);
684 if (open("/dev/null", O_RDWR) < 0)
685 die("Cannot open /dev/null: %m");
686 dup2(0, 1);
687 dup2(0, 2);
0bcba21e
MM
688 }
689
b5d9ee5c
MM
690 signal_init();
691
9a220cab
MM
692#ifdef LOCAL_DEBUG
693 async_dump_flag = 1;
694#endif
8a48ecb8 695
76b53a4e 696 log(L_INFO "Started");
6b9fa320 697 DBG("Entering I/O loop.\n");
25697773 698
b5d9ee5c 699 io_loop();
08c69a77 700 bug("I/O loop died");
25697773 701}