diff tunnel.c @ 0:17cb7cdbb8be draft default tip

Working prototype
author Ivo Smits <Ivo@UCIS.nl>
date Fri, 07 Feb 2014 23:28:39 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tunnel.c	Fri Feb 07 23:28:39 2014 +0100
@@ -0,0 +1,134 @@
+/* Copyright 2014 Ivo Smits <Ivo@UCIS.nl>. All rights reserved.
+   Redistribution and use in source and binary forms, with or without modification, are
+   permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright notice, this list
+      of conditions and the following disclaimer in the documentation and/or other materials
+      provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   The views and conclusions contained in the software and documentation are those of the
+   authors and should not be interpreted as representing official policies, either expressed
+   or implied, of Ivo Smits.*/
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef linux
+	#include <linux/if_tun.h>
+	#include <linux/if_ether.h>
+#else
+	#define ETH_FRAME_LEN 1514
+	#include <net/if_tun.h>
+	#ifdef SOLARIS
+		#include <sys/stropts.h>
+		#include <sys/sockio.h>
+	#endif
+#endif
+#include "include.h"
+
+static unsigned char readbuffer[2000];
+
+bool tunnel_write_data(tunnel_context* context, unsigned char* buffer, int len) {
+	if (context->fake_pi) {
+		if (len == 0) return true;
+		int ipver = (*buffer >> 4) & 0xf;
+		int pihdr = 0;
+#if defined linux
+		if (ipver == 4) pihdr = 0x0000 | (0x0008 << 16); //little endian: flags and protocol are swapped
+		else if (ipver == 6) pihdr = 0x0000 | (0xdd86 << 16);
+#else
+		if (ipver == 4) pihdr = htonl(AF_INET);
+		else if (ipver == 6) pihdr = htonl(AF_INET6);
+#endif
+		struct iovec iov[2];
+		iov[0].iov_base = &pihdr;
+		iov[0].iov_len = sizeof(pihdr);
+		iov[1].iov_base = buffer;
+		iov[1].iov_len = len;
+		writev(context->fd, iov, 2);
+	} else {
+		write(context->fd, buffer, len);
+	}
+	return true;
+}
+
+bool tunnel_read(tunnel_context* context) {
+	int len = read(context->fd, readbuffer, sizeof(readbuffer));
+	if (len < 0) return errorexitp("read failure on tap device");
+	if (!context->connection) return true;
+	if (context->fake_pi) {
+		if (len < 4) return errorexit("short packet received from tap device");
+		connection_write_data(context->connection, readbuffer + 4, len - 4);
+	} else {
+		connection_write_data(context->connection, readbuffer, len);
+	}
+	return true;
+}
+
+bool tunnel_init(tunnel_context* context) {
+	memset(context, 0, sizeof(tunnel_context));
+	char* envval;
+	fprintf(stderr, "Initializing tun/tap device...\n");
+	int ttfd; //Tap device file descriptor
+	int tunmode = 0;
+	if ((envval = getconf("TUN_MODE"))) tunmode = atoi(envval);
+#if defined(__linux__)
+	struct ifreq ifr; //required for tun/tap setup
+	memset(&ifr, 0, sizeof(ifr));
+	if ((ttfd = open("/dev/net/tun", O_RDWR)) < 0) return errorexitp("Could not open tun/tap device file");
+	if ((envval = getconf("INTERFACE"))) strcpy(ifr.ifr_name, envval);
+	ifr.ifr_flags = tunmode ? IFF_TUN : IFF_TAP;
+	ifr.ifr_flags |= IFF_NO_PI;
+	if (ioctl(ttfd, TUNSETIFF, (void *)&ifr) < 0) return errorexitp("TUNSETIFF ioctl failed");
+#elif defined SOLARIS
+	int ip_fd = -1, if_fd = -1, ppa = 0;
+	if ((ttfd = open("/dev/tun", O_RDWR)) < 0) return errorexitp("Could not open tun device file");
+	if ((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) return errorexitp("Could not open /dev/ip");
+	if ((envval = getconf("INTERFACE"))) {
+		while (*envval && !isdigit((int)*envval)) envval++;
+		ppa = atoi(envval);
+	}
+	if ((ppa = ioctl(ttfd, TUNNEWPPA, ppa)) < 0) return errorexitp("Could not assign new PPA");
+	if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) return errorexitp("Could not open tun device file again");
+	if (ioctl(if_fd, I_PUSH, "ip") < 0) return errorexitp("Could not push IP module");
+	if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) return errorexitp("Could not set PPA");
+	if (ioctl(ip_fd, I_LINK, if_fd) < 0) return errorexitp("Could not link TUN device to IP");
+#else
+	if (!(envval = getconf("INTERFACE"))) envval = "/dev/tun0";
+	if ((ttfd = open(envval, O_RDWR)) < 0) return errorexitp("Could not open tun device file");
+	if (tunmode) {
+		int i = IFF_POINTOPOINT | IFF_MULTICAST;
+		ioctl(ttfd, TUNSIFMODE, &i);
+#if defined(__OpenBSD__)
+		context->fake_pi = true;
+#else
+		i = 1;
+		ioctl(ttfd, TUNSIFHEAD, &i);
+#endif
+	}
+#endif
+	if ((envval = getconf("TUN_UP_SCRIPT"))) system(envval);
+	context->fd = ttfd;
+	return true;
+}
+