0
|
1 /* Copyright 2014 Ivo Smits <Ivo@UCIS.nl>. All rights reserved. |
|
2 Redistribution and use in source and binary forms, with or without modification, are |
|
3 permitted provided that the following conditions are met: |
|
4 |
|
5 1. Redistributions of source code must retain the above copyright notice, this list of |
|
6 conditions and the following disclaimer. |
|
7 |
|
8 2. Redistributions in binary form must reproduce the above copyright notice, this list |
|
9 of conditions and the following disclaimer in the documentation and/or other materials |
|
10 provided with the distribution. |
|
11 |
|
12 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
|
13 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
|
14 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR |
|
15 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
16 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
17 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
|
18 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
19 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
20 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
21 |
|
22 The views and conclusions contained in the software and documentation are those of the |
|
23 authors and should not be interpreted as representing official policies, either expressed |
|
24 or implied, of Ivo Smits.*/ |
|
25 |
|
26 #include <stdio.h> |
|
27 #include <stdbool.h> |
|
28 #include <stdlib.h> |
|
29 #include <unistd.h> |
|
30 #include <sys/types.h> |
|
31 #include <sys/uio.h> |
|
32 #include <string.h> |
|
33 #include <fcntl.h> |
|
34 #include <sys/ioctl.h> |
|
35 #include <net/if.h> |
|
36 #ifdef linux |
|
37 #include <linux/if_tun.h> |
|
38 #include <linux/if_ether.h> |
|
39 #else |
|
40 #define ETH_FRAME_LEN 1514 |
|
41 #include <net/if_tun.h> |
|
42 #ifdef SOLARIS |
|
43 #include <sys/stropts.h> |
|
44 #include <sys/sockio.h> |
|
45 #endif |
|
46 #endif |
|
47 #include "include.h" |
|
48 |
|
49 static unsigned char readbuffer[2000]; |
|
50 |
|
51 bool tunnel_write_data(tunnel_context* context, unsigned char* buffer, int len) { |
|
52 if (context->fake_pi) { |
|
53 if (len == 0) return true; |
|
54 int ipver = (*buffer >> 4) & 0xf; |
|
55 int pihdr = 0; |
|
56 #if defined linux |
|
57 if (ipver == 4) pihdr = 0x0000 | (0x0008 << 16); //little endian: flags and protocol are swapped |
|
58 else if (ipver == 6) pihdr = 0x0000 | (0xdd86 << 16); |
|
59 #else |
|
60 if (ipver == 4) pihdr = htonl(AF_INET); |
|
61 else if (ipver == 6) pihdr = htonl(AF_INET6); |
|
62 #endif |
|
63 struct iovec iov[2]; |
|
64 iov[0].iov_base = &pihdr; |
|
65 iov[0].iov_len = sizeof(pihdr); |
|
66 iov[1].iov_base = buffer; |
|
67 iov[1].iov_len = len; |
|
68 writev(context->fd, iov, 2); |
|
69 } else { |
|
70 write(context->fd, buffer, len); |
|
71 } |
|
72 return true; |
|
73 } |
|
74 |
|
75 bool tunnel_read(tunnel_context* context) { |
|
76 int len = read(context->fd, readbuffer, sizeof(readbuffer)); |
|
77 if (len < 0) return errorexitp("read failure on tap device"); |
|
78 if (!context->connection) return true; |
|
79 if (context->fake_pi) { |
|
80 if (len < 4) return errorexit("short packet received from tap device"); |
|
81 connection_write_data(context->connection, readbuffer + 4, len - 4); |
|
82 } else { |
|
83 connection_write_data(context->connection, readbuffer, len); |
|
84 } |
|
85 return true; |
|
86 } |
|
87 |
|
88 bool tunnel_init(tunnel_context* context) { |
|
89 memset(context, 0, sizeof(tunnel_context)); |
|
90 char* envval; |
|
91 fprintf(stderr, "Initializing tun/tap device...\n"); |
|
92 int ttfd; //Tap device file descriptor |
|
93 int tunmode = 0; |
|
94 if ((envval = getconf("TUN_MODE"))) tunmode = atoi(envval); |
|
95 #if defined(__linux__) |
|
96 struct ifreq ifr; //required for tun/tap setup |
|
97 memset(&ifr, 0, sizeof(ifr)); |
|
98 if ((ttfd = open("/dev/net/tun", O_RDWR)) < 0) return errorexitp("Could not open tun/tap device file"); |
|
99 if ((envval = getconf("INTERFACE"))) strcpy(ifr.ifr_name, envval); |
|
100 ifr.ifr_flags = tunmode ? IFF_TUN : IFF_TAP; |
|
101 ifr.ifr_flags |= IFF_NO_PI; |
|
102 if (ioctl(ttfd, TUNSETIFF, (void *)&ifr) < 0) return errorexitp("TUNSETIFF ioctl failed"); |
|
103 #elif defined SOLARIS |
|
104 int ip_fd = -1, if_fd = -1, ppa = 0; |
|
105 if ((ttfd = open("/dev/tun", O_RDWR)) < 0) return errorexitp("Could not open tun device file"); |
|
106 if ((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) return errorexitp("Could not open /dev/ip"); |
|
107 if ((envval = getconf("INTERFACE"))) { |
|
108 while (*envval && !isdigit((int)*envval)) envval++; |
|
109 ppa = atoi(envval); |
|
110 } |
|
111 if ((ppa = ioctl(ttfd, TUNNEWPPA, ppa)) < 0) return errorexitp("Could not assign new PPA"); |
|
112 if ((if_fd = open("/dev/tun", O_RDWR, 0)) < 0) return errorexitp("Could not open tun device file again"); |
|
113 if (ioctl(if_fd, I_PUSH, "ip") < 0) return errorexitp("Could not push IP module"); |
|
114 if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) return errorexitp("Could not set PPA"); |
|
115 if (ioctl(ip_fd, I_LINK, if_fd) < 0) return errorexitp("Could not link TUN device to IP"); |
|
116 #else |
|
117 if (!(envval = getconf("INTERFACE"))) envval = "/dev/tun0"; |
|
118 if ((ttfd = open(envval, O_RDWR)) < 0) return errorexitp("Could not open tun device file"); |
|
119 if (tunmode) { |
|
120 int i = IFF_POINTOPOINT | IFF_MULTICAST; |
|
121 ioctl(ttfd, TUNSIFMODE, &i); |
|
122 #if defined(__OpenBSD__) |
|
123 context->fake_pi = true; |
|
124 #else |
|
125 i = 1; |
|
126 ioctl(ttfd, TUNSIFHEAD, &i); |
|
127 #endif |
|
128 } |
|
129 #endif |
|
130 if ((envval = getconf("TUN_UP_SCRIPT"))) system(envval); |
|
131 context->fd = ttfd; |
|
132 return true; |
|
133 } |
|
134 |