| /* | |
| * Copyright (C) 2011 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <arpa/inet.h> | |
| #include <netinet/in.h> | |
| #include <sys/ioctl.h> | |
| #include <sys/socket.h> | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #ifdef __linux__ | |
| // There are several ways to play with this program. Here we just give an | |
| // example for the simplest scenario. Let us say that a Linux box has a | |
| // public IPv4 address on eth0. Please try the following steps and adjust | |
| // the parameters when necessary. | |
| // | |
| // # Enable IP forwarding | |
| // echo 1 > /proc/sys/net/ipv4/ip_forward | |
| // | |
| // # Pick a range of private addresses and perform NAT over eth0. | |
| // iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE | |
| // | |
| // # Create a TUN interface. | |
| // ip tuntap add dev tun0 mode tun | |
| // | |
| // # Set the addresses and bring up the interface. | |
| // ifconfig tun0 10.0.0.1 dstaddr 10.0.0.2 up | |
| // | |
| // # Create a server on port 8000 with shared secret "test". | |
| // ./ToyVpnServer tun0 8000 test -m 1400 -a 10.0.0.2 32 -d 8.8.8.8 -r 0.0.0.0 0 | |
| // | |
| // This program only handles a session at a time. To allow multiple sessions, | |
| // multiple servers can be created on the same port, but each of them requires | |
| // its own TUN interface. A short shell script will be sufficient. Since this | |
| // program is designed for demonstration purpose, it performs neither strong | |
| // authentication nor encryption. DO NOT USE IT IN PRODUCTION! | |
| #include <net/if.h> | |
| #include <linux/if_tun.h> | |
| static int get_interface(char *name) | |
| { | |
| int interface = open("/dev/net/tun", O_RDWR | O_NONBLOCK); | |
| ifreq ifr; | |
| memset(&ifr, 0, sizeof(ifr)); | |
| ifr.ifr_flags = IFF_TUN | IFF_NO_PI; | |
| strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |
| if (ioctl(interface, TUNSETIFF, &ifr)) { | |
| perror("Cannot get TUN interface"); | |
| exit(1); | |
| } | |
| return interface; | |
| } | |
| #else | |
| #error Sorry, you have to implement this part by yourself. | |
| #endif | |
| static int get_tunnel(char *port, char *secret) | |
| { | |
| // We use an IPv6 socket to cover both IPv4 and IPv6. | |
| int tunnel = socket(AF_INET6, SOCK_DGRAM, 0); | |
| int flag = 1; | |
| setsockopt(tunnel, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); | |
| flag = 0; | |
| setsockopt(tunnel, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)); | |
| // Accept packets received on any local address. | |
| sockaddr_in6 addr; | |
| memset(&addr, 0, sizeof(addr)); | |
| addr.sin6_family = AF_INET6; | |
| addr.sin6_port = htons(atoi(port)); | |
| // Call bind(2) in a loop since Linux does not have SO_REUSEPORT. | |
| while (bind(tunnel, (sockaddr *)&addr, sizeof(addr))) { | |
| if (errno != EADDRINUSE) { | |
| return -1; | |
| } | |
| usleep(100000); | |
| } | |
| // Receive packets till the secret matches. | |
| char packet[1024]; | |
| socklen_t addrlen; | |
| do { | |
| addrlen = sizeof(addr); | |
| int n = recvfrom(tunnel, packet, sizeof(packet), 0, | |
| (sockaddr *)&addr, &addrlen); | |
| if (n <= 0) { | |
| return -1; | |
| } | |
| packet[n] = 0; | |
| } while (packet[0] != 0 || strcmp(secret, &packet[1])); | |
| // Connect to the client as we only handle one client at a time. | |
| connect(tunnel, (sockaddr *)&addr, addrlen); | |
| return tunnel; | |
| } | |
| static void build_parameters(char *parameters, int size, int argc, char **argv) | |
| { | |
| // Well, for simplicity, we just concatenate them (almost) blindly. | |
| int offset = 0; | |
| for (int i = 4; i < argc; ++i) { | |
| char *parameter = argv[i]; | |
| int length = strlen(parameter); | |
| char delimiter = ','; | |
| // If it looks like an option, prepend a space instead of a comma. | |
| if (length == 2 && parameter[0] == '-') { | |
| ++parameter; | |
| --length; | |
| delimiter = ' '; | |
| } | |
| // This is just a demo app, really. | |
| if (offset + length >= size) { | |
| puts("Parameters are too large"); | |
| exit(1); | |
| } | |
| // Append the delimiter and the parameter. | |
| parameters[offset] = delimiter; | |
| memcpy(¶meters[offset + 1], parameter, length); | |
| offset += 1 + length; | |
| } | |
| // Fill the rest of the space with spaces. | |
| memset(¶meters[offset], ' ', size - offset); | |
| // Control messages always start with zero. | |
| parameters[0] = 0; | |
| } | |
| //----------------------------------------------------------------------------- | |
| int main(int argc, char **argv) | |
| { | |
| if (argc < 5) { | |
| printf("Usage: %s <tunN> <port> <secret> options...\n" | |
| "\n" | |
| "Options:\n" | |
| " -m <MTU> for the maximum transmission unit\n" | |
| " -a <address> <prefix-length> for the private address\n" | |
| " -r <address> <prefix-length> for the forwarding route\n" | |
| " -d <address> for the domain name server\n" | |
| " -s <domain> for the search domain\n" | |
| "\n" | |
| "Note that TUN interface needs to be configured properly\n" | |
| "BEFORE running this program. For more information, please\n" | |
| "read the comments in the source code.\n\n", argv[0]); | |
| exit(1); | |
| } | |
| // Parse the arguments and set the parameters. | |
| char parameters[1024]; | |
| build_parameters(parameters, sizeof(parameters), argc, argv); | |
| // Get TUN interface. | |
| int interface = get_interface(argv[1]); | |
| // Wait for a tunnel. | |
| int tunnel; | |
| while ((tunnel = get_tunnel(argv[2], argv[3])) != -1) { | |
| printf("%s: Here comes a new tunnel\n", argv[1]); | |
| // On UN*X, there are many ways to deal with multiple file | |
| // descriptors, such as poll(2), select(2), epoll(7) on Linux, | |
| // kqueue(2) on FreeBSD, pthread(3), or even fork(2). Here we | |
| // mimic everything from the client, so their source code can | |
| // be easily compared side by side. | |
| // Put the tunnel into non-blocking mode. | |
| fcntl(tunnel, F_SETFL, O_NONBLOCK); | |
| // Send the parameters several times in case of packet loss. | |
| for (int i = 0; i < 3; ++i) { | |
| send(tunnel, parameters, sizeof(parameters), MSG_NOSIGNAL); | |
| } | |
| // Allocate the buffer for a single packet. | |
| char packet[32767]; | |
| // We use a timer to determine the status of the tunnel. It | |
| // works on both sides. A positive value means sending, and | |
| // any other means receiving. We start with receiving. | |
| int timer = 0; | |
| // We keep forwarding packets till something goes wrong. | |
| while (true) { | |
| // Assume that we did not make any progress in this iteration. | |
| bool idle = true; | |
| // Read the outgoing packet from the input stream. | |
| int length = read(interface, packet, sizeof(packet)); | |
| if (length > 0) { | |
| // Write the outgoing packet to the tunnel. | |
| send(tunnel, packet, length, MSG_NOSIGNAL); | |
| // There might be more outgoing packets. | |
| idle = false; | |
| // If we were receiving, switch to sending. | |
| if (timer < 1) { | |
| timer = 1; | |
| } | |
| } | |
| // Read the incoming packet from the tunnel. | |
| length = recv(tunnel, packet, sizeof(packet), 0); | |
| if (length == 0) { | |
| break; | |
| } | |
| if (length > 0) { | |
| // Ignore control messages, which start with zero. | |
| if (packet[0] != 0) { | |
| // Write the incoming packet to the output stream. | |
| write(interface, packet, length); | |
| } | |
| // There might be more incoming packets. | |
| idle = false; | |
| // If we were sending, switch to receiving. | |
| if (timer > 0) { | |
| timer = 0; | |
| } | |
| } | |
| // If we are idle or waiting for the network, sleep for a | |
| // fraction of time to avoid busy looping. | |
| if (idle) { | |
| usleep(100000); | |
| // Increase the timer. This is inaccurate but good enough, | |
| // since everything is operated in non-blocking mode. | |
| timer += (timer > 0) ? 100 : -100; | |
| // We are receiving for a long time but not sending. | |
| // Can you figure out why we use a different value? :) | |
| if (timer < -16000) { | |
| // Send empty control messages. | |
| packet[0] = 0; | |
| for (int i = 0; i < 3; ++i) { | |
| send(tunnel, packet, 1, MSG_NOSIGNAL); | |
| } | |
| // Switch to sending. | |
| timer = 1; | |
| } | |
| // We are sending for a long time but not receiving. | |
| if (timer > 20000) { | |
| break; | |
| } | |
| } | |
| } | |
| printf("%s: The tunnel is broken\n", argv[1]); | |
| close(tunnel); | |
| } | |
| perror("Cannot create tunnels"); | |
| exit(1); | |
| } |