Root/package/ead/src/ead.c

1/*
2 * Emergency Access Daemon
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <sys/types.h>
16#include <sys/time.h>
17#include <sys/select.h>
18#include <stdio.h>
19#include <stddef.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <stdbool.h>
24#include <fcntl.h>
25#include <signal.h>
26#include <pcap.h>
27#include <pcap-bpf.h>
28#include <t_pwd.h>
29#include <t_read.h>
30#include <t_sha.h>
31#include <t_defines.h>
32#include <t_server.h>
33
34#include "list.h"
35#include "ead.h"
36#include "ead-pcap.h"
37#include "ead-crypt.h"
38
39#include "filter.c"
40
41#ifdef linux
42#include "libbridge_init.c"
43#endif
44
45#ifdef linux
46#include <linux/if_packet.h>
47#endif
48
49#define PASSWD_FILE "/etc/passwd"
50
51#ifndef DEFAULT_IFNAME
52#define DEFAULT_IFNAME "eth0"
53#endif
54
55#ifndef DEFAULT_DEVNAME
56#define DEFAULT_DEVNAME "Unknown"
57#endif
58
59#define PCAP_MRU 1600
60#define PCAP_TIMEOUT 200
61
62#if EAD_DEBUGLEVEL >= 1
63#define DEBUG(n, format, ...) do { \
64    if (EAD_DEBUGLEVEL >= n) \
65        fprintf(stderr, format, ##__VA_ARGS__); \
66} while (0);
67
68#else
69#define DEBUG(n, format, ...) do {} while(0)
70#endif
71
72struct ead_instance {
73    struct list_head list;
74    char ifname[16];
75    int pid;
76    char id;
77#ifdef linux
78    char bridge[16];
79    bool br_check;
80#endif
81};
82
83static char ethmac[6] = "\x00\x13\x37\x00\x00\x00"; /* last 3 bytes will be randomized */
84static pcap_t *pcap_fp = NULL;
85static pcap_t *pcap_fp_rx = NULL;
86static char pktbuf_b[PCAP_MRU];
87static struct ead_packet *pktbuf = (struct ead_packet *)pktbuf_b;
88static u16_t nid = 0xffff; /* node id */
89static char username[32] = "";
90static int state = EAD_TYPE_SET_USERNAME;
91static const char *passwd_file = PASSWD_FILE;
92static const char password[MAXPARAMLEN];
93static bool child_pending = false;
94
95static unsigned char abuf[MAXPARAMLEN + 1];
96static unsigned char pwbuf[MAXPARAMLEN];
97static unsigned char saltbuf[MAXSALTLEN];
98static unsigned char pw_saltbuf[MAXSALTLEN];
99static struct list_head instances;
100static const char *dev_name = DEFAULT_DEVNAME;
101static bool nonfork = false;
102static struct ead_instance *instance = NULL;
103
104static struct t_pwent tpe = {
105    .name = username,
106    .index = 1,
107    .password.data = pwbuf,
108    .password.len = 0,
109    .salt.data = saltbuf,
110    .salt.len = 0,
111};
112struct t_confent *tce = NULL;
113static struct t_server *ts = NULL;
114static struct t_num A, *B = NULL;
115unsigned char *skey;
116
117static void
118set_recv_type(pcap_t *p, bool rx)
119{
120#ifdef PACKET_RECV_TYPE
121    struct sockaddr_ll sll;
122    struct ifreq ifr;
123    int ifindex, mask;
124    int fd, ret;
125
126    fd = pcap_get_selectable_fd(p);
127    if (fd < 0)
128        return;
129
130    if (rx)
131        mask = 1 << PACKET_BROADCAST;
132    else
133        mask = 0;
134
135    ret = setsockopt(fd, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask));
136#endif
137}
138
139
140static pcap_t *
141ead_open_pcap(const char *ifname, char *errbuf, bool rx)
142{
143    pcap_t *p;
144
145    p = pcap_create(ifname, errbuf);
146    if (p == NULL)
147        goto out;
148
149    pcap_set_snaplen(p, PCAP_MRU);
150    pcap_set_promisc(p, rx);
151    pcap_set_timeout(p, PCAP_TIMEOUT);
152#ifdef HAS_PROTO_EXTENSION
153    pcap_set_protocol(p, (rx ? htons(ETH_P_IP) : 0));
154#endif
155    pcap_set_buffer_size(p, (rx ? 10 : 1) * PCAP_MRU);
156    pcap_activate(p);
157    set_recv_type(p, rx);
158out:
159    return p;
160}
161
162static void
163get_random_bytes(void *ptr, int len)
164{
165    int fd;
166
167    fd = open("/dev/urandom", O_RDONLY);
168    if (fd < 0) {
169        perror("open");
170        exit(1);
171    }
172    read(fd, ptr, len);
173    close(fd);
174}
175
176static bool
177prepare_password(void)
178{
179    static char lbuf[1024];
180    unsigned char dig[SHA_DIGESTSIZE];
181    BigInteger x, v, n, g;
182    SHA1_CTX ctxt;
183    int ulen = strlen(username);
184    FILE *f;
185
186    lbuf[sizeof(lbuf) - 1] = 0;
187
188    f = fopen(passwd_file, "r");
189    if (!f)
190        return false;
191
192    while (fgets(lbuf, sizeof(lbuf) - 1, f) != NULL) {
193        char *str, *s2;
194
195        if (strncmp(lbuf, username, ulen) != 0)
196            continue;
197
198        if (lbuf[ulen] != ':')
199            continue;
200
201        str = &lbuf[ulen + 1];
202
203        if (strncmp(str, "$1$", 3) != 0)
204            continue;
205
206        s2 = strchr(str + 3, '$');
207        if (!s2)
208            continue;
209
210        if (s2 - str >= MAXSALTLEN)
211            continue;
212
213        strncpy((char *) pw_saltbuf, str, s2 - str);
214        pw_saltbuf[s2 - str] = 0;
215
216        s2 = strchr(s2, ':');
217        if (!s2)
218            continue;
219
220        *s2 = 0;
221        if (s2 - str >= MAXPARAMLEN)
222            continue;
223
224        strncpy((char *)password, str, MAXPARAMLEN);
225        fclose(f);
226        goto hash_password;
227    }
228
229    /* not found */
230    fclose(f);
231    return false;
232
233hash_password:
234    tce = gettcid(tpe.index);
235    do {
236        t_random(tpe.password.data, SALTLEN);
237    } while (memcmp(saltbuf, (char *)dig, sizeof(saltbuf)) == 0);
238    if (saltbuf[0] == 0)
239        saltbuf[0] = 0xff;
240
241    n = BigIntegerFromBytes(tce->modulus.data, tce->modulus.len);
242    g = BigIntegerFromBytes(tce->generator.data, tce->generator.len);
243    v = BigIntegerFromInt(0);
244
245    SHA1Init(&ctxt);
246    SHA1Update(&ctxt, (unsigned char *) username, strlen(username));
247    SHA1Update(&ctxt, (unsigned char *) ":", 1);
248    SHA1Update(&ctxt, (unsigned char *) password, strlen(password));
249    SHA1Final(dig, &ctxt);
250
251    SHA1Init(&ctxt);
252    SHA1Update(&ctxt, saltbuf, tpe.salt.len);
253    SHA1Update(&ctxt, dig, sizeof(dig));
254    SHA1Final(dig, &ctxt);
255
256    /* x = H(s, H(u, ':', p)) */
257    x = BigIntegerFromBytes(dig, sizeof(dig));
258
259    BigIntegerModExp(v, g, x, n);
260    tpe.password.len = BigIntegerToBytes(v, (unsigned char *)pwbuf);
261
262    BigIntegerFree(v);
263    BigIntegerFree(x);
264    BigIntegerFree(g);
265    BigIntegerFree(n);
266    return true;
267}
268
269static u16_t
270chksum(u16_t sum, const u8_t *data, u16_t len)
271{
272    u16_t t;
273    const u8_t *dataptr;
274    const u8_t *last_byte;
275
276    dataptr = data;
277    last_byte = data + len - 1;
278
279    while(dataptr < last_byte) { /* At least two more bytes */
280        t = (dataptr[0] << 8) + dataptr[1];
281        sum += t;
282        if(sum < t) {
283            sum++; /* carry */
284        }
285        dataptr += 2;
286    }
287
288    if(dataptr == last_byte) {
289        t = (dataptr[0] << 8) + 0;
290        sum += t;
291        if(sum < t) {
292            sum++; /* carry */
293        }
294    }
295
296    /* Return sum in host byte order. */
297    return sum;
298}
299
300static void
301ead_send_packet_clone(struct ead_packet *pkt)
302{
303    u16_t len, sum;
304
305    memcpy(pktbuf, pkt, offsetof(struct ead_packet, msg));
306    memcpy(pktbuf->eh.ether_shost, ethmac, 6);
307    memcpy(pktbuf->eh.ether_dhost, pkt->eh.ether_shost, 6);
308
309    /* ip header */
310    len = sizeof(struct ead_packet) - sizeof(struct ether_header) + ntohl(pktbuf->msg.len);
311    pktbuf->len[0] = len >> 8;
312    pktbuf->len[1] = len & 0xff;
313    memcpy(pktbuf->srcipaddr, &pkt->msg.ip, 4);
314    memcpy(pktbuf->destipaddr, pkt->srcipaddr, 4);
315
316    /* ip checksum */
317    pktbuf->ipchksum = 0;
318    sum = chksum(0, (void *) &pktbuf->vhl, UIP_IPH_LEN);
319    if (sum == 0)
320        sum = 0xffff;
321    pktbuf->ipchksum = htons(~sum);
322
323    /* udp header */
324    pktbuf->srcport = pkt->destport;
325    pktbuf->destport = pkt->srcport;
326
327    /* udp checksum */
328    len -= UIP_IPH_LEN;
329    pktbuf->udplen = htons(len);
330    pktbuf->udpchksum = 0;
331    sum = len + UIP_PROTO_UDP;
332    sum = chksum(sum, (void *) &pktbuf->srcipaddr[0], 8); /* src, dest ip */
333    sum = chksum(sum, (void *) &pktbuf->srcport, len);
334    if (sum == 0)
335        sum = 0xffff;
336    pktbuf->udpchksum = htons(~sum);
337    pcap_sendpacket(pcap_fp, (void *) pktbuf, sizeof(struct ead_packet) + ntohl(pktbuf->msg.len));
338}
339
340static void
341set_state(int nstate)
342{
343    if (state == nstate)
344        return;
345
346    if (nstate < state) {
347        if ((nstate < EAD_TYPE_GET_PRIME) &&
348            (state >= EAD_TYPE_GET_PRIME)) {
349            t_serverclose(ts);
350            ts = NULL;
351        }
352        goto done;
353    }
354
355    switch(state) {
356    case EAD_TYPE_SET_USERNAME:
357        if (!prepare_password())
358            goto error;
359        ts = t_serveropenraw(&tpe, tce);
360        if (!ts)
361            goto error;
362        break;
363    case EAD_TYPE_GET_PRIME:
364        B = t_servergenexp(ts);
365        break;
366    case EAD_TYPE_SEND_A:
367        skey = t_servergetkey(ts, &A);
368        if (!skey)
369            goto error;
370
371        ead_set_key(skey);
372        break;
373    }
374done:
375    state = nstate;
376error:
377    return;
378}
379
380static bool
381handle_ping(struct ead_packet *pkt, int len, int *nstate)
382{
383    struct ead_msg *msg = &pktbuf->msg;
384    struct ead_msg_pong *pong = EAD_DATA(msg, pong);
385    int slen;
386
387    slen = strlen(dev_name);
388    if (slen > 1024)
389        slen = 1024;
390
391    msg->len = htonl(sizeof(struct ead_msg_pong) + slen);
392    strncpy(pong->name, dev_name, slen);
393    pong->name[slen] = 0;
394    pong->auth_type = htons(EAD_AUTH_MD5);
395
396    return true;
397}
398
399static bool
400handle_set_username(struct ead_packet *pkt, int len, int *nstate)
401{
402    struct ead_msg *msg = &pkt->msg;
403    struct ead_msg_user *user = EAD_DATA(msg, user);
404
405    set_state(EAD_TYPE_SET_USERNAME); /* clear old state */
406    strncpy(username, user->username, sizeof(username));
407    username[sizeof(username) - 1] = 0;
408
409    msg = &pktbuf->msg;
410    msg->len = 0;
411
412    *nstate = EAD_TYPE_GET_PRIME;
413    return true;
414}
415
416static bool
417handle_get_prime(struct ead_packet *pkt, int len, int *nstate)
418{
419    struct ead_msg *msg = &pktbuf->msg;
420    struct ead_msg_salt *salt = EAD_DATA(msg, salt);
421
422    msg->len = htonl(sizeof(struct ead_msg_salt));
423    salt->prime = tce->index - 1;
424    salt->len = ts->s.len;
425    memcpy(salt->salt, ts->s.data, ts->s.len);
426    memcpy(salt->ext_salt, pw_saltbuf, MAXSALTLEN);
427
428    *nstate = EAD_TYPE_SEND_A;
429    return true;
430}
431
432static bool
433handle_send_a(struct ead_packet *pkt, int len, int *nstate)
434{
435    struct ead_msg *msg = &pkt->msg;
436    struct ead_msg_number *number = EAD_DATA(msg, number);
437    len = ntohl(msg->len) - sizeof(struct ead_msg_number);
438
439    if (len > MAXPARAMLEN + 1)
440        return false;
441
442    A.len = len;
443    A.data = abuf;
444    memcpy(A.data, number->data, len);
445
446    msg = &pktbuf->msg;
447    number = EAD_DATA(msg, number);
448    msg->len = htonl(sizeof(struct ead_msg_number) + B->len);
449    memcpy(number->data, B->data, B->len);
450
451    *nstate = EAD_TYPE_SEND_AUTH;
452    return true;
453}
454
455static bool
456handle_send_auth(struct ead_packet *pkt, int len, int *nstate)
457{
458    struct ead_msg *msg = &pkt->msg;
459    struct ead_msg_auth *auth = EAD_DATA(msg, auth);
460
461    if (t_serververify(ts, auth->data) != 0) {
462        DEBUG(2, "Client authentication failed\n");
463        *nstate = EAD_TYPE_SET_USERNAME;
464        return false;
465    }
466
467    msg = &pktbuf->msg;
468    auth = EAD_DATA(msg, auth);
469    msg->len = htonl(sizeof(struct ead_msg_auth));
470
471    DEBUG(2, "Client authentication successful\n");
472    memcpy(auth->data, t_serverresponse(ts), sizeof(auth->data));
473
474    *nstate = EAD_TYPE_SEND_CMD;
475    return true;
476}
477
478static bool
479handle_send_cmd(struct ead_packet *pkt, int len, int *nstate)
480{
481    struct ead_msg *msg = &pkt->msg;
482    struct ead_msg_cmd *cmd = EAD_ENC_DATA(msg, cmd);
483    struct ead_msg_cmd_data *cmddata;
484    struct timeval tv, to, tn;
485    int pfd[2], fd;
486    fd_set fds;
487    pid_t pid;
488    bool stream = false;
489    int timeout;
490    int type;
491    int datalen;
492
493    datalen = ead_decrypt_message(msg) - sizeof(struct ead_msg_cmd);
494    if (datalen <= 0)
495        return false;
496
497    type = ntohs(cmd->type);
498    timeout = ntohs(cmd->timeout);
499
500    FD_ZERO(&fds);
501    cmd->data[datalen] = 0;
502    switch(type) {
503    case EAD_CMD_NORMAL:
504        if (pipe(pfd) < 0)
505            return false;
506
507        fcntl(pfd[0], F_SETFL, O_NONBLOCK | fcntl(pfd[0], F_GETFL));
508        child_pending = true;
509        pid = fork();
510        if (pid == 0) {
511            close(pfd[0]);
512            fd = open("/dev/null", O_RDWR);
513            if (fd > 0) {
514                dup2(fd, 0);
515                dup2(pfd[1], 1);
516                dup2(pfd[1], 2);
517            }
518            system((char *)cmd->data);
519            exit(0);
520        } else if (pid > 0) {
521            close(pfd[1]);
522            if (!timeout)
523                timeout = EAD_CMD_TIMEOUT;
524
525            stream = true;
526            break;
527        }
528        return false;
529    case EAD_CMD_BACKGROUND:
530        pid = fork();
531        if (pid == 0) {
532            /* close stdin, stdout, stderr, replace with fd to /dev/null */
533            fd = open("/dev/null", O_RDWR);
534            if (fd > 0) {
535                dup2(fd, 0);
536                dup2(fd, 1);
537                dup2(fd, 2);
538            }
539            system((char *)cmd->data);
540            exit(0);
541        } else if (pid > 0) {
542            break;
543        }
544        return false;
545    default:
546        return false;
547    }
548
549    msg = &pktbuf->msg;
550    cmddata = EAD_ENC_DATA(msg, cmd_data);
551
552    if (stream) {
553        int nfds, bytes;
554
555        /* send keepalive packets every 200 ms so that the client doesn't timeout */
556        gettimeofday(&to, NULL);
557        memcpy(&tn, &to, sizeof(tn));
558        tv.tv_usec = PCAP_TIMEOUT * 1000;
559        tv.tv_sec = 0;
560        do {
561            cmddata->done = 0;
562            FD_SET(pfd[0], &fds);
563            nfds = select(pfd[0] + 1, &fds, NULL, NULL, &tv);
564            bytes = 0;
565            if (nfds > 0) {
566                bytes = read(pfd[0], cmddata->data, 1024);
567                if (bytes < 0)
568                    bytes = 0;
569            }
570            if (!bytes && !child_pending)
571                break;
572            DEBUG(3, "Sending %d bytes of console data, type=%d, timeout=%d\n", bytes, ntohl(msg->type), timeout);
573            ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data) + bytes);
574            ead_send_packet_clone(pkt);
575            gettimeofday(&tn, NULL);
576        } while (tn.tv_sec < to.tv_sec + timeout);
577        if (child_pending) {
578            kill(pid, SIGKILL);
579            return false;
580        }
581    }
582    cmddata->done = 1;
583    ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data));
584
585    return true;
586}
587
588
589
590static void
591parse_message(struct ead_packet *pkt, int len)
592{
593    bool (*handler)(struct ead_packet *pkt, int len, int *nstate);
594    int min_len = sizeof(struct ead_packet);
595    int nstate = state;
596    int type = ntohl(pkt->msg.type);
597
598    if ((type >= EAD_TYPE_GET_PRIME) &&
599        (state != type))
600        return;
601
602    if ((type != EAD_TYPE_PING) &&
603        ((ntohs(pkt->msg.sid) & EAD_INSTANCE_MASK) >>
604         EAD_INSTANCE_SHIFT) != instance->id)
605        return;
606
607    switch(type) {
608    case EAD_TYPE_PING:
609        handler = handle_ping;
610        break;
611    case EAD_TYPE_SET_USERNAME:
612        handler = handle_set_username;
613        min_len += sizeof(struct ead_msg_user);
614        break;
615    case EAD_TYPE_GET_PRIME:
616        handler = handle_get_prime;
617        break;
618    case EAD_TYPE_SEND_A:
619        handler = handle_send_a;
620        min_len += sizeof(struct ead_msg_number);
621        break;
622    case EAD_TYPE_SEND_AUTH:
623        handler = handle_send_auth;
624        min_len += sizeof(struct ead_msg_auth);
625        break;
626    case EAD_TYPE_SEND_CMD:
627        handler = handle_send_cmd;
628        min_len += sizeof(struct ead_msg_cmd) + sizeof(struct ead_msg_encrypted);
629        break;
630    default:
631        return;
632    }
633
634    if (len < min_len) {
635        DEBUG(2, "discarding packet: message too small\n");
636        return;
637    }
638
639    pktbuf->msg.magic = htonl(EAD_MAGIC);
640    pktbuf->msg.type = htonl(type + 1);
641    pktbuf->msg.nid = htons(nid);
642    pktbuf->msg.sid = pkt->msg.sid;
643    pktbuf->msg.len = 0;
644
645    if (handler(pkt, len, &nstate)) {
646        DEBUG(2, "sending response to packet type %d: %d\n", type + 1, ntohl(pktbuf->msg.len));
647        /* format response packet */
648        ead_send_packet_clone(pkt);
649    }
650    set_state(nstate);
651}
652
653static void
654handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
655{
656    struct ead_packet *pkt = (struct ead_packet *) bytes;
657
658    if (h->len < sizeof(struct ead_packet))
659        return;
660
661    if (pkt->eh.ether_type != htons(ETHERTYPE_IP))
662        return;
663
664    if (memcmp(pkt->eh.ether_dhost, "\xff\xff\xff\xff\xff\xff", 6) != 0)
665        return;
666
667    if (pkt->proto != UIP_PROTO_UDP)
668        return;
669
670    if (pkt->destport != htons(EAD_PORT))
671        return;
672
673    if (pkt->msg.magic != htonl(EAD_MAGIC))
674        return;
675
676    if (h->len < sizeof(struct ead_packet) + ntohl(pkt->msg.len))
677        return;
678
679    if ((pkt->msg.nid != 0xffff) &&
680        (pkt->msg.nid != htons(nid)))
681        return;
682
683    parse_message(pkt, h->len);
684}
685
686static void
687ead_pcap_reopen(bool first)
688{
689    static char errbuf[PCAP_ERRBUF_SIZE] = "";
690
691    if (pcap_fp_rx && (pcap_fp_rx != pcap_fp))
692        pcap_close(pcap_fp_rx);
693
694    if (pcap_fp)
695        pcap_close(pcap_fp);
696
697    pcap_fp_rx = NULL;
698    do {
699#ifdef linux
700        if (instance->bridge[0]) {
701            pcap_fp_rx = ead_open_pcap(instance->bridge, errbuf, 1);
702            pcap_fp = ead_open_pcap(instance->ifname, errbuf, 0);
703        } else
704#endif
705        {
706            pcap_fp = ead_open_pcap(instance->ifname, errbuf, 1);
707        }
708
709        if (!pcap_fp_rx)
710            pcap_fp_rx = pcap_fp;
711        if (first && !pcap_fp) {
712            DEBUG(1, "WARNING: unable to open interface '%s'\n", instance->ifname);
713            first = false;
714        }
715        if (!pcap_fp)
716            sleep(1);
717    } while (!pcap_fp);
718    pcap_setfilter(pcap_fp_rx, &pktfilter);
719}
720
721
722static void
723ead_pktloop(void)
724{
725    while (1) {
726        if (pcap_dispatch(pcap_fp_rx, 1, handle_packet, NULL) < 0) {
727            ead_pcap_reopen(false);
728            continue;
729        }
730    }
731}
732
733
734static int
735usage(const char *prog)
736{
737    fprintf(stderr, "Usage: %s [<options>]\n"
738        "Options:\n"
739        "\t-B Run in background mode\n"
740        "\t-d <device> Set the device to listen on\n"
741        "\t-D <name> Set the name of the device visible to clients\n"
742        "\t-p <file> Set the password file for authenticating\n"
743        "\t-P <file> Write a pidfile\n"
744        "\n", prog);
745    return -1;
746}
747
748static void
749server_handle_sigchld(int sig)
750{
751    struct ead_instance *in;
752    struct list_head *p;
753    int pid = 0;
754    wait(&pid);
755
756    list_for_each(p, &instances) {
757        in = list_entry(p, struct ead_instance, list);
758        if (pid != in->pid)
759            continue;
760
761        in->pid = 0;
762        break;
763    }
764}
765
766static void
767instance_handle_sigchld(int sig)
768{
769    int pid = 0;
770    wait(&pid);
771    child_pending = false;
772}
773
774static void
775start_server(struct ead_instance *i)
776{
777    if (!nonfork) {
778        i->pid = fork();
779        if (i->pid != 0) {
780            if (i->pid < 0)
781                i->pid = 0;
782            return;
783        }
784    }
785
786    instance = i;
787    signal(SIGCHLD, instance_handle_sigchld);
788    ead_pcap_reopen(true);
789    ead_pktloop();
790    pcap_close(pcap_fp);
791    if (pcap_fp_rx != pcap_fp)
792        pcap_close(pcap_fp_rx);
793
794    exit(0);
795}
796
797
798static void
799start_servers(bool restart)
800{
801    struct ead_instance *in;
802    struct list_head *p;
803
804    list_for_each(p, &instances) {
805        in = list_entry(p, struct ead_instance, list);
806        if (in->pid > 0)
807            continue;
808
809        sleep(1);
810        start_server(in);
811    }
812}
813
814static void
815stop_server(struct ead_instance *in, bool do_free)
816{
817    if (in->pid > 0)
818        kill(in->pid, SIGKILL);
819    in->pid = 0;
820    if (do_free) {
821        list_del(&in->list);
822        free(in);
823    }
824}
825
826static void
827server_handle_sigint(int sig)
828{
829    struct ead_instance *in;
830    struct list_head *p, *tmp;
831
832    list_for_each_safe(p, tmp, &instances) {
833        in = list_entry(p, struct ead_instance, list);
834        stop_server(in, true);
835    }
836    exit(1);
837}
838
839#ifdef linux
840static int
841check_bridge_port(const char *br, const char *port, void *arg)
842{
843    struct ead_instance *in;
844    struct list_head *p, *tmp;
845
846    list_for_each(p, &instances) {
847        in = list_entry(p, struct ead_instance, list);
848
849        if (strcmp(in->ifname, port) != 0)
850            continue;
851
852        in->br_check = true;
853        if (strcmp(in->bridge, br) == 0)
854            break;
855
856        strncpy(in->bridge, br, sizeof(in->bridge));
857        DEBUG(2, "assigning port %s to bridge %s\n", in->ifname, in->bridge);
858        stop_server(in, false);
859    }
860    return 0;
861}
862
863static int
864check_bridge(const char *name, void *arg)
865{
866    br_foreach_port(name, check_bridge_port, arg);
867    return 0;
868}
869#endif
870
871static void
872check_all_interfaces(void)
873{
874#ifdef linux
875    struct ead_instance *in;
876    struct list_head *p, *tmp;
877
878    br_foreach_bridge(check_bridge, NULL);
879
880    /* look for interfaces that are no longer part of a bridge */
881    list_for_each(p, &instances) {
882        in = list_entry(p, struct ead_instance, list);
883
884        if (in->br_check) {
885            in->br_check = false;
886        } else if (in->bridge[0]) {
887            DEBUG(2, "removing port %s from bridge %s\n", in->ifname, in->bridge);
888            in->bridge[0] = 0;
889            stop_server(in, false);
890        }
891    }
892#endif
893}
894
895
896int main(int argc, char **argv)
897{
898    struct ead_instance *in;
899    struct timeval tv;
900    const char *pidfile = NULL;
901    bool background = false;
902    int n_iface = 0;
903    int fd, ch;
904
905    if (argc == 1)
906        return usage(argv[0]);
907
908    INIT_LIST_HEAD(&instances);
909    while ((ch = getopt(argc, argv, "Bd:D:fhp:P:")) != -1) {
910        switch(ch) {
911        case 'B':
912            background = true;
913            break;
914        case 'f':
915            nonfork = true;
916            break;
917        case 'h':
918            return usage(argv[0]);
919        case 'd':
920            in = malloc(sizeof(struct ead_instance));
921            memset(in, 0, sizeof(struct ead_instance));
922            INIT_LIST_HEAD(&in->list);
923            strncpy(in->ifname, optarg, sizeof(in->ifname) - 1);
924            list_add(&in->list, &instances);
925            in->id = n_iface++;
926            break;
927        case 'D':
928            dev_name = optarg;
929            break;
930        case 'p':
931            passwd_file = optarg;
932            break;
933        case 'P':
934            pidfile = optarg;
935            break;
936        }
937    }
938    signal(SIGCHLD, server_handle_sigchld);
939    signal(SIGINT, server_handle_sigint);
940    signal(SIGTERM, server_handle_sigint);
941    signal(SIGKILL, server_handle_sigint);
942
943    if (!n_iface) {
944        fprintf(stderr, "Error: ead needs at least one interface\n");
945        return -1;
946    }
947
948    if (background) {
949        if (fork() > 0)
950            exit(0);
951
952        fd = open("/dev/null", O_RDWR);
953        dup2(fd, 0);
954        dup2(fd, 1);
955        dup2(fd, 2);
956    }
957
958    if (pidfile) {
959        char pid[8];
960        int len;
961
962        unlink(pidfile);
963        fd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
964        if (fd > 0) {
965            len = sprintf(pid, "%d\n", getpid());
966            write(fd, pid, len);
967            close(fd);
968        }
969    }
970
971    /* randomize the mac address */
972    get_random_bytes(ethmac + 3, 3);
973    nid = *(((u16_t *) ethmac) + 2);
974
975    start_servers(false);
976#ifdef linux
977    br_init();
978#endif
979    tv.tv_sec = 1;
980    tv.tv_usec = 0;
981    while (1) {
982        check_all_interfaces();
983        start_servers(true);
984        sleep(1);
985    }
986#ifdef linux
987    br_shutdown();
988#endif
989
990    return 0;
991}
992

Archive Download this file



interactive