From owner-p4-projects@FreeBSD.ORG Sun Aug 5 23:53:51 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BD10216A421; Sun, 5 Aug 2007 23:53:50 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 908AD16A417 for ; Sun, 5 Aug 2007 23:53:50 +0000 (UTC) (envelope-from mharvan@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 8202E13C457 for ; Sun, 5 Aug 2007 23:53:50 +0000 (UTC) (envelope-from mharvan@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l75Nrorp079348 for ; Sun, 5 Aug 2007 23:53:50 GMT (envelope-from mharvan@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l75NroZD079345 for perforce@freebsd.org; Sun, 5 Aug 2007 23:53:50 GMT (envelope-from mharvan@FreeBSD.org) Date: Sun, 5 Aug 2007 23:53:50 GMT Message-Id: <200708052353.l75NroZD079345@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to mharvan@FreeBSD.org using -f From: Matus Harvan To: Perforce Change Reviews Cc: Subject: PERFORCE change 124758 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 05 Aug 2007 23:53:51 -0000 http://perforce.freebsd.org/chv.cgi?CH=124758 Change 124758 by mharvan@mharvan_bike-planet on 2007/08/05 23:53:35 changed the icmp plugin to simulate ICMP echo request/reply exchanges Affected files ... .. //depot/projects/soc2007/mharvan-mtund/mtund.doc/design.txt#3 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/README#2 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin.h#3 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_icmp.c#4 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_tcp.c#6 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_udp.c#5 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.c#13 edit .. //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.h#7 edit Differences ... ==== //depot/projects/soc2007/mharvan-mtund/mtund.doc/design.txt#3 (text+ko) ==== @@ -4,11 +4,13 @@ mentors. TODO: -o use libevent (http://www.monkey.org/~provos/libevent/) -o configuration of tun iface done by daemon (call ifconfig&friends) o man page o port skeleton +TODO this document +o plugin_send() return values - prevent filling the stack +o fragmenation, fragment reassembly, framing + TUN(4) INTERFACE (OR SOMETHING ELSE?) My original idea, as described in the proposal is to use the tun(4) interface. It gives a virtual network interface (point-to-point). ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/README#2 (text+ko) ==== @@ -65,4 +65,8 @@ 3333: iptables -t filter -A INPUT --protocol tcp --destination-port 3333 -j DROP -To get some security, you may want to set up IPSec on the tun interface.+To get some security, you may want to set up IPSec on the tun interface. + +Older FreeBSD versions may have problems with kqueue. You can use +alternative mechanisms by setting the environment variable +EVENT_NOKQUEUE. ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin.h#3 (text+ko) ==== @@ -60,6 +60,12 @@ void plugin_receive(int fd, short ev_type, void *arg); /* + * Check whether plugin is ready to send data. + * Return: 1 if ready to send, 0 if not. + */ +int plugin_is_ready_to_send(); + +/* * Send the data. * Return: number of bytes sent, -1 on error. */ ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_icmp.c#4 (text+ko) ==== @@ -1,3 +1,12 @@ +/* + * ICMP encapsulation plugin + * + * Client encapsulates the data as ICMP payload of ICMP echo + * requests. The server encapsulates the data as ICMP payload of + * replies to the received ICMP echo requests. For this reasons, the + * server always queues one packet at a time from the daemon. + */ + #include #include #include @@ -16,18 +25,14 @@ #include #include +#include +#include +#include +#include + #include "tunneld.h" #include "plugin.h" -#define ID 0x42 - -/* - * Establish a connected UDP endpoint. First get the list of potential - * network layer addresses and transport layer port numbers. Iterate - * through the returned address list until an attempt to create and - * connect a UDP endpoint is successful (or no other alternative - * exists). - */ typedef struct { int fd; /* udp socket to the other endpoint */ @@ -35,7 +40,7 @@ int server; } plugin_icmp_datat; -struct myicmp { +struct my_icmp_hdr { u_int8_t type; u_int8_t code; u_int16_t cksum; @@ -46,6 +51,13 @@ static struct sockaddr_in dst_addr; /* address of the other endpoint */ static socklen_t dst_addr_len = sizeof(dst_addr); +char *queued_data = NULL; +int queued_data_len = 0; +u_int16_t id = 0; +u_int16_t seq = 0; +int old_sysctl; +size_t old_sysctl_size = sizeof(old_sysctl); + u_int16_t in_cksum(u_int16_t *addr, int len) { register int nleft = len; @@ -60,6 +72,13 @@ return (answer); } +/* + * Establish a connected ICMP endpoint. First get the list of + * potential network layer addresses. Iterate through the returned + * address list until an attempt to create and connect an ICMP + * endpoint is successful (or no other alternative exists). + */ + /* static int */ /* icmp_connect(char *host) */ /* { */ @@ -111,13 +130,16 @@ return close(fd); } -int plugin_register(plugint* pl) { +int +plugin_register(plugint* pl) +{ pl->name = "icmp"; - pl->need_frag = 1; + pl->mtu = 1400; pl->initialize = plugin_initialize; pl->deinitialize = plugin_deinitialize; + pl->receive = plugin_receive; + pl->is_ready_to_send = plugin_is_ready_to_send; pl->send = plugin_send; - pl->receive = plugin_receive; pl->next = NULL; pl->data = malloc(sizeof(plugin_icmp_datat)); @@ -131,7 +153,9 @@ return 0; } -void plugin_unregister(plugint* pl) { +void +plugin_unregister(plugint* pl) +{ if (pl->data) { free(pl->data); pl->data = NULL; @@ -145,9 +169,12 @@ * not work. It will fail once we try to send data, so it may be wise * to first send some handshake data. */ -int plugin_initialize(plugint *pl, const int server, char *host, char *port) { +int +plugin_initialize(plugint *pl, const int server, char *host, char *port) +{ struct addrinfo hints, *ai; int n; + int new_sysctl = 1; plugin_icmp_datat *data = (plugin_icmp_datat*) pl->data; fprintf(stderr, "starting plugin_initialize...\n"); @@ -155,7 +182,13 @@ data->server = server; if (server) { + id = 0; + seq = 0; } else { + srandomdev(); + id = random(); + seq = random(); + memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_RAW; @@ -185,11 +218,17 @@ } if (data->server) { - #ifdef __FreeBSD__ +#ifdef __FreeBSD__ + if (0 != sysctlbyname("net.inet.icmp.echo_user", + &old_sysctl, &old_sysctl_size, + &new_sysctl, sizeof(new_sysctl))) + errx(EX_UNAVAILABLE, "Cannot set net.inet.icmp.echo_user " + "sysctl. Maybe you need to patch your kernel?"); + //system("sysctl net.inet.icmp.echo_user=1"); +#endif +#ifdef __linux__ system("sysctl net.ipv4.icmp_echo_ignore_all=0"); - #else - system("sysctl net.ipv4.icmp_echo_ignore_all=0"); - #endif +#endif } return 0; } else { @@ -197,26 +236,76 @@ } } -void plugin_deinitialize(plugint *pl) { +void +plugin_deinitialize(plugint *pl) +{ plugin_icmp_datat *data = (plugin_icmp_datat*) pl->data; unregister_select_fd(data->fd); icmp_close(data->fd); data->state = PLUGIN_STATE_UNINITIALIZED; + +#ifdef __FreeBSD__ + if (data->server) + sysctlbyname("net.inet.icmp.echo_user", NULL, 0, + &old_sysctl, old_sysctl_size); +#endif } -void plugin_receive(int fd, short ev_type, void *arg) { +static int +send_icmp_pkt(plugint *pl, int id, int seq, char *data, int len) +{ + plugin_icmp_datat *datapl = (plugin_icmp_datat*)pl->data; + int n = 0; + char* packet; + struct my_icmp_hdr *icmp; + + packet = malloc(sizeof(struct my_icmp_hdr) + len); + if (!packet) { + fprintf(stderr, "plugin_send: out of memory\n"); + return PLUGIN_SEND_ERROR_MALLOC; + } + memset (packet, 0, sizeof(struct my_icmp_hdr) + len); + memcpy (packet+sizeof(struct my_icmp_hdr), data, len); + + icmp = (struct my_icmp_hdr*)(packet); + if (datapl->server) { + icmp->type = ICMP_ECHOREPLY; + } else { /* client */ + icmp->type = ICMP_ECHO; + //icmp->type = 123; + } + + icmp->code = 0; + icmp->id = htons(id); + icmp->seq = htons(seq); + icmp->cksum = 0; + icmp->cksum = in_cksum((u_int16_t*)packet, sizeof(struct my_icmp_hdr) + len); + + n = sendto(datapl->fd, (char*)packet, sizeof(struct my_icmp_hdr) + len, 0, + (struct sockaddr*)&dst_addr, dst_addr_len); + //(struct sockaddr*)dst, sizeof (struct sockaddr_in)); + fprintf(stderr, "plugin_send: send returned %d\n", n); + return n; +} + + +void +plugin_receive(int fd, short ev_type, void *arg) +{ plugint *pl = (plugint *) arg; plugin_icmp_datat *data = (plugin_icmp_datat*) pl->data; int n = 0; - char packet[PACKETLEN]; + char packet[PACKETLEN]; + char *packetp = packet; struct sockaddr_in from; socklen_t fromlen = sizeof(from); char host[NI_MAXHOST]; char serv[NI_MAXSERV]; + struct my_icmp_hdr *icmp = NULL; if (! (data->state == PLUGIN_STATE_CONNECTED || data->state == PLUGIN_STATE_INITIALIZED)) { - //return -1; + return; } fprintf(stderr, "data on plugin fd\n"); @@ -240,66 +329,104 @@ memcpy(&dst_addr, &from, fromlen); dst_addr_len = fromlen; data->state = PLUGIN_STATE_CONNECTED; - + } else { // TODO: fix the comparison - if (memcmp(&dst_addr, &from, dst_addr_len) == 0 || 1) { - if (n == -1) { - //return -1; - } else if (n > 0) { - // TODO: check values in the ICMP header - process_data_from_plugin(pl, packet + sizeof(struct myicmp) - + 20, - //+ sizeof(struct ip), - n - sizeof(struct myicmp) - //- sizeof(struct ip) - - 20); + if (n == -1) { + report_plugin_error(pl, PLUGIN_ERROR_RECEIVE); + return; + } + if (memcmp(&dst_addr, &from, dst_addr_len) != 0) { + goto pkt_not_for_us; + } + + if (n < 20 + sizeof(struct my_icmp_hdr)) { + warnx("plugin_icmp: plugin_receive: received data too short " + "to contain IP and ICMP headers\n"); + } else { + /* skip the IP header */ + packetp += 20; + n -= 20; + + /* skip the icmp header */ + //icmp = (struct my_icmp_header*)packetp; + icmp = (void*)packetp; + packetp += sizeof(struct my_icmp_hdr); + n -= sizeof(struct my_icmp_hdr); + + /* check values in the ICMP header */ + if (//(ntohs(icmp->id) == id ) && + icmp->type == ((data->server)? + ICMP_ECHO : ICMP_ECHOREPLY)) + process_data_from_plugin(pl, packetp, n); + // else // pkt not for us, send back an echo reply + // goto pkt_not_for_us; + + /* use the reply to send data */ + if (queued_data != NULL) { + send_icmp_pkt(pl, ntohs(icmp->id), ntohs(icmp->seq), + queued_data, queued_data_len); + free(queued_data); + queued_data = NULL; + queued_data_len = 0; + report_plugin_error(pl, PLUGIN_ERROR_PKT_SENT); + } else if (!data->server) { /* client */ + /* client should send back an empty request + * to give the server a chance to send data back + */ + if (seq == 65535) + seq = 0; + else + seq++; + send_icmp_pkt(pl, id, seq, NULL, 0); } - fprintf(stderr, "plugin_receive: recv return 0\n"); - } else { - fprintf(stderr, "discarding data from a different client\n"); } + return; + + pkt_not_for_us: + fprintf(stderr, "discarding data from a different client\n"); } - //return 0; +} + +int +plugin_is_ready_to_send() +{ + if (queued_data == NULL) + return 1; + else + return 0; } -int plugin_send(plugint *pl, char *data, int len) { +int +plugin_send(plugint *pl, char *data, int len) +{ plugin_icmp_datat *datapl = (plugin_icmp_datat*) pl->data; int n = 0; - char* packet; - struct myicmp *icmp; if (datapl->state != PLUGIN_STATE_CONNECTED) { fprintf(stderr, "no client connected yet, discarding data\n"); - return 0; - } else { - packet = malloc(sizeof(struct myicmp) + len); - if (!packet) { - fprintf(stderr, "plugin_send: out of memory\n"); - return -1; + return PLUGIN_SEND_ERROR; + } + + if (datapl->server) { /* server */ + if (queued_data == NULL) { + queued_data = malloc(len); + if (queued_data == NULL) { + return PLUGIN_SEND_ERROR_MALLOC; + } + memcpy(queued_data, data, len); + queued_data_len = len; + return PLUGIN_SEND_PKT_QUEUED; + } else { + return PLUGIN_SEND_ERROR_QUEUE_FULL; } - memset (packet, 0, sizeof(struct myicmp) + len); - memcpy (packet+sizeof(struct myicmp), data, len); - - icmp = (struct myicmp*)(packet); -/* if (datapl->server) { */ -/* icmp->type = ICMP_ECHOREPLY; */ -/* } else { */ -/* icmp->type = ICMP_ECHO; */ -/* } */ - //icmp->type = ICMP_ECHO; - icmp->type = 123; - - icmp->code = 0; - icmp->id = ID; - icmp->seq = 0; - icmp->cksum = 0; - icmp->cksum = in_cksum((u_int16_t*)packet, sizeof(struct myicmp) + len); - - n = sendto(datapl->fd, (char*)packet, sizeof(struct myicmp) + len, 0, - (struct sockaddr*)&dst_addr, dst_addr_len); - //(struct sockaddr*)dst, sizeof (struct sockaddr_in)); - fprintf(stderr, "plugin_send: send returned %d\n", n); + } else { /* client */ + n = send_icmp_pkt(pl, id, seq, data, len); + seq++; + fprintf(stderr, "send_icmp_pkt: send returned %d\n", n); + if (n > 0) + return PLUGIN_SEND_PKT_SENT; + else + return PLUGIN_SEND_ERROR; } - return n; } ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_tcp.c#6 (text+ko) ==== @@ -190,9 +190,10 @@ int plugin_register(plugint* pl) { pl->name = "tcp"; - pl->need_frag = 0; + pl->mtu = 1450; pl->initialize = plugin_initialize; pl->deinitialize = plugin_deinitialize; + pl->is_ready_to_send = plugin_is_ready_to_send; pl->send = plugin_send; pl->receive = plugin_receive; pl->next = NULL; @@ -315,6 +316,12 @@ } } +int +plugin_is_ready_to_send() +{ + return 1; +} + /* * BUG: the write might not send the whole buffer in one go, should check * and call again, but then the receiver would have to reassemble packets @@ -338,5 +345,6 @@ if (n < 0 || (len != 0 && n == 0) ) { report_plugin_error(pl, PLUGIN_ERROR_RECEIVE); } - return n; + //return n; + return PLUGIN_SEND_PKT_SENT; } ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/plugin_udp.c#5 (text+ko) ==== @@ -129,9 +129,10 @@ int plugin_register(plugint* pl) { pl->name = "udp"; - pl->need_frag = 1; + pl->mtu = 1450; pl->initialize = plugin_initialize; pl->deinitialize = plugin_deinitialize; + pl->is_ready_to_send = plugin_is_ready_to_send; pl->send = plugin_send; pl->receive = plugin_receive; pl->next = NULL; @@ -246,6 +247,12 @@ //return 0; } +int +plugin_is_ready_to_send() +{ + return 1; +} + int plugin_send(plugint *pl, char *data, int len) { plugin_udp_datat *datapl = (plugin_udp_datat*) pl->data; int n = 0; @@ -256,5 +263,5 @@ n = send(datapl->fd, data, len, 0); fprintf(stderr, "plugin_send: send returned %d\n", n); } - return n; + return PLUGIN_SEND_PKT_SENT; } ==== //depot/projects/soc2007/mharvan-mtund/mtund.src/tunneld.c#13 (text+ko) ==== @@ -10,34 +10,37 @@ * > VTun - Virtual Tunnel over TCP/IP network. */ -//#include "driver.h" -#include -#include -#include -#include - -//#include #include -#include #include #include #include +#include +#include +#include +#include +#include +#include #include #include "tun_dev.h" - #include "tunneld.h" -// linux only -#include -#include +// Linux only +//#include +//#include #define min(a,b) ( (a>b) ? b : a ) +/* + * Pass data received from the tun interface to the daemon. + */ +static int process_data_from_tun(char *data, int len); + + /* max transfered unit - encapsulated packet size */ -//const int mtu = 1400; #define MTU 1500 /* how many pings can fail before the plugin is declared broken */ +#define PING_INTERVAL 20 #define PING_FAIL 3 int server = 0; /* are we a server or a client? */ @@ -55,6 +58,7 @@ uint echo_seq = 0; /* fragment id for the next packet to be fragmented */ +frag_hdr_t frag_hdr; uint frag_id = 0; // TODO: randomize /* fragmentat reassembly info list */ @@ -132,28 +136,37 @@ return system(cmd); } -/* tun functions - this could be turned into a plugin as well */ - -void tun_receive(int fd, short ev_type, void *arg) { +/* read data from the tun interface and pass it to the daemon */ +static void +tun_receive() +{ char packet[PACKETLEN]; - int result = 0; + int nread = 0; + int nwrite = 0; + + printf("tun_receive()\n"); + if (current_pl == NULL) + return; - /* data available on tunnel device */ - memset(packet, 0, sizeof(packet)); - result = tun_read(tun_fd, packet, PACKETLEN); - - if (!result) { - //return 0; - } else if (result==-1) { - perror ("read"); - //return -1; - } - //fprintf(stderr, "data on tun interface\n"); - process_data_from_tun(packet, result); - //return result; + do { + /* only read from the tun device of the plugin is ready to send data */ + if (current_pl->is_ready_to_send() != 0) { + memset(packet, 0, sizeof(packet)); + nread = tun_read(tun_fd, packet, PACKETLEN); + if (nread > 0) { + nwrite = process_data_from_tun(packet, nread); + } + } + /* continue the loop if we read something + * and the plugin has sent it immediately + */ + printf("tun_receive: nread: %d, nwrite: %d\n", nread, nwrite); + } while (nread > 0 && nwrite == PLUGIN_SEND_PKT_SENT); } -int tun_send(char *data, int len) { +/* send data via the tun interface */ +static int +tun_send(char *data, int len) { int n; n = tun_write(tun_fd, data, len); /* @@ -166,13 +179,22 @@ return n; } +/* handler function for events on the tun device - called by libevent */ +static void +tun_ev_handler(int fd, short ev_type, void *arg) +{ + printf("tun_ev_handler(): ev_type: 0x%x\n", ev_type); + tun_receive(); +} + /* * BUGS: if dlclose() is called, I get a segfault when trying to use * the loaded functions. Maybe I'm not passing the right flags to * dlopen()? Well, RTLD_NODELETE seems to help here, at least on * linux. */ -int load_plugin(char *path) { +static int +load_plugin(char *path) { plugint *pl; int (*plugin_register)(plugint*); void *handle; @@ -198,7 +220,7 @@ //dlclose(handle); - /* add plugin to the list of laoded plugins */ + /* add plugin to the list of loaded plugins */ pl->next = plugins; plugins = pl; @@ -213,7 +235,12 @@ return 2; } -void send_echo_request() +/* + * Send a tunnel probe - echo request. Note that this is different + * from ICMP echo. + */ +static void +send_echo_request() { char data[10]; plugint *pl = current_pl; @@ -225,7 +252,9 @@ } } -void timer_ev_handler(int fd, short ev_type, void *arg) +/* handler function for the libevent timer event */ +static void +timer_ev_handler(int fd, short ev_type, void *arg) { struct timeval tv; struct frag_info *np, *np_temp; @@ -245,19 +274,19 @@ /* fragment reassembly timeout */ if (gettimeofday(&tv, NULL) != 0) { errx(EX_OSERR, "gettimeofday() failed"); - //TODO: maybe fail - } - LIST_FOREACH_SAFE(np, &frag_info_list, frag_infos, np_temp) { - if (tv.tv_sec - np->tv_sec > FRAG_TIMEOUT) { - LIST_REMOVE(np, frag_infos); - free(np->bitmap); - free(np->buf); - free(np); + } else { + LIST_FOREACH_SAFE(np, &frag_info_list, frag_infos, np_temp) { + if (tv.tv_sec - np->tv_sec > FRAG_TIMEOUT) { + LIST_REMOVE(np, frag_infos); + free(np->bitmap); + free(np->buf); + free(np); + } } } /* register a timer event again */ - tv.tv_sec=1; + tv.tv_sec=PING_INTERVAL; tv.tv_usec=0; evtimer_set(&timer_ev, timer_ev_handler, NULL); evtimer_add(&timer_ev, &tv); @@ -266,7 +295,8 @@ /* * Pass data received by the plugin to the daemon. */ -void process_data_from_plugin(plugint *pl, char *data, int len) +void +process_data_from_plugin(plugint *pl, char *data, int len) { u_int8_t dispatch = *data; frag_hdr_t *frag_hdr = NULL; @@ -340,7 +370,6 @@ /* collect information about the fragments */ if (gettimeofday(&tv, NULL) != 0) { errx(EX_OSERR, "gettimeofday() failed"); - //TODO: maybe fail } p->id = frag_hdr->id; p->size = frag_hdr->size; @@ -408,117 +437,124 @@ /* * Pass data received from the tun interface to the daemon. */ -void process_data_from_tun(char *data, int len) +static int +process_data_from_tun(char *data, int len) { int n = 0; char ldata[MTU+1]; char *ldatap = ldata; - frag_hdr_t frag_hdr; - int mtu = 100; // TODO: add mtu to plugint if (current_pl == NULL) { fprintf(stderr, "no plugin connected yet, discarding tun data\n"); report_plugin_error(NULL, PLUGIN_ERROR_BOOTSTRAP); - return; + return PLUGIN_SEND_ERROR; } /* no need to add the fragmentation header */ - if (! current_pl->need_frag) { + printf("process_data_from_tun: len: %d, current_pl->mtu: %d\n", + len, current_pl->mtu); + if (len < current_pl->mtu || 1) { *ldata = DISPATCH_DATA; memcpy(ldata+1, data, min(sizeof(ldata)-1, len)); - n = current_pl->send(current_pl, ldata, min(sizeof(ldata), len+1)); - - if (n < min(sizeof(ldata), len+1)) { - fprintf(stderr, "process_data_from_tun: plugind sent less " - "bytes (%d) than requested (%d)\n", n, len); - } + return current_pl->send(current_pl, ldata, min(sizeof(ldata), len+1)); + /* add the fragmentation header */ } else { - // mtu = current_pl->mtu; - - /* prepare the frag header */ - frag_hdr.dispatch = DISPATCH_FRAG; - frag_hdr.id = frag_id; - frag_id++; - frag_hdr.size = len; - frag_hdr.offset = 0; - - /* copy the payload */ - memcpy(ldatap + sizeof(frag_hdr), data, - min(sizeof(ldata) - sizeof(frag_hdr), len)); - len += sizeof(frag_hdr); + /* prepare the frag header */ + frag_hdr.dispatch = DISPATCH_FRAG; + frag_hdr.id = frag_id; + frag_id++; + frag_hdr.size = len; + frag_hdr.offset = 0; + + /* copy the payload */ + memcpy(ldatap + sizeof(frag_hdr), data, + min(sizeof(ldata) - sizeof(frag_hdr), len)); + len += sizeof(frag_hdr); + + while(len > sizeof(frag_hdr)) { + printf("process_data_from_tun: sending frag " + "offset %d, send_len %d, len %d\n", + frag_hdr.offset, min(current_pl->mtu, len), len); + /* prepend the frag dispatch and header before the payload */ + memcpy(ldatap, &frag_hdr, sizeof(frag_hdr)); - while(len > sizeof(frag_hdr)) { - printf("process_data_from_tun: sending frag " - "offset %d, send_len %d, len %d\n", - frag_hdr.offset, min(mtu, len), len); - /* prepend the frag dispatch and header before the payload */ - memcpy(ldatap, &frag_hdr, sizeof(frag_hdr)); - - /* send it */ - //TODO: change the logic here, we should not fragment based - // on the return value from send() - n = min(mtu, len); - (void) current_pl->send(current_pl, ldatap, min(mtu, len)); - n -= sizeof(frag_hdr); - if (n <= 0) { - fprintf(stderr, "process_data_from_tun: failed to send" - "data (%d)\n", n); - report_plugin_error(current_pl, PLUGIN_ERROR_SEND); - return; - } - ldatap += n; - frag_hdr.offset += n; - len -= n; + /* send it */ + //TODO: change the logic here, we should not fragment based + // on the return value from send() + n = min(current_pl->mtu, len); + (void) current_pl->send(current_pl, ldatap, + min(current_pl->mtu, len)); + n -= sizeof(frag_hdr); + if (n <= 0) { + fprintf(stderr, "process_data_from_tun: failed to send " + "data (%d)\n", n); + report_plugin_error(current_pl, PLUGIN_ERROR_SEND); + return PLUGIN_SEND_ERROR; } + ldatap += n; + frag_hdr.offset += n; + len -= n; + } + return PLUGIN_SEND_PKT_SENT; } } -void report_plugin_error(plugint *pl, int err) +void +report_plugin_error(plugint *pl, int err) { - if (err == PLUGIN_ERROR_SUCCESS) { + switch (err) { + case PLUGIN_ERROR_SUCCESS: + return; + case PLUGIN_ERROR_PKT_SENT: + /* plugin is ready to send the next packet */ + tun_receive(); return; - } - - /* server */ - if (server) { - if (pl) { - /* reinitialize the broken plugin */ - fprintf(stderr, "plugin %s failed, reinitializing...\n", pl->name); - // TODO: pl->reinitialize(pl); + default: /* errors */ + /* server */ + if (server) { + if (pl) { + /* reinitialize the broken plugin */ + fprintf(stderr, "plugin %s failed, reinitializing...\n", + pl->name); + // TODO: pl->reinitialize(pl); //pl->deinitialize(pl); //(void) pl->initialize(pl, server, host, 1234); - } - /* client */ - } else { - if (pl) { - /* deinitialize the broken plugin */ - fprintf(stderr, "plugin failed: %s\n", pl->name); - pl->deinitialize(pl); - - /* move to next plugin */ - pl = pl->next; - } - - /* scan - find a working plugin */ - //for (pl=plugins; pl; pl = pl->next) { - if (!pl) pl=plugins; - for (; pl; pl = pl->next) { - /* try to initialize plugin */ - //if (((pl->initialize)(server, host, port)) == 0) { - fprintf(stderr, "initalizing plugin: %s...\n", pl->name); - if (((pl->initialize)(pl, server, host, pl->name+4)) == 0) { - fprintf(stderr, "found a working plugin: %s\n", pl->name); - current_pl = pl; - return; - } else { - fprintf(stderr, "plugin %s failed to initialize\n", pl->name); + } + /* client */ + } else { + if (pl) { + /* deinitialize the broken plugin */ + fprintf(stderr, "plugin failed: %s\n", pl->name); + pl->deinitialize(pl); + + /* move to next plugin */ + pl = pl->next; + } + + /* scan - find a working plugin */ + //for (pl=plugins; pl; pl = pl->next) { + if (!pl) pl=plugins; + for (; pl; pl = pl->next) { + /* try to initialize plugin */ + //if (((pl->initialize)(server, host, port)) == 0) { + fprintf(stderr, "initalizing plugin: %s...\n", pl->name); + if (((pl->initialize)(pl, server, host, pl->name+4)) == 0) { + fprintf(stderr, "found a working plugin: %s\n", pl->name); + current_pl = pl; + return; + } else { + fprintf(stderr, "plugin %s failed to initialize\n", + pl->name); + } } } } } -void cleanup() +/* garbage collection before exiting */ +void +cleanup() { plugint *pl; struct frag_info *p; @@ -547,20 +583,25 @@ exit(0); } -void sigcb(int sig) +/* signal handler */ +void +sigcb(int sig) { cleanup(); } -void usage() { +void +usage() { fprintf(stderr, "usage:\n"); fprintf(stderr, "server: tunneld -s -p port\n"); fprintf(stderr, "client: tunneld -c -p port host\n"); } -int main(int argc, char **argv) { +int +main(int argc, char **argv) { plugint *pl; char opt; + int tun_flags; /* argument parsing */ while((opt=getopt(argc, argv, "scp:")) != EOF) { @@ -607,14 +648,17 @@ printf("Could not create tunnel device\n"); return 1; } - /* Initalize one event */ - event_set(&tun_ev, tun_fd, EV_PERSIST | EV_READ, tun_receive, NULL); - /* Add it to the active events, without a timeout */ + /* non-blocking i/o */ + tun_flags = fcntl(tun_fd, F_GETFL, 0); + if (tun_flags == -1) + errx(EX_OSFILE, "Failed to get flags from the tun device\n"); + fcntl(tun_fd, F_SETFL, tun_flags|O_NONBLOCK); + /* watch the tun device with libevent */ + event_set(&tun_ev, tun_fd, EV_PERSIST | EV_READ, tun_ev_handler, NULL); event_add(&tun_ev, NULL); >>> TRUNCATED FOR MAIL (1000 lines) <<<