def test_dst_mac_masking(): """ Title: Test destination MAC masking in chain rules Scenario 1: When: There's a rule dropping any traffic with the multicast bit on Then: Multicast traffic is blocked and unicast traffic goes through Scenario 2: When: There's a rule dropping any traffic with the multicast bit off Then: Multicast traffic goes through and unicast traffic is blocked """ bridge = VTM.get_bridge('bridge-000-001') if1 = BM.get_iface_for_port('bridge-000-001', 1) if2 = BM.get_iface_for_port('bridge-000-001', 2) if1_hw_addr = if1.get_mac_addr() # interface['hw_addr'] if2_hw_addr = if2.get_mac_addr() # interface['hw_addr'] if2_ip_addr = if2.get_ip() rcv_filter = 'udp and ether src %s' % if1_hw_addr bridge.set_inbound_filter(VTM.get_chain('drop_multicast')) # Send a frame to an arbitrary multicast address. Bridge doesn't # recognize it and will try to flood it to the other port, but the # masked MAC rule should drop it since it has the multicast bit set. f1 = async_assert_that(if2, should_NOT_receive(rcv_filter, within_sec(10))) f2 = if1.send_udp("01:23:45:67:89:ab", if2_ip_addr) wait_on_futures([f1, f2]) # If2's actual MAC address should work, since it doesn't have the bit set. f1 = async_assert_that(if2, receives(rcv_filter, within_sec(10))) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr) wait_on_futures([f1, f2]) # Change to the chain that allows only multicast addresses. bridge.set_inbound_filter(VTM.get_chain('allow_only_multicast')) # Send another frame to the multicast address. Bridge doesn't # recognize it and will try to flood it to the other port. This # time the rule should allow it through. f1 = async_assert_that(if2, receives(rcv_filter, within_sec(10))) f2 = if1.send_udp("01:23:45:67:89:ab", if2_ip_addr) wait_on_futures([f1, f2]) # If2's actual MAC address should be blocked, since it doesn't # have the multicast bit set. f1 = async_assert_that(if2, should_NOT_receive(rcv_filter, within_sec(10))) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr) wait_on_futures([f1, f2])
def test_floating_ip(): """ Title: Tests a floating IP. Scenario 1: When: a VM sends an ICMP echo request to a floating IP address (100.100.100.100). Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the receiver sends back an ICMP reply with its original IP address as a source address. And: the router applies SNAT to the reply packet. And: the sender receives the reply with src address NATed to the floating IP address. """ sender = BM.get_iface_for_port("bridge-000-001", 2) receiver = BM.get_iface_for_port("bridge-000-002", 2) # Reset in-/out-bound filters. unset_filters("router-000-001") feed_receiver_mac(receiver) f1 = async_assert_that(receiver, should_NOT_receive("dst host 172.16.2.1 and icmp", within_sec(10))) sender.ping_ipv4_addr("100.100.100.100") wait_on_futures([f1]) # Configure floating IP address with the router set_filters("router-000-001", "pre_filter_floating_ip", "post_filter_floating_ip") f1 = async_assert_that(receiver, receives("dst host 172.16.2.1 and icmp", within_sec(10))) f2 = async_assert_that(sender, receives("src host 100.100.100.100 and icmp", within_sec(10))) sender.ping_ipv4_addr("100.100.100.100") wait_on_futures([f1, f2])
def test_filter_ipv6(): """ Title: Filter IPv6 packets out on Bridge Scenario 1: When: there is no filter settings Then: IPv6 packets go through the bridge Scenario 2: When: the bridge has a chain in which there is a drop rule for IPv6 Then: IPv6 packets should not go through the bridge Scenario 3: When: the chain is removed from the bridge Then: IPv6 packets should go through again. """ iface1 = BM.get_iface_for_port('bridge-000-001', 1) iface2 = BM.get_iface_for_port('bridge-000-001', 2) iface1_hw_addr = iface1.interface['hw_addr'] iface2_hw_addr = iface2.interface['hw_addr'] ipv6_proto = "86:dd" ipv6_icmp = ("60:00:00:00:00:20:3a:ff:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b1:ff:02:00:00:00:00:00:00:00:00:00:01:ff:29:a9:b2:" "87:00:32:26:00:00:00:00:fe:80:00:00:00:00:00:00:1a:03:73:ff:" "fe:29:a9:b2:01:01:18:03:73:29:a9:b1") packet = '%s-%s-%s-%s' % (iface2_hw_addr, iface1_hw_addr, ipv6_proto, ipv6_icmp) rcv_filter = 'ether dst %s' % iface2_hw_addr # Sceneario 1: f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) # async_assert_that expects only 1 packet. Send only one, because the next # tcpdump might capture it (and fail the test) in case it takes some time # to arrive. # FIXME: make the tcpdump listener configurable f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Scenario 2: # setting chain and make sure it's dropped chain = VTM.get_chain('drop_ipv6') VTM.get_bridge('bridge-000-001').set_inbound_filter(chain) f1 = async_assert_that(iface2, should_NOT_receive( rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2]) # Remove the filter and verify that packets go through again. VTM.get_bridge('bridge-000-001').set_inbound_filter(None) time.sleep(1) f1 = async_assert_that(iface2, receives(rcv_filter, within_sec(10))) f2 = iface1.send_ether(packet, count=1) wait_on_futures([f1, f2])
def test_filtering_by_dl(): ''' Title: Tests dl-based packet filtering. Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reach the receiver without filtering rule chains. Then: A filtering rule chain based on mac address is set on the bridge. And: UDP packets from the same host do NOT reach the same destination host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Reset an in-bound filter. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: inside receives UDP packets from outside.') wait_on_futures([f1]) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') f1 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(inside, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on mac address.') wait_on_futures([f1])
def test_filtering_by_network_address(): ''' Title: Tests packets filtering based on network address Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reaches the receiver. Then: Filtering rule chains based on network address (IP address) are set on the bridge port that the receiver host is connected to. And: The UDP packets from the same sender do NOT reach the receiver. ''' sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-001', 3) # Reset in/out-bound filters. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(receiver, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: receiver receives UDP packets from sender.') wait_on_futures([f1]) # Set a filtering rule based on network address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') f1 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(receiver, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on IP address.') wait_on_futures([f1])
def test_dnat(): """ Title: Tests DNAT on ping messages. Scenario 1: When: a VM sends ICMP echo request with ping command to an unassigned IP address. Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f2 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2]) # Set DNAT rule chains to the router set_filters('router-000-001', 'pre_filter_001', 'post_filter_001') f2 = async_assert_that(receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f3 = async_assert_that(sender, receives('src host 100.100.100.100 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2, f3])
def test_filtering_by_dl(): """ Title: Tests dl-based packet filtering. Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reach the receiver without filtering rule chains. Then: A filtering rule chain based on mac address is set on the bridge. And: UDP packets from the same host do NOT reach the same destination host. """ outside = BM.get_iface_for_port("bridge-000-001", 2) inside = BM.get_iface_for_port("bridge-000-001", 3) # Reset an in-bound filter. unset_bridge_port_filters("bridge-000-001", 3) port_num = get_random_port_num() f1 = async_assert_that( inside, receives("dst host 172.16.1.2 and udp", within_sec(5)), "No filtering: inside receives UDP packets from outside.", ) f2 = outside.send_udp("aa:bb:cc:00:01:02", "172.16.1.2", 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on mac addresses set_bridge_port_filters("bridge-000-001", 3, "connection_tracking_dl_in", "connection_tracking_dl_out") f1 = async_assert_that( inside, should_NOT_receive("dst host 172.16.1.2 and udp", within_sec(5)), "Packets are filtered based on mac address.", ) f2 = outside.send_udp("aa:bb:cc:00:01:02", "172.16.1.2", 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_snat(): """ Title: Tests SNAT on ping messages. Scenario: When: a VM sends ICMP echo request with ping command to a different subnet, Then: the router performs SNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, with src address NATted, And: the ping command succeeds. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that(receiver, should_NOT_receive('src host 172.16.1.100 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that(receiver, receives('src host 172.16.1.100 and icmp', within_sec(5))) f3 = async_assert_that(sender, receives('dst host 172.16.1.1 and icmp', within_sec(5))) f1 = sender.ping4(receiver) wait_on_futures([f1, f2, f3])
def _async_assert_receives_icmp_frag_needed(sender, should_receive): icmp_filter = 'icmp[icmptype] == icmp-unreach and icmp[icmpcode] == 4' if should_receive: return async_assert_that(sender, receives(icmp_filter, within_sec(5))) else: return async_assert_that(sender, should_NOT_receive(icmp_filter, within_sec(5)))
def test_snat_for_udp(): """ Title: Tests SNAT on UDP packets. Scenario: When: a VM sends UDP packets to an unassigned IP address. Then: the router performs SNAT on the message according to the rule chain set to the router, And: the UDP packets reach the receiver VM, with src address NATted, And: because the UDP port is not open, the receiver VM returns ICMP error responses. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # Target hardware is a router's incoming port. router_port = VTM.get_router('router-000-001').get_port(1) router_mac = router_port.get_mn_resource().get_port_mac() # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that( receiver, should_NOT_receive('src host 172.16.1.100 and udp', within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that( receiver, receives('src host 172.16.1.100 and udp', within_sec(5))) # Sender should receive ICMP unreachable as the receiver port is not open. f3 = async_assert_that( sender, receives_icmp_unreachable_for_udp('172.16.1.1', '172.16.2.1', udp_src_port=9, udp_dst_port=65000, timeout=within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2, f3])
def test_flow_invalidation_on_mac_update(): """ Title: Flow invalidation, learning MACs The bridge learns the MACs from the traffic flowing by its ports. When the bridge learns a MAC that has 'moved' to another port, it should send traffic only to that port. """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 2) intruder = BM.get_iface_for_port('bridge-000-001', 3) receiver_MAC = receiver.get_mac_addr() frame = '%s-%s-aa:bb' % (receiver_MAC, receiver_MAC) capture = 'icmp and src host %s' % (sender.get_ip()) # Populate ARP table sender.execute('arp -s %s %s' % (receiver.get_ip(), receiver_MAC)) receiver.execute('arp -s %s %s' % (sender.get_ip(), sender.get_mac_addr())) # Trigger receiver MAC learning receiver.send_ether(frame) # First: packets go from sender to receiver f1 = async_assert_that(receiver, receives(capture, within_sec(5))) f2 = async_assert_that(intruder, should_NOT_receive(capture, within_sec(5))) f3 = sender.ping4(receiver) wait_on_futures([f1, f2, f3]) # Second: intruder claims to be receiver intruder.send_ether(frame) # Third: packets go from sender to intruder f1 = async_assert_that(receiver, should_NOT_receive(capture, within_sec(5))) f2 = async_assert_that(intruder, receives(capture, within_sec(5))) f3 = sender.ping4(receiver) wait_on_futures([f1, f2, f3])
def run_garp_scenario(BM, sender_port, target_ip, enable_vip, disable_vip): vip1 = BM.get_interface_on_vport('port_int1') vip2 = BM.get_interface_on_vport('port_int2') sender = BM.get_interface_on_vport(sender_port) # allow sender to accept gratutious arps (only makes sense if on same network) sender.execute('bash -c "echo 1 > /proc/sys/net/ipv4/conf/%s/arp_accept"' % sender.get_ifname()) rcv_filter = 'icmp and ip src %s' % (sender.get_ip()) # noone responds initially f1 = async_assert_that(vip1, should_NOT_receive(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip1 enable_vip(vip1) disable_vip(vip2) f1 = async_assert_that(vip1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip2 enable_vip(vip2) disable_vip(vip1) f1 = async_assert_that(vip1, should_NOT_receive(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, receives(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3]) # enable for vip1 enable_vip(vip1) disable_vip(vip2) f1 = async_assert_that(vip1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(vip2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = sender.ping_ipv4_addr(target_ip, count=5) wait_on_futures([f1, f2, f3])
def test_src_mac_masking(): """ Title: Test source MAC masking in chain rules Scenario 1: When: There's a rule dropping any traffic with an even source MAC Then: Traffic from if2 to if1 is blocked because if2's MAC ends with 2 And: Traffic from if1 to if2 goes through because if1's MAC ends with 1 FIXME: moving to the new bindings mechanisms should allow removing this restriction. Only running this with the one-host binding, because: 1. The multi-host binding breaks the assumptions that if1 will have an odd MAC address and if2 an even one. 2. This is basically just a sanity test to make sure dl_src_mask is wired up. Unit tests and test_dst_mac_masking provide enough coverage of the other aspects. 3. These tests are slow enough as it is. """ bridge = VTM.get_bridge('bridge-000-001') if1 = BM.get_iface_for_port('bridge-000-001', 1) if2 = BM.get_iface_for_port('bridge-000-001', 2) if1_hw_addr = if1.interface['hw_addr'] if2_hw_addr = if2.interface['hw_addr'] if1_ip_addr = if1.get_ip() if2_ip_addr = if2.get_ip() if1_rcv_filter = 'udp and ether dst %s' % if1_hw_addr if2_rcv_filter = 'udp and ether dst %s' % if2_hw_addr bridge.set_inbound_filter(VTM.get_chain('drop_even_src_mac')) # If2 has an even MAC (ends with 2), so traffic from if2 to if1 # should be dropped. f1 = async_assert_that(if1, should_NOT_receive(if1_rcv_filter, within_sec(5))) time.sleep(1) f2 = if2.send_udp(if1_hw_addr, if1_ip_addr, 41) wait_on_futures([f1, f2]) # If1 has an odd MAC (ends with 1), so traffic from if1 to if2 # should go through. f1 = async_assert_that(if2, receives(if2_rcv_filter, within_sec(5))) time.sleep(1) f2 = if1.send_udp(if2_hw_addr, if2_ip_addr, 41) wait_on_futures([f1, f2])
def test_mac_learning(): """ Title: Bridge mac learning Scenario 1: When: the destination ethernet address has never been seen before. Then: the bridge should flood the ethernet unicast Scenario 2: When: the destination ethernet address has been seen before. Then: the bridge should not flood the ethernet frame, instaed it should forward to only the port that is connected to the interface with the mac address. """ sender = BM.get_iface_for_port('bridge-000-001', 1) iface_with_the_hw_addr = BM.get_iface_for_port('bridge-000-001', 2) iface_x = BM.get_iface_for_port('bridge-000-001', 3) hw_addr = iface_with_the_hw_addr.get_mac_addr() match_on_the_hw_addr = 'ether dst ' + hw_addr ethernet_unicast_to_the_hw_addr = '%s-7e:1f:ff:ff:ff:ff-aa:bb' % (hw_addr) # Scenario 1: # Both interfaces should get the frname as the bridge should flood it. f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, receives(match_on_the_hw_addr, within_sec(5))) time.sleep(1) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=3) wait_on_futures([f1, f2]) # Scenario 2: # Get the bridge to learn the mac address iface_with_the_hw_addr.ping4(sender, sync=True) time.sleep(1) # only iface_with_the_hw_addr should receives the ehternet unicast f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, should_NOT_receive(match_on_the_hw_addr, within_sec(5))) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=1) wait_on_futures([f1, f2])
def test_mac_learning(): """ Title: Bridge mac learning Scenario 1: When: the destination ethernet address has never been seen before. Then: the bridge should flood the ethernet unicast Scenario 2: When: the destination ethernet address has been seen before. Then: the bridge should not flood the ethernet frame, instaed it should forward to only the port that is connected to the interface with the mac address. """ sender = BM.get_iface_for_port('bridge-000-001', 1) iface_with_the_hw_addr = BM.get_iface_for_port('bridge-000-001', 2) iface_x = BM.get_iface_for_port('bridge-000-001', 3) hw_addr = iface_with_the_hw_addr.get_mac_addr() match_on_the_hw_addr = 'ether dst ' + hw_addr ethernet_unicast_to_the_hw_addr = '%s-7e:1f:ff:ff:ff:ff-aa:bb' % (hw_addr) # Scenario 1: # Both interfaces should get the frname as the bridge should flood it. f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that(iface_x, receives(match_on_the_hw_addr, within_sec(5))) time.sleep(1) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=3) wait_on_futures([f1, f2]) # Scenario 2: # Get the bridge to learn the mac address iface_with_the_hw_addr.ping4(sender, sync=True) time.sleep(1) # only iface_with_the_hw_addr should receives the ehternet unicast f1 = async_assert_that(iface_with_the_hw_addr, receives(match_on_the_hw_addr, within_sec(5))) f2 = async_assert_that( iface_x, should_NOT_receive(match_on_the_hw_addr, within_sec(5))) sender.send_ether(ethernet_unicast_to_the_hw_addr, count=1) wait_on_futures([f1, f2])
def test_two_isolated_bridges(): """ Title: Two isolated bridges All traffic between two VMs in different and unconnected bridges should be independent, so receiver shouldn't get any packets """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-002', 1) f2 = async_assert_that(receiver, should_NOT_receive('', within_sec(5))) f1 = sender.ping4(receiver, 0.5, 3, False, 100) wait_on_futures([f1, f2])
def test_snat_for_udp(): """ Title: Tests SNAT on UDP packets. Scenario: When: a VM sends UDP packets to an unassigned IP address. Then: the router performs SNAT on the message according to the rule chain set to the router, And: the UDP packets reach the receiver VM, with src address NATted, And: because the UDP port is not open, the receiver VM returns ICMP error responses. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) # Target hardware is a router's incoming port. router_port = VTM.get_router('router-000-001').get_port(1) router_mac = router_port.get_mn_resource().get_port_mac() # No SNAT configured. Should not receive SNATed messages. f2 = async_assert_that(receiver, should_NOT_receive('src host 172.16.1.100 and udp', within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2]) # Set SNAT rule chains to the router set_filters('router-000-001', 'pre_filter_002', 'post_filter_002') # The receiver should receive SNATed messages. f2 = async_assert_that(receiver, receives('src host 172.16.1.100 and udp', within_sec(5))) # Sender should receive ICMP unreachable as the receiver port is not open. f3 = async_assert_that(sender, receives_icmp_unreachable_for_udp( '172.16.1.1', '172.16.2.1', udp_src_port=9, udp_dst_port=65000, timeout=within_sec(5))) f1 = sender.send_udp(router_mac, '172.16.2.1', 29, src_port=9, dst_port=65000) wait_on_futures([f1, f2, f3])
def test_filtering_by_network_address(): ''' Title: Tests packets filtering based on network address Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reaches the receiver. Then: Filtering rule chains based on network address (IP address) are set on the bridge port that the receiver host is connected to. And: The UDP packets from the same sender do NOT reach the receiver. ''' sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-001', 3) # Reset in/out-bound filters. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(receiver, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: receiver receives UDP packets from sender.') wait_on_futures([f1]) # Set a filtering rule based on network address. set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_nw_in', 'connection_tracking_nw_out') f1 = sender.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that( receiver, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on IP address.') wait_on_futures([f1])
def test_icmp_after_interface_recovery(): """ Title: ICMP reachability over bridge before and after interfaces go down Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds Then: the receiver VM's tap goes down And: the ping command fails Then: the receiver VM's tap goes back up And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that(receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_down() f1 = async_assert_that(receiver, should_NOT_receive('icmp', within_sec(5), on_host_interface(True))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_up() f1 = async_assert_that(receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_rule_changes(): """ Title: ICMP reachability over bridge before and after adding rule to drop IPv4 traffic. Scenario 1: When: A VM sends ICMP echo request with ping command Then: The receiver VM should receive the ICMP echo packet. And: The ping command succeeds Then: The receiver adds a rule blocking IPv4 traffic. And: The ping command fails Then: the receiver removes the rule And: The ping succeeds again. """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 2) # There are no filters, so the first ping should succeed. f1 = async_assert_that(receiver, receives('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2]) # Add a filter dropping all IPv4 traffic to port 2. chain = VTM.get_chain('drop_ipv4') VTM.get_device_port('bridge-000-001', 2).set_outbound_filter(chain) # The second ping should not reach port 2. f1 = async_assert_that(receiver, should_NOT_receive('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2]) # After removing the filter, ping should succeed again. VTM.get_device_port('bridge-000-001', 2).set_outbound_filter(None) f1 = async_assert_that(receiver, receives('icmp', within_sec(5))) f2 = sender.ping4(receiver, do_arp=True) wait_on_futures([f1, f2])
def test_filtering_by_dl(): ''' Title: Tests dl-based packet filtering. Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reach the receiver without filtering rule chains. Then: A filtering rule chain based on mac address is set on the bridge. And: UDP packets from the same host do NOT reach the same destination host. ''' outside = BM.get_iface_for_port('bridge-000-001', 2) inside = BM.get_iface_for_port('bridge-000-001', 3) # Reset an in-bound filter. unset_bridge_port_filters('bridge-000-001', 3) port_num = get_random_port_num() f1 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that(inside, receives('dst host 172.16.1.2 and udp', within_sec(5)), 'No filtering: inside receives UDP packets from outside.') wait_on_futures([f1]) # Set a filtering rule based on mac addresses set_bridge_port_filters('bridge-000-001', 3, 'connection_tracking_dl_in', 'connection_tracking_dl_out') f1 = outside.send_udp('aa:bb:cc:00:01:02', '172.16.1.2', 41, src_port=port_num, dst_port=port_num) assert_that( inside, should_NOT_receive('dst host 172.16.1.2 and udp', within_sec(5)), 'Packets are filtered based on mac address.') wait_on_futures([f1])
def test_dnat_for_udp(): """ Title: Tests DNAT on UDP packets. Scenario: When: a VM sends UDP packets to an unassigned IP address. Then: the router performs DNAT on the message according to the rule chain set to the router, And: the UDP packets reach the receiver VM. And: because the UDP port is not open, the receiver VM returns ICMP error responses. """ sender = BM.get_iface_for_port("bridge-000-001", 2) receiver = BM.get_iface_for_port("bridge-000-002", 2) # Reset in-/out-bound filters. unset_filters("router-000-001") feed_receiver_mac(receiver) # Target hardware is a router's incoming port. router_port = VTM.get_router("router-000-001").get_port(1) router_mac = router_port.get_mn_resource().get_port_mac() f2 = async_assert_that(receiver, should_NOT_receive("dst host 172.16.2.1 and udp", within_sec(5))) f1 = sender.send_udp(router_mac, "100.100.100.100", 29, src_port=9, dst_port=9) wait_on_futures([f1, f2]) # Set DNAT rule chains to the router set_filters("router-000-001", "pre_filter_001", "post_filter_001") f2 = async_assert_that(receiver, receives("dst host 172.16.2.1 and udp", within_sec(5))) # Sender should receive ICMP unreachable as the receiver port is not open. f3 = async_assert_that( sender, receives_icmp_unreachable_for_udp( "172.16.1.1", "100.100.100.100", udp_src_port=9, udp_dst_port=9, timeout=within_sec(5) ), ) f1 = sender.send_udp(router_mac, "100.100.100.100", 29, src_port=9, dst_port=9) wait_on_futures([f1, f2, f3])
def test_ping_delete_port(): """ Title: L3 connectivity over bridge and router, then deletes a port and verifies that there is no connectivity. Implemented to cover the old DeletePortTest. Scenario 1: When: a VM sends ICMP echo request with ping command to a different subnet Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds When: the destination port on the router is deleted Then: the receiver VM should NOT receive the ICMP echo packet """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # The receiver VM needs to send some frames so the MN Router learns # the VM's mac address. Otherwise this test would fail with binding2 # because the MidoNet Router forwards the ICMP with the previous mac # found in bindings1 in ethernet headers. # Issue: https://midobugs.atlassian.net/browse/MN-79 receiver.ping4(sender) f1 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) port = VTM.get_device_port('router-000-001', 2) port.destroy() f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_floating_ip(): """ Title: Tests a floating IP. Scenario 1: When: a VM sends an ICMP echo request to a floating IP address (100.100.100.100). Then: the router performs DNAT on the message according to the rule chain set to the router, And: the receiver VM should receive the ICMP echo packet, And: the receiver sends back an ICMP reply with its original IP address as a source address. And: the router applies SNAT to the reply packet. And: the sender receives the reply with src address NATed to the floating IP address. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # Reset in-/out-bound filters. unset_filters('router-000-001') feed_receiver_mac(receiver) f2 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.1 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100', suppress_failure=True) wait_on_futures([f1, f2]) # Configure floating IP address with the router set_filters('router-000-001', 'pre_filter_floating_ip', 'post_filter_floating_ip') f2 = async_assert_that( receiver, receives('dst host 172.16.2.1 and icmp', within_sec(5))) f3 = async_assert_that( sender, receives('src host 100.100.100.100 and icmp', within_sec(5))) f1 = sender.ping_ipv4_addr('100.100.100.100') wait_on_futures([f1, f2, f3])
def test_icmp_after_interface_recovery(): """ Title: ICMP reachability over bridge before and after interfaces go down Scenario 1: When: a VM sends ICMP echo request with ping command Then: the receiver VM should receive the ICMP echo packet. And: the ping command succeeds Then: the receiver VM's tap goes down And: the ping command fails Then: the receiver VM's tap goes back up And: the ping command succeeds """ sender = BM.get_iface_for_port('bridge-000-001', 1) receiver = BM.get_iface_for_port('bridge-000-001', 3) f1 = async_assert_that( receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_down() f1 = async_assert_that( receiver, should_NOT_receive('icmp', within_sec(5), on_host_interface(True))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2]) receiver.set_up() f1 = async_assert_that( receiver, receives('dst host 172.16.1.3 and icmp', within_sec(5))) f2 = sender.ping4(receiver) wait_on_futures([f1, f2])
def test_filtering_by_network_address(): """ Title: Tests packets filtering based on network address Scenario: When: A VM sends UDP packets to another host on the same bridge. Then: The UDP packets reaches the receiver. Then: Filtering rule chains based on network address (IP address) are set on the bridge port that the receiver host is connected to. And: The UDP packets from the same sender do NOT reach the receiver. """ sender = BM.get_iface_for_port("bridge-000-001", 2) receiver = BM.get_iface_for_port("bridge-000-001", 3) # Reset in/out-bound filters. unset_bridge_port_filters("bridge-000-001", 3) port_num = get_random_port_num() # FIXME: do not use harcoded values! f1 = async_assert_that( receiver, receives("dst host 172.16.1.2 and udp", within_sec(5)), "No filtering: receives UDP packets from sender.", ) f2 = sender.send_udp("aa:bb:cc:00:01:02", "172.16.1.2", 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2]) # Set a filtering rule based on network address. set_bridge_port_filters("bridge-000-001", 3, "connection_tracking_nw_in", "connection_tracking_nw_out") f1 = async_assert_that( receiver, should_NOT_receive("dst host 172.16.1.2 and udp", within_sec(5)), "Packets are filtered based on IP address.", ) f2 = sender.send_udp("aa:bb:cc:00:01:02", "172.16.1.2", 41, src_port=port_num, dst_port=port_num) wait_on_futures([f1, f2])
def test_l2insertion_fail_open(): """ Title: Test insertions with fail open 2 L2 insertions on a port, each insertion with a different bad pattern. One of the insertions is set to fail open. Test both bad patterns can't get through. Take down the fail open insertion. Verify that that bad pattern can now get through. Take down the non fail open insertion. Verify that no traffic can get through. Also verify both directions """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) other_port = BM.get_iface_for_port('bridge-000-001', 4) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(True) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port.get_ip() rcv_filter_ret = 'ip src %s and icmp[icmptype] == 8' % insertion_port.get_ip() LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter_ret, within_sec(10))) f3 = async_assert_that(other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) set_interface_admin_down(service_port1) time.sleep(5) # give midolman a chance to see it LOG.info("Sending dead beef again") f1 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef") wait_on_futures([f1, f2]) LOG.info("Sending dead beef the other way again") f1 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef") wait_on_futures([f1, f2]) LOG.info("Sending cafe food again") f1 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2]) set_interface_admin_down(service_port2) time.sleep(5) # nothing should get through LOG.info("Sending good packet") f1 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c", should_succeed=False) wait_on_futures([f1]) LOG.info("Sending good packet the other way") f1 = async_assert_that(other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="f00b4c", should_succeed=False) wait_on_futures([f1]) finally: fakesnort2.kill() fakesnort1.kill()
def test_l2insertion_both_ends_protected(): """ Title: Test insertions with both ends protected 2 L2 insertions on 2 ports, each insertion with a different bad pattern. The bad packets matching the different patterns should be blocked at different insertions depending on the direction of the packet. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port1 = BM.get_iface_for_port('bridge-000-001', 1) insertion_port2 = BM.get_iface_for_port('bridge-000-001', 4) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port1.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port1.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port1.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port1.get_mac_addr()) insertion2.create() insertion3 = api.add_l2insertion() insertion3.srv_port(service_port1.vport_id) insertion3.port(insertion_port2.vport_id) insertion3.position(1) insertion3.fail_open(False) insertion3.vlan(3) insertion3.mac(insertion_port2.get_mac_addr()) insertion3.create() insertion4 = api.add_l2insertion() insertion4.srv_port(service_port2.vport_id) insertion4.port(insertion_port2.vport_id) insertion4.position(2) insertion4.fail_open(False) insertion4.vlan(4) insertion4.mac(insertion_port2.get_mac_addr()) insertion4.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port2.get_ip() LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10), count=2)) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10), count=2)) f3 = async_assert_that(insertion_port2, receives(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port2, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port2, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) finally: fakesnort2.kill() fakesnort1.kill()
def test_l2insertion_with_flowstate(): """ Title: Test insertions with flow state 2 L2 insertions on a port, each with a different bad pattern. Packets are sent over DNAT so that flow state is generated and necessary to return the packet. The bad packets matching the different patterns should be blocked at different points. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() router = VTM.get_router('router-000-001') conntrack_filter = VTM.get_chain('conntrack_filter_001') router.set_inbound_filter(conntrack_filter) # Sleep here to make sure that the settings have been propagated. time.sleep(5) service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) other_port = BM.get_iface_for_port('bridge-000-002', 1) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port.get_ip() LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="beeff00d") wait_on_futures([f1, f2, f3]) finally: fakesnort1.kill() fakesnort2.kill()
def test_multi_l2insertion(): """ Title: Multiple insertions on a port 2 L2 insertions on a port, each with a different bad pattern. The bad packets matching the different patterns should be blocked at different points. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ether dst %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr() rcv_filter_ret = 'ether src %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr() other_port = BM.get_iface_for_port('bridge-000-001', 4) LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="beeff00d") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter_ret, within_sec(10))) f3 = async_assert_that(other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f3 = async_assert_that(other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f3 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="beeff00d") wait_on_futures([f1, f2, f3]) finally: fakesnort1.kill() fakesnort2.kill()
def test_l2insertion_fail_open(): """ Title: Test insertions with fail open 2 L2 insertions on a port, each insertion with a different bad pattern. One of the insertions is set to fail open. Test both bad patterns can't get through. Take down the fail open insertion. Verify that that bad pattern can now get through. Take down the non fail open insertion. Verify that no traffic can get through. Also verify both directions """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) other_port = BM.get_iface_for_port('bridge-000-001', 4) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(True) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port.get_ip( ) rcv_filter_ret = 'ip src %s and icmp[icmptype] == 8' % insertion_port.get_ip( ) LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that( service_port2, should_NOT_receive(rcv_filter_ret, within_sec(10))) f3 = async_assert_that( other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) set_interface_admin_down(service_port1) time.sleep(5) # give midolman a chance to see it LOG.info("Sending dead beef again") f1 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef") wait_on_futures([f1, f2]) LOG.info("Sending dead beef the other way again") f1 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef") wait_on_futures([f1, f2]) LOG.info("Sending cafe food again") f1 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2]) set_interface_admin_down(service_port2) time.sleep(5) # nothing should get through LOG.info("Sending good packet") f1 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c", should_succeed=False) wait_on_futures([f1]) LOG.info("Sending good packet the other way") f1 = async_assert_that( other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="f00b4c", should_succeed=False) wait_on_futures([f1]) finally: fakesnort2.kill() fakesnort1.kill()
def test_multi_l2insertion(): """ Title: Multiple insertions on a port 2 L2 insertions on a port, each with a different bad pattern. The bad packets matching the different patterns should be blocked at different points. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ether dst %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr( ) rcv_filter_ret = 'ether src %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr( ) other_port = BM.get_iface_for_port('bridge-000-001', 4) LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="beeff00d") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that( service_port2, should_NOT_receive(rcv_filter_ret, within_sec(10))) f3 = async_assert_that( other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f3 = async_assert_that( other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet the other way") f1 = async_assert_that(service_port1, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter_ret, within_sec(10))) f3 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="beeff00d") wait_on_futures([f1, f2, f3]) finally: fakesnort1.kill() fakesnort2.kill()
def test_l2insertion_with_flowstate(): """ Title: Test insertions with flow state 2 L2 insertions on a port, each with a different bad pattern. Packets are sent over DNAT so that flow state is generated and necessary to return the packet. The bad packets matching the different patterns should be blocked at different points. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() router = VTM.get_router('router-000-001') conntrack_filter = VTM.get_chain('conntrack_filter_001') router.set_inbound_filter(conntrack_filter) # Sleep here to make sure that the settings have been propagated. time.sleep(5) service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port = BM.get_iface_for_port('bridge-000-001', 1) other_port = BM.get_iface_for_port('bridge-000-002', 1) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port.get_mac_addr()) insertion2.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port.get_ip( ) LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="beeff00d") wait_on_futures([f1, f2, f3]) finally: fakesnort1.kill() fakesnort2.kill()
def test_l2insertion_both_ends_protected(): """ Title: Test insertions with both ends protected 2 L2 insertions on 2 ports, each insertion with a different bad pattern. The bad packets matching the different patterns should be blocked at different insertions depending on the direction of the packet. Verify that packets are blocked in the same order regardless of the direction. """ api = get_midonet_api() service_port1 = BM.get_iface_for_port('bridge-000-001', 2) service_port2 = BM.get_iface_for_port('bridge-000-001', 3) fakesnort1 = FakeSnort(service_port1, "deadbeef") fakesnort2 = FakeSnort(service_port2, "cafef00d") try: fakesnort1.run() fakesnort2.run() insertion_port1 = BM.get_iface_for_port('bridge-000-001', 1) insertion_port2 = BM.get_iface_for_port('bridge-000-001', 4) insertion1 = api.add_l2insertion() insertion1.srv_port(service_port1.vport_id) insertion1.port(insertion_port1.vport_id) insertion1.position(1) insertion1.fail_open(False) insertion1.vlan(1) insertion1.mac(insertion_port1.get_mac_addr()) insertion1.create() insertion2 = api.add_l2insertion() insertion2.srv_port(service_port2.vport_id) insertion2.port(insertion_port1.vport_id) insertion2.position(2) insertion2.fail_open(False) insertion2.vlan(2) insertion2.mac(insertion_port1.get_mac_addr()) insertion2.create() insertion3 = api.add_l2insertion() insertion3.srv_port(service_port1.vport_id) insertion3.port(insertion_port2.vport_id) insertion3.position(1) insertion3.fail_open(False) insertion3.vlan(3) insertion3.mac(insertion_port2.get_mac_addr()) insertion3.create() insertion4 = api.add_l2insertion() insertion4.srv_port(service_port2.vport_id) insertion4.port(insertion_port2.vport_id) insertion4.position(2) insertion4.fail_open(False) insertion4.vlan(4) insertion4.mac(insertion_port2.get_mac_addr()) insertion4.create() time.sleep(5) rcv_filter = 'ip dst %s and icmp[icmptype] == 8' % insertion_port2.get_ip( ) LOG.info("Sending good packet") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10), count=2)) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10), count=2)) f3 = async_assert_that(insertion_port2, receives(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="f00b4c") wait_on_futures([f1, f2, f3]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, should_NOT_receive(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port2, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2, f3]) LOG.info("Sending cafe food") f1 = async_assert_that(service_port1, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(service_port2, receives(rcv_filter, within_sec(10))) f3 = async_assert_that(insertion_port2, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(insertion_port1, insertion_port2, data="cafef00d", should_succeed=False) wait_on_futures([f1, f2, f3]) finally: fakesnort2.kill() fakesnort1.kill()
def test_router_service(): """ Title: TCP/UDP services on router Scenario 1: When: A client tries to access a TCP or UDP service on a router. Then: the router should redirect the traffic to a namespace. And: the namespace should respond correctly. """ router = VTM.get_router('router-000-001') pre_filter = VTM.get_chain('pre_filter_001') router.set_local_redirect_chain(pre_filter) sender1 = BM.get_iface_for_port('bridge-000-001', 2) service1 = BM.get_iface_for_port('router-000-001', 2) service2 = BM.get_iface_for_port('router-000-001', 3) # setup extra parameters in namespaces service1.execute("ip a add 172.16.1.254/32 dev lo") service1.execute("arp -s 169.254.1.1 aa:bb:cc:00:11:33") service2.execute("ip a add 172.16.1.254/32 dev lo") service2.execute("arp -s 169.254.2.1 aa:bb:cc:00:11:33") # assert udp traffic goes to correct node f1 = async_assert_that( service1, receives('dst host 172.16.1.254 and udp port 500', within_sec(5))) f2 = async_assert_that( service2, should_NOT_receive('dst host 172.16.1.2 and udp port 500', within_sec(5))) f3 = sender1.send_udp('aa:bb:cc:00:00:22', '172.16.1.254', 41, src_port=500, dst_port=500) wait_on_futures([f1, f2, f3]) # assert udp traffic is returned f1 = async_assert_that( sender1, receives('dst host 172.16.1.1 and udp port 500', within_sec(5))) f2 = service1.send_udp('aa:bb:cc:00:11:22', '172.16.1.1', 41, src_port=500, dst_port=500, src_hw='aa:bb:cc:00:00:22', src_ipv4='172.16.1.254') wait_on_futures([f1, f2]) # assert tcp traffic goes both ways try: service2.execute("sh -c \"echo foobar | nc -l 1500\"") f1 = async_assert_that( service2, receives('dst host 172.16.1.254 and tcp port 1500', within_sec(5))) f2 = async_assert_that( sender1, receives('dst host 172.16.1.1 and tcp port 1500', within_sec(5))) f3 = async_assert_that( service1, should_NOT_receive('dst host 172.16.1.254', within_sec(5))) sender1.execute("sh -c \"echo foobar | nc 172.16.1.254 1500\"") wait_on_futures([f1, f2, f3]) finally: service2.execute("pkill nc")
def test_spoofed_arp_reply(): """ Title: Test spoofed ARP reply Given: Sender is bridge-000-001, port 2, at 176.16.1.1 Receiver is bridge-000-002, port 2, at 176.16.2.1 Scenario 1: When: Sender pings 176.16.2.2 Then: The ping fails. Scenario 2: When: Receiver sends an unsolicited ARP reply to its gateway (172.16.2.254) with source IP 176.16.2.2 and its own MAC address as source MAC. Then: The router maps 176.16.2.2 to receiver's MAC address. And: Sender pings 176.16.2.2 Then: The ping succeeds. Scenario 3: When: Receiver sends an unsolicited ARP reply to its gateway (172.16.2.254) with source IP 176.16.1.2 and its own MAC address as source MAC. Then: The router ignores it because 176.16.1.2 is not in the subnet (172.16.2.254/24) of the port through which the ARP reply came in. And: Sender pings 176.16.1.2 Then: The ping fails. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # 176.16.2.2 is not in the router's ARP table. Ping fails. f1 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.2.2 and icmp', within_sec(5))) sender.ping_ipv4_addr('172.16.2.2') wait_on_futures([f1]) # Sender sends an unsolicited ARP reply with source IP 172.16.2.2, # which the router maps to sender's MAC address. router_port = VTM.get_router('router-000-001').get_port(2) router_mac = router_port.get_mn_resource().get_port_mac() receiver.send_arp_reply(receiver.get_mac_addr(), router_mac, '172.16.2.2', '172.16.2.254') # wait for the arp reply effect to be propagated time.sleep(20) # Ping now succeeds. f1 = async_assert_that(receiver, receives('dst host 172.16.2.2 and icmp', within_sec(5))) sender.ping_ipv4_addr('172.16.2.2') wait_on_futures([f1]) # This ARP reply is ignored because 172.16.1.2 is not in the subnet of # router port 2, so a ping to 172.16.1.2 is ignored. f1 = async_assert_that(receiver, should_NOT_receive('dst host 172.16.1.2 and icmp', within_sec(5))) receiver.send_arp_reply(receiver.get_mac_addr(), router_mac, '172.16.1.2', '172.16.2.254') sender.ping_ipv4_addr('172.16.1.2') wait_on_futures([f1])
def test_basic_l2insertion(): """ Title: Basic insertion functionallity L2Service insertion on 1, which redirects traffic through port 3. Good traffic should go through. Traffic that matches the bad pattern should be dropped. """ api = get_midonet_api() service_port = BM.get_iface_for_port('bridge-000-001', 2) fakesnort = FakeSnort(service_port, "deadbeef") fakesnort.run() try: insertion_port = BM.get_iface_for_port('bridge-000-001', 1) insertion = api.add_l2insertion() insertion.srv_port(service_port.vport_id) insertion.port(insertion_port.vport_id) insertion.position(1) insertion.fail_open(False) insertion.mac(insertion_port.get_mac_addr()) insertion.create() time.sleep(5) other_port = BM.get_iface_for_port('bridge-000-001', 3) rcv_filter = 'ether dst %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr( ) rcv_filter_ret = 'ether src %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr( ) LOG.info("Sending good packet") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2]) LOG.info("Sending bad packet the other way") f1 = async_assert_that(service_port, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that( other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2]) LOG.info("Sending good packet the other way") f1 = async_assert_that(service_port, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="b00f00") wait_on_futures([f1, f2]) finally: fakesnort.kill()
def test_spoofed_arp_reply(): """ Title: Test spoofed ARP reply Given: Sender is bridge-000-001, port 2, at 176.16.1.1 Receiver is bridge-000-002, port 2, at 176.16.2.1 Scenario 1: When: Sender pings 176.16.2.2 Then: The ping fails. Scenario 2: When: Receiver sends an unsolicited ARP reply to its gateway (172.16.2.254) with source IP 176.16.2.2 and its own MAC address as source MAC. Then: The router maps 176.16.2.2 to receiver's MAC address. And: Sender pings 176.16.2.2 Then: The ping succeeds. Scenario 3: When: Receiver sends an unsolicited ARP reply to its gateway (172.16.2.254) with source IP 176.16.1.2 and its own MAC address as source MAC. Then: The router ignores it because 176.16.1.2 is not in the subnet (172.16.2.254/24) of the port through which the ARP reply came in. And: Sender pings 176.16.1.2 Then: The ping fails. """ sender = BM.get_iface_for_port('bridge-000-001', 2) receiver = BM.get_iface_for_port('bridge-000-002', 2) # 176.16.2.2 is not in the router's ARP table. Ping fails. f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.2.2 and icmp', within_sec(5))) sender.ping_ipv4_addr('172.16.2.2') wait_on_futures([f1]) # Sender sends an unsolicited ARP reply with source IP 172.16.2.2, # which the router maps to sender's MAC address. router_port = VTM.get_router('router-000-001').get_port(2) router_mac = router_port.get_mn_resource().get_port_mac() receiver.send_arp_reply(receiver.get_mac_addr(), router_mac, '172.16.2.2', '172.16.2.254') # wait for the arp reply effect to be propagated time.sleep(20) # Ping now succeeds. f1 = async_assert_that( receiver, receives('dst host 172.16.2.2 and icmp', within_sec(5))) sender.ping_ipv4_addr('172.16.2.2') wait_on_futures([f1]) # This ARP reply is ignored because 172.16.1.2 is not in the subnet of # router port 2, so a ping to 172.16.1.2 is ignored. f1 = async_assert_that( receiver, should_NOT_receive('dst host 172.16.1.2 and icmp', within_sec(5))) receiver.send_arp_reply(receiver.get_mac_addr(), router_mac, '172.16.1.2', '172.16.2.254') sender.ping_ipv4_addr('172.16.1.2') wait_on_futures([f1])
def test_basic_l2insertion(): """ Title: Basic insertion functionallity L2Service insertion on 1, which redirects traffic through port 3. Good traffic should go through. Traffic that matches the bad pattern should be dropped. """ api = get_midonet_api() service_port = BM.get_iface_for_port('bridge-000-001', 2) fakesnort = FakeSnort(service_port, "deadbeef") fakesnort.run() try: insertion_port = BM.get_iface_for_port('bridge-000-001', 1) insertion = api.add_l2insertion() insertion.srv_port(service_port.vport_id) insertion.port(insertion_port.vport_id) insertion.position(1) insertion.fail_open(False) insertion.mac(insertion_port.get_mac_addr()) insertion.create() time.sleep(5) other_port = BM.get_iface_for_port('bridge-000-001', 3) rcv_filter = 'ether dst %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr() rcv_filter_ret = 'ether src %s and icmp[icmptype] == 8' % insertion_port.get_mac_addr() LOG.info("Sending good packet") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2]) LOG.info("Sending dead beef") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, should_NOT_receive(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2]) LOG.info("Sending another good packet") f1 = async_assert_that(service_port, receives(rcv_filter, within_sec(10))) f2 = async_assert_that(insertion_port, receives(rcv_filter, within_sec(10))) ping_port(other_port, insertion_port, data="f00b4c") wait_on_futures([f1, f2]) LOG.info("Sending bad packet the other way") f1 = async_assert_that(service_port, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(other_port, should_NOT_receive(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="deadbeef", should_succeed=False) wait_on_futures([f1, f2]) LOG.info("Sending good packet the other way") f1 = async_assert_that(service_port, receives(rcv_filter_ret, within_sec(10))) f2 = async_assert_that(other_port, receives(rcv_filter_ret, within_sec(10))) ping_port(insertion_port, other_port, data="b00f00") wait_on_futures([f1, f2]) finally: fakesnort.kill()
def expect_return_dropped(dst_port_no): return async_assert_that( downlink_iface(), should_NOT_receive(return_filter(dst_port_no), within_sec(10)), 'Return flow gets dropped.')
def test_router_service(): """ Title: TCP/UDP services on router Scenario 1: When: A client tries to access a TCP or UDP service on a router. Then: the router should redirect the traffic to a namespace. And: the namespace should respond correctly. """ router = VTM.get_router('router-000-001') pre_filter = VTM.get_chain('pre_filter_001') router.set_local_redirect_chain(pre_filter) sender1 = BM.get_iface_for_port('bridge-000-001', 2) service1 = BM.get_iface_for_port('router-000-001', 2) service2 = BM.get_iface_for_port('router-000-001', 3) # setup extra parameters in namespaces service1.execute("ip a add 172.16.1.254/32 dev lo") service1.execute("arp -s 169.254.1.1 aa:bb:cc:00:11:33") service2.execute("ip a add 172.16.1.254/32 dev lo") service2.execute("arp -s 169.254.2.1 aa:bb:cc:00:11:33") # assert udp traffic goes to correct node f1 = async_assert_that(service1, receives('dst host 172.16.1.254 and udp port 500', within_sec(5))) f2 = async_assert_that(service2, should_NOT_receive('dst host 172.16.1.2 and udp port 500', within_sec(5))) f3 = sender1.send_udp('aa:bb:cc:00:00:22', '172.16.1.254', 41, src_port=500, dst_port=500) wait_on_futures([f1, f2, f3]) # assert udp traffic is returned f1 = async_assert_that(sender1, receives('dst host 172.16.1.1 and udp port 500', within_sec(5))) f2 = service1.send_udp('aa:bb:cc:00:11:22', '172.16.1.1', 41, src_port=500, dst_port=500, src_hw='aa:bb:cc:00:00:22', src_ipv4='172.16.1.254') wait_on_futures([f1, f2]) # assert tcp traffic goes both ways try: service2.execute("sh -c \"echo foobar | nc -l 1500\"") f1 = async_assert_that(service2, receives('dst host 172.16.1.254 and tcp port 1500', within_sec(5))) f2 = async_assert_that(sender1, receives('dst host 172.16.1.1 and tcp port 1500', within_sec(5))) f3 = async_assert_that(service1, should_NOT_receive('dst host 172.16.1.254', within_sec(5))) sender1.execute("sh -c \"echo foobar | nc 172.16.1.254 1500\"") wait_on_futures([f1, f2, f3]) finally: service2.execute("pkill nc")