Neil Klingensmith 2013-09-14
naklingensmi at wisc dot edu
This pair of programs provides simple IP-in-TCP traffic tunneling, similar to OpenVPN. It uses the linux tun driver, which allows a program to generate packets instead of a network interface.
It is intended for use in resource-constrained systems for penetrating firewalls or NATs. Since the code is small and simple, it is easily-extendable.
To make the program work, you need to have one machine running a server and another running a client. Compile the server code using:
make srv
Compile the client using:
make cli
1.) Start the server (./srv). Note the IP address of its main network interface. For example, 192.168.0.1:
$ ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 21960292 bytes 3371943341 (3.1 GiB)
RX errors 0 dropped 8105 overruns 4 frame 4
TX packets 17367322 bytes 2135880048 (1.9 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2.) Start the client with the IP address of the the server:
./cli -s 192.168.0.1
The client will get an IP address from the server and configure its tun
interface and routes correctly. At present, all addresses on the VPN must
be in the form 10.0.0.0/16.
The server listens on port 2002 and accepts incoming connections from clients. The server maintains a list of associated clients. Each element in the list stores the client's IP address on the VPN as well as a file descriptor for the socket that it uses to communicate with that client.
When a new client associates to the VPN (by opening a connection with the server), the server makes a new list entry for the client and spawns a new thread to handle message passing to and from the client.
When a client thread receives a message from its associated client, it searches the list of associated clients, looking for one that has an IP address matching the destination IP of the packet. If it finds a match, it forwards the packet to that client. If no match is found, it passes the message to the local tun interface so it can be handled by linux.
IP addresses can be assigned automatically by the VPN using a custom protocol. DHCP cannot be used because it uses lower levels of the OSI stack to exchange messages, so it is not supported by the Linux TUN driver. Instead simplevpn implements a custom dynamic address assignment protocol.
Client and server can exchange special messages to configure IP addresses of new clients. There are two options for IP address assignment: static and dynamic. Static addresses are requested by the client, and the user can choose what IP address the client should request by passing an address in on the command line with the -s option. Dynamic addresses are used if the user does not request an IP address on the command line.
Assignment Protocol
When the client establishes a connection with the server, the first message it sends is an IP address request. This consists of an IP packet with no payload and a destination address of zero. A static address request will have the requested IP address in the source IP field. A dynamic address request has a source IP address field of zero. Currently, clients hardcode their netmasks to 255.255.0.0 when setting up the interface. This should be extended to allow the user to specify the netmask at the server, and the server to push netmask assignment to the client.
Once the client knows what IP address to use, it must set the interface up with that address. This is done using a series of ioctl() calls in a function called set_ip() and add_host_route().
Keepalive packets are used by clients to tell the server that they are still connected to the network. This is useful in environments where clients frequently go down because of network outages or other problems. If a client falls off of the network, it will stop sending keepalive packets, and the server will presume that it is safe to free resources that were previously allocted for that client (IP address, memory, etc.).
Keepalive packets only need to be sent from client to server if no other traffic has been sent for a long time. If traffic is being sent regularly, keepalive packets are not necessary.
Keepalive Packet Structure
Keepalive packets are IPv4 packets with source and destination IP addresses set to -1: src ip dest ip
.---^---. .---^---. |
---|
Encap IP Hdr |
------------------------------------------------------------------ |
Encap IP Hdr is the IP header of the encapsulating packet that is sent over the physical network interface.
The remainder of the packet (starting with 4514...) is the IP header of the keepalive packet. The only requirements for this header are that the source IP and destination IP addresses are both set to -1 (as in the diagram). All other fields can be anything (zero, garbage data, etc).
When the server receives this packet, it will respond by sending it back to the client unaltered.
Clients should do the following (in order):
0.) Open a TCP socket with the server on port 2002.
1.) Obtain an IP address from the server, statically or dynamically.
2.) Send keepalive packets if no other data is being sent.