11import threading
2- from scapy .all import Ether , IP , Raw
2+ from scapy .all import Ether , IP , ICMP , Raw
33
44from src .device import Device
55from src .manipulation import ManipulateArgs , ManipulateRet
1717def forward_d1_to_d3 (arg : ManipulateArgs ) -> ManipulateRet :
1818 '''
1919 Replace addresses of d2 with d4, so the packet will be hopped
20- to the second vlan
20+ to the second vlan.
2121 '''
2222 global GLOBAL_D3_MAC
2323 global GLOBAL_D4_MAC
2424 packet = Ether (arg .packet )
2525
26- if not (IP in packet and packet [IP ].dst == D2_ADDR and packet [IP ].src == D1_ADDR ):
27- return ManipulateRet (arg .packet , False )
28-
2926 packet [IP ].src = D4_ADDR
3027 packet [IP ].dst = D3_ADDR
3128
@@ -35,16 +32,19 @@ def forward_d1_to_d3(arg: ManipulateArgs) -> ManipulateRet:
3532 return ManipulateRet (Raw (packet ).load , False )
3633
3734
38- def test_vlan_hopping (switch ):
39- '''
35+ def test_vlan_hopping_and_punt_policies (switch ):
36+ """
4037 In this test, d1 is in vlan 20, and it'll try to connect
4138 to d3, which is part of vlan 10. The manipulation callback works follow:
4239 For each packet that its source is d1 and destined to d2,
4340 the callback will change the packet so it'll look like the source is d4,
4441 and it's destined to d3. The switch will think that the packet came from
4542 d4 who's part of vlan 10, so it'll forward the packet to d3 (who's also in vlan 10).
4643 That is an example of a VLAN hopping.
47- '''
44+
45+ This test also shows the behaviour of the "punt-policies":
46+ Only packets from d1 to d2 will be passed to the manipulation callback.
47+ """
4848 global GLOBAL_D3_MAC
4949 global GLOBAL_D4_MAC
5050
@@ -54,27 +54,37 @@ def test_vlan_hopping(switch):
5454 d3 = Device ('c' , D3_ADDR , '255.255.255.0' )
5555 d4 = Device ('d' , D4_ADDR , '255.255.255.0' )
5656
57- assert switch .connect_device_trunk (d1 , 20 )
58- assert switch .connect_device_access (d2 , 20 )
57+ switch .connect_device_trunk (d1 , 20 )
58+ switch .connect_device_access (d2 , 20 )
5959
60- assert switch .connect_device_trunk (d3 , 10 )
61- assert switch .connect_device_access (d4 , 10 )
60+ switch .connect_device_trunk (d3 , 10 )
61+ switch .connect_device_access (d4 , 10 )
6262
6363 GLOBAL_D3_MAC = d3 .get_mac
6464 GLOBAL_D4_MAC = d4 .get_mac
6565
66- switch .set_manipulation (forward_d1_to_d3 )
66+ # Setting the manipulation routine, and punt-policies
67+ switch .set_manipulation (forward_d1_to_d3 , 'src host {} && dst host {}' .format (
68+ D1_ADDR , D2_ADDR ))
6769
6870 def _run_listening_nc (dev ):
69- out = dev .run_from_namespace ('timeout 5s nc -lu 0.0.0.0 4444' )
71+ out = dev .run_from_namespace ('timeout 7s nc -lu 0.0.0.0 4444' )
7072 assert 'hello' == out
7173
74+ # d3 is going to listen
7275 t = threading .Thread (target = _run_listening_nc , args = (d3 , ))
7376 t .start ()
7477
75- out = d1 .run_from_namespace ('bash -c "echo hello | nc -u 192.168.250.2 4444 -w 3"' )
78+ # and d1 will connect to it
79+ out = d1 .run_from_namespace ('bash -c "echo hello | nc -u 192.168.250.2 4444 -w 5"' )
7680 assert '' == out
7781
82+ # Note that the manipulation callback modifies every packet that it recieves,
83+ # But it won't recieve this packet (and its reply) since they won't match the
84+ # bpf filter that we set before. That's why we expect an echo-reply.
85+ out = d3 .run_from_namespace ('ping -c 1 192.168.1.2' )
86+ assert '1 packets transmitted, 1 received' in out
87+
7888 switch .disconnect_device (d1 )
7989 switch .disconnect_device (d2 )
8090 switch .disconnect_device (d3 )
0 commit comments