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
61static 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
84static 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
125static 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
162int 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