PERFORCE change 124758 for review
Matus Harvan
mharvan at FreeBSD.org
Sun Aug 5 16:53:51 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=124758
Change 124758 by mharvan at 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) <<<
More information about the p4-projects
mailing list