aboutsummaryrefslogtreecommitdiffstats
path: root/package/ead/src/ead.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/ead/src/ead.c')
-rw-r--r--package/ead/src/ead.c991
1 files changed, 0 insertions, 991 deletions
diff --git a/package/ead/src/ead.c b/package/ead/src/ead.c
deleted file mode 100644
index 36235207bc..0000000000
--- a/package/ead/src/ead.c
+++ /dev/null
@@ -1,991 +0,0 @@
-/*
- * Emergency Access Daemon
- * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/select.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pcap.h>
-#include <pcap-bpf.h>
-#include <t_pwd.h>
-#include <t_read.h>
-#include <t_sha.h>
-#include <t_defines.h>
-#include <t_server.h>
-
-#include "list.h"
-#include "ead.h"
-#include "ead-pcap.h"
-#include "ead-crypt.h"
-
-#include "filter.c"
-
-#ifdef linux
-#include "libbridge_init.c"
-#endif
-
-#ifdef linux
-#include <linux/if_packet.h>
-#endif
-
-#define PASSWD_FILE "/etc/passwd"
-
-#ifndef DEFAULT_IFNAME
-#define DEFAULT_IFNAME "eth0"
-#endif
-
-#ifndef DEFAULT_DEVNAME
-#define DEFAULT_DEVNAME "Unknown"
-#endif
-
-#define PCAP_MRU 1600
-#define PCAP_TIMEOUT 200
-
-#if EAD_DEBUGLEVEL >= 1
-#define DEBUG(n, format, ...) do { \
- if (EAD_DEBUGLEVEL >= n) \
- fprintf(stderr, format, ##__VA_ARGS__); \
-} while (0);
-
-#else
-#define DEBUG(n, format, ...) do {} while(0)
-#endif
-
-struct ead_instance {
- struct list_head list;
- char ifname[16];
- int pid;
- char id;
-#ifdef linux
- char bridge[16];
- bool br_check;
-#endif
-};
-
-static char ethmac[6] = "\x00\x13\x37\x00\x00\x00"; /* last 3 bytes will be randomized */
-static pcap_t *pcap_fp = NULL;
-static pcap_t *pcap_fp_rx = NULL;
-static char pktbuf_b[PCAP_MRU];
-static struct ead_packet *pktbuf = (struct ead_packet *)pktbuf_b;
-static u16_t nid = 0xffff; /* node id */
-static char username[32] = "";
-static int state = EAD_TYPE_SET_USERNAME;
-static const char *passwd_file = PASSWD_FILE;
-static const char password[MAXPARAMLEN];
-static bool child_pending = false;
-
-static unsigned char abuf[MAXPARAMLEN + 1];
-static unsigned char pwbuf[MAXPARAMLEN];
-static unsigned char saltbuf[MAXSALTLEN];
-static unsigned char pw_saltbuf[MAXSALTLEN];
-static struct list_head instances;
-static const char *dev_name = DEFAULT_DEVNAME;
-static bool nonfork = false;
-static struct ead_instance *instance = NULL;
-
-static struct t_pwent tpe = {
- .name = username,
- .index = 1,
- .password.data = pwbuf,
- .password.len = 0,
- .salt.data = saltbuf,
- .salt.len = 0,
-};
-struct t_confent *tce = NULL;
-static struct t_server *ts = NULL;
-static struct t_num A, *B = NULL;
-unsigned char *skey;
-
-static void
-set_recv_type(pcap_t *p, bool rx)
-{
-#ifdef PACKET_RECV_TYPE
- struct sockaddr_ll sll;
- struct ifreq ifr;
- int ifindex, mask;
- int fd, ret;
-
- fd = pcap_get_selectable_fd(p);
- if (fd < 0)
- return;
-
- if (rx)
- mask = 1 << PACKET_BROADCAST;
- else
- mask = 0;
-
- ret = setsockopt(fd, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask));
-#endif
-}
-
-
-static pcap_t *
-ead_open_pcap(const char *ifname, char *errbuf, bool rx)
-{
- pcap_t *p;
-
- p = pcap_create(ifname, errbuf);
- if (p == NULL)
- goto out;
-
- pcap_set_snaplen(p, PCAP_MRU);
- pcap_set_promisc(p, rx);
- pcap_set_timeout(p, PCAP_TIMEOUT);
-#ifdef HAS_PROTO_EXTENSION
- pcap_set_protocol(p, (rx ? htons(ETH_P_IP) : 0));
-#endif
- pcap_set_buffer_size(p, (rx ? 10 : 1) * PCAP_MRU);
- pcap_activate(p);
- set_recv_type(p, rx);
-out:
- return p;
-}
-
-static void
-get_random_bytes(void *ptr, int len)
-{
- int fd;
-
- fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(1);
- }
- read(fd, ptr, len);
- close(fd);
-}
-
-static bool
-prepare_password(void)
-{
- static char lbuf[1024];
- unsigned char dig[SHA_DIGESTSIZE];
- BigInteger x, v, n, g;
- SHA1_CTX ctxt;
- int ulen = strlen(username);
- FILE *f;
-
- lbuf[sizeof(lbuf) - 1] = 0;
-
- f = fopen(passwd_file, "r");
- if (!f)
- return false;
-
- while (fgets(lbuf, sizeof(lbuf) - 1, f) != NULL) {
- char *str, *s2;
-
- if (strncmp(lbuf, username, ulen) != 0)
- continue;
-
- if (lbuf[ulen] != ':')
- continue;
-
- str = &lbuf[ulen + 1];
-
- if (strncmp(str, "$1$", 3) != 0)
- continue;
-
- s2 = strchr(str + 3, '$');
- if (!s2)
- continue;
-
- if (s2 - str >= MAXSALTLEN)
- continue;
-
- strncpy((char *) pw_saltbuf, str, s2 - str);
- pw_saltbuf[s2 - str] = 0;
-
- s2 = strchr(s2, ':');
- if (!s2)
- continue;
-
- *s2 = 0;
- if (s2 - str >= MAXPARAMLEN)
- continue;
-
- strncpy((char *)password, str, MAXPARAMLEN);
- fclose(f);
- goto hash_password;
- }
-
- /* not found */
- fclose(f);
- return false;
-
-hash_password:
- tce = gettcid(tpe.index);
- do {
- t_random(tpe.password.data, SALTLEN);
- } while (memcmp(saltbuf, (char *)dig, sizeof(saltbuf)) == 0);
- if (saltbuf[0] == 0)
- saltbuf[0] = 0xff;
-
- n = BigIntegerFromBytes(tce->modulus.data, tce->modulus.len);
- g = BigIntegerFromBytes(tce->generator.data, tce->generator.len);
- v = BigIntegerFromInt(0);
-
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, (unsigned char *) username, strlen(username));
- SHA1Update(&ctxt, (unsigned char *) ":", 1);
- SHA1Update(&ctxt, (unsigned char *) password, strlen(password));
- SHA1Final(dig, &ctxt);
-
- SHA1Init(&ctxt);
- SHA1Update(&ctxt, saltbuf, tpe.salt.len);
- SHA1Update(&ctxt, dig, sizeof(dig));
- SHA1Final(dig, &ctxt);
-
- /* x = H(s, H(u, ':', p)) */
- x = BigIntegerFromBytes(dig, sizeof(dig));
-
- BigIntegerModExp(v, g, x, n);
- tpe.password.len = BigIntegerToBytes(v, (unsigned char *)pwbuf);
-
- BigIntegerFree(v);
- BigIntegerFree(x);
- BigIntegerFree(g);
- BigIntegerFree(n);
- return true;
-}
-
-static u16_t
-chksum(u16_t sum, const u8_t *data, u16_t len)
-{
- u16_t t;
- const u8_t *dataptr;
- const u8_t *last_byte;
-
- dataptr = data;
- last_byte = data + len - 1;
-
- while(dataptr < last_byte) { /* At least two more bytes */
- t = (dataptr[0] << 8) + dataptr[1];
- sum += t;
- if(sum < t) {
- sum++; /* carry */
- }
- dataptr += 2;
- }
-
- if(dataptr == last_byte) {
- t = (dataptr[0] << 8) + 0;
- sum += t;
- if(sum < t) {
- sum++; /* carry */
- }
- }
-
- /* Return sum in host byte order. */
- return sum;
-}
-
-static void
-ead_send_packet_clone(struct ead_packet *pkt)
-{
- u16_t len, sum;
-
- memcpy(pktbuf, pkt, offsetof(struct ead_packet, msg));
- memcpy(pktbuf->eh.ether_shost, ethmac, 6);
- memcpy(pktbuf->eh.ether_dhost, pkt->eh.ether_shost, 6);
-
- /* ip header */
- len = sizeof(struct ead_packet) - sizeof(struct ether_header) + ntohl(pktbuf->msg.len);
- pktbuf->len[0] = len >> 8;
- pktbuf->len[1] = len & 0xff;
- memcpy(pktbuf->srcipaddr, &pkt->msg.ip, 4);
- memcpy(pktbuf->destipaddr, pkt->srcipaddr, 4);
-
- /* ip checksum */
- pktbuf->ipchksum = 0;
- sum = chksum(0, (void *) &pktbuf->vhl, UIP_IPH_LEN);
- if (sum == 0)
- sum = 0xffff;
- pktbuf->ipchksum = htons(~sum);
-
- /* udp header */
- pktbuf->srcport = pkt->destport;
- pktbuf->destport = pkt->srcport;
-
- /* udp checksum */
- len -= UIP_IPH_LEN;
- pktbuf->udplen = htons(len);
- pktbuf->udpchksum = 0;
- sum = len + UIP_PROTO_UDP;
- sum = chksum(sum, (void *) &pktbuf->srcipaddr[0], 8); /* src, dest ip */
- sum = chksum(sum, (void *) &pktbuf->srcport, len);
- if (sum == 0)
- sum = 0xffff;
- pktbuf->udpchksum = htons(~sum);
- pcap_sendpacket(pcap_fp, (void *) pktbuf, sizeof(struct ead_packet) + ntohl(pktbuf->msg.len));
-}
-
-static void
-set_state(int nstate)
-{
- if (state == nstate)
- return;
-
- if (nstate < state) {
- if ((nstate < EAD_TYPE_GET_PRIME) &&
- (state >= EAD_TYPE_GET_PRIME)) {
- t_serverclose(ts);
- ts = NULL;
- }
- goto done;
- }
-
- switch(state) {
- case EAD_TYPE_SET_USERNAME:
- if (!prepare_password())
- goto error;
- ts = t_serveropenraw(&tpe, tce);
- if (!ts)
- goto error;
- break;
- case EAD_TYPE_GET_PRIME:
- B = t_servergenexp(ts);
- break;
- case EAD_TYPE_SEND_A:
- skey = t_servergetkey(ts, &A);
- if (!skey)
- goto error;
-
- ead_set_key(skey);
- break;
- }
-done:
- state = nstate;
-error:
- return;
-}
-
-static bool
-handle_ping(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pktbuf->msg;
- struct ead_msg_pong *pong = EAD_DATA(msg, pong);
- int slen;
-
- slen = strlen(dev_name);
- if (slen > 1024)
- slen = 1024;
-
- msg->len = htonl(sizeof(struct ead_msg_pong) + slen);
- strncpy(pong->name, dev_name, slen);
- pong->name[slen] = 0;
- pong->auth_type = htons(EAD_AUTH_MD5);
-
- return true;
-}
-
-static bool
-handle_set_username(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pkt->msg;
- struct ead_msg_user *user = EAD_DATA(msg, user);
-
- set_state(EAD_TYPE_SET_USERNAME); /* clear old state */
- strncpy(username, user->username, sizeof(username));
- username[sizeof(username) - 1] = 0;
-
- msg = &pktbuf->msg;
- msg->len = 0;
-
- *nstate = EAD_TYPE_GET_PRIME;
- return true;
-}
-
-static bool
-handle_get_prime(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pktbuf->msg;
- struct ead_msg_salt *salt = EAD_DATA(msg, salt);
-
- msg->len = htonl(sizeof(struct ead_msg_salt));
- salt->prime = tce->index - 1;
- salt->len = ts->s.len;
- memcpy(salt->salt, ts->s.data, ts->s.len);
- memcpy(salt->ext_salt, pw_saltbuf, MAXSALTLEN);
-
- *nstate = EAD_TYPE_SEND_A;
- return true;
-}
-
-static bool
-handle_send_a(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pkt->msg;
- struct ead_msg_number *number = EAD_DATA(msg, number);
- len = ntohl(msg->len) - sizeof(struct ead_msg_number);
-
- if (len > MAXPARAMLEN + 1)
- return false;
-
- A.len = len;
- A.data = abuf;
- memcpy(A.data, number->data, len);
-
- msg = &pktbuf->msg;
- number = EAD_DATA(msg, number);
- msg->len = htonl(sizeof(struct ead_msg_number) + B->len);
- memcpy(number->data, B->data, B->len);
-
- *nstate = EAD_TYPE_SEND_AUTH;
- return true;
-}
-
-static bool
-handle_send_auth(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pkt->msg;
- struct ead_msg_auth *auth = EAD_DATA(msg, auth);
-
- if (t_serververify(ts, auth->data) != 0) {
- DEBUG(2, "Client authentication failed\n");
- *nstate = EAD_TYPE_SET_USERNAME;
- return false;
- }
-
- msg = &pktbuf->msg;
- auth = EAD_DATA(msg, auth);
- msg->len = htonl(sizeof(struct ead_msg_auth));
-
- DEBUG(2, "Client authentication successful\n");
- memcpy(auth->data, t_serverresponse(ts), sizeof(auth->data));
-
- *nstate = EAD_TYPE_SEND_CMD;
- return true;
-}
-
-static bool
-handle_send_cmd(struct ead_packet *pkt, int len, int *nstate)
-{
- struct ead_msg *msg = &pkt->msg;
- struct ead_msg_cmd *cmd = EAD_ENC_DATA(msg, cmd);
- struct ead_msg_cmd_data *cmddata;
- struct timeval tv, to, tn;
- int pfd[2], fd;
- fd_set fds;
- pid_t pid;
- bool stream = false;
- int timeout;
- int type;
- int datalen;
-
- datalen = ead_decrypt_message(msg) - sizeof(struct ead_msg_cmd);
- if (datalen <= 0)
- return false;
-
- type = ntohs(cmd->type);
- timeout = ntohs(cmd->timeout);
-
- FD_ZERO(&fds);
- cmd->data[datalen] = 0;
- switch(type) {
- case EAD_CMD_NORMAL:
- if (pipe(pfd) < 0)
- return false;
-
- fcntl(pfd[0], F_SETFL, O_NONBLOCK | fcntl(pfd[0], F_GETFL));
- child_pending = true;
- pid = fork();
- if (pid == 0) {
- close(pfd[0]);
- fd = open("/dev/null", O_RDWR);
- if (fd > 0) {
- dup2(fd, 0);
- dup2(pfd[1], 1);
- dup2(pfd[1], 2);
- }
- system((char *)cmd->data);
- exit(0);
- } else if (pid > 0) {
- close(pfd[1]);
- if (!timeout)
- timeout = EAD_CMD_TIMEOUT;
-
- stream = true;
- break;
- }
- return false;
- case EAD_CMD_BACKGROUND:
- pid = fork();
- if (pid == 0) {
- /* close stdin, stdout, stderr, replace with fd to /dev/null */
- fd = open("/dev/null", O_RDWR);
- if (fd > 0) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- }
- system((char *)cmd->data);
- exit(0);
- } else if (pid > 0) {
- break;
- }
- return false;
- default:
- return false;
- }
-
- msg = &pktbuf->msg;
- cmddata = EAD_ENC_DATA(msg, cmd_data);
-
- if (stream) {
- int nfds, bytes;
-
- /* send keepalive packets every 200 ms so that the client doesn't timeout */
- gettimeofday(&to, NULL);
- memcpy(&tn, &to, sizeof(tn));
- tv.tv_usec = PCAP_TIMEOUT * 1000;
- tv.tv_sec = 0;
- do {
- cmddata->done = 0;
- FD_SET(pfd[0], &fds);
- nfds = select(pfd[0] + 1, &fds, NULL, NULL, &tv);
- bytes = 0;
- if (nfds > 0) {
- bytes = read(pfd[0], cmddata->data, 1024);
- if (bytes < 0)
- bytes = 0;
- }
- if (!bytes && !child_pending)
- break;
- DEBUG(3, "Sending %d bytes of console data, type=%d, timeout=%d\n", bytes, ntohl(msg->type), timeout);
- ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data) + bytes);
- ead_send_packet_clone(pkt);
- gettimeofday(&tn, NULL);
- } while (tn.tv_sec < to.tv_sec + timeout);
- if (child_pending) {
- kill(pid, SIGKILL);
- return false;
- }
- }
- cmddata->done = 1;
- ead_encrypt_message(msg, sizeof(struct ead_msg_cmd_data));
-
- return true;
-}
-
-
-
-static void
-parse_message(struct ead_packet *pkt, int len)
-{
- bool (*handler)(struct ead_packet *pkt, int len, int *nstate);
- int min_len = sizeof(struct ead_packet);
- int nstate = state;
- int type = ntohl(pkt->msg.type);
-
- if ((type >= EAD_TYPE_GET_PRIME) &&
- (state != type))
- return;
-
- if ((type != EAD_TYPE_PING) &&
- ((ntohs(pkt->msg.sid) & EAD_INSTANCE_MASK) >>
- EAD_INSTANCE_SHIFT) != instance->id)
- return;
-
- switch(type) {
- case EAD_TYPE_PING:
- handler = handle_ping;
- break;
- case EAD_TYPE_SET_USERNAME:
- handler = handle_set_username;
- min_len += sizeof(struct ead_msg_user);
- break;
- case EAD_TYPE_GET_PRIME:
- handler = handle_get_prime;
- break;
- case EAD_TYPE_SEND_A:
- handler = handle_send_a;
- min_len += sizeof(struct ead_msg_number);
- break;
- case EAD_TYPE_SEND_AUTH:
- handler = handle_send_auth;
- min_len += sizeof(struct ead_msg_auth);
- break;
- case EAD_TYPE_SEND_CMD:
- handler = handle_send_cmd;
- min_len += sizeof(struct ead_msg_cmd) + sizeof(struct ead_msg_encrypted);
- break;
- default:
- return;
- }
-
- if (len < min_len) {
- DEBUG(2, "discarding packet: message too small\n");
- return;
- }
-
- pktbuf->msg.magic = htonl(EAD_MAGIC);
- pktbuf->msg.type = htonl(type + 1);
- pktbuf->msg.nid = htons(nid);
- pktbuf->msg.sid = pkt->msg.sid;
- pktbuf->msg.len = 0;
-
- if (handler(pkt, len, &nstate)) {
- DEBUG(2, "sending response to packet type %d: %d\n", type + 1, ntohl(pktbuf->msg.len));
- /* format response packet */
- ead_send_packet_clone(pkt);
- }
- set_state(nstate);
-}
-
-static void
-handle_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
-{
- struct ead_packet *pkt = (struct ead_packet *) bytes;
-
- if (h->len < sizeof(struct ead_packet))
- return;
-
- if (pkt->eh.ether_type != htons(ETHERTYPE_IP))
- return;
-
- if (memcmp(pkt->eh.ether_dhost, "\xff\xff\xff\xff\xff\xff", 6) != 0)
- return;
-
- if (pkt->proto != UIP_PROTO_UDP)
- return;
-
- if (pkt->destport != htons(EAD_PORT))
- return;
-
- if (pkt->msg.magic != htonl(EAD_MAGIC))
- return;
-
- if (h->len < sizeof(struct ead_packet) + ntohl(pkt->msg.len))
- return;
-
- if ((pkt->msg.nid != 0xffff) &&
- (pkt->msg.nid != htons(nid)))
- return;
-
- parse_message(pkt, h->len);
-}
-
-static void
-ead_pcap_reopen(bool first)
-{
- static char errbuf[PCAP_ERRBUF_SIZE] = "";
-
- if (pcap_fp_rx && (pcap_fp_rx != pcap_fp))
- pcap_close(pcap_fp_rx);
-
- if (pcap_fp)
- pcap_close(pcap_fp);
-
- pcap_fp_rx = NULL;
- do {
-#ifdef linux
- if (instance->bridge[0]) {
- pcap_fp_rx = ead_open_pcap(instance->bridge, errbuf, 1);
- pcap_fp = ead_open_pcap(instance->ifname, errbuf, 0);
- } else
-#endif
- {
- pcap_fp = ead_open_pcap(instance->ifname, errbuf, 1);
- }
-
- if (!pcap_fp_rx)
- pcap_fp_rx = pcap_fp;
- if (first && !pcap_fp) {
- DEBUG(1, "WARNING: unable to open interface '%s'\n", instance->ifname);
- first = false;
- }
- if (!pcap_fp)
- sleep(1);
- } while (!pcap_fp);
- pcap_setfilter(pcap_fp_rx, &pktfilter);
-}
-
-
-static void
-ead_pktloop(void)
-{
- while (1) {
- if (pcap_dispatch(pcap_fp_rx, 1, handle_packet, NULL) < 0) {
- ead_pcap_reopen(false);
- continue;
- }
- }
-}
-
-
-static int
-usage(const char *prog)
-{
- fprintf(stderr, "Usage: %s [<options>]\n"
- "Options:\n"
- "\t-B Run in background mode\n"
- "\t-d <device> Set the device to listen on\n"
- "\t-D <name> Set the name of the device visible to clients\n"
- "\t-p <file> Set the password file for authenticating\n"
- "\t-P <file> Write a pidfile\n"
- "\n", prog);
- return -1;
-}
-
-static void
-server_handle_sigchld(int sig)
-{
- struct ead_instance *in;
- struct list_head *p;
- int pid = 0;
- wait(&pid);
-
- list_for_each(p, &instances) {
- in = list_entry(p, struct ead_instance, list);
- if (pid != in->pid)
- continue;
-
- in->pid = 0;
- break;
- }
-}
-
-static void
-instance_handle_sigchld(int sig)
-{
- int pid = 0;
- wait(&pid);
- child_pending = false;
-}
-
-static void
-start_server(struct ead_instance *i)
-{
- if (!nonfork) {
- i->pid = fork();
- if (i->pid != 0) {
- if (i->pid < 0)
- i->pid = 0;
- return;
- }
- }
-
- instance = i;
- signal(SIGCHLD, instance_handle_sigchld);
- ead_pcap_reopen(true);
- ead_pktloop();
- pcap_close(pcap_fp);
- if (pcap_fp_rx != pcap_fp)
- pcap_close(pcap_fp_rx);
-
- exit(0);
-}
-
-
-static void
-start_servers(bool restart)
-{
- struct ead_instance *in;
- struct list_head *p;
-
- list_for_each(p, &instances) {
- in = list_entry(p, struct ead_instance, list);
- if (in->pid > 0)
- continue;
-
- sleep(1);
- start_server(in);
- }
-}
-
-static void
-stop_server(struct ead_instance *in, bool do_free)
-{
- if (in->pid > 0)
- kill(in->pid, SIGKILL);
- in->pid = 0;
- if (do_free) {
- list_del(&in->list);
- free(in);
- }
-}
-
-static void
-server_handle_sigint(int sig)
-{
- struct ead_instance *in;
- struct list_head *p, *tmp;
-
- list_for_each_safe(p, tmp, &instances) {
- in = list_entry(p, struct ead_instance, list);
- stop_server(in, true);
- }
- exit(1);
-}
-
-#ifdef linux
-static int
-check_bridge_port(const char *br, const char *port, void *arg)
-{
- struct ead_instance *in;
- struct list_head *p, *tmp;
-
- list_for_each(p, &instances) {
- in = list_entry(p, struct ead_instance, list);
-
- if (strcmp(in->ifname, port) != 0)
- continue;
-
- in->br_check = true;
- if (strcmp(in->bridge, br) == 0)
- break;
-
- strncpy(in->bridge, br, sizeof(in->bridge));
- DEBUG(2, "assigning port %s to bridge %s\n", in->ifname, in->bridge);
- stop_server(in, false);
- }
- return 0;
-}
-
-static int
-check_bridge(const char *name, void *arg)
-{
- br_foreach_port(name, check_bridge_port, arg);
- return 0;
-}
-#endif
-
-static void
-check_all_interfaces(void)
-{
-#ifdef linux
- struct ead_instance *in;
- struct list_head *p, *tmp;
-
- br_foreach_bridge(check_bridge, NULL);
-
- /* look for interfaces that are no longer part of a bridge */
- list_for_each(p, &instances) {
- in = list_entry(p, struct ead_instance, list);
-
- if (in->br_check) {
- in->br_check = false;
- } else if (in->bridge[0]) {
- DEBUG(2, "removing port %s from bridge %s\n", in->ifname, in->bridge);
- in->bridge[0] = 0;
- stop_server(in, false);
- }
- }
-#endif
-}
-
-
-int main(int argc, char **argv)
-{
- struct ead_instance *in;
- struct timeval tv;
- const char *pidfile = NULL;
- bool background = false;
- int n_iface = 0;
- int fd, ch;
-
- if (argc == 1)
- return usage(argv[0]);
-
- INIT_LIST_HEAD(&instances);
- while ((ch = getopt(argc, argv, "Bd:D:fhp:P:")) != -1) {
- switch(ch) {
- case 'B':
- background = true;
- break;
- case 'f':
- nonfork = true;
- break;
- case 'h':
- return usage(argv[0]);
- case 'd':
- in = malloc(sizeof(struct ead_instance));
- memset(in, 0, sizeof(struct ead_instance));
- INIT_LIST_HEAD(&in->list);
- strncpy(in->ifname, optarg, sizeof(in->ifname) - 1);
- list_add(&in->list, &instances);
- in->id = n_iface++;
- break;
- case 'D':
- dev_name = optarg;
- break;
- case 'p':
- passwd_file = optarg;
- break;
- case 'P':
- pidfile = optarg;
- break;
- }
- }
- signal(SIGCHLD, server_handle_sigchld);
- signal(SIGINT, server_handle_sigint);
- signal(SIGTERM, server_handle_sigint);
- signal(SIGKILL, server_handle_sigint);
-
- if (!n_iface) {
- fprintf(stderr, "Error: ead needs at least one interface\n");
- return -1;
- }
-
- if (background) {
- if (fork() > 0)
- exit(0);
-
- fd = open("/dev/null", O_RDWR);
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- }
-
- if (pidfile) {
- char pid[8];
- int len;
-
- unlink(pidfile);
- fd = open(pidfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
- if (fd > 0) {
- len = sprintf(pid, "%d\n", getpid());
- write(fd, pid, len);
- close(fd);
- }
- }
-
- /* randomize the mac address */
- get_random_bytes(ethmac + 3, 3);
- nid = *(((u16_t *) ethmac) + 2);
-
- start_servers(false);
-#ifdef linux
- br_init();
-#endif
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- while (1) {
- check_all_interfaces();
- start_servers(true);
- sleep(1);
- }
-#ifdef linux
- br_shutdown();
-#endif
-
- return 0;
-}