Task 1: Network Setup
dcup启动docker后测试不同网络主机
hostA ping不通client,client ping 不通hostA
hostA与client都可与server相互ping通
Task 2: Create and Confifigure TUN Interface
Task 2.a: Name of the Interface
docker cp tun.py e9://tmp/ 复制文件进入client
python3 tun.py 启动接口
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))
自动调节路由
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))
######################
可以看到成功收到了返回包
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的包连接到接口,从接口读出包发给服务器
从上面可以看到,从客户端发往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是添加路由,机器到哪个网段的包走哪个网卡归它管
这里在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
注意配置一下路由
互通实现
Task6: Tunnel-Breaking Experiment
断开client或server后,telnet将无法再键入字符,但是当重启client与server后,键入字符将全部打印在屏幕上。
连接不会因为VPN程序断开而断开,这里是超时导致的断开
Task 7: Routing Experiment on Host V
Task 8: VPN Between Private Networks
网络搭建及测试
docker-compose -f docker-compose2.yml build
docker-compose -f docker-compose2.yml up
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
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