/* * * $Id: main.c,v 1.65 2005/10/07 02:30:30 psionic Exp $ */ #include #include #include "../config.h" #include #include #include #include #ifdef __FreeBSD__ #include #endif #include #include #include #include #include #ifdef HAVE_NET_ETHERNET_H #include #define MACTYPE u_char #define ETHERCONV(ether) (ether) #endif #ifdef HAVE_NETINET_IF_ETHER_H #include #include #ifndef MACTYPE #define MACTYPE uchar_t #endif #ifndef ETHERCONV #define ETHERCONV(ether) (&((ether).ether_addr_octet)) #endif #endif #include #include #include #include "ugly.h" static int BIGSERVER; #ifndef ETHER_ADDR_LEN #define ETHER_ADDR_LEN 6 #endif #include "log.h" #include "hash.h" #define SERVER_PORT 3434 #define HASHSIZE 512 /* xbox broadcasts to FF:FF:FF:FF:FF:FF */ static const char broadcastmac[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* multicast mac address is 01:00:5E:XX:XX:XX */ static const char multicastmac[ETHER_ADDR_LEN] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00, /* Last 3 octets are unknown and don't matter */ }; struct proxy; typedef struct xbox { MACTYPE macaddr[ETHER_ADDR_LEN]; struct proxy *proxy; /* The IP address of the proxy this xbox is located at */ time_t lastseen; /* Last time a packet was seen from this xbox */ } xbox_t; static hash_t *xboxen = NULL; /* Container for remote proxies */ typedef struct proxy { int ip; /* The ip address of this proxy */ struct in_addr addr; int port; /* The port! */ int fd; /* File descriptor for the connection to this proxy */ hash_t *xboxen; /* Table containing known xboxes on this proxy */ } proxy_t; static hash_t *proxies = NULL; static fd_set proxysocks; static char *progname; static char *pcapdev = NULL; static char *bindhost = NULL; static struct in_addr bindaddr; static char *proxyserver = NULL; /* Some defaults */ static int use_udp = 1; static int forwardmulticast = 0; static int forwardbroadcast = 0; static int forwardxbox = 1; static int serverport = SERVER_PORT; static char *user_filter = NULL; my_libnet_t *libnet; void addxbox(MACTYPE *macaddr, proxy_t *ppt); proxy_t *addproxy(struct sockaddr_in *addr, int sock); void packet_handler(u_char *args, const struct pcap_pkthdr *head, const u_char *packet); void remove_proxy(proxy_t *ppt); void connect_to_proxy(); int recv_from_proxy(proxy_t *ppt); void distribute_packet(proxy_t *ppt, char *packet, int pktlen); void usage() { debuglog(0, "Usage: %s [-bxm] [-u] [-B ] [-s ] [-i ] [-d ] [-p ] [-h]", progname); debuglog(0, "-x forward xbox system link packets"); debuglog(0, "-b forward broadcast traffic"); debuglog(0, "-m forward multicast packets"); debuglog(0, "-u use udp encapsulation instead of tcp (default)"); debuglog(0, "-B specify a specific ip to bind the listen server to"); debuglog(0, "-s specify another proxy to send packets to"); debuglog(0, "-i ethernet device to sniff packets on"); debuglog(0, "-d specify debug level, (0-1000)"); debuglog(0, "-p which port to send data on when talkin to other proxies"); debuglog(0, "-f an additional bpf filter string you wish to use"); debuglog(0, "-h this message!"); } int comparemac(const void *k1, const void *k2) { extern loglevel; if (loglevel >= 30) { char foo[25]; strcpy(foo,ether_ntoa((struct ether_addr *)k1)); debuglog(30, "comparemac %s vs %s", foo, ether_ntoa((struct ether_addr *)k2)); } return memcmp(k1, k2, ETHER_ADDR_LEN); } int compareip(const void *k1, const void *k2) { int a, b; a = *(unsigned int *)k1; b = *(unsigned int *)k2; debuglog(30, "compareip: %08x vs %08x = %d", a, b, (a < b ? -1 : (a > b ? 1 : 0)) ); return (a < b ? -1 : (a > b ? 1 : 0)); } hash_val_t haship(const void *key) { static unsigned long randbox[] = { 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U, 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU, 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU, 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU, }; const unsigned char *str = key; int c = 0; hash_val_t acc = 0; while (c < sizeof(int)) { acc ^= randbox[(*str + acc) & 0xf]; acc = (acc << 1) | (acc >> 31); acc &= 0xffffffffU; acc ^= randbox[((*str++ >> 4) + acc) & 0xf]; acc = (acc << 2) | (acc >> 30); acc &= 0xffffffffU; c++; } return acc; } hash_val_t hashmac(const void *key) { static unsigned long randbox[] = { 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U, 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU, 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU, 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU, }; const unsigned char *str = key; int c = 0; hash_val_t acc = 0; while (c < ETHER_ADDR_LEN) { acc ^= randbox[(*str + acc) & 0xf]; acc = (acc << 1) | (acc >> 31); acc &= 0xffffffffU; acc ^= randbox[((*str++ >> 4) + acc) & 0xf]; acc = (acc << 2) | (acc >> 30); acc &= 0xffffffffU; c++; } return acc; } /* * Packet handling routine. */ void packet_handler(u_char *args, const struct pcap_pkthdr *head, const u_char *packet) { struct ether_header *eptr; eptr = (struct ether_header *) packet; /* Try adding this xbox to the list */ //debuglog(1, "Adding xbox in packet_handler"); addxbox((MACTYPE *) ETHERCONV(eptr->ether_shost), 0); /* If this packet is sent to our local net, ignore it... */ if (hash_lookup(xboxen, ETHERCONV(eptr->ether_shost)) != NULL) { debuglog(15, "Packet!"); debuglog(3, "From: %s", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_shost))); debuglog(3, "To: %s", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_dhost))); } /* * If this is broadcast or multicast, send it to all known proxies */ if ((memcmp(ETHERCONV(eptr->ether_dhost), broadcastmac, ETHER_ADDR_LEN) == 0) || (forwardmulticast && (memcmp(ETHERCONV(eptr->ether_dhost), multicastmac, 3) == 0))) { hscan_t hs; hnode_t *node; debuglog(11, "BROADCAST"); hash_scan_begin(&hs, proxies); while ((node = hash_scan_next(&hs))) { proxy_t *p = (proxy_t *)(node->hash_data); /* Make sure the source addr of this packet is not getting * sent this packet. Do not send! */ if ((hash_lookup(p->xboxen, ETHERCONV(eptr->ether_shost)) != NULL)) continue; debuglog(3, "Sending ethernet packet to %s:%d [Length: %d]", inet_ntoa(p->addr), htons(p->port), head->caplen); if (use_udp) { struct sockaddr_in to; to.sin_addr = p->addr; //to.sin_port = htons(serverport); to.sin_port = p->port; to.sin_family = PF_INET; sendto(p->fd, packet, head->caplen, 0, (struct sockaddr *)&to, sizeof(struct sockaddr)); } else { /* TCP */ } } } else { /* This packet is for a specific mac */ proxy_t *p; hnode_t *box; box = hash_lookup(xboxen, ETHERCONV(eptr->ether_dhost)); if (box == NULL) { debuglog(3, "Unknown destination %s, hasn't been seen yet.", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_dhost))); return; } debuglog(3, "Found packet destined for %s! (len: %d)", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_dhost)), head->caplen); p = ((xbox_t *)(box->hash_data))->proxy; if (p == NULL) { debuglog(3, "Packet is destined for this net, ignore it"); return; } debuglog(3, "Proxy is: %s", (p == NULL ? "Local" : inet_ntoa(p->addr))); if (use_udp) { struct sockaddr_in to; to.sin_addr = p->addr; //to.sin_port = htons(serverport); to.sin_port = p->port; to.sin_family = PF_INET; sendto(p->fd, packet, head->caplen, 0, (struct sockaddr *)&to, sizeof(struct sockaddr)); } else { /* TCP */ } } } proxy_t *addproxy(struct sockaddr_in *addr, int sock) { proxy_t *newproxy = NULL; hnode_t *proxy = NULL; debuglog(5, "Data from proxy: %s", inet_ntoa(addr->sin_addr)); proxy = hash_lookup(proxies, &(addr->sin_addr.s_addr)); if (proxy == NULL) { hscan_t hs; hnode_t *node; newproxy = malloc(sizeof(proxy_t)); newproxy->ip = (int) addr->sin_addr.s_addr; newproxy->addr = addr->sin_addr; newproxy->port = addr->sin_port; /* XXX: Is this correct? * If we're using UDP, 'sock' is the server udp socket, so this is correct * If we're using TCP, well... tcp doesn't work properly yet. */ newproxy->fd = sock; newproxy->xboxen = hash_create(HASHSIZE, comparemac, hashmac); debuglog(1, "NEW PROXY FOUND: %s", inet_ntoa(addr->sin_addr)); hash_alloc_insert(proxies, &(newproxy->ip), newproxy); /* Check known proxy connections for data */ hash_scan_begin(&hs, proxies); fprintf(stderr, "KNOWN PROXIES:\n"); while ((node = hash_scan_next(&hs))) { proxy_t *p = (proxy_t *)(node->hash_data); struct sockaddr_in i; i.sin_addr.s_addr = *(int *)(node->hash_key); fprintf(stderr, "PROXY: %s\n", inet_ntoa(p->addr)); } fprintf(stderr, "END\n"); return newproxy; } else { proxy_t *p = proxy->hash_data; debuglog(15, "Packet from known proxy..."); if (p->port != addr->sin_port) { debuglog(0, "Port changed on client %s (%d -> %d)", inet_ntoa(addr->sin_addr), p->port, addr->sin_port); p->port = addr->sin_port; } return (proxy->hash_data); } } void addxbox(MACTYPE *macaddr, proxy_t *ppt) { xbox_t *newbox = NULL; hnode_t *box = NULL; box = hash_lookup(xboxen, macaddr); if (box == NULL) { hscan_t hs; hnode_t *node; //fprintf(stderr, "NEW XBOX FOUND: %s / LOCATION: %s\n", //ether_ntoa((struct ether_addr *)macaddr), //(ppt == NULL ? "Local" : inet_ntoa(ppt->addr))); debuglog(1, "NEW XBOX FOUND: %s", ether_ntoa((struct ether_addr *)macaddr)); debuglog(1, "\tLocation: %s", (ppt == NULL ? "Local" : inet_ntoa(ppt->addr))); newbox = malloc(sizeof(xbox_t)); memcpy(newbox->macaddr,macaddr,ETHER_ADDR_LEN); //fprintf(stderr, "Stored macaddr: %s\n\n", ether_ntoa((struct ether_addr *)(newbox->macaddr))); newbox->lastseen = time(NULL); newbox->proxy = ppt; //hash_alloc_insert(xboxen, macaddr, newbox); hash_alloc_insert(xboxen, newbox->macaddr, newbox); if (ppt != NULL) hash_alloc_insert(ppt->xboxen, newbox->macaddr, newbox); /* Check known proxy connections for data */ hash_scan_begin(&hs, xboxen); fprintf(stderr, "KNOWN XBOXES:\n"); while ((node = hash_scan_next(&hs))) { xbox_t *x = (xbox_t *)(node->hash_data); fprintf(stderr, "XBOX: %s\n", ether_ntoa((struct ether_addr *)x->macaddr)); } fprintf(stderr, "END\n"); } } void pcap(void *args) { pcap_t *handle; struct bpf_program filter; char errbuf[PCAP_ERRBUF_SIZE]; bpf_u_int32 mask, net; char *bpf_filter; char netstring[17]; char maskstring[17]; pcap_lookupnet(pcapdev, &net, &mask, errbuf); #define GETBYTE(data,i) (*(((unsigned char *)&data) + i)) sprintf(netstring, "%u.%u.%u.%u", GETBYTE(net, 0), GETBYTE(net,1), GETBYTE(net,2), GETBYTE(net, 3)); sprintf(maskstring, "%u.%u.%u.%u", GETBYTE(mask, 0), GETBYTE(mask,1), GETBYTE(mask,2), GETBYTE(mask, 3)); debuglog(0, "Network: %s / %s", netstring, maskstring); /* A generous cap length */ handle = pcap_open_live(pcapdev, 2048, 1, 10, errbuf); if (handle == NULL) { debuglog(0, "Error trying to open %s: %s", pcapdev, errbuf); //return 1; pthread_exit(NULL); } libnet = my_libnet_init(pcapdev, errbuf); if (libnet == NULL) { debuglog(0, "libnet_init() failed: %s", errbuf); pthread_exit(NULL); } debuglog(2, "Opened %s, listening for xbox traffic", pcapdev); bpf_filter = malloc(1024); memset(bpf_filter, 0, 1024); if (user_filter != NULL) { sprintf(bpf_filter, "(%s)", user_filter); if (forwardmulticast || forwardbroadcast || forwardxbox) sprintf(bpf_filter + strlen(bpf_filter), " and ("); } /* Build the pcap bpf filter string */ if (forwardmulticast) { sprintf(bpf_filter + strlen(bpf_filter), "(src net %s mask %s and (multicast))", netstring, maskstring); if (forwardbroadcast || forwardxbox) sprintf(bpf_filter + strlen(bpf_filter), " or "); } /* XXX: Should this match any broadcast? Ether broadcast? or just ip broadcast? */ if (forwardbroadcast) { sprintf(bpf_filter + strlen(bpf_filter), "(ip broadcast)"); if (forwardxbox) sprintf(bpf_filter + strlen(bpf_filter), " or "); } if (forwardxbox) sprintf(bpf_filter + strlen(bpf_filter), "(host 0.0.0.1)"); if (user_filter != NULL) sprintf(bpf_filter + strlen(bpf_filter), ")"); debuglog(0, "pcap filter: %s", bpf_filter); if (-1 == pcap_compile(handle, &filter, bpf_filter, 1, net)) { debuglog(0, "%s: %s", progname, pcap_geterr(handle)); if (user_filter != NULL) { debuglog(0, "%s: You specified an additional packet filter, it probably has an error", progname); debuglog(0, "%s: The filter is '%s'", progname, user_filter); debuglog(5, "%s: Generated filter: %s", progname, bpf_filter); } exit(-1); } pcap_setfilter(handle, &filter); pcap_loop(handle, -1, packet_handler, NULL); pcap_close(handle); pthread_exit(NULL); } void proxy(void *args) { int server; struct sockaddr_in serveraddr; FD_ZERO(&proxysocks); if (use_udp) { server = socket(PF_INET, SOCK_DGRAM, 0); } else { server = socket(PF_INET, SOCK_STREAM, 0); } BIGSERVER = server; serveraddr.sin_family = PF_INET; if (bindhost != NULL) { serveraddr.sin_addr = bindaddr; } else { serveraddr.sin_addr.s_addr = INADDR_ANY; } serveraddr.sin_port = htons(serverport); debuglog(5, "Binding to any on port %d", serverport); if (bind(server, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) == -1) { debuglog(0, "bind() failed: %s", strerror(errno)); pthread_exit(NULL); } if (!use_udp) { if (listen(server, SOMAXCONN) < 0) { debuglog(0, "listen() failed: %s", strerror(errno)); debuglog(0, "UDP: %d", use_udp); pthread_exit(NULL); } } debuglog(1, "Listening on port %d", serverport); FD_SET(server, &proxysocks); /* If server is non-null, connect to that server and listen for data on it */ if (proxyserver != NULL) { connect_to_proxy(); } for (;;) { int fd; struct sockaddr_in srcaddr; int size = sizeof(struct sockaddr_in); /* sizeof(srcaddr) */ int sel; struct timeval timeout; struct fd_set proxycopy; timeout.tv_sec = 10; timeout.tv_usec = 0; /* Some sort of select() thing here */ proxycopy = proxysocks; FD_SET(server, &proxysocks); debuglog(150, "select: %08x", proxysocks); sel = select(FD_SETSIZE, &proxysocks, NULL, NULL, &timeout); if (sel < 0) { debuglog(0, "select() failed: %s", strerror(errno)); pthread_exit(NULL); } else if (sel == 0) { debuglog(150, "select() timed out waiting for data... trying again"); proxysocks = proxycopy; } else { hscan_t hs; hnode_t *node; debuglog(15, "Data ready from %d descriptors", sel); if (use_udp) { if (FD_ISSET(server, &proxysocks)) { proxy_t p; p.fd = server; debuglog(13, "Data received on udp"); if (recv_from_proxy(&p) > 0 ) FD_SET(server, &proxysocks); else FD_CLR(server, &proxysocks); } else { FD_SET(server, &proxysocks); } } else { /* if using TCP... */ } } /* else, selected data is available */ } /* infinite loop */ } void connect_to_proxy() { int sock; struct sockaddr_in destaddr; struct hostent *hostdata; struct in_addr in; //proxy_t *newproxy; if (use_udp) { if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { debuglog(0, "socket() failed: %s", strerror(errno)); pthread_exit(NULL); } } else { if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { debuglog(0, "socket() failed: %s", strerror(errno)); pthread_exit(NULL); } } /* XXX: Should we bind the socket here to port 3434? */ if ((hostdata = gethostbyname(proxyserver))== NULL) { debuglog(0, "gethostbyname() failed: %s", strerror(errno)); pthread_exit(NULL); } /* Grab the IP this hostname is, this is an ugly oneliner */ memcpy(&(in.s_addr),hostdata->h_addr_list[0],hostdata->h_length); debuglog(1, "%s is %s (%s)", proxyserver, hostdata->h_name, inet_ntoa(in)); //inet_ntoa((struct in_addr *)(hostdata->h_addr_list[0]))); destaddr.sin_family = PF_INET; destaddr.sin_addr = in; destaddr.sin_port = htons(serverport); if (use_udp) { debuglog(30, "Sending UDP hello packet to %s", proxyserver); if (sendto(BIGSERVER, NULL, 0, 0, (struct sockaddr *)&destaddr, sizeof(struct sockaddr)) < 0) { debuglog(0, "sendto() failed [while saying hi]: %s", strerror(errno)); pthread_exit(NULL); } } else { /* TCP */ } /* After we establish a connection with the proxy server host, * we should completely forget about this relationship * (us being the client). Now, add it to the list of * known proxies and move along. */ addproxy(&destaddr, BIGSERVER); FD_SET(sock, &proxysocks); } int recv_from_proxy(proxy_t *ppt) { int bytes = 0; int pktlen = 0; int total; char *packet; if (use_udp) { bytes = 4; pktlen = 8192; } else { bytes = recv(ppt->fd, &pktlen, 4, 0); debuglog(100, "Bytes read: [%d] %d", bytes, pktlen); /* if bytes read is 0, then the connection was closed. */ if (bytes < 0) { debuglog(0, "recv_from_proxy - recv() (1) failed: %s", strerror(errno)); return bytes; } else if (bytes == 0) { remove_proxy(ppt); return 0; } } packet = malloc(pktlen); if (use_udp) { struct sockaddr_in from; int len = sizeof(struct sockaddr); bytes = recvfrom(ppt->fd, packet, pktlen, 0, (struct sockaddr *)&from, &len); pktlen = bytes; /* XXX: Is this a good idea? */ ppt = addproxy(&from, ppt->fd); } else { bytes = recv(ppt->fd, packet, pktlen, 0); } if (bytes < 0) { if (use_udp) debuglog(0, "recv_from_proxy - recvfrom() (2) failed: %s", strerror(errno)); else debuglog(0, "recv_from_proxy - recv() (2) failed: %s", strerror(errno)); return bytes; } if (bytes == 0) { if (!use_udp) remove_proxy(ppt); return 0; } //debuglog(1, "Adding xbox in recv_from_proxy"); addxbox(ETHERCONV(((struct ether_header *)packet)->ether_shost), ppt); debuglog(1, "Packet received from %s. Length: %d vs %d (%s)", inet_ntoa(ppt->addr), bytes, pktlen, (bytes == pktlen ? "OK" : "FRAGMENTED")); if (bytes < pktlen) { total = bytes; while (total < pktlen) { bytes = recv(ppt->fd, packet + total, pktlen - total, 0); debuglog(1, "REASSEMBLY PROGRESS - %s. Length: %d vs %d", inet_ntoa(ppt->addr), total, pktlen); total += bytes; } } distribute_packet(ppt, packet, bytes); free(packet); return bytes; } void distribute_packet(proxy_t *ppt, char *packet, int pktlen) { struct ether_header *eptr; u_short ether_type; int bytes = 0; eptr = (struct ether_header *)packet; ether_type = ntohs(eptr->ether_type); debuglog(30, "----- REMOTE PACKET From: %s", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_shost))); debuglog(30, "----- REMOTE PACKET To: %s", ether_ntoa((struct ether_addr *)ETHERCONV(eptr->ether_dhost))); bytes = my_libnet_write_link_layer(libnet,pcapdev,packet,pktlen); if (bytes < 0) { debuglog(0, "FATAL ERROR WRITING RAW PACKET TO DEVICE"); } else { debuglog(4, "Packet dumped on local net (%s), bytes vs length = %d vs %d", pcapdev, bytes, pktlen); } if (get_log_level() > 10) hexdump(packet, pktlen); } void remove_proxy(proxy_t *ppt) { hscan_t hs; hnode_t *node; debuglog(1, "Removing proxy %s", inet_ntoa(ppt->addr)); hash_scan_begin(&hs, proxies); while ((node = hash_scan_next(&hs))) { proxy_t *p = (proxy_t *)(node->hash_data); if (ppt->ip == p->ip) { hash_delete(proxies, node); break; } } } int main(int argc, char **argv) { char errbuf[PCAP_ERRBUF_SIZE]; //int *pthread_return; char ch; pthread_t pcapthread, proxythread; progname = argv[0]; /* Initialization and Defaults */ xboxen = hash_create(HASHSIZE, comparemac, hashmac); proxies = hash_create(HASHSIZE, compareip, haship); set_log_level(0); /* Argument Processing */ while ((ch = getopt(argc, argv, "B:bxmus:i:d:h?p:f:")) != -1) { switch (ch) { case 'B': bindhost = malloc(strlen(optarg) + 1); //strlcpy(bindhost,optarg,strlen(optarg) + 1); strcpy(bindhost,optarg); if (inet_aton(bindhost, &bindaddr) == 0) { bindhost = NULL; debuglog(0, "-B flag: Invalid IP address '%s'", bindhost); } case 'b': debuglog(10, "-b flag, enabling broadcast forwarding"); forwardbroadcast = 1; break; case 'd': set_log_level(atoi(optarg)); break; case 'f': user_filter = malloc(strlen(optarg)); strcpy(user_filter, optarg); break; case 'i': pcapdev = malloc(strlen(optarg) + 1); memset(pcapdev,0,strlen(optarg) + 1); //strlcpy(pcapdev,optarg,strlen(optarg) + 1); strncpy(pcapdev,optarg,strlen(optarg)); debuglog(10, "-i flag, setting device to %s", pcapdev); break; case 'm': debuglog(10, "-m flag, enabling multicast forwarding"); forwardmulticast = 1; break; case 'p': serverport = atoi(optarg); debuglog(10, "-p flag, setting proxy port to %d", serverport); break; case 's': proxyserver = malloc(strlen(optarg) + 1); memset(proxyserver,0,strlen(optarg) + 1); //strlcpy(proxyserver,optarg,strlen(optarg) + 1); strncpy(proxyserver,optarg,strlen(optarg)); debuglog(10, "-s flag, setting proxy server to %s", proxyserver); break; case 'u': debuglog(10, "-u flag, enabling udp"); use_udp = 1; break; case 'x': debuglog(10, "-x flag, enabling xbox system link forwarding"); forwardxbox = 1; break; case 'h': case '?': default: usage(); exit(1); break; } } argc -= optind; argv += optind; if (pcapdev == NULL) pcapdev = pcap_lookupdev(errbuf); if (pcapdev == NULL) { debuglog(0, "No device specified or unable to find a device to open."); debuglog(0, "Error message: %s", errbuf); return 1; } pthread_create(&pcapthread, NULL, (void*)pcap, NULL); pthread_create(&proxythread, NULL, (void*)proxy, NULL); pthread_join(pcapthread, NULL); debuglog(0, "pcap thread exited unexpectedly"); exit(1); pthread_join(proxythread, NULL); return 0; }