Mercurial > hg > quicktun-tcp
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; +} +