Virtual Private Network (VPN) Lab
Virtual Private Network (VPN) Lab
Virtual Private Network (VPN) Lab
1 Overview
A Virtual Private Network (VPN) is used for creating a private scope of computer communications or pro-
viding a secure extension of a private network into an insecure network such as the Internet. VPN is a
widely used security technology. VPN can be built upon IPSec or TLS/SSL (Transport Layer Security/Se-
cure Socket Layer). These are two fundamentally different approaches for building VPNs. In this lab, we
focus on the TLS/SSL-based VPNs. This type of VPNs is often referred to as TLS/SSL VPNs.
The learning objective of this lab is for students to master the network and security technologies under-
lying VPNs. To achieve this goal, students will be asked to implement a simple TLS/SSL VPN. Although
this VPN is simple, it does include all the essential elements of a VPN. The design and implementation of
TLS/SSL VPNs exemplify a number of security principles, including the following:
Readings and videos. Detailed coverage of VPN, PKI, and TLS can be found in the following:
• Chapters 19, 24, and 25 of the SEED Book, Computer & Internet Security: A Hands-on Approach,
2nd Edition, by Wenliang Du. See details at https://www.handsonsecurity.net.
• Section 8 of the SEED Lecture, Internet Security: A Hands-on Approach, by Wenliang Du. See details
at https://www.handsonsecurity.net/video.html.
Related labs. We have a separate SEED lab on PKI, and another one on TLS. It is recommended that
students finish these two crypto labs before working on this comprehensive VPN lab. If students are only
interested in the tunneling part of the VPN (without the crypto part), they should use the VPN Tunneling
Lab, instead of this one.
Lab Environment. This lab has been tested on our pre-built Ubuntu 16.04 VM. We need to use the
opensslpackage in this lab. The package includes the header files, libraries, and commands. The package
was already installed in our pre-built VM image.
SEED Labs – VPN Lab 2
2 Lab Tasks
In this lab, students need to implement a simple VPN for Linux. We will call it miniVPN.
Gateway
VPN Client (VPN Server)
User `
192.168.60.1
192.168.60.101
Host V `
In practice, the VPN client and VPN server are connected via the Internet. For the sake of simplicity,
we directly connect these two machines to the same LAN in this lab, i.e., this LAN simulates the Internet.
We will use the “NAT Network” adaptor for this LAN. The third machine, Host V, is a computer inside the
private network. Users on Host U (outside of the private network) want to communicate with Host V via
the VPN tunnel. To simulate this setup, we connect Host V to VPN Server (also serving as a gateway) via
an “Internal Network”. In such a setup, Host V is not directly accessible from the Internet; nor is it directly
accessible from Host U.
Note if a VM uses the “Internal Network” mode, VirtualBox provides no DHCP to it, so the VM must
be statically configured. To do this, click the network icon on the top-right corner of the desktop, and select
"Edit Connections". You will see a list of "Wired connections", one for each of the network
adaptors used by the VM. For Host V, there is only one connection, but for VPN Server, we will see two.
To make sure that you pick the one that is corresponding to the “Internal Network” adapter, You can check
the MAC address displayed in the pop-up window after you have picked a connection to edit. Compare this
MAC address with the one that you get from ifconfig, and you will know whether you picked the right
connection.
After you have selected the right connection to edit, pick the "ipv4 Settings" tab and select the
"Manual" method, instead of the default "Automatic (DHCP)". Click the "Add" button to set up
the new IP address for the VM. See Figure 2 for details.
SEED Labs – VPN Lab 3
Figure 2: Manually set up the IP address for the "Internal Network" adaptor on VPN Server.
VPN VPN
Client Program Server Program
tun0 tun0
VPN VPN
Client VPN Tunnel (TCP or UDP) Server
VM ` VM
Step 1: Run VPN Server. We first run the VPN server program vpnserver on the Server VM. Af-
ter the program runs, a virtual TUN network interface will appear in the system (we can see it using the
"ifconfig -a" command; the name of the interface will be tun0 in most cases, but they can be tunX,
where X is a number). This new interface is not yet configured, so we need to configure it by giving it an IP
address. We use 192.168.53.1 for this interface.
Run the following commands. The first command will start the server program, and the second command
assigns an IP address to the tun0 interface and then activates it. It should be noted that the first command
will block and wait for connections, so we need to find another window run the second command.
$ sudo ./vpnserver
Unless specifically configured, a computer will only act as a host, not as a gateway. The VPN Server
needs to forward packets between the private network and the tunnel, so it needs to function as a gateway.
We need to enable the IP forwarding for a computer to behave like a gateway. IP forwarding can be enabled
using the following command:
$ sudo sysctl net.ipv4.ip_forward=1
Step 2: Run VPN Client. We now run the VPN client program on the Client VM. We run the follow-
ing command on this machine (the first command will connect to the VPN server program running on
10.0.2.8. This command will block as well, so we need to find another window to configure the tun0
interface created by the VPN client program. We assign IP address 192.168.53.5 to the tun0 interface.
On VPN Client VM:
$ sudo ./vpnclient 10.0.2.8
Step 3: Set Up Routing on Client and Server VMs: After the above two steps, the tunnel will be
established. Before we can use the tunnel, we need to set up routing paths on both client and server machines
to direct the intended traffic through the tunnel. On the client machine, we need to direct all the packets going
to the private network (192.168.60.0/24) towards the tun0 interface, from where the packets can be
forwarded through the VPN tunnel. Without this setup, we will not be able to access the private network at
all. We can use the route command to add an routing entry. The following example shows how to route
the 10.20.30.0/24-bound packets to the interface eth0.
$ sudo route add -net 10.20.30.0/24 eth0
On both client and server machines, we also need to set up a routing entry so all the traffic going to the
192.168.53.0/24 network are directed to the tun0 interface. This entry will usually be automatically
added when we assign 192.169.53.X to the tun0 interface. If for some reasons it is not added, we can
use the route command to add it.
Step 4: Set Up Routing on Host V. When Host V replies to a packet sent from Host U, it needs to route
the packets to the VPN Server VM, from where, it can be fed into the VPN tunnel toward the other end.
You need to find out what entry to add, and then use the route command to add the routing entry. Hint:
when Host V receives a packet from Host U (via the tunnel), you need to know what the source IP is in the
packet; in the reply packet, the source IP becomes the destination IP, which will be used by the routing table.
Therefore, you need to figure out the source IP of the packets from U to V. It is your task to figure this out
and set the routing correctly in this step.
Step 5: Test the VPN Tunnel: After everything is set up, we can access Host V from Host U via the
tunnel. Please conduct the following tests using ping and telnet; please report your results. You should
use Wireshark to capture the network traffics on all the interfaces on the client VM, and pinpoint which
packets are part of the tunnel traffic, and which packets are not the tunnel traffic.
On Host U:
$ ping 192.168.60.101
$ telnet 192.168.60.101
Step 6: Tunnel-Breaking Test. On Host U, telnet to Host V. While keeping the telnet connection
alive, we break the VPN tunnel. We then type something in the telnet window, and report what you
observe. We then reconnect the VPN tunnel. What is going to happen to the telnet connection? Will it
be broken or resumed? Please describe and explain your observations.
and tlsserver) is provided in a zip file that can be downloaded from the website. Instructions on how to
compile and run the code is provided in the README file included in the zip file. For detailed explanation
of the sample code, please read Chapter 25 of the SEED book (Computer & Internet Security: A Hands-on
Approach, 2nd Edition). In your demonstration, you need to use Wireshark to capture the traffic inside the
VPN tunnel, and show that the traffic is indeed encrypted.
Note: Our MiniVPN program should be able to communicate with VPN servers on different machines,
so you cannot hardcode the hostname of the VPN server in the program. The hostname needs to be typed in
from the command line. This name represents the user’s intention, so it should be used in the verification.
This name should also be used to find the IP address of the server. Section 3.2 provides a sample program
to show you how to get the IP address for a given hostname.
Our sample TLS client and server programs. Server authentication is implemented in the sample pro-
grams provided by us. Part of the authentication requires the certificate of the CA who issues the server
certificate. We have put two CA certificates in the ./ca client folder: one is the CA that issues our
server’s certificate (the hostname of the server is vpnlabserver.com), and the other is the CA that is-
sues Google’s certificate. Therefore, the sample TLS client program can talk to our own server, as well as
Google’s HTTPS server:
$ ./tlsclient vpnlabserver.com 4433
$ ./tlsclient www.google.com 443
It should be noted that students should not use vpnlabserver.com from the sample code as their
VPN server name; instead, they should include their last name in the server name. Students should gen-
SEED Labs – VPN Lab 7
erate their own CA in order to create server certificates. The objective of this requirement is to differentiate
student’s work.
To use our client to talk to an HTTPS server, we need to get its CA’s certificate, save the certificate in
the ./ca client folder, and create a symbolic link to it (or rename it) using the hash value generated
from its subject field. For example, to enable our client to talk to Google, who gets its certificate from a root
CA called “GeoTrust Global CA”, we get this root CA’s certificate (GeoTrustGlobalCA.pem) from the
Firefox browser, and run the following command to get its hash and then set up the symbolic link:
$ openssl x509 -in GeoTrustGlobalCA.pem -noout -subject_hash
2c543cd1
$ ln -s GeoTrustGlobalCA.pem 2c543cd1.0
$ ls -l
lrwxrwxrwx 1 ... 2c543cd1.0 -> GeoTrustGlobalCA.pem
lrwxrwxrwx 1 ... 9b58639a.0 -> cacert.pem
-rw-r--r-- 1 ... cacert.pem
-rw-r--r-- 1 ... GeoTrustGlobalCA.pem
Parent Process
Tunnel 1 Process 1
Client 1
`
Tunnel 2 Process 2
Client 2 Which Packets
`
tun0
way?
Tunnel 3 Process 3
Client 3
`
3 Guidelines
3.1 Displaying TLS Traffic in Wireshark
Wireshark identifies TLS/SSL traffic based on port numbers. It knows 443 is the default port number for
HTTPS, but our VPN server listens to a different and non-standard port number. We need to let Wireshark
know that; otherwise, Wireshark will not label our traffic as SSL/TLS traffic. Here is what we can do:
go to the Edit menu in Wireshark, and click Preferences, Protocols, HTTP, and then find the
"SSL/TLS Ports" entry. Add your SSL server port. For example, we can change the content of the
entry to 443,4433, where 4433 is the port used by our SSL server.
Displaying decrypted traffic. The approach shown above only gets Wireshark to recognize the traffic as
TLS/SSL traffic; Wireshark cannot decrypt the encrypted traffic. For debugging purposes, we would like
to see the decrypted traffic. Wireshark provides such a feature; all we need to do is to provide the server’s
private key to Wireshark, and Wireshark will automatically derive the session keys from the TLS/SSL hand-
shake protocol, and use these keys to decrypt traffic. To provide the server’s private key to Wireshark, do
the following:
Click Edit -> Preferences -> Protocols -> SSL
Find the "RSA key list", and click the Edit button
Provide the required information about the server, see this example:
IP Address: 10.0.2.65
Port: 4433
Protocol: ssl
Key File: /home/seed/vpn/server-key.pem (privat key file)
Password: deesdees
SEED Labs – VPN Lab 9
int main() {
// The result may contain a list of IP address; we take the first one.
struct sockaddr_in* ip = (struct sockaddr_in *) result->ai_addr;
printf("IP Address: %s\n", (char *)inet_ntoa(ip->sin_addr));
freeaddrinfo(result);
return 0;
}
pw = getspnam(user);
if (pw == NULL) {
return -1;
}
return 1;
}
We can compile the code above and run it with a user name and a password. It should be noted that the
root privilege is needed when reading from the shadow file. See the following commands for compilation
and execution.
$ gcc login.c -lcrypt
$ sudo ./a.out seed dees
It should be noted that we use -lcrypt in the above compilation; we used -lcrypto when compiling
our TLS programs. The crypt and crypto are two different libraries, so this is not a typo.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int fd[2], nbytes;
pid_t pid;
char string[] = "Hello, world!\n";
char readbuffer[80];
pipe(fd); À
which will block the process until data are available on one of the file descriptors in the set. We can then use
the FD ISSET macro to figure out which file descriptor has received data. In the following code example,
we use select() to monitor a TUN and a socket file descriptor.
fd_set readFDSet;
int ret, sockfd, tunfd;
FD_ZERO(&readFDSet);
FD_SET(sockfd, &readFDSet); À
FD_SET(tunfd, &readFDSet); Á
ret = select(FD_SETSIZE, &readFDSet, NULL, NULL, NULL); Â
if (FD_ISSET(sockfd, &readFDSet){
// Read data from sockfd, and do something.
}
if (FD_ISSET(tunfd, &readFDSet){
// Read data from tunfd, and do something.
}
7. The packet will now flow through the Internet, with the original telnet packet being entirely en-
crypted, and carried in the payload of the packet. This is why it is called a tunnel.
8. The packet will reach our gateway 128.230.208.97 through its interface eth1.
9. The kernel will give the UDP payload (i.e. the encrypted IP packet) to the VPN program (Point B),
which is waiting for UDP data. This is through the UDP port.
10. The VPN program will decrypt the payload, and then feed the decrypted payload, which is the original
telnet packet, back to the kernel through the virtual network interface tun0.
11. Since it comes through a network interface, the kernel will treat it as an IP packet (it is indeed an IP
packet), look at its destination IP address, and decide where to route it. Remember, the destination IP
address of this packet is 10.0.20.100. If your routing table is set up correctly, the packet should
be routed through eth2, because this is the interface that connects to the 10.0.20.0/24 network.
12. The telnet packet will now be delivered to its final destination 10.0.20.100.
• The total time of the demo will be 15 minutes, no more additional time would be given. So prepare
your demonstration so you can cover the important features.
• You are entirely responsible for showing the demo. We will NOT even touch the keyboard during
the demonstration; so you should not depend on us to test your system. If you fail to demo some
important features of your system, we will assume that your system does not have those features.
• You need to practice before you come to the demonstration. If the system crashes or anything goes
wrong, it is your own fault. We will not debug your problems, nor give you extra time for it.
• During the demo, you should consider yourself as salesmen, and you want to sell your system to us.
You are given 15 minutes to show us how good your system is. So think about your sales strategies.
If you have implemented a great system, but fail to show us how good it is, you are not likely to get a
good grade.
• Do turn off the messages your system prints out for debugging purposes. Those messages should not
appear in a demonstration.
How packets flow from client to server when running “telnet 10.0.20.100” using a VPN
10.0.4.1 10.0.5.1
TCP Port UDP Port UDP Port
tun0 tun0
New IP New IP
IP
UDP UDP IP
TCP Routing
IP IP TCP Routing
Data
TCP TCP Data
Data Data
Kernel Kernel
209.164.131.32 eth1 128.230.208.97 eth1 eth2
Internet
(a) An Example of packet flow from telnet client to server in Host-to-Gateway Tunnel
How packets return from server to client when running “telnet 10.0.20.100” using a VPN
10.0.4.1 10.0.5.1
TCP Port UDP Port UDP Port
tun0 tun0
New IP New IP
IP
UDP UDP IP
TCP
IP IP Routing TCP
Data TCP TCP Data
Data Data
Kernel Kernel
209.164.131.32 eth1 128.230.208.97 eth1 eth2
Internet
(b) An Example of packet flow from telnet server to client in Host-to-Gateway Tunnel
Requirements Details
Initial State • Rebooting all three VMs. Start recording after the VMs are rebooted. You should
start demo immediately after rebooting. If you wait too long, you will have to do
the rebooting again.
• Type "last reboot; date" in a terminal to show the rebooting time and cur-
rent time on all three VMs. The difference between these two times should not be
more than 5 minute.
Pre-Tunnel Test • Before VPN is set up, ping Host V from Host U and explain your observation.
– You need to type passwords to authenticate yourself to the server, the password
should not be visible (10 points will be deducted if we see your passwords).
You can use getpass() to achieve that (type “man getpass” to see its
manual).
– Passwords cannot be hardcoded in your program. If you do this, 50 points will
be deducted.
• Perform configuration on all VMs. Although you can put the configuration com-
mands in a script, you do need to show the script and explain the commands in your
script.
Tunnel-Breaking • On Host U, telnet to Host V. While keeping the telnet connection alive, break the
Test VPN tunnel by stopping the vpn client and/or vpn server programs. Then type
something in the telnet window. Do you see what you type? What happens to the
TCP connection? Is the connection broken?
• Let us now reconnect the VPN tunnel (do not wait for too long). Run the client and
server programs again, and conduct the necessary configuration (no need to explain
or show commands). Once the tunnel is re-established, what is going to happen to
the telnet connection? Please describe and explain your observation.
Large Packet Test • Send a large packet (size > 3000) from Host U to Host V. You can use "ping -s"
to do that.
TLS Setup • Show us how you set up your TLS on both client and server sides.
• Show us where you place the server certificates and self-signed certificate.
MITM Test • Demonstrate that your system can successfully defeat MITM attacks. You need
to set up a simulated MITM attack, and demonstrate that your client program can
defeat it.
Code Explanation 1 Which lines of code are responsible for the following:
• verifying that the server certificate is valid
Code Explanation 2 Which line of code in the client forces TLS handshake to stop if the server certificate
verification fails?
Code Explanation 3 Which line(s) of code do the following?
• sending username and password to the server
Ending Time Type "last reboot; date" commands to display the time before ending your
demo.