• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 
30 #ifdef __linux__
31 
32 // There are several ways to play with this program. Here we just give an
33 // example for the simplest scenario. Let us say that a Linux box has a
34 // public IPv4 address on eth0. Please try the following steps and adjust
35 // the parameters when necessary.
36 //
37 // # Enable IP forwarding
38 // echo 1 > /proc/sys/net/ipv4/ip_forward
39 //
40 // # Pick a range of private addresses and perform NAT over eth0.
41 // iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
42 //
43 // # Create a TUN interface.
44 // ip tuntap add dev tun0 mode tun
45 //
46 // # Set the addresses and bring up the interface.
47 // ifconfig tun0 10.0.0.1 dstaddr 10.0.0.2 up
48 //
49 // # Create a server on port 8000 with shared secret "test".
50 // ./ToyVpnServer tun0 8000 test -m 1400 -a 10.0.0.2 32 -d 8.8.8.8 -r 0.0.0.0 0
51 //
52 // This program only handles a session at a time. To allow multiple sessions,
53 // multiple servers can be created on the same port, but each of them requires
54 // its own TUN interface. A short shell script will be sufficient. Since this
55 // program is designed for demonstration purpose, it performs neither strong
56 // authentication nor encryption. DO NOT USE IT IN PRODUCTION!
57 
58 #include <net/if.h>
59 #include <linux/if_tun.h>
60 
get_interface(char * name)61 static int get_interface(char *name)
62 {
63     int interface = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
64 
65     ifreq ifr;
66     memset(&ifr, 0, sizeof(ifr));
67     ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
68     strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
69 
70     if (ioctl(interface, TUNSETIFF, &ifr)) {
71         perror("Cannot get TUN interface");
72         exit(1);
73     }
74 
75     return interface;
76 }
77 
78 #else
79 
80 #error Sorry, you have to implement this part by yourself.
81 
82 #endif
83 
get_tunnel(char * port,char * secret)84 static int get_tunnel(char *port, char *secret)
85 {
86     // We use an IPv6 socket to cover both IPv4 and IPv6.
87     int tunnel = socket(AF_INET6, SOCK_DGRAM, 0);
88     int flag = 1;
89     setsockopt(tunnel, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
90     flag = 0;
91     setsockopt(tunnel, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
92 
93     // Accept packets received on any local address.
94     sockaddr_in6 addr;
95     memset(&addr, 0, sizeof(addr));
96     addr.sin6_family = AF_INET6;
97     addr.sin6_port = htons(atoi(port));
98 
99     // Call bind(2) in a loop since Linux does not have SO_REUSEPORT.
100     while (bind(tunnel, (sockaddr *)&addr, sizeof(addr))) {
101         if (errno != EADDRINUSE) {
102             return -1;
103         }
104         usleep(100000);
105     }
106 
107     // Receive packets till the secret matches.
108     char packet[1024];
109     socklen_t addrlen;
110     do {
111         addrlen = sizeof(addr);
112         int n = recvfrom(tunnel, packet, sizeof(packet), 0,
113                 (sockaddr *)&addr, &addrlen);
114         if (n <= 0) {
115             return -1;
116         }
117         packet[n] = 0;
118     } while (packet[0] != 0 || strcmp(secret, &packet[1]));
119 
120     // Connect to the client as we only handle one client at a time.
121     connect(tunnel, (sockaddr *)&addr, addrlen);
122     return tunnel;
123 }
124 
build_parameters(char * parameters,int size,int argc,char ** argv)125 static void build_parameters(char *parameters, int size, int argc, char **argv)
126 {
127     // Well, for simplicity, we just concatenate them (almost) blindly.
128     int offset = 0;
129     for (int i = 4; i < argc; ++i) {
130         char *parameter = argv[i];
131         int length = strlen(parameter);
132         char delimiter = ',';
133 
134         // If it looks like an option, prepend a space instead of a comma.
135         if (length == 2 && parameter[0] == '-') {
136             ++parameter;
137             --length;
138             delimiter = ' ';
139         }
140 
141         // This is just a demo app, really.
142         if (offset + length >= size) {
143             puts("Parameters are too large");
144             exit(1);
145         }
146 
147         // Append the delimiter and the parameter.
148         parameters[offset] = delimiter;
149         memcpy(&parameters[offset + 1], parameter, length);
150         offset += 1 + length;
151     }
152 
153     // Fill the rest of the space with spaces.
154     memset(&parameters[offset], ' ', size - offset);
155 
156     // Control messages always start with zero.
157     parameters[0] = 0;
158 }
159 
160 //-----------------------------------------------------------------------------
161 
main(int argc,char ** argv)162 int main(int argc, char **argv)
163 {
164     if (argc < 5) {
165         printf("Usage: %s <tunN> <port> <secret> options...\n"
166                "\n"
167                "Options:\n"
168                "  -m <MTU> for the maximum transmission unit\n"
169                "  -a <address> <prefix-length> for the private address\n"
170                "  -r <address> <prefix-length> for the forwarding route\n"
171                "  -d <address> for the domain name server\n"
172                "  -s <domain> for the search domain\n"
173                "\n"
174                "Note that TUN interface needs to be configured properly\n"
175                "BEFORE running this program. For more information, please\n"
176                "read the comments in the source code.\n\n", argv[0]);
177         exit(1);
178     }
179 
180     // Parse the arguments and set the parameters.
181     char parameters[1024];
182     build_parameters(parameters, sizeof(parameters), argc, argv);
183 
184     // Get TUN interface.
185     int interface = get_interface(argv[1]);
186 
187     // Wait for a tunnel.
188     int tunnel;
189     while ((tunnel = get_tunnel(argv[2], argv[3])) != -1) {
190         printf("%s: Here comes a new tunnel\n", argv[1]);
191 
192         // On UN*X, there are many ways to deal with multiple file
193         // descriptors, such as poll(2), select(2), epoll(7) on Linux,
194         // kqueue(2) on FreeBSD, pthread(3), or even fork(2). Here we
195         // mimic everything from the client, so their source code can
196         // be easily compared side by side.
197 
198         // Put the tunnel into non-blocking mode.
199         fcntl(tunnel, F_SETFL, O_NONBLOCK);
200 
201         // Send the parameters several times in case of packet loss.
202         for (int i = 0; i < 3; ++i) {
203             send(tunnel, parameters, sizeof(parameters), MSG_NOSIGNAL);
204         }
205 
206         // Allocate the buffer for a single packet.
207         char packet[32767];
208 
209         // We use a timer to determine the status of the tunnel. It
210         // works on both sides. A positive value means sending, and
211         // any other means receiving. We start with receiving.
212         int timer = 0;
213 
214         // We keep forwarding packets till something goes wrong.
215         while (true) {
216             // Assume that we did not make any progress in this iteration.
217             bool idle = true;
218 
219             // Read the outgoing packet from the input stream.
220             int length = read(interface, packet, sizeof(packet));
221             if (length > 0) {
222                 // Write the outgoing packet to the tunnel.
223                 send(tunnel, packet, length, MSG_NOSIGNAL);
224 
225                 // There might be more outgoing packets.
226                 idle = false;
227 
228                 // If we were receiving, switch to sending.
229                 if (timer < 1) {
230                     timer = 1;
231                 }
232             }
233 
234             // Read the incoming packet from the tunnel.
235             length = recv(tunnel, packet, sizeof(packet), 0);
236             if (length == 0) {
237                 break;
238             }
239             if (length > 0) {
240                 // Ignore control messages, which start with zero.
241                 if (packet[0] != 0) {
242                     // Write the incoming packet to the output stream.
243                     write(interface, packet, length);
244                 }
245 
246                 // There might be more incoming packets.
247                 idle = false;
248 
249                 // If we were sending, switch to receiving.
250                 if (timer > 0) {
251                     timer = 0;
252                 }
253             }
254 
255             // If we are idle or waiting for the network, sleep for a
256             // fraction of time to avoid busy looping.
257             if (idle) {
258                 usleep(100000);
259 
260                 // Increase the timer. This is inaccurate but good enough,
261                 // since everything is operated in non-blocking mode.
262                 timer += (timer > 0) ? 100 : -100;
263 
264                 // We are receiving for a long time but not sending.
265                 // Can you figure out why we use a different value? :)
266                 if (timer < -16000) {
267                     // Send empty control messages.
268                     packet[0] = 0;
269                     for (int i = 0; i < 3; ++i) {
270                         send(tunnel, packet, 1, MSG_NOSIGNAL);
271                     }
272 
273                     // Switch to sending.
274                     timer = 1;
275                 }
276 
277                 // We are sending for a long time but not receiving.
278                 if (timer > 20000) {
279                     break;
280                 }
281             }
282         }
283         printf("%s: The tunnel is broken\n", argv[1]);
284         close(tunnel);
285     }
286     perror("Cannot create tunnels");
287     exit(1);
288 }
289