babeld.c 33.4 KB
Newer Older
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1
/*
2
Copyright (c) 2007, 2008 by Juliusz Chroboczek
dermiste's avatar
dermiste committed
3
Copyright (c) 2010 by Vincent Gross
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <assert.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

42
#include "babeld.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
43 44 45
#include "util.h"
#include "net.h"
#include "kernel.h"
46
#include "interface.h"
47
#include "source.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
48 49 50 51
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
52
#include "resend.h"
53
#include "configuration.h"
54
#include "local.h"
55
#include "rule.h"
56
#include "version.h"
57
#include "ctl.h"
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
58 59 60

struct timeval now;

61
unsigned char myid[8];
62
int have_id = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
63 64
int debug = 0;

65
int link_detect = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
66
int all_wireless = 0;
67
int has_ipv6_subtrees = 0;
68 69
int default_wireless_hello_interval = -1;
int default_wired_hello_interval = -1;
70
int resend_delay = -1;
71
int random_id = 0;
72
int do_daemonise = 0;
73
int skip_kernel_setup = 0;
74
const char *logfile = NULL,
75 76
    *pidfile = "/var/run/babeld.pid",
    *state_file = "/var/lib/babel-state";
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
77

78 79 80
unsigned char *receive_buffer = NULL;
int receive_buffer_size = 0;

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
81
const unsigned char zeroes[16] = {0};
82 83 84
const unsigned char ones[16] =
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
85 86 87 88

int protocol_port;
unsigned char protocol_group[16];
int protocol_socket = -1;
89
int kernel_socket = -1;
90
static int kernel_routes_changed = 0;
91
static int kernel_rules_changed = 0;
92 93
static int kernel_link_changed = 0;
static int kernel_addr_changed = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
94

95
struct timeval check_neighbours_timeout, check_interfaces_timeout;
96

97
static volatile sig_atomic_t exiting = 0, dumping = 0, reopening = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
98

99
static int accept_local_connections(void);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
100
static void init_signals(void);
101
static void dump_tables(FILE *out);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
102

103 104 105 106 107 108 109
static int
kernel_route_notify(struct kernel_route *route, void *closure)
{
    kernel_routes_changed = 1;
    return -1;
}

110 111 112 113 114 115 116
static int
kernel_addr_notify(struct kernel_addr *addr, void *closure)
{
    kernel_addr_changed = 1;
    return -1;
}

117 118 119 120 121 122 123 124 125 126 127 128 129
static int
kernel_link_notify(struct kernel_link *link, void *closure)
{
    struct interface *ifp;
    FOR_ALL_INTERFACES(ifp) {
        if(strcmp(ifp->name, link->ifname) == 0) {
            kernel_link_changed = 1;
            return -1;
        }
    }
    return 0;
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
static int
kernel_rule_notify(struct kernel_rule *rule, void *closure)
{
    int i;
    if(martian_prefix(rule->src, rule->src_plen))
        return 0;

    i = rule->priority - src_table_prio;

    if(i < 0 || SRC_TABLE_NUM <= i)
        return 0;

    kernel_rules_changed = 1;
    return -1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
146 147 148 149
int
main(int argc, char **argv)
{
    struct sockaddr_in6 sin6;
150
    int rc, fd, i, opt;
151
    time_t expiry_time, source_expiry_time, kernel_dump_time;
152 153
    const char **config_files = NULL;
    int num_config_files = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
154 155
    void *vrc;
    unsigned int seed;
156
    struct interface *ifp;
157
    int ctl_sockfd;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
158

159 160
    gettime(&now);

161 162 163 164 165 166
    rc = read_random_bytes(&seed, sizeof(seed));
    if(rc < 0) {
        perror("read(random)");
        seed = 42;
    }

167 168 169
    seed ^= (now.tv_sec ^ now.tv_usec);
    srandom(seed);

170
    parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
171
    protocol_port = 6696;
172
    change_smoothing_half_life(4);
173
    has_ipv6_subtrees = kernel_has_ipv6_subtrees();
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
174

175
    while(1) {
176
        opt = getopt(argc, argv,
177
                     "m:p:h:H:i:k:A:srS:d:g:G:lwz:M:t:T:c:C:DL:I:X:V");
178
        if(opt < 0)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
179
            break;
180 181 182 183

        switch(opt) {
        case 'm':
            rc = parse_address(optarg, protocol_group, NULL);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
184
            if(rc < 0)
185
                goto usage;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
186 187
            if(protocol_group[0] != 0xff) {
                fprintf(stderr,
188 189
                        "%s is not a multicast address\n", optarg);
                goto usage;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
190 191 192 193
            }
            if(protocol_group[1] != 2) {
                fprintf(stderr,
                        "Warning: %s is not a link-local multicast address\n",
194
                        optarg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
195
            }
196 197
            break;
        case 'p':
198 199 200
            protocol_port = parse_nat(optarg);
            if(protocol_port <= 0 || protocol_port > 0xFFFF)
                goto usage;
201 202
            break;
        case 'h':
203
            default_wireless_hello_interval = parse_thousands(optarg);
204 205
            if(default_wireless_hello_interval <= 0 ||
               default_wireless_hello_interval > 0xFFFF * 10)
206 207 208
                goto usage;
            break;
        case 'H':
209
            default_wired_hello_interval = parse_thousands(optarg);
210 211
            if(default_wired_hello_interval <= 0 ||
               default_wired_hello_interval > 0xFFFF * 10)
212 213 214
                goto usage;
            break;
        case 'k':
215
            kernel_metric = parse_nat(optarg);
216
            if(kernel_metric < 0 || kernel_metric > 0xFFFF)
217 218
                goto usage;
            break;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
219
        case 'A':
220
            allow_duplicates = parse_nat(optarg);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
221 222 223
            if(allow_duplicates < 0 || allow_duplicates > 0xFFFF)
                goto usage;
            break;
224
        case 's':
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
225
            split_horizon = 0;
226
            break;
227 228 229
        case 'r':
            random_id = 1;
            break;
230 231 232 233
        case 'S':
            state_file = optarg;
            break;
        case 'd':
234 235 236
            debug = parse_nat(optarg);
            if(debug < 0)
                goto usage;
237 238
            break;
        case 'g':
239
        case 'G':
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
            if(opt == 'g')
                local_server_write = 0;
            else
                local_server_write = 1;
            if(optarg[0] == '/') {
                local_server_port = -1;
                free(local_server_path);
                local_server_path = strdup(optarg);
            } else {
                local_server_port = parse_nat(optarg);
                free(local_server_path);
                local_server_path = NULL;
                if(local_server_port <= 0 || local_server_port > 0xFFFF)
                    goto usage;
            }
255 256
            break;
        case 'l':
257
            link_detect = 1;
258 259
            break;
        case 'w':
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
260
            all_wireless = 1;
261
            break;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
262 263
        case 'z':
            {
264 265 266
                char *comma;
                diversity_kind = (int)strtol(optarg, &comma, 0);
                if(*comma == '\0')
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
267
                    diversity_factor = 128;
268 269
                else if(*comma == ',')
                    diversity_factor = parse_nat(comma + 1);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
270
                else
271
                    goto usage;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
272 273 274 275
                if(diversity_factor <= 0 || diversity_factor > 256)
                    goto usage;
            }
            break;
276 277 278 279 280 281 282
        case 'M': {
            int l = parse_nat(optarg);
            if(l < 0 || l > 3600)
                goto usage;
            change_smoothing_half_life(l);
            break;
        }
283
        case 't':
284
            export_table = parse_nat(optarg);
285
            if(export_table < 0 || export_table > 0xFFFF)
286 287 288
                goto usage;
            break;
        case 'T':
289
            if(add_import_table(parse_nat(optarg)))
290 291 292
                goto usage;
            break;
        case 'c':
293 294 295 296 297 298 299
            config_files = realloc(config_files,
                                   (num_config_files + 1) * sizeof(char*));
            if(config_files == NULL) {
                fprintf(stderr, "Couldn't allocate config file.\n");
                exit(1);
            }
            config_files[num_config_files++] = optarg;
300 301
            break;
        case 'C':
302
            rc = parse_config_from_string(optarg, strlen(optarg), NULL);
303
            if(rc != CONFIG_ACTION_DONE) {
304 305 306 307
                fprintf(stderr,
                        "Couldn't parse configuration from command line.\n");
                exit(1);
            }
308 309
            break;
        case 'D':
310
            do_daemonise = 1;
311 312 313 314 315 316 317
            break;
        case 'L':
            logfile = optarg;
            break;
        case 'I':
            pidfile = optarg;
            break;
318 319 320 321
        case 'V':
            fprintf(stderr, "%s\n", BABELD_VERSION);
            exit(0);
            break;
322 323 324
        case 'X':
            control_socket_path = optarg;
            break;
325 326
        default:
            goto usage;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
327 328 329
        }
    }

330 331 332 333 334 335 336 337 338
    if(num_config_files == 0) {
        if(access("/etc/babeld.conf", F_OK) >= 0) {
            config_files = malloc(sizeof(char*));
            if(config_files == NULL) {
                fprintf(stderr, "Couldn't allocate config file.\n");
                exit(1);
            }
            config_files[num_config_files++] = "/etc/babeld.conf";
        }
339
    }
340 341

    for(i = 0; i < num_config_files; i++) {
342
        int line;
343
        rc = parse_config_from_file(config_files[i], &line);
344 345
        if(rc < 0) {
            fprintf(stderr,
346 347
                    "Couldn't parse configuration from file %s "
                    "(error at line %d).\n",
348
                    config_files[i], line);
349 350 351 352
            exit(1);
        }
    }

353 354
    free(config_files);

355 356 357
    if(default_wireless_hello_interval <= 0)
        default_wireless_hello_interval = 4000;
    default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
358

359 360 361
    if(default_wired_hello_interval <= 0)
        default_wired_hello_interval = 4000;
    default_wired_hello_interval = MAX(default_wired_hello_interval, 5);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
362

363
    resend_delay = 2000;
364 365
    resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2);
    resend_delay = MIN(resend_delay, default_wired_hello_interval / 2);
366 367
    resend_delay = MAX(resend_delay, 20);

368 369
    if(do_daemonise) {
        if(logfile == NULL)
370
            logfile = "/var/log/babeld.log";
371 372
    }

373 374 375
    rc = reopen_logfile();
    if(rc < 0) {
        perror("reopen_logfile()");
376
        exit(1);
377 378 379 380 381
    }

    fd = open("/dev/null", O_RDONLY);
    if(fd < 0) {
        perror("open(null)");
382
        exit(1);
383 384 385 386 387
    }

    rc = dup2(fd, 0);
    if(rc < 0) {
        perror("dup2(null, 0)");
388
        exit(1);
389 390 391 392 393 394 395 396
    }

    close(fd);

    if(do_daemonise) {
        rc = daemonise();
        if(rc < 0) {
            perror("daemonise");
397
            exit(1);
398 399 400
        }
    }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
401
    if(pidfile && pidfile[0] != '\0') {
402 403 404 405 406 407
        int pfd, len;
        char buf[100];

        len = snprintf(buf, 100, "%lu", (unsigned long)getpid());
        if(len < 0 || len >= 100) {
            perror("snprintf(getpid)");
408
            exit(1);
409 410 411 412
        }

        pfd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644);
        if(pfd < 0) {
413 414 415 416
            char buf[40];
            snprintf(buf, 40, "creat(%s)", pidfile);
            buf[39] = '\0';
            perror(buf);
417
            exit(1);
418 419 420 421 422
        }

        rc = write(pfd, buf, len);
        if(rc < len) {
            perror("write(pidfile)");
423
            goto fail_pid;
424 425 426 427 428
        }

        close(pfd);
    }

429 430 431
    rc = kernel_setup(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup failed.\n");
432
        goto fail_pid;
433 434 435 436 437 438
    }

    rc = kernel_setup_socket(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup_socket failed.\n");
        kernel_setup(0);
439
        goto fail_pid;
440
    }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
441

442 443 444
    rc = finalise_config();
    if(rc < 0) {
        fprintf(stderr, "Couldn't finalise configuration.\n");
445
        goto fail;
446 447
    }

448
    for(i = optind; i < argc; i++) {
449
        vrc = add_interface(argv[i], NULL);
450
        if(vrc == NULL)
451
            goto fail;
452 453
    }

454
    if(interfaces == NULL) {
455 456 457 458
        fprintf(stderr, "Eek... asked to run on no interfaces!\n");
        goto fail;
    }

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    if(!have_id && !random_id) {
        /* We use all available interfaces here, since this increases the
           chances of getting a stable router-id in case the set of Babel
           interfaces changes. */

        for(i = 1; i < 256; i++) {
            char buf[IF_NAMESIZE], *ifname;
            unsigned char eui[8];
            ifname = if_indextoname(i, buf);
            if(ifname == NULL)
                continue;
            rc = if_eui64(ifname, i, eui);
            if(rc < 0)
                continue;
            memcpy(myid, eui, 8);
            have_id = 1;
            break;
        }
477 478
    }

479 480 481 482 483 484 485 486 487 488 489 490
    if(!have_id) {
        if(!random_id)
            fprintf(stderr,
                    "Warning: couldn't find router id -- "
                    "using random value.\n");
        rc = read_random_bytes(myid, 8);
        if(rc < 0) {
            perror("read(random)");
            goto fail;
        }
        /* Clear group and global bits */
        myid[0] &= ~3;
491
    }
492

493
    myseqno = (random() & 0xFFFF);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
494 495 496

    fd = open(state_file, O_RDONLY);
    if(fd < 0 && errno != ENOENT)
497
        perror("open(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
498
    rc = unlink(state_file);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
499
    if(fd >= 0 && rc < 0) {
500
        perror("unlink(babel-state)");
501
        /* If we couldn't unlink it, it's probably stale. */
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
502 503 504 505 506
        close(fd);
        fd = -1;
    }
    if(fd >= 0) {
        char buf[100];
507
        int s;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
508 509
        rc = read(fd, buf, 99);
        if(rc < 0) {
510
            perror("read(babel-state)");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
511 512
        } else {
            buf[rc] = '\0';
513 514 515
            rc = sscanf(buf, "%d\n", &s);
            if(rc == 1 && s >= 0 && s <= 0xFFFF) {
                myseqno = seqno_plus(s, 1);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
516
            } else {
517
                fprintf(stderr, "Couldn't parse babel-state.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
518 519 520
            }
        }
        close(fd);
521
        fd = -1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
522 523
    }

524
    protocol_socket = babel_socket(protocol_port);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
525 526 527 528 529
    if(protocol_socket < 0) {
        perror("Couldn't create link local socket");
        goto fail;
    }

530 531 532 533 534 535
    if(local_server_port >= 0) {
        local_server_socket = tcp_server_socket(local_server_port, 1);
        if(local_server_socket < 0) {
            perror("local_server_socket");
            goto fail;
        }
536 537 538 539 540 541
    } else if(local_server_path) {
        local_server_socket = unix_server_socket(local_server_path);
        if(local_server_socket < 0) {
            perror("local_server_socket");
            goto fail;
        }
542 543
    }

544 545 546 547 548 549
    ctl_sockfd = init_control_socket();
    if(ctl_sockfd < 0) {
        perror("Couldn't create control socket");
        goto fail;
    }

550
    init_signals();
551 552 553
    rc = resize_receive_buffer(1500);
    if(rc < 0)
        goto fail;
554 555 556
    if(receive_buffer == NULL)
        goto fail;

557 558
    check_interfaces();

559 560 561
    rc = check_xroutes(0);
    if(rc < 0)
        fprintf(stderr, "Warning: couldn't check exported routes.\n");
562 563 564
    rc = check_rules();
    if(rc < 0)
        fprintf(stderr, "Warning: couldn't check rules.\n");
565

566
    kernel_routes_changed = 0;
567
    kernel_rules_changed = 0;
568 569
    kernel_link_changed = 0;
    kernel_addr_changed = 0;
570
    kernel_dump_time = now.tv_sec + roughly(30);
571
    schedule_neighbours_check(5000, 1);
572
    schedule_interfaces_check(30000, 1);
573 574
    expiry_time = now.tv_sec + roughly(30);
    source_expiry_time = now.tv_sec + roughly(300);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
575

576 577
    /* Make some noise so that others notice us, and send retractions in
       case we were restarted recently */
578 579
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
580
            continue;
581
        /* Apply jitter before we send the first message. */
582
        usleep(roughly(10000));
583
        gettime(&now);
584 585
        send_hello(ifp);
        send_wildcard_retraction(ifp);
586
        flushupdates(ifp);
587
        flushbuf(&ifp->buf, ifp);
588 589
    }

590 591
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
592 593 594
            continue;
        usleep(roughly(10000));
        gettime(&now);
595 596 597
        send_hello(ifp);
        send_wildcard_retraction(ifp);
        send_self_update(ifp);
598
        send_multicast_request(ifp, NULL, 0, NULL, 0);
599
        flushupdates(ifp);
600
        flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
601 602 603 604 605 606
    }

    debugf("Entering main loop.\n");

    while(1) {
        struct timeval tv;
607
        struct neighbour *neigh;
608 609
        fd_set readfds, writefds;
        struct ctl *ctl, *ctl_next;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
610

611
        gettime(&now);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
612

613
        tv = check_neighbours_timeout;
614
        timeval_min(&tv, &check_interfaces_timeout);
615
        timeval_min_sec(&tv, expiry_time);
616
        timeval_min_sec(&tv, source_expiry_time);
617
        timeval_min_sec(&tv, kernel_dump_time);
618
        timeval_min(&tv, &resend_time);
619 620
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
621
                continue;
622
            timeval_min(&tv, &ifp->buf.timeout);
623 624 625
            timeval_min(&tv, &ifp->hello_timeout);
            timeval_min(&tv, &ifp->update_timeout);
            timeval_min(&tv, &ifp->update_flush_timeout);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
626
        }
627 628 629
        FOR_ALL_NEIGHBOURS(neigh) {
            timeval_min(&tv, &neigh->buf.timeout);
        }
630
        FD_ZERO(&readfds);
631
        FD_ZERO(&writefds);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
632
        if(timeval_compare(&tv, &now) > 0) {
633
            int maxfd = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
634 635
            timeval_minus(&tv, &tv, &now);
            FD_SET(protocol_socket, &readfds);
636
            maxfd = MAX(maxfd, protocol_socket);
637
            if(kernel_socket < 0) kernel_setup_socket(1);
638
            if(kernel_socket >= 0) {
639
                FD_SET(kernel_socket, &readfds);
640 641
                maxfd = MAX(maxfd, kernel_socket);
            }
642 643
            if(local_server_socket >= 0 &&
               num_local_sockets < MAX_LOCAL_SOCKETS) {
644 645 646
                FD_SET(local_server_socket, &readfds);
                maxfd = MAX(maxfd, local_server_socket);
            }
647
            for(i = 0; i < num_local_sockets; i++) {
648 649
                FD_SET(local_sockets[i].fd, &readfds);
                maxfd = MAX(maxfd, local_sockets[i].fd);
650
            }
651 652 653 654 655 656 657 658 659 660
            FD_SET(ctl_sockfd, &readfds);
            maxfd = MAX(maxfd, ctl_sockfd);
            for(ctl = ctl_connection; ctl; ctl = ctl->next) {
                if(ctl->write < ctl->buffer_out.end)
                    FD_SET(ctl->fd, &writefds);
                else
                    FD_SET(ctl->fd, &readfds);
                maxfd = MAX(maxfd, ctl->fd);
            }
            rc = select(maxfd + 1, &readfds, &writefds, NULL, &tv);
661
            if(rc < 0) {
662
                if(errno != EINTR) {
663
                    perror("select");
664
                    sleep(1);
665
                }
666 667
                rc = 0;
                FD_ZERO(&readfds);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
668 669 670
            }
        }

671
        gettime(&now);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
672 673 674 675

        if(exiting)
            break;

676 677 678
        if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) {
            struct kernel_filter filter = {0};
            filter.route = kernel_route_notify;
679
            filter.addr = kernel_addr_notify;
680
            filter.link = kernel_link_notify;
681
            filter.rule = kernel_rule_notify;
682 683
            kernel_callback(&filter);
        }
684

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
685
        if(FD_ISSET(protocol_socket, &readfds)) {
686
	    unsigned char to[16];
687 688
            rc = babel_recv(protocol_socket,
                            receive_buffer, receive_buffer_size,
689
                            (struct sockaddr*)&sin6, sizeof(sin6), to);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
690 691 692
            if(rc < 0) {
                if(errno != EAGAIN && errno != EINTR) {
                    perror("recv");
693
                    sleep(1);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
694 695
                }
            } else {
696 697
                FOR_ALL_INTERFACES(ifp) {
                    if(!if_up(ifp))
698
                        continue;
699 700
                    if(ifp->ifindex == sin6.sin6_scope_id) {
                        parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
701
                                     receive_buffer, rc, to);
702 703
                        VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer,
                                                    receive_buffer_size);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
704 705 706 707 708 709
                        break;
                    }
                }
            }
        }

710 711
        if(local_server_socket >= 0 && FD_ISSET(local_server_socket, &readfds))
           accept_local_connections();
712

713 714
        i = 0;
        while(i < num_local_sockets) {
715 716
            if(FD_ISSET(local_sockets[i].fd, &readfds)) {
                rc = local_read(&local_sockets[i]);
717
                if(rc <= 0) {
718
                    if(rc < 0) {
719
                        if(errno == EINTR || errno == EAGAIN)
720
                            continue;
721
                        perror("read(local_socket)");
722
                    }
723
                    local_socket_destroy(i);
724
                }
725
            }
726
            i++;
727 728
        }

729 730 731 732 733 734 735 736 737 738
        if(FD_ISSET(ctl_sockfd, &readfds)) {
            accept_ctl_connection(ctl_sockfd);
        }
        for(ctl = ctl_connection; ctl; ctl = ctl_next) {
            ctl_next = ctl->next;
            if (FD_ISSET(ctl->fd, &writefds))
                ctl_write(ctl);
            if (FD_ISSET(ctl->fd, &readfds))
                ctl_read(ctl);
        }
739
        if(reopening) {
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
740
            kernel_dump_time = now.tv_sec;
741
            check_neighbours_timeout = now;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
742
            expiry_time = now.tv_sec;
743 744 745 746 747
            rc = reopen_logfile();
            if(rc < 0) {
                perror("reopen_logfile");
                break;
            }
748
            reopening = 0;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
749 750
        }

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
751
        if(kernel_link_changed || kernel_addr_changed) {
752
            check_interfaces();
753 754 755
            kernel_link_changed = 0;
        }

756
        if(kernel_routes_changed || kernel_addr_changed ||
757
           kernel_rules_changed || now.tv_sec >= kernel_dump_time) {
758 759
            rc = check_xroutes(1);
            if(rc < 0)
760
                fprintf(stderr, "Warning: couldn't check exported routes.\n");
761 762 763
            rc = check_rules();
            if(rc < 0)
                fprintf(stderr, "Warning: couldn't check rules.\n");
764 765
            kernel_routes_changed = kernel_rules_changed =
                kernel_addr_changed = 0;
766
            if(kernel_socket >= 0)
767
                kernel_dump_time = now.tv_sec + roughly(300);
768
            else
769
                kernel_dump_time = now.tv_sec + roughly(30);
770 771
        }

772
        if(timeval_compare(&check_neighbours_timeout, &now) < 0) {
773 774
            int msecs;
            msecs = check_neighbours();
775 776
            /* Multiply by 3/2 to allow neighbours to expire. */
            msecs = MAX(3 * msecs / 2, 10);
777
            schedule_neighbours_check(msecs, 1);
778 779
        }

780
        if(timeval_compare(&check_interfaces_timeout, &now) < 0) {
781
            check_interfaces();
782 783 784 785
            schedule_interfaces_check(30000, 1);
        }

        if(now.tv_sec >= expiry_time) {
786
            expire_routes();
787
            expire_resend();
788
            expiry_time = now.tv_sec + roughly(30);
789 790
        }

791 792
        if(now.tv_sec >= source_expiry_time) {
            expire_sources();
793
            source_expiry_time = now.tv_sec + roughly(300);
794 795
        }

796 797
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
798
                continue;
799 800 801
            if(timeval_compare(&now, &ifp->hello_timeout) >= 0)
                send_hello(ifp);
            if(timeval_compare(&now, &ifp->update_timeout) >= 0)
802
                send_update(ifp, 0, NULL, 0, NULL, 0);
803 804
            if(timeval_compare(&now, &ifp->update_flush_timeout) >= 0)
                flushupdates(ifp);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
805 806
        }

807 808 809 810
        if(resend_time.tv_sec != 0) {
            if(timeval_compare(&now, &resend_time) >= 0)
                do_resend();
        }
811

812 813
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
814
                continue;
815
            if(ifp->buf.timeout.tv_sec != 0) {
816 817
                if(timeval_compare(&now, &ifp->buf.timeout) >= 0) {
                    flushupdates(ifp);
818
                    flushbuf(&ifp->buf, ifp);
819
                }
820 821 822
            }
        }

823 824 825
        FOR_ALL_NEIGHBOURS(neigh) {
            if(neigh->buf.timeout.tv_sec != 0) {
                if(timeval_compare(&now, &neigh->buf.timeout) >= 0) {
826
                    flushbuf(&neigh->buf, neigh->ifp);
827 828 829 830
                }
            }
        }

831
        if(UNLIKELY(debug || dumping)) {
832
            dump_tables(stdout);
833 834
            dumping = 0;
        }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
835 836 837
    }

    debugf("Exiting...\n");
838
    usleep(roughly(10000));
839
    gettime(&now);
840

841
    /* We need to flush so interface_updown won't try to reinstall. */
842
    flush_all_routes();
843

844 845
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
846
            continue;
847
        send_wildcard_retraction(ifp);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
848
        /* Make sure that we expire quickly from our neighbours'
849
           association caches. */
850
        send_multicast_hello(ifp, 10, 1);
851
        flushbuf(&ifp->buf, ifp);
852
        usleep(roughly(1000));
853
        gettime(&now);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
854
    }
855 856
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
857
            continue;
858
        /* Make sure they got it. */
859
        send_wildcard_retraction(ifp);
860
        send_multicast_hello(ifp, 1, 1);
861
        flushbuf(&ifp->buf, ifp);
862
        usleep(roughly(10000));
863
        gettime(&now);
864
        interface_updown(ifp, 0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
865
    }
866
    release_tables();
867
    kernel_setup_socket(0);
868
    kernel_setup(0);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
869 870 871

    fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
    if(fd < 0) {
872
        perror("creat(babel-state)");
873
        unlink(state_file);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
874
    } else {
875 876 877
        char buf[10];
        rc = snprintf(buf, 10, "%d\n", (int)myseqno);
        if(rc < 0 || rc >= 10) {
878
            fprintf(stderr, "write(babel-state): overflow.\n");
879
            unlink(state_file);
880 881 882 883 884 885 886
        } else {
            rc = write(fd, buf, rc);
            if(rc < 0) {
                perror("write(babel-state)");
                unlink(state_file);
            }
            fsync(fd);
887
        }
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
888 889
        close(fd);
    }
890 891 892 893
    if(local_server_socket >= 0 && local_server_path) {
        unlink(local_server_path);
        free(local_server_path);
    }
894 895
    if(pidfile)
        unlink(pidfile);
896
    debugf("Done.\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
897 898
    return 0;

899
 usage:
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
900
    fprintf(stderr,
901 902 903 904
            "%s\n"
            "Syntax: babeld "
            "[-V] [-m multicast_address] [-p port] [-S state-file]\n"
            "               "
905
            "[-h hello] [-H wired_hello] [-z kind[,factor]]\n"
906
            "               "
907
            "[-g port] [-G port] [-k metric] [-A metric] [-s] [-l] [-w] [-r]\n"
908
            "               "
909
            "[-u] [-t table] [-T table] [-c file] [-C statement]\n"
910
            "               "
911
            "[-d level] [-D] [-L logfile] [-I pidfile] [-X control-socket]\n"
912
            "               "
913
            "interface...\n",
914
            BABELD_VERSION);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
915 916 917
    exit(1);

 fail:
918 919
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
920
            continue;
921
        interface_updown(ifp, 0);
922
    }
923
    kernel_setup_socket(0);
924
    kernel_setup(0);
925 926 927
 fail_pid:
    if(pidfile)
        unlink(pidfile);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
928 929 930
    exit(1);
}

931
static int
932
accept_local_connections()
933
{
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
934
    int rc, s;
935
    struct local_socket *ls;
936

937
    if(local_server_socket < 0)
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
        return 0;

    s = accept(local_server_socket, NULL, NULL);

    if(s < 0) {
        if(errno != EINTR && errno != EAGAIN) {
            perror("accept(local_server_socket)");
            return -1;
        }
        return 0;
    }

    if(num_local_sockets >= MAX_LOCAL_SOCKETS) {
        /* This should never happen, since we don't select for
           the server socket in this case.  But I'm paranoid. */
        fprintf(stderr, "Internal error: too many local sockets.\n");
        close(s);
        return -1;
    }

958 959 960 961 962 963 964 965 966 967 968 969 970 971
    rc = fcntl(s, F_GETFL, 0);
    if(rc < 0) {
        fprintf(stderr, "Unable to get flags of local socket.\n");
        close(s);
        return -1;
    }

    rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
    if(rc < 0) {
        fprintf(stderr, "Unable to set flags of local socket.\n");
        close(s);
        return -1;
    }

972
    ls = local_socket_create(s);
973 974 975 976 977 978
    if(ls == NULL) {
        fprintf(stderr, "Unable create local socket.\n");
        close(s);
        return -1;
    }
    local_header(ls);
979 980 981
    return 1;
}

982 983 984 985 986
void
schedule_neighbours_check(int msecs, int override)
{
    struct timeval timeout;

987
    timeval_add_msec(&timeout, &now, roughly(msecs));
988 989 990 991 992 993
    if(override)
        check_neighbours_timeout = timeout;
    else
        timeval_min(&check_neighbours_timeout, &timeout);
}

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
void
schedule_interfaces_check(int msecs, int override)
{
    struct timeval timeout;

    timeval_add_msec(&timeout, &now, roughly(msecs));
    if(override)
        check_interfaces_timeout = timeout;
    else
        timeval_min(&check_interfaces_timeout, &timeout);
}

1006
int
1007 1008
resize_receive_buffer(int size)
{
1009 1010
    unsigned char *new;

1011
    if(size <= receive_buffer_size)
1012
        return 0;
1013

1014 1015 1016 1017
    new = realloc(receive_buffer, size);
    if(new == NULL) {
        perror("realloc(receive_buffer)");
        return -1;
1018
    }
1019 1020 1021
    receive_buffer = new;
    receive_buffer_size = size;

1022
    return 1;
1023 1024
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1025 1026 1027 1028 1029 1030
static void
sigexit(int signo)
{
    exiting = 1;
}

1031 1032 1033 1034 1035 1036
static void
sigdump(int signo)
{
    dumping = 1;
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1037
static void
1038
sigreopening(int signo)
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1039
{
1040
    reopening = 1;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1041 1042
}

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
static void
init_signals(void)
{
    struct sigaction sa;
    sigset_t ss;

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGHUP, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
1066

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1067 1068 1069 1070 1071 1072
    sigemptyset(&ss);
    sa.sa_handler = SIG_IGN;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGPIPE, &sa, NULL);

1073 1074 1075 1076 1077
    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);
1078

Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1079
    sigemptyset(&ss);
1080
    sa.sa_handler = sigreopening;
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1081 1082 1083 1084
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);

1085 1086 1087 1088 1089 1090 1091
#ifdef SIGINFO
    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINFO, &sa, NULL);
#endif
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1092 1093
}

1094
static void
1095
dump_route(FILE *out, struct babel_route *route)
1096 1097 1098 1099 1100 1101
{
    const unsigned char *nexthop =
        memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
        NULL : route->nexthop;
    char channels[100];

1102
    if(route->channels_len == 0) {
1103
        channels[0] = '\0';
1104
    } else {
1105 1106 1107
        int k, j = 0;
        snprintf(channels, 100, " chan (");
        j = strlen(channels);
1108
        for(k = 0; k < route->channels_len; k++) {
1109 1110
            if(k > 0)
                channels[j++] = ',';
1111
            snprintf(channels + j, 100 - j, "%u", (unsigned)route->channels[k]);
1112 1113 1114 1115 1116
            j = strlen(channels);
        }
        snprintf(channels + j, 100 - j, ")");
    }

1117
    fprintf(out, "%s%s%s metric %d (%d) refmetric %d id %s "
1118
            "seqno %d%s age %d via %s neigh %s%s%s%s\n",
1119
            format_prefix(route->src->prefix, route->src->plen),
1120 1121 1122
            route->src->src_plen > 0 ? " from " : "",
            route->src->src_plen > 0 ?
            format_prefix(route->src->src_prefix, route->src->src_plen) : "",
1123
            route_metric(route), route_smoothed_metric(route), route->refmetric,
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
            format_eui64(route->src->id),
            (int)route->seqno,
            channels,
            (int)(now.tv_sec - route->time),
            route->neigh->ifp->name,
            format_address(route->neigh->address),
            nexthop ? " nexthop " : "",
            nexthop ? format_address(nexthop) : "",
            route->installed ? " (installed)" :
            route_feasible(route) ? " (feasible)" : "");
}

1136
static void
1137
dump_xroute(FILE *out, struct xroute *xroute)
1138
{
1139
    fprintf(out, "%s%s%s metric %d (exported)\n",
1140
            format_prefix(xroute->prefix, xroute->plen),
1141 1142 1143
            xroute->src_plen > 0 ? " from " : "",
            xroute->src_plen > 0 ?
            format_prefix(xroute->src_prefix, xroute->src_plen) : "",
1144 1145 1146
            xroute->metric);
}

1147 1148 1149
static void
dump_tables(FILE *out)
{
1150
    struct neighbour *neigh;
1151
    struct xroute_stream *xroutes;
1152
    struct route_stream *routes;
1153 1154

    fprintf(out, "\n");
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1155

1156
    fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno);
Juliusz Chroboczek's avatar
Juliusz Chroboczek committed
1157

1158
    FOR_ALL_NEIGHBOURS(neigh) {
1159
        fprintf(out, "Neighbour %s dev %s reach %04x ureach %04x "
1160
                "rxcost %u txcost %d rtt %s rttcost %u chan %d%s.\n",
1161
                format_address(neigh->address),
1162
                neigh->ifp->name,
1163
                neigh->hello.reach,
1164
                neigh->uhello.reach,
1165 1166
                neighbour_rxcost(neigh),
                neigh->txcost,
1167
                format_thousands(neigh->rtt),
1168
                neighbour_rttcost(neigh),
1169 1170
                neigh->ifp->channel,
                if_up(neigh->ifp) ? "" : " (down)");
1171
    }
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182

    xroutes = xroute_stream();
    if(xroutes) {
        while(1) {
            struct xroute *xroute = xroute_stream_next(xroutes);
            if(xroute == NULL) break;
            dump_xroute(out, xroute);
        }
        xroute_stream_done(xroutes);
    }

1183
    routes = route_stream(ROUTE_ALL);
1184 1185 1186 1187 1188 1189 1190 1191
    if(routes) {
        while(1) {
            struct babel_route *route = route_stream_next(routes);
            if(route == NULL) break;
            dump_route(out, route);
        }
        route_stream_done(routes);
    }
1192

1193 1194 1195
    fflush(out);
}

1196
int
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
reopen_logfile()
{
    int lfd, rc;

    if(logfile == NULL)
        return 0;

    lfd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0644);
    if(lfd < 0)
        return -1;

    fflush(stdout);
    fflush(stderr);

    rc = dup2(lfd, 1);
    if(rc < 0)
        return -1;

    rc = dup2(lfd, 2);
    if(rc < 0)
        return -1;

    if(lfd >