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(¶meters[offset + 1], parameter, length);
150 offset += 1 + length;
151 }
152
153 // Fill the rest of the space with spaces.
154 memset(¶meters[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