1/*
2 *  This file is free software: you may copy, redistribute and/or modify it
3 *  under the terms of the GNU General Public License as published by the
4 *  Free Software Foundation, either version 2 of the License, or (at your
5 *  option) any later version.
6 *
7 *  This file is distributed in the hope that it will be useful, but
8 *  WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 *  General Public License for more details.
11 *
12 *  You should have received a copy of the GNU General Public License
13 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
14 *
15 * This file incorporates work covered by the following copyright and
16 * permission notice:
17 *
18
19Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21Permission is hereby granted, free of charge, to any person obtaining a copy
22of this software and associated documentation files (the "Software"), to deal
23in the Software without restriction, including without limitation the rights
24to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25copies of the Software, and to permit persons to whom the Software is
26furnished to do so, subject to the following conditions:
27
28The above copyright notice and this permission notice shall be included in
29all copies or substantial portions of the Software.
30
31THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
34AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37THE SOFTWARE.
38*/
39
40/* include zebra library */
41#include <zebra.h>
42#include "getopt.h"
43#include "if.h"
44#include "log.h"
45#include "thread.h"
46#include "privs.h"
47#include "sigevent.h"
48#include "version.h"
49#include "command.h"
50#include "vty.h"
51#include "memory.h"
52
53#include "babel_main.h"
54#include "babeld.h"
55#include "util.h"
56#include "kernel.h"
57#include "babel_interface.h"
58#include "neighbour.h"
59#include "route.h"
60#include "xroute.h"
61#include "message.h"
62#include "resend.h"
63#include "babel_zebra.h"
64
65
66static void babel_init (int argc, char **argv);
67static char *babel_get_progname(char *argv_0);
68static void babel_fail(void);
69static void babel_init_random(void);
70static void babel_replace_by_null(int fd);
71static void babel_init_signals(void);
72static void babel_exit_properly(void);
73static void babel_save_state_file(void);
74
75
76struct thread_master *master;     /* quagga's threads handler */
77struct timeval babel_now;         /* current time             */
78
79unsigned char myid[8];            /* unique id (mac address of an interface) */
80int debug = 0;
81
82int resend_delay = -1;
83static const char *pidfile = PATH_BABELD_PID;
84
85const unsigned char zeroes[16] = {0};
86const unsigned char ones[16] =
87    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
88     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
89
90static const char *state_file = DAEMON_VTY_DIR "/babel-state";
91
92unsigned char protocol_group[16]; /* babel's link-local multicast address */
93int protocol_port;                /* babel's port */
94int protocol_socket = -1;         /* socket: communicate with others babeld */
95
96static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
97static char *babel_config_file = NULL;
98static char *babel_vty_addr = NULL;
99static int babel_vty_port = BABEL_VTY_PORT;
100
101/* Babeld options. */
102struct option longopts[] =
103{
104    { "daemon",      no_argument,       NULL, 'd'},
105    { "config_file", required_argument, NULL, 'f'},
106    { "pid_file",    required_argument, NULL, 'i'},
107    { "socket",      required_argument, NULL, 'z'},
108    { "help",        no_argument,       NULL, 'h'},
109    { "vty_addr",    required_argument, NULL, 'A'},
110    { "vty_port",    required_argument, NULL, 'P'},
111    { "user",        required_argument, NULL, 'u'},
112    { "group",       required_argument, NULL, 'g'},
113    { "version",     no_argument,       NULL, 'v'},
114    { 0 }
115};
116
117/* babeld privileges */
118static zebra_capabilities_t _caps_p [] =
119{
120    ZCAP_NET_RAW,
121    ZCAP_BIND
122};
123static struct zebra_privs_t babeld_privs =
124{
125#if defined(QUAGGA_USER)
126    .user = QUAGGA_USER,
127#endif
128#if defined QUAGGA_GROUP
129    .group = QUAGGA_GROUP,
130#endif
131#ifdef VTY_GROUP
132    .vty_group = VTY_GROUP,
133#endif
134    .caps_p = _caps_p,
135    .cap_num_p = 2,
136    .cap_num_i = 0
137};
138
139
140int
141main(int argc, char **argv)
142{
143    struct thread thread;
144    /* and print banner too */
145    babel_init(argc, argv);
146    while (thread_fetch (master, &thread)) {
147        thread_call (&thread);
148    }
149    return 0;
150}
151
152static void
153babel_usage (char *progname, int status)
154{
155  if (status != 0)
156    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
157  else
158    {
159      printf ("Usage : %s [OPTION...]\n\
160Daemon which manages Babel routing protocol.\n\n\
161-d, --daemon       Runs in daemon mode\n\
162-f, --config_file  Set configuration file name\n\
163-i, --pid_file     Set process identifier file name\n\
164-z, --socket       Set path of zebra socket\n\
165-A, --vty_addr     Set vty's bind address\n\
166-P, --vty_port     Set vty's port number\n\
167-u, --user         User to run as\n\
168-g, --group        Group to run as\n\
169-v, --version      Print program version\n\
170-h, --help         Display this help and exit\n\
171\n\
172Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
173    }
174  exit (status);
175}
176
177/* make initialisations witch don't need infos about kernel(interfaces, etc.) */
178static void
179babel_init(int argc, char **argv)
180{
181    int rc, opt;
182    int do_daemonise = 0;
183    char *progname = NULL;
184
185    /* Set umask before anything for security */
186    umask (0027);
187    progname = babel_get_progname(argv[0]);
188
189    /* set default log (lib/log.h) */
190    zlog_default = openzlog(progname, ZLOG_BABEL,
191                            LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
192    /* set log destination as stdout until the config file is read */
193    zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING);
194
195    babel_init_random();
196
197    /* set the Babel's default link-local multicast address and Babel's port */
198    parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
199    protocol_port = 6696;
200
201    /* get options */
202    while(1) {
203        opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0);
204        if(opt < 0)
205            break;
206
207        switch(opt) {
208            case 0:
209                break;
210            case 'd':
211                do_daemonise = -1;
212                break;
213            case 'f':
214                babel_config_file = optarg;
215                break;
216            case 'i':
217                pidfile = optarg;
218                break;
219            case 'z':
220                zclient_serv_path_set (optarg);
221                break;
222            case 'A':
223                babel_vty_addr = optarg;
224                break;
225            case 'P':
226                babel_vty_port = atoi (optarg);
227                if (babel_vty_port <= 0 || babel_vty_port > 0xffff)
228                    babel_vty_port = BABEL_VTY_PORT;
229                break;
230            case 'u':
231                babeld_privs.user = optarg;
232                break;
233            case 'g':
234                babeld_privs.group = optarg;
235                break;
236            case 'v':
237                print_version (progname);
238                exit (0);
239                break;
240            case 'h':
241                babel_usage (progname, 0);
242                break;
243            default:
244                babel_usage (progname, 1);
245                break;
246        }
247    }
248
249    /* create the threads handler */
250    master = thread_master_create ();
251
252    /* Library inits. */
253    zprivs_init (&babeld_privs);
254    babel_init_signals();
255    cmd_init (1);
256    vty_init (master);
257    memory_init ();
258
259    resend_delay = BABEL_DEFAULT_RESEND_DELAY;
260
261    babel_replace_by_null(STDIN_FILENO);
262
263    if (do_daemonise && daemonise() < 0) {
264        zlog_err("daemonise: %s", safe_strerror(errno));
265        exit (1);
266    }
267
268    /* write pid file */
269    if (pid_output(pidfile) < 0) {
270        zlog_err("error while writing pidfile");
271        exit (1);
272    };
273
274    /* init some quagga's dependencies, and babeld's commands */
275    babeld_quagga_init();
276    /* init zebra client's structure and it's commands */
277    /* this replace kernel_setup && kernel_setup_socket */
278    babelz_zebra_init ();
279
280    /* Get zebra configuration file. */
281    zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
282    vty_read_config (babel_config_file, babel_config_default);
283
284    /* Create VTY socket */
285    vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH);
286
287    /* init buffer */
288    rc = resize_receive_buffer(1500);
289    if(rc < 0)
290        babel_fail();
291
292    schedule_neighbours_check(5000, 1);
293
294    zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
295}
296
297/* return the progname (without path, example: "./x/progname" --> "progname") */
298static char *
299babel_get_progname(char *argv_0) {
300    char *p = strrchr (argv_0, '/');
301    return (p ? ++p : argv_0);
302}
303
304static void
305babel_fail(void)
306{
307    exit(1);
308}
309
310/* initialize random value, and set 'babel_now' by the way. */
311static void
312babel_init_random(void)
313{
314    gettime(&babel_now);
315    int rc;
316    unsigned int seed;
317
318    rc = read_random_bytes(&seed, sizeof(seed));
319    if(rc < 0) {
320        zlog_err("read(random): %s", safe_strerror(errno));
321        seed = 42;
322    }
323
324    seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
325    srandom(seed);
326}
327
328/*
329 close fd, and replace it by "/dev/null"
330 exit if error
331 */
332static void
333babel_replace_by_null(int fd)
334{
335    int fd_null;
336    int rc;
337
338    fd_null = open("/dev/null", O_RDONLY);
339    if(fd_null < 0) {
340        zlog_err("open(null): %s", safe_strerror(errno));
341        exit(1);
342    }
343
344    rc = dup2(fd_null, fd);
345    if(rc < 0) {
346        zlog_err("dup2(null, 0): %s", safe_strerror(errno));
347        exit(1);
348    }
349
350    close(fd_null);
351}
352
353/*
354 Load the state file: check last babeld's running state, usefull in case of
355 "/etc/init.d/babeld restart"
356 */
357void
358babel_load_state_file(void)
359{
360    int fd;
361    int rc;
362
363    fd = open(state_file, O_RDONLY);
364    if(fd < 0 && errno != ENOENT)
365        zlog_err("open(babel-state: %s)", safe_strerror(errno));
366    rc = unlink(state_file);
367    if(fd >= 0 && rc < 0) {
368        zlog_err("unlink(babel-state): %s", safe_strerror(errno));
369        /* If we couldn't unlink it, it's probably stale. */
370        close(fd);
371        fd = -1;
372    }
373    if(fd >= 0) {
374        char buf[100];
375        char buf2[100];
376        int s;
377        long t;
378        rc = read(fd, buf, 99);
379        if(rc < 0) {
380            zlog_err("read(babel-state): %s", safe_strerror(errno));
381        } else {
382            buf[rc] = '\0';
383            rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
384            if(rc == 3 && s >= 0 && s <= 0xFFFF) {
385                unsigned char sid[8];
386                rc = parse_eui64(buf2, sid);
387                if(rc < 0) {
388                    zlog_err("Couldn't parse babel-state.");
389                } else {
390                    struct timeval realnow;
391                    debugf(BABEL_DEBUG_COMMON,
392                           "Got %s %d %ld from babel-state.",
393                           format_eui64(sid), s, t);
394                    gettimeofday(&realnow, NULL);
395                    if(memcmp(sid, myid, 8) == 0)
396                        myseqno = seqno_plus(s, 1);
397                    else
398                        zlog_err("ID mismatch in babel-state. id=%s; old=%s",
399                                 format_eui64(myid),
400                                 format_eui64(sid));
401                }
402            } else {
403                zlog_err("Couldn't parse babel-state.");
404            }
405        }
406        close(fd);
407        fd = -1;
408    }
409}
410
411static void
412babel_sigexit(void)
413{
414    zlog_notice("Terminating on signal");
415
416    babel_exit_properly();
417}
418
419static void
420babel_sigusr1 (void)
421{
422    zlog_rotate (NULL);
423}
424
425static void
426babel_init_signals(void)
427{
428    static struct quagga_signal_t babel_signals[] =
429    {
430        {
431            .signal = SIGUSR1,
432            .handler = &babel_sigusr1,
433        },
434        {
435            .signal = SIGINT,
436            .handler = &babel_sigexit,
437        },
438        {
439            .signal = SIGTERM,
440            .handler = &babel_sigexit,
441        },
442    };
443
444    signal_init (master, array_size(babel_signals), babel_signals);
445}
446
447static void
448babel_exit_properly(void)
449{
450    debugf(BABEL_DEBUG_COMMON, "Exiting...");
451    usleep(roughly(10000));
452    gettime(&babel_now);
453
454    /* Uninstall and flush all routes. */
455    debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
456    flush_all_routes();
457    babel_interface_close_all();
458    babel_zebra_close_connexion();
459    babel_save_state_file();
460    debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
461    if(pidfile)
462        unlink(pidfile);
463    debugf(BABEL_DEBUG_COMMON, "Done.");
464
465    exit(0);
466}
467
468static void
469babel_save_state_file(void)
470{
471    int fd;
472    int rc;
473
474    debugf(BABEL_DEBUG_COMMON, "Save state file.");
475    fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
476    if(fd < 0) {
477        zlog_err("creat(babel-state): %s", safe_strerror(errno));
478        unlink(state_file);
479    } else {
480        struct timeval realnow;
481        char buf[100];
482        gettimeofday(&realnow, NULL);
483        rc = snprintf(buf, 100, "%s %d %ld\n",
484                      format_eui64(myid), (int)myseqno,
485                      (long)realnow.tv_sec);
486        if(rc < 0 || rc >= 100) {
487            zlog_err("write(babel-state): overflow.");
488            unlink(state_file);
489        } else {
490            rc = write(fd, buf, rc);
491            if(rc < 0) {
492                zlog_err("write(babel-state): %s", safe_strerror(errno));
493                unlink(state_file);
494            }
495            fsync(fd);
496        }
497        close(fd);
498    }
499}
500
501void
502show_babel_main_configuration (struct vty *vty)
503{
504    vty_out(vty,
505            "pid file                = %s%s"
506            "state file              = %s%s"
507            "configuration file      = %s%s"
508            "protocol informations:%s"
509            "  multicast address     = %s%s"
510            "  port                  = %d%s"
511            "vty address             = %s%s"
512            "vty port                = %d%s"
513            "id                      = %s%s"
514            "allow_duplicates        = %s%s"
515            "kernel_metric           = %d%s",
516            pidfile, VTY_NEWLINE,
517            state_file, VTY_NEWLINE,
518            babel_config_file ? babel_config_file : babel_config_default,
519            VTY_NEWLINE,
520            VTY_NEWLINE,
521            format_address(protocol_group), VTY_NEWLINE,
522            protocol_port, VTY_NEWLINE,
523            babel_vty_addr ? babel_vty_addr : "None",
524            VTY_NEWLINE,
525            babel_vty_port, VTY_NEWLINE,
526            format_eui64(myid), VTY_NEWLINE,
527            format_bool(allow_duplicates), VTY_NEWLINE,
528            kernel_metric, VTY_NEWLINE);
529}
530