Task 1: Network Setup

dcup启动docker后测试不同网络主机

hostA ping不通client,client ping 不通hostA

hostA与client都可与server相互ping通

image-20220725105805463

image-20220725110358517

Task 2: Create and Confifigure TUN Interface

Task 2.a: Name of the Interface

docker cp tun.py e9://tmp/ 复制文件进入client

python3 tun.py 启动接口

image-20220725111537979

Task 2.b: Set up the TUN Interface

加入

os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

自动调节路由

image-20220725112741272

Task 2.c: Read from the TUN Interface

加入

while True:
# Get a packet from the tun interface
    packet = os.read(tun, 2048)
    if packet:
        ip = IP(packet)
        print(ip.summary())

在client中运行tun.py

ping 192.168.53.60时

IP / ICMP 192.168.53.99 > 192.168.53.60 echo-request 0 / Raw

ping 192.168.60.60时则不会抓到包相关信息

原因配置了路由,发往网络192.168.53.0/24的包会发给tun0接口从而被接收到,而发往192.168.60.0/24不会被接收

Task 2.d: Write to the TUN Interface

完整程序

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

while True:
    packet = os.read(tun, 2048)
    if packet:
        pkt=IP(packet)
        print(pkt.summary())
        #################### 将通过的包抓取后回复,构造响应echo应答报文
        if ICMP in pkt:
            newip=IP(src=pkt[IP].dst,dst=pkt[IP].src,ihl=pkt[IP].ihl)
            newip.ttl=99
            newicmp=ICMP(type=0,id=pkt[ICMP].id,seq=pkt[ICMP].seq)
            if pkt.haslayer(Raw):
                data=pkt[Raw].load
                newpkt=newip/newicmp/data
            else:
                newpkt = newip/newicmp
            
            os.write(tun, bytes(newpkt))
        ######################

image-20220725194821827

可以看到成功收到了返回包

Task 3: Send the IP Packet to VPN Server Through a Tunnel

#!/usr/bin/env python3

from scapy.all import *


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))

服务器程序,监听过本机9090端口的包并进行内容打印

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 192.168.60.0/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    packet = os.read(tun, 2048)
    if packet:
        sock.sendto(packet, ("10.9.0.11", 9090))

客户端程序,起接口,将发往192.168.60.0/24的包连接到接口,从接口读出包发给服务器

image-20220726104131680

从上面可以看到,从客户端发往192.168.60.0/24的包成功发送出去

Task 4: Set Up the VPN Server

经历了九九八十一难终于把这个task4做出来了!

tun_server

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
#配置网卡地址与路由
os.system("ip addr add 192.168.53.11/24 dev {}".format(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))
    #send(pkt)
    print(pkt.summary())
    os.write(tun,bytes(pkt))

tun_client

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
#配置网卡地址与路由
os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

os.system("ip route add 192.168.60.0/24 dev {}".format(ifname))

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    packet = os.read(tun, 2048)
    print(IP(packet).summary())
    if packet:
        sock.sendto(packet, ("10.9.0.11", 9090))

遇到的坑:

ip addr add与ip route add没分清
ip addr add是给网卡分配地址
ip route add是添加路由,机器到哪个网段的包走哪个网卡归它管

image-20220726233308861

这里在host 192.168.60.5上执行tcpdump -n 抓包

可以看到包确实是发到了host上且host也做出了回应

Task 5: Handling Traffific in Both Directions

完善回来的通道,使相互可以ping通

tun_client_server.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

os.system("ip route add 192.168.60.0/24 dev {}".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:
    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))
            print(pkt.summary())
            os.write(tun,bytes(pkt))
        
    for fd in ready:
        if fd is tun:
            packet = os.read(tun, 2048)
            pkt=IP(packet)
            print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
            if packet:
                sock.sendto(packet, ("10.9.0.11", 9090))

tun_server_select.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 192.168.53.11/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

os.system("ip route add 10.9.0.0/24 dev {}".format(ifname))

IP_A = "0.0.0.0"
PORT = 9090
ip_C=""
portC=0
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((IP_A, PORT))

while True:
    ready, _, _ = select.select([sock, tun], [], [])
    for fd in ready:
        if fd is sock:
            data, (ip, port) = sock.recvfrom(2048)
            ip_C=ip
            portC=port
            print("{}:{} --> {}:{}".format(ip, port, IP_A, PORT))
            pkt = IP(data)
            print(" Inside: {} --> {}".format(pkt.src, pkt.dst))
            os.write(tun,bytes(pkt))
            
    for fd in ready:
        if fd is tun:
            packet = os.read(tun, 2048)
            pkt=IP(packet)
            print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
            if packet:
                sock.sendto(packet, (ip_C, portC))
            

两边都做成select式的,分别监听tun和sock

注意配置一下路由

image-20220727102934094

互通实现

Task6: Tunnel-Breaking Experiment

断开client或server后,telnet将无法再键入字符,但是当重启client与server后,键入字符将全部打印在屏幕上。

image-20220727105428768

连接不会因为VPN程序断开而断开,这里是超时导致的断开

Task 7: Routing Experiment on Host V

image-20220727110647661

Task 8: VPN Between Private Networks

网络搭建及测试

docker-compose -f docker-compose2.yml build
docker-compose -f docker-compose2.yml up

image-20220727114006748

50与60两个网络相互ping不通

tun_client_select2.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 10.9.0.12/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

os.system("ip route add 192.168.60.0/24 dev {}".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:
    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))
            print(pkt.summary())
            os.write(tun,bytes(pkt))
        
    for fd in ready:
        if fd is tun:
            packet = os.read(tun, 2048)
            pkt=IP(packet)
            print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
            if packet:
                sock.sendto(packet, ("10.9.0.11", 9090))

tun_server_select2.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
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'tun%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))
os.system("ip addr add 10.9.0.11/24 dev {}".format(ifname))
os.system("ip link set dev {} up".format(ifname))

os.system("ip route add 192.168.50.0/24 dev {}".format(ifname))

IP_A = "0.0.0.0"
PORT = 9090
ip_C=""
portC=0
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((IP_A, PORT))

while True:
    ready, _, _ = select.select([sock, tun], [], [])
    for fd in ready:
        if fd is sock:
            data, (ip, port) = sock.recvfrom(2048)
            ip_C=ip
            portC=port
            print("{}:{} --> {}:{}".format(ip, port, IP_A, PORT))
            pkt = IP(data)
            print(" Inside: {} --> {}".format(pkt.src, pkt.dst))
            os.write(tun,bytes(pkt))
            
    for fd in ready:
        if fd is tun:
            packet = os.read(tun, 2048)
            pkt=IP(packet)
            print("From tun ==>: {} --> {}".format(pkt.src, pkt.dst))
            if packet:
                sock.sendto(packet, ("10.9.0.12", 9090))
            

在客户端路由器192.168.50.12上运行tun_client_select2.py,虚拟网卡设置在10.9.0.12

在服务器路由器192.168.60.11上运行tun_server_select2.py,虚拟网卡设置在10.9.0.11

VPN服务器客户端设置完毕,开始检验

通过wireshark的抓包可以看到,期间的通讯确实通过了VPN tunnel

image-20220727114641145

Task 9: Experiment with the TAP Interface

在任意一台client运行以下代码

tap2.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import time
from scapy.all import *


TUNSETIFF = 0x400454ca
IFF_TUN   = 0x0001
IFF_TAP   = 0x0002
IFF_NO_PI = 0x1000

# Create the tun interface
tap = os.open("/dev/net/tun", os.O_RDWR)
ifr = struct.pack('16sH', b'tap%d', IFF_TAP | IFF_NO_PI)
ifname_bytes  = fcntl.ioctl(tap, TUNSETIFF, ifr)

# Get the interface name
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00")
print("Interface Name: {}".format(ifname))
#os.system("ip addr add 10.9.0.12/24 dev {}".format(ifname))
#os.system("ip link set dev {} up".format(ifname))

os.system("ip addr add 192.168.53.99/24 dev {}".format(ifname))
os.system("ip route add 192.168.60.0/24 dev {}".format(ifname))

os.system("ip link set dev {} up".format(ifname))
br='br0'
os.system("ip link add name {} type bridge".format(br))
os.system("ip link set {} master {}".format("eth1",br))
os.system("ip link set {} master {}".format(ifname,br))
os.system("ip link set dev {} up".format(br))

while True:
    packet = os.read(tap, 2048)
    if packet:
        print("--------------------------------")
        ether = Ether(packet)
        print(ether.summary())
        # Send a spoofed ARP response
        FAKE_MAC = "aa:bb:cc:dd:ee:ff"
    if ARP in ether and ether[ARP].op == 1 :
        arp = ether[ARP]
        newether = Ether(dst=ether.src, src=FAKE_MAC)
        newarp = ARP(psrc=arp.pdst, hwsrc=FAKE_MAC,
        pdst=arp.psrc, hwdst=ether.src, op=2)
        newpkt = newether/newarp
        print("***** Fake response: {}".format(newpkt.summary()))
        os.write(tap, bytes(newpkt))

        

使用以下代码检验得

arping -I tap0 192.168.53.33

可以看到程序是给出了回显的,不过好像被判断出了Fake respose

image-20220727131747519

image-20220727132222923

发表评论