X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7619ddb0a299ecde33f5dbaf89bcf6c875507d7f..c5757539b2ac71eed67f9131affcafe37a137d22:/package/ead/src/ead.c diff --git a/package/ead/src/ead.c b/package/ead/src/ead.c index c4d3dd9f4..36235207b 100644 --- a/package/ead/src/ead.c +++ b/package/ead/src/ead.c @@ -42,6 +42,10 @@ #include "libbridge_init.c" #endif +#ifdef linux +#include +#endif + #define PASSWD_FILE "/etc/passwd" #ifndef DEFAULT_IFNAME @@ -65,10 +69,20 @@ #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 const char *ifname = DEFAULT_IFNAME; static char pktbuf_b[PCAP_MRU]; static struct ead_packet *pktbuf = (struct ead_packet *)pktbuf_b; static u16_t nid = 0xffff; /* node id */ @@ -85,20 +99,7 @@ static unsigned char pw_saltbuf[MAXSALTLEN]; static struct list_head instances; static const char *dev_name = DEFAULT_DEVNAME; static bool nonfork = false; - -#ifdef linux -static const char *brname = NULL; -#endif - -struct ead_instance { - struct list_head list; - char name[16]; - int pid; -#ifdef linux - char bridge[16]; - bool br_check; -#endif -}; +static struct ead_instance *instance = NULL; static struct t_pwent tpe = { .name = username, @@ -113,6 +114,65 @@ 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) { @@ -250,7 +310,7 @@ ead_send_packet_clone(struct ead_packet *pkt) 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->destipaddr, 4); + memcpy(pktbuf->srcipaddr, &pkt->msg.ip, 4); memcpy(pktbuf->destipaddr, pkt->srcipaddr, 4); /* ip checksum */ @@ -344,7 +404,7 @@ handle_set_username(struct ead_packet *pkt, int len, int *nstate) set_state(EAD_TYPE_SET_USERNAME); /* clear old state */ strncpy(username, user->username, sizeof(username)); - username[sizeof(username)] = 0; + username[sizeof(username) - 1] = 0; msg = &pktbuf->msg; msg->len = 0; @@ -539,6 +599,11 @@ parse_message(struct ead_packet *pkt, int len) (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; @@ -574,6 +639,7 @@ parse_message(struct ead_packet *pkt, int len) 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)) { @@ -622,30 +688,34 @@ ead_pcap_reopen(bool first) { static char errbuf[PCAP_ERRBUF_SIZE] = ""; - if (pcap_fp_rx != pcap_fp) + if (pcap_fp_rx && (pcap_fp_rx != pcap_fp)) pcap_close(pcap_fp_rx); if (pcap_fp) pcap_close(pcap_fp); - pcap_fp_rx = pcap_fp; + pcap_fp_rx = NULL; do { - pcap_fp = pcap_open_live(ifname, PCAP_MRU, 1, PCAP_TIMEOUT, errbuf); #ifdef linux - if (brname) { - pcap_fp_rx = pcap_open_live(brname, PCAP_MRU, 1, PCAP_TIMEOUT, errbuf); - if (!pcap_fp_rx) - pcap_fp_rx = pcap_fp; - } + 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_setfilter(pcap_fp_rx, &pktfilter); + { + 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", ifname); + 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); } @@ -713,12 +783,8 @@ start_server(struct ead_instance *i) } } + instance = i; signal(SIGCHLD, instance_handle_sigchld); - ifname = i->name; -#ifdef linux - if (i->bridge[0]) - brname = i->bridge; -#endif ead_pcap_reopen(true); ead_pktloop(); pcap_close(pcap_fp); @@ -780,7 +846,7 @@ check_bridge_port(const char *br, const char *port, void *arg) list_for_each(p, &instances) { in = list_entry(p, struct ead_instance, list); - if (strcmp(in->name, port) != 0) + if (strcmp(in->ifname, port) != 0) continue; in->br_check = true; @@ -788,7 +854,7 @@ check_bridge_port(const char *br, const char *port, void *arg) break; strncpy(in->bridge, br, sizeof(in->bridge)); - DEBUG(2, "assigning port %s to bridge %s\n", in->name, in->bridge); + DEBUG(2, "assigning port %s to bridge %s\n", in->ifname, in->bridge); stop_server(in, false); } return 0; @@ -818,7 +884,7 @@ check_all_interfaces(void) if (in->br_check) { in->br_check = false; } else if (in->bridge[0]) { - DEBUG(2, "removing port %s from bridge %s\n", in->name, in->bridge); + DEBUG(2, "removing port %s from bridge %s\n", in->ifname, in->bridge); in->bridge[0] = 0; stop_server(in, false); } @@ -831,10 +897,10 @@ int main(int argc, char **argv) { struct ead_instance *in; struct timeval tv; - int fd, ch; const char *pidfile = NULL; bool background = false; int n_iface = 0; + int fd, ch; if (argc == 1) return usage(argv[0]); @@ -854,9 +920,9 @@ int main(int argc, char **argv) in = malloc(sizeof(struct ead_instance)); memset(in, 0, sizeof(struct ead_instance)); INIT_LIST_HEAD(&in->list); - strncpy(in->name, optarg, sizeof(in->name) - 1); + strncpy(in->ifname, optarg, sizeof(in->ifname) - 1); list_add(&in->list, &instances); - n_iface++; + in->id = n_iface++; break; case 'D': dev_name = optarg; @@ -903,13 +969,7 @@ int main(int argc, char **argv) } /* randomize the mac address */ - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - perror("open"); - exit(1); - } - read(fd, ethmac + 3, 3); - close(fd); + get_random_bytes(ethmac + 3, 3); nid = *(((u16_t *) ethmac) + 2); start_servers(false);