VPN Tunneling Lab - ananthan05/Networking-Fundamentals-IP- GitHub Wiki
2 Task 1: Network Setup We need at least three VMs:
Testing
- VPN client can communicate with VPN Server
- VPN Server can communicate with Host V
VPN Server and Host V must be statically configured
Host V
VPN Server
- Host U should not be able to communicate with Host V
Task 2: Create and Configure TUN Interface
3.1 Task 2.a: Name of the Interface
After changing tun as the prefix of the interface as my name
3.2 Task 2.b: Set up the TUN Interface
After running the two commands,run the "ip address" command again we can notice that ip address are assigned
Task 2.c: Read from the TUN Interface
Task 2.d: Write to the TUN Interface
Yes,this packet is an ICMP echo request packet
Task 3: Send the IP Packet to VPN Server Through a Tunnel
After modifing the code
Task 4: Set Up the VPN Server
-
Please modify tun_server.py, so it can do the following:
-
Create a TUN interface and configure it.
#!/usr/bin/python3
import fcntl
import struct
import os
from scapy.all import *
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
# The IP address is set so that it is on the same subnet
# This is not the IP address that is set on the tun_client
TUN_IP = "192.168.53.98"
# Create the tun interface
tun = os.open("/dev/net/tun", os.O_RDWR)
# The tun interface name should match the name set on the tun_client
ifr = struct.pack('16sH', b'Ananthan%d', IFF_TUN | IFF_NO_PI)
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr)
# Get the interface name
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00")
print("Interface Name: {}".format(ifname))
# Set up the tun interface
os.system("ip addr add {}/24 dev {}".format(TUN_IP, ifname))
os.system("ip link set dev {} up".format(ifname))
IP_A = "0.0.0.0"
PORT = 9090
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((IP_A, PORT))
while True:
data, (ip, port) = sock.recvfrom(2048)
print("{}:{} --> {}:{}".format(ip, port, IP_A, PORT))
pkt = IP(data)
print("Inside: {} --> {}".format(pkt.src, pkt.dst))
-
Get the data from the socket interface; treat the received data as an IP packet.
-
Write the packet to the TUN interface
#!/usr/bin/python3
import fcntl
import struct
import os
from scapy.all import *
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
# The IP address is set so that it is on the same subnet
# This is not the IP address that is set on the tun_client
TUN_IP = "192.168.53.98"
# Create the tun interface
tun = os.open("/dev/net/tun", os.O_RDWR)
# The tun interface name should match the name set on the tun_client
ifr = struct.pack('16sH', b'uk%d', IFF_TUN | IFF_NO_PI)
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr)
# Get the interface name
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00")
print("Interface Name: {}".format(ifname))
# Set up the tun interface
os.system("ip addr add {}/24 dev {}".format(TUN_IP, ifname))
os.system("ip link set dev {} up".format(ifname))
IP_A = "0.0.0.0"
PORT = 9090
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# bind the socket to the specified port
sock.bind((IP_A, PORT))
while True:
data, (ip, port) = sock.recvfrom(2048)
print("{}:{} --> {}:{}".format(ip, port, IP_A, PORT))
# treat the received data as an IP packet
pkt = IP(data)
os.write(tun, bytes(pkt))
Before running the modified tun server.py, we need to enable the IP forwarding. Unless specifically configured, a computer will only act as a host, not as a gateway. 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:
Testing: If everything is set up properly, we can ping Host V from Host U. The ICMP echo request packets should eventually arrive at Host V through the tunnel. Please show your proof. It should be noted that although Host V will respond to the ICMP packets, the reply will not get back to Host U, because we have not set up everything yet. Therefore, for this task, it is sufficient to show (using Wireshark) that the ICMP packets have arrived at Host V. On the VPN Server, the code is run with sudo ./tun_server.py
On the Host U,
in one Terminal, sudo ./tun_client.py is run
in another Terminal, sudo ip route add 192.168.60.0/24 dev uk0 via 192.168.53.99 is run
On the Host V,
Wireshark packet capture is started
in a Terminal, ping 192.168.60.101 command is run
The packet capture is observed as shown in below screenshot.
Task 5: Handling Traffic in Both Directions
- On the Host V, the default gateway needs to be set using the below command.
server.py
#!/usr/bin/python3
import fcntl
import struct
import os
import socket
import subprocess
import select
from scapy.all import *
# Enable IP forwarding
subprocess.run(["sudo", "sysctl", "net.ipv4.ip_forward=1"])
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_NO_PI = 0x1000
TUN_IP = "192.168.53.98" # IP address of the TUN interface on the server
SERVER_IP = "10.0.2.4" # VPN Server's IP on NAT Network
PORT = 9090
# Create the TUN interface
tun = os.open("/dev/net/tun", os.O_RDWR)
ifr = struct.pack('16sH', b'Ananthan%d', IFF_TUN | IFF_NO_PI)
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr)
# Get the interface name
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00")
print("Interface Name: {}".format(ifname))
# Set up the TUN interface with an IP address
os.system("ip addr add {}/24 dev {}".format(TUN_IP, ifname))
# Enable the TUN interface
os.system("ip link set dev {} up".format(ifname))
# Create a UDP socket to receive data from the VPN Client
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((SERVER_IP, PORT))
ip = "10.0.2.15" # NAT Network IP for VPN Client
while True:
# This will block until at least one interface is ready
ready, _, _ = select.select([sock, tun], [], [])
for fd in ready:
if fd is sock:
data, (ip, port) = sock.recvfrom(2048)
pkt = IP(data)
print("From socket <==: {} --> {}".format(pkt.src, pkt.dst))
os.write(tun, data)
if fd is tun:
packet = os.read(tun, 2048)
pkt = IP(packet)
print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
sock.sendto(packet, (ip, port))
client code
#!/usr/bin/python3
import fcntl
import struct
import os
import time
import socket
import select
from scapy.all import *
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
# Create the tun interface
tun = os.open("/dev/net/tun", os.O_RDWR)
ifr = struct.pack('16sH', b'suz%d', IFF_TUN | IFF_NO_PI)
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr)
# Get the interface name
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00")
print("Interface Name: {}".format(ifname))
# Configure the network interface
os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))
# Add a route for the 192.168.60.0/24 network through the tun interface
os.system("ip route add 192.168.60.0/24 dev {}".format(ifname))
# Function to check if a packet is an ICMP echo request
def check_icmp_req(bytes_in):
pkt_in = IP(bytes_in)
if ICMP in pkt_in and pkt_in[ICMP].type == 8:
return True
return False
# Define the server's IP address and port
SERVER_IP = "10.0.2.4" # Replace with the actual server IP address
SERVER_PORT = 9090 # Replace with the actual server port number
# Create a UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
try:
# This will block until at least one interface is ready
ready, _, _ = select.select([sock, tun], [], [])
for fd in ready:
if fd is sock:
data, (ip, port) = sock.recvfrom(2048)
pkt = IP(data)
print("From socket <==: {} --> {}".format(pkt.src, pkt.dst))
os.write(tun, bytes(pkt))
if fd is tun:
packet = os.read(tun, 2048)
pkt = IP(packet)
print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
sock.sendto(packet, (SERVER_IP, SERVER_PORT))
except Exception as e:
print(f"Error processing packet: {e}")
time.sleep(1) # Adjust the sleep time as needed
Testing: Once this is done, we should be able to communicate with Machine V from Machine U, and the VPN tunnel (un-encrypted) is now complete. Please show your wireshark proof using about ping and telnet commands. In your proof, you need to point out how your packets flow
To proof that the VPN tunnel works and trace the sequence of events, a single ping can be done from Host U to Host V with ping 192.168.60.101 as seen below
Wireshark Packet capture is started on Host V
ping 192.168.60.101 command is run on Host U
A similar process can be observed with telnet as well. Host U can telnet to Host V using telnet 192.168.60.101 as shown below.
As ping and telnet from Host U to Host V can be performed successfully, it can be seen that the VPN tunnel is complete and enables Host U to communicate with Host V and vice versa.