Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 5 Aug 2007 23:53:50 GMT
From:      Matus Harvan <mharvan@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 124758 for review
Message-ID:  <200708052353.l75NroZD079345@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -16,18 +25,14 @@
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
 
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <sysexits.h>
+
 #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<string.h>
-#include<stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-
-//#include <sys/select.h>
 #include <dlfcn.h>
-#include <signal.h>
 #include <sys/time.h>
 #include <event.h>
 #include <err.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
 #include <sysexits.h>
 
 #include "tun_dev.h"
-
 #include "tunneld.h"
 
-// linux only
-#include <stdarg.h>
-#include <sys/types.h>
+// Linux only
+//#include <stdarg.h>
+//#include <sys/types.h>
 
 #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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708052353.l75NroZD079345>