Home | History | Annotate | Download | only in linux
      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 
     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 
     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 
    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 
    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