self.logger.error(ppp("Unexpected or invalid packet:", packet))
raise
+ def test_hairpinning_avoid_inf_loop(self):
+ """ NAT44 hairpinning - 1:1 NAPT avoid infinite loop """
+
+ host = self.pg0.remote_hosts[0]
+ server = self.pg0.remote_hosts[1]
+ host_in_port = 1234
+ host_out_port = 0
+ server_in_port = 5678
+ server_out_port = 8765
+
+ self.nat44_add_address(self.nat_addr)
+ flags = self.config_flags.NAT_IS_INSIDE
+ self.vapi.nat44_interface_add_del_feature(
+ sw_if_index=self.pg0.sw_if_index,
+ flags=flags, is_add=1)
+ self.vapi.nat44_interface_add_del_feature(
+ sw_if_index=self.pg1.sw_if_index,
+ is_add=1)
+
+ # add static mapping for server
+ self.nat44_add_static_mapping(server.ip4, self.nat_addr,
+ server_in_port, server_out_port,
+ proto=IP_PROTOS.tcp)
+
+ # add another static mapping that maps pg0.local_ip4 address to itself
+ self.nat44_add_static_mapping(self.pg0.local_ip4, self.pg0.local_ip4)
+
+ # send packet from host to VPP (the packet should get dropped)
+ p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
+ IP(src=host.ip4, dst=self.pg0.local_ip4) /
+ TCP(sport=host_in_port, dport=server_out_port))
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ # Here VPP used to crash due to an infinite loop
+
+ cnt = self.statistics.get_counter('/nat44/hairpinning')[0]
+ # send packet from host to server
+ p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
+ IP(src=host.ip4, dst=self.nat_addr) /
+ TCP(sport=host_in_port, dport=server_out_port))
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg0.get_capture(1)
+ p = capture[0]
+ try:
+ ip = p[IP]
+ tcp = p[TCP]
+ self.assertEqual(ip.src, self.nat_addr)
+ self.assertEqual(ip.dst, server.ip4)
+ self.assertNotEqual(tcp.sport, host_in_port)
+ self.assertEqual(tcp.dport, server_in_port)
+ self.assert_packet_checksums_valid(p)
+ host_out_port = tcp.sport
+ except:
+ self.logger.error(ppp("Unexpected or invalid packet:", p))
+ raise
+
+ after = self.statistics.get_counter('/nat44/hairpinning')[0]
+ if_idx = self.pg0.sw_if_index
+ self.assertEqual(after[if_idx] - cnt[if_idx], 1)
+
+ # send reply from server to host
+ p = (Ether(src=server.mac, dst=self.pg0.local_mac) /
+ IP(src=server.ip4, dst=self.nat_addr) /
+ TCP(sport=server_in_port, dport=host_out_port))
+ self.pg0.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ capture = self.pg0.get_capture(1)
+ p = capture[0]
+ try:
+ ip = p[IP]
+ tcp = p[TCP]
+ self.assertEqual(ip.src, self.nat_addr)
+ self.assertEqual(ip.dst, host.ip4)
+ self.assertEqual(tcp.sport, server_out_port)
+ self.assertEqual(tcp.dport, host_in_port)
+ self.assert_packet_checksums_valid(p)
+ except:
+ self.logger.error(ppp("Unexpected or invalid packet:", p))
+ raise
+
+ after = self.statistics.get_counter('/nat44/hairpinning')[0]
+ if_idx = self.pg0.sw_if_index
+ self.assertEqual(after[if_idx] - cnt[if_idx], 2)
+
def test_interface_addr(self):
""" Acquire NAT44 addresses from interface """
self.vapi.nat44_add_del_interface_addr(
data = ipfix.decode_data_set(p.getlayer(Set))
self.verify_ipfix_addr_exhausted(data)
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
def test_ipfix_max_sessions(self):
""" IPFIX logging maximum session entries exceeded """
self.nat44_add_address(self.nat_addr)
self.pg1.resolve_arp()
self.pg2.resolve_arp()
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
- def test_session_timeout(self):
- """ NAT44 session timeouts """
- self.nat44_add_address(self.nat_addr)
- flags = self.config_flags.NAT_IS_INSIDE
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg0.sw_if_index,
- flags=flags, is_add=1)
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg1.sw_if_index,
- is_add=1)
- self.vapi.nat_set_timeouts(udp=5, tcp_established=7440,
- tcp_transitory=240, icmp=60)
-
- max_sessions = 1000
- pkts = []
- for i in range(0, max_sessions):
- src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
- p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
- IP(src=src, dst=self.pg1.remote_ip4) /
- UDP(sport=1025, dport=53))
- pkts.append(p)
- self.pg0.add_stream(pkts)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- self.pg1.get_capture(max_sessions)
-
- sleep(6)
-
- pkts = []
- for i in range(0, max_sessions):
- src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
- p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
- IP(src=src, dst=self.pg1.remote_ip4) /
- UDP(sport=1026, dport=53))
- pkts.append(p)
- self.pg0.add_stream(pkts)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- self.pg1.get_capture(max_sessions)
-
- nsessions = 0
- users = self.vapi.nat44_user_dump()
- for user in users:
- nsessions = nsessions + user.nsessions
- self.assertLess(nsessions, 2 * max_sessions)
-
def test_mss_clamping(self):
""" TCP MSS clamping """
self.nat44_add_address(self.nat_addr)
# Negotiated MSS value smaller than configured - unchanged
self.verify_mss_value(capture[0], 1400)
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
def test_ha_send(self):
""" Send HA session synchronization events (active) """
- self.nat44_add_address(self.nat_addr)
flags = self.config_flags.NAT_IS_INSIDE
self.vapi.nat44_interface_add_del_feature(
sw_if_index=self.pg0.sw_if_index,
self.vapi.nat44_interface_add_del_feature(
sw_if_index=self.pg1.sw_if_index,
is_add=1)
+ self.nat44_add_address(self.nat_addr)
+
self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
port=12345,
path_mtu=512)
sessions = self.vapi.nat44_user_session_dump(server.ip4, 0)
self.assertEqual(len(sessions), 0)
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
def test_static_lb_multi_clients(self):
""" NAT44 local service load balancing - multiple clients"""
'probability': 10,
'vrf_id': 0}]
- self.nat44_add_address(self.nat_addr)
- self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
- external_addr=external_addr,
- external_port=external_port,
- protocol=IP_PROTOS.tcp,
- local_num=len(locals),
- locals=locals)
flags = self.config_flags.NAT_IS_INSIDE
self.vapi.nat44_interface_add_del_feature(
sw_if_index=self.pg0.sw_if_index,
sw_if_index=self.pg1.sw_if_index,
is_add=1)
+ self.nat44_add_address(self.nat_addr)
+ self.vapi.nat44_add_del_lb_static_mapping(is_add=1,
+ external_addr=external_addr,
+ external_port=external_port,
+ protocol=IP_PROTOS.tcp,
+ local_num=len(locals),
+ locals=locals)
+
server1_n = 0
server2_n = 0
clients = ip4_range(self.pg1.remote_ip4, 10, 50)
def test_tcp_close(self):
""" Close TCP session from inside network - output feature """
+ old_timeouts = self.vapi.nat_get_timeouts()
+ new_transitory = 2
+ self.vapi.nat_set_timeouts(
+ udp=old_timeouts.udp,
+ tcp_established=old_timeouts.tcp_established,
+ icmp=old_timeouts.icmp,
+ tcp_transitory=new_transitory)
+
self.vapi.nat44_forwarding_enable_disable(enable=1)
self.nat44_add_address(self.pg1.local_ip4)
twice_nat_addr = '10.0.1.3'
self.pg_start()
self.pg1.get_capture(1)
- sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4,
- 0)
+ # session now in transitory timeout
+ # try SYN packet out->in - should be dropped
+ p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
+ IP(src=self.pg1.remote_ip4, dst=service_ip) /
+ TCP(sport=33898, dport=80, flags="S"))
+ self.pg1.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ self.sleep(new_transitory, "wait for transitory timeout")
+ self.pg0.assert_nothing_captured(0)
+
+ # session should still exist
+ sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
+ self.assertEqual(len(sessions) - start_sessnum, 1)
+
+ # send FIN+ACK packet out -> in - will cause session to be wiped
+ # but won't create a new session
+ p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
+ IP(src=self.pg1.remote_ip4, dst=service_ip) /
+ TCP(sport=33898, dport=80, flags="FA", seq=300, ack=101))
+ self.pg1.add_stream(p)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
self.assertEqual(len(sessions) - start_sessnum, 0)
+ self.pg0.assert_nothing_captured(0)
def test_tcp_session_close_in(self):
""" Close TCP session from inside network """
self.logger.error(ppp("Unexpected or invalid packet:", p))
raise
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
- def test_session_timeout(self):
- """ NAT44 session timeouts """
- self.nat44_add_address(self.nat_addr)
- flags = self.config_flags.NAT_IS_INSIDE
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg0.sw_if_index,
- flags=flags, is_add=1)
- self.vapi.nat44_interface_add_del_feature(
- sw_if_index=self.pg1.sw_if_index,
- is_add=1)
- self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
- tcp_transitory=240, icmp=5)
-
- max_sessions = 1000
- pkts = []
- for i in range(0, max_sessions):
- src = "10.10.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
- p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
- IP(src=src, dst=self.pg1.remote_ip4) /
- ICMP(id=1025, type='echo-request'))
- pkts.append(p)
- self.pg0.add_stream(pkts)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- self.pg1.get_capture(max_sessions)
-
- sleep(10)
-
- pkts = []
- for i in range(0, max_sessions):
- src = "10.11.%u.%u" % ((i & 0xFF00) >> 8, i & 0xFF)
- p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
- IP(src=src, dst=self.pg1.remote_ip4) /
- ICMP(id=1026, type='echo-request'))
- pkts.append(p)
- self.pg0.add_stream(pkts)
- self.pg_enable_capture(self.pg_interfaces)
- self.pg_start()
- self.pg1.get_capture(max_sessions)
-
- nsessions = 0
- users = self.vapi.nat44_user_dump()
- for user in users:
- nsessions = nsessions + user.nsessions
- self.assertLess(nsessions, 2 * max_sessions)
-
- @unittest.skipUnless(running_extended_tests, "part of extended tests")
def test_session_rst_timeout(self):
""" NAT44 session RST timeouts """
self.nat44_add_address(self.nat_addr)