blob: c3279655420387d56f517b56c24982c062b31507 [file] [log] [blame]
Filip Varga1f360232020-09-14 11:20:16 +02001#!/usr/bin/env python3
2
3import ipaddress
4import random
5import socket
6import struct
7import unittest
8from io import BytesIO
Filip Varga1f360232020-09-14 11:20:16 +02009
10import scapy.compat
Klement Sekerab23ffd72021-05-31 16:08:53 +020011from config import config
Dave Wallace8800f732023-08-31 00:47:44 -040012from framework import VppTestCase
13from asfframework import (
14 tag_fixme_vpp_workers,
15 tag_fixme_ubuntu2204,
16 is_distro_ubuntu2204,
17 VppTestRunner,
18)
Filip Varga1f360232020-09-14 11:20:16 +020019from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
20from scapy.data import IP_PROTOS
21from scapy.layers.inet import IP, TCP, UDP, ICMP
22from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
23from scapy.layers.inet6 import ICMPv6DestUnreach, IPerror6, IPv6ExtHdrFragment
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020024from scapy.layers.inet6 import (
25 IPv6,
26 ICMPv6EchoRequest,
27 ICMPv6EchoReply,
28 ICMPv6ND_NS,
29 ICMPv6ND_NA,
30 ICMPv6NDOptDstLLAddr,
31 fragment6,
32)
Filip Varga1f360232020-09-14 11:20:16 +020033from scapy.layers.l2 import Ether, GRE
34from scapy.packet import Raw
35from syslog_rfc5424_parser import SyslogMessage, ParseError
36from syslog_rfc5424_parser.constants import SyslogSeverity
37from util import ppc, ppp
38from vpp_papi import VppEnum
39
40
Andrew Yourtchenko8dc0d482021-01-29 13:17:19 +000041@tag_fixme_vpp_workers
Dave Wallace670724c2022-09-20 21:52:18 -040042@tag_fixme_ubuntu2204
Filip Varga1f360232020-09-14 11:20:16 +020043class TestNAT64(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020044 """NAT64 Test Cases"""
Filip Varga1f360232020-09-14 11:20:16 +020045
46 @property
47 def SYSLOG_SEVERITY(self):
48 return VppEnum.vl_api_syslog_severity_t
49
50 @property
51 def config_flags(self):
52 return VppEnum.vl_api_nat_config_flags_t
53
54 @classmethod
55 def setUpClass(cls):
56 super(TestNAT64, cls).setUpClass()
57
58 cls.tcp_port_in = 6303
59 cls.tcp_port_out = 6303
60 cls.udp_port_in = 6304
61 cls.udp_port_out = 6304
62 cls.icmp_id_in = 6305
63 cls.icmp_id_out = 6305
64 cls.tcp_external_port = 80
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020065 cls.nat_addr = "10.0.0.3"
Filip Varga1f360232020-09-14 11:20:16 +020066 cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
67 cls.vrf1_id = 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020068 cls.vrf1_nat_addr = "10.0.10.3"
Filip Varga1f360232020-09-14 11:20:16 +020069 cls.ipfix_src_port = 4739
70 cls.ipfix_domain_id = 1
71
72 cls.create_pg_interfaces(range(6))
73 cls.ip6_interfaces = list(cls.pg_interfaces[0:1])
74 cls.ip6_interfaces.append(cls.pg_interfaces[2])
75 cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
76
BenoƮt Ganneff570d32024-04-16 09:36:05 +020077 cls.vapi.ip_table_add_del_v2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020078 is_add=1, table={"table_id": cls.vrf1_id, "is_ip6": 1}
79 )
Filip Varga1f360232020-09-14 11:20:16 +020080
81 cls.pg_interfaces[2].set_table_ip6(cls.vrf1_id)
82
83 cls.pg0.generate_remote_hosts(2)
84
85 for i in cls.ip6_interfaces:
86 i.admin_up()
87 i.config_ip6()
88 i.configure_ipv6_neighbors()
89
90 for i in cls.ip4_interfaces:
91 i.admin_up()
92 i.config_ip4()
93 i.resolve_arp()
94
95 cls.pg3.admin_up()
96 cls.pg3.config_ip4()
97 cls.pg3.resolve_arp()
98 cls.pg3.config_ip6()
99 cls.pg3.configure_ipv6_neighbors()
100
101 cls.pg5.admin_up()
102 cls.pg5.config_ip6()
103
104 @classmethod
105 def tearDownClass(cls):
106 super(TestNAT64, cls).tearDownClass()
107
108 def setUp(self):
109 super(TestNAT64, self).setUp()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200110 self.vapi.nat64_plugin_enable_disable(enable=1, bib_buckets=128, st_buckets=256)
Filip Varga1f360232020-09-14 11:20:16 +0200111
112 def tearDown(self):
113 super(TestNAT64, self).tearDown()
114 if not self.vpp_dead:
115 self.vapi.nat64_plugin_enable_disable(enable=0)
116
117 def show_commands_at_teardown(self):
118 self.logger.info(self.vapi.cli("show nat64 pool"))
119 self.logger.info(self.vapi.cli("show nat64 interfaces"))
120 self.logger.info(self.vapi.cli("show nat64 prefix"))
121 self.logger.info(self.vapi.cli("show nat64 bib all"))
122 self.logger.info(self.vapi.cli("show nat64 session table all"))
123
124 def create_stream_in_ip6(self, in_if, out_if, hlim=64, pref=None, plen=0):
125 """
126 Create IPv6 packet stream for inside network
127
128 :param in_if: Inside interface
129 :param out_if: Outside interface
130 :param ttl: Hop Limit of generated packets
131 :param pref: NAT64 prefix
132 :param plen: NAT64 prefix length
133 """
134 pkts = []
135 if pref is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200136 dst = "".join(["64:ff9b::", out_if.remote_ip4])
Filip Varga1f360232020-09-14 11:20:16 +0200137 else:
138 dst = self.compose_ip6(out_if.remote_ip4, pref, plen)
139
140 # TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200141 p = (
142 Ether(dst=in_if.local_mac, src=in_if.remote_mac)
143 / IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim)
144 / TCP(sport=self.tcp_port_in, dport=20)
145 )
Filip Varga1f360232020-09-14 11:20:16 +0200146 pkts.append(p)
147
148 # UDP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 p = (
150 Ether(dst=in_if.local_mac, src=in_if.remote_mac)
151 / IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim)
152 / UDP(sport=self.udp_port_in, dport=20)
153 )
Filip Varga1f360232020-09-14 11:20:16 +0200154 pkts.append(p)
155
156 # ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200157 p = (
158 Ether(dst=in_if.local_mac, src=in_if.remote_mac)
159 / IPv6(src=in_if.remote_ip6, dst=dst, hlim=hlim)
160 / ICMPv6EchoRequest(id=self.icmp_id_in)
161 )
Filip Varga1f360232020-09-14 11:20:16 +0200162 pkts.append(p)
163
164 return pkts
165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 def create_stream_out(self, out_if, dst_ip=None, ttl=64, use_inside_ports=False):
Filip Varga1f360232020-09-14 11:20:16 +0200167 """
168 Create packet stream for outside network
169
170 :param out_if: Outside interface
171 :param dst_ip: Destination IP address (Default use global NAT address)
172 :param ttl: TTL of generated packets
173 :param use_inside_ports: Use inside NAT ports as destination ports
174 instead of outside ports
175 """
176 if dst_ip is None:
177 dst_ip = self.nat_addr
178 if not use_inside_ports:
179 tcp_port = self.tcp_port_out
180 udp_port = self.udp_port_out
181 icmp_id = self.icmp_id_out
182 else:
183 tcp_port = self.tcp_port_in
184 udp_port = self.udp_port_in
185 icmp_id = self.icmp_id_in
186 pkts = []
187 # TCP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 p = (
189 Ether(dst=out_if.local_mac, src=out_if.remote_mac)
190 / IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl)
191 / TCP(dport=tcp_port, sport=20)
192 )
Filip Varga1f360232020-09-14 11:20:16 +0200193 pkts.extend([p, p])
194
195 # UDP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200196 p = (
197 Ether(dst=out_if.local_mac, src=out_if.remote_mac)
198 / IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl)
199 / UDP(dport=udp_port, sport=20)
200 )
Filip Varga1f360232020-09-14 11:20:16 +0200201 pkts.append(p)
202
203 # ICMP
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200204 p = (
205 Ether(dst=out_if.local_mac, src=out_if.remote_mac)
206 / IP(src=out_if.remote_ip4, dst=dst_ip, ttl=ttl)
207 / ICMP(id=icmp_id, type="echo-reply")
208 )
Filip Varga1f360232020-09-14 11:20:16 +0200209 pkts.append(p)
210
211 return pkts
212
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200213 def verify_capture_out(
214 self,
215 capture,
216 nat_ip=None,
217 same_port=False,
218 dst_ip=None,
219 is_ip6=False,
220 ignore_port=False,
221 ):
Filip Varga1f360232020-09-14 11:20:16 +0200222 """
223 Verify captured packets on outside network
224
225 :param capture: Captured packets
226 :param nat_ip: Translated IP address (Default use global NAT address)
227 :param same_port: Source port number is not translated (Default False)
228 :param dst_ip: Destination IP address (Default do not verify)
229 :param is_ip6: If L3 protocol is IPv6 (Default False)
230 """
231 if is_ip6:
232 IP46 = IPv6
233 ICMP46 = ICMPv6EchoRequest
234 else:
235 IP46 = IP
236 ICMP46 = ICMP
237 if nat_ip is None:
238 nat_ip = self.nat_addr
239 for packet in capture:
240 try:
241 if not is_ip6:
242 self.assert_packet_checksums_valid(packet)
243 self.assertEqual(packet[IP46].src, nat_ip)
244 if dst_ip is not None:
245 self.assertEqual(packet[IP46].dst, dst_ip)
246 if packet.haslayer(TCP):
247 if not ignore_port:
248 if same_port:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200249 self.assertEqual(packet[TCP].sport, self.tcp_port_in)
Filip Varga1f360232020-09-14 11:20:16 +0200250 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200251 self.assertNotEqual(packet[TCP].sport, self.tcp_port_in)
Filip Varga1f360232020-09-14 11:20:16 +0200252 self.tcp_port_out = packet[TCP].sport
253 self.assert_packet_checksums_valid(packet)
254 elif packet.haslayer(UDP):
255 if not ignore_port:
256 if same_port:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 self.assertEqual(packet[UDP].sport, self.udp_port_in)
Filip Varga1f360232020-09-14 11:20:16 +0200258 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200259 self.assertNotEqual(packet[UDP].sport, self.udp_port_in)
Filip Varga1f360232020-09-14 11:20:16 +0200260 self.udp_port_out = packet[UDP].sport
261 else:
262 if not ignore_port:
263 if same_port:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200264 self.assertEqual(packet[ICMP46].id, self.icmp_id_in)
Filip Varga1f360232020-09-14 11:20:16 +0200265 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200266 self.assertNotEqual(packet[ICMP46].id, self.icmp_id_in)
Filip Varga1f360232020-09-14 11:20:16 +0200267 self.icmp_id_out = packet[ICMP46].id
268 self.assert_packet_checksums_valid(packet)
269 except:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200270 self.logger.error(
271 ppp("Unexpected or invalid packet (outside network):", packet)
272 )
Filip Varga1f360232020-09-14 11:20:16 +0200273 raise
274
275 def verify_capture_in_ip6(self, capture, src_ip, dst_ip):
276 """
277 Verify captured IPv6 packets on inside network
278
279 :param capture: Captured packets
280 :param src_ip: Source IP
281 :param dst_ip: Destination IP address
282 """
283 for packet in capture:
284 try:
285 self.assertEqual(packet[IPv6].src, src_ip)
286 self.assertEqual(packet[IPv6].dst, dst_ip)
287 self.assert_packet_checksums_valid(packet)
288 if packet.haslayer(TCP):
289 self.assertEqual(packet[TCP].dport, self.tcp_port_in)
290 elif packet.haslayer(UDP):
291 self.assertEqual(packet[UDP].dport, self.udp_port_in)
292 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200293 self.assertEqual(packet[ICMPv6EchoReply].id, self.icmp_id_in)
Filip Varga1f360232020-09-14 11:20:16 +0200294 except:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200295 self.logger.error(
296 ppp("Unexpected or invalid packet (inside network):", packet)
297 )
Filip Varga1f360232020-09-14 11:20:16 +0200298 raise
299
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200300 def create_stream_frag(
301 self, src_if, dst, sport, dport, data, proto=IP_PROTOS.tcp, echo_reply=False
302 ):
Filip Varga1f360232020-09-14 11:20:16 +0200303 """
304 Create fragmented packet stream
305
306 :param src_if: Source interface
307 :param dst: Destination IPv4 address
308 :param sport: Source port
309 :param dport: Destination port
310 :param data: Payload data
311 :param proto: protocol (TCP, UDP, ICMP)
312 :param echo_reply: use echo_reply if protocol is ICMP
313 :returns: Fragments
314 """
315 if proto == IP_PROTOS.tcp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 p = (
317 IP(src=src_if.remote_ip4, dst=dst)
318 / TCP(sport=sport, dport=dport)
319 / Raw(data)
320 )
Filip Varga1f360232020-09-14 11:20:16 +0200321 p = p.__class__(scapy.compat.raw(p))
322 chksum = p[TCP].chksum
323 proto_header = TCP(sport=sport, dport=dport, chksum=chksum)
324 elif proto == IP_PROTOS.udp:
325 proto_header = UDP(sport=sport, dport=dport)
326 elif proto == IP_PROTOS.icmp:
327 if not echo_reply:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200328 proto_header = ICMP(id=sport, type="echo-request")
Filip Varga1f360232020-09-14 11:20:16 +0200329 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200330 proto_header = ICMP(id=sport, type="echo-reply")
Filip Varga1f360232020-09-14 11:20:16 +0200331 else:
332 raise Exception("Unsupported protocol")
333 id = random.randint(0, 65535)
334 pkts = []
335 if proto == IP_PROTOS.tcp:
336 raw = Raw(data[0:4])
337 else:
338 raw = Raw(data[0:16])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200339 p = (
340 Ether(src=src_if.remote_mac, dst=src_if.local_mac)
341 / IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=0, id=id)
342 / proto_header
343 / raw
344 )
Filip Varga1f360232020-09-14 11:20:16 +0200345 pkts.append(p)
346 if proto == IP_PROTOS.tcp:
347 raw = Raw(data[4:20])
348 else:
349 raw = Raw(data[16:32])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200350 p = (
351 Ether(src=src_if.remote_mac, dst=src_if.local_mac)
352 / IP(src=src_if.remote_ip4, dst=dst, flags="MF", frag=3, id=id, proto=proto)
353 / raw
354 )
Filip Varga1f360232020-09-14 11:20:16 +0200355 pkts.append(p)
356 if proto == IP_PROTOS.tcp:
357 raw = Raw(data[20:])
358 else:
359 raw = Raw(data[32:])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200360 p = (
361 Ether(src=src_if.remote_mac, dst=src_if.local_mac)
362 / IP(src=src_if.remote_ip4, dst=dst, frag=5, proto=proto, id=id)
363 / raw
364 )
Filip Varga1f360232020-09-14 11:20:16 +0200365 pkts.append(p)
366 return pkts
367
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200368 def create_stream_frag_ip6(
369 self, src_if, dst, sport, dport, data, pref=None, plen=0, frag_size=128
370 ):
Filip Varga1f360232020-09-14 11:20:16 +0200371 """
372 Create fragmented packet stream
373
374 :param src_if: Source interface
375 :param dst: Destination IPv4 address
376 :param sport: Source TCP port
377 :param dport: Destination TCP port
378 :param data: Payload data
379 :param pref: NAT64 prefix
380 :param plen: NAT64 prefix length
381 :param fragsize: size of fragments
382 :returns: Fragments
383 """
384 if pref is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 dst_ip6 = "".join(["64:ff9b::", dst])
Filip Varga1f360232020-09-14 11:20:16 +0200386 else:
387 dst_ip6 = self.compose_ip6(dst, pref, plen)
388
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200389 p = (
390 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
391 / IPv6(src=src_if.remote_ip6, dst=dst_ip6)
392 / IPv6ExtHdrFragment(id=random.randint(0, 65535))
393 / TCP(sport=sport, dport=dport)
394 / Raw(data)
395 )
Filip Varga1f360232020-09-14 11:20:16 +0200396
397 return fragment6(p, frag_size)
398
399 def reass_frags_and_verify(self, frags, src, dst):
400 """
401 Reassemble and verify fragmented packet
402
403 :param frags: Captured fragments
404 :param src: Source IPv4 address to verify
405 :param dst: Destination IPv4 address to verify
406
407 :returns: Reassembled IPv4 packet
408 """
409 buffer = BytesIO()
410 for p in frags:
411 self.assertEqual(p[IP].src, src)
412 self.assertEqual(p[IP].dst, dst)
413 self.assert_ip_checksum_valid(p)
414 buffer.seek(p[IP].frag * 8)
415 buffer.write(bytes(p[IP].payload))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200416 ip = IP(src=frags[0][IP].src, dst=frags[0][IP].dst, proto=frags[0][IP].proto)
Filip Varga1f360232020-09-14 11:20:16 +0200417 if ip.proto == IP_PROTOS.tcp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200418 p = ip / TCP(buffer.getvalue())
Filip Varga1f360232020-09-14 11:20:16 +0200419 self.logger.debug(ppp("Reassembled:", p))
420 self.assert_tcp_checksum_valid(p)
421 elif ip.proto == IP_PROTOS.udp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200422 p = ip / UDP(buffer.getvalue()[:8]) / Raw(buffer.getvalue()[8:])
Filip Varga1f360232020-09-14 11:20:16 +0200423 elif ip.proto == IP_PROTOS.icmp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200424 p = ip / ICMP(buffer.getvalue())
Filip Varga1f360232020-09-14 11:20:16 +0200425 return p
426
427 def reass_frags_and_verify_ip6(self, frags, src, dst):
428 """
429 Reassemble and verify fragmented packet
430
431 :param frags: Captured fragments
432 :param src: Source IPv6 address to verify
433 :param dst: Destination IPv6 address to verify
434
435 :returns: Reassembled IPv6 packet
436 """
437 buffer = BytesIO()
438 for p in frags:
439 self.assertEqual(p[IPv6].src, src)
440 self.assertEqual(p[IPv6].dst, dst)
441 buffer.seek(p[IPv6ExtHdrFragment].offset * 8)
442 buffer.write(bytes(p[IPv6ExtHdrFragment].payload))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200443 ip = IPv6(
444 src=frags[0][IPv6].src,
445 dst=frags[0][IPv6].dst,
446 nh=frags[0][IPv6ExtHdrFragment].nh,
447 )
Filip Varga1f360232020-09-14 11:20:16 +0200448 if ip.nh == IP_PROTOS.tcp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200449 p = ip / TCP(buffer.getvalue())
Filip Varga1f360232020-09-14 11:20:16 +0200450 elif ip.nh == IP_PROTOS.udp:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200451 p = ip / UDP(buffer.getvalue())
Filip Varga1f360232020-09-14 11:20:16 +0200452 self.logger.debug(ppp("Reassembled:", p))
453 self.assert_packet_checksums_valid(p)
454 return p
455
Filip Varga1f360232020-09-14 11:20:16 +0200456 def verify_ipfix_max_bibs(self, data, limit):
457 """
458 Verify IPFIX maximum BIB entries exceeded event
459
460 :param data: Decoded IPFIX data records
461 :param limit: Number of maximum BIB entries that can be created.
462 """
463 self.assertEqual(1, len(data))
464 record = data[0]
465 # natEvent
466 self.assertEqual(scapy.compat.orb(record[230]), 13)
467 # natQuotaExceededEvent
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +0500468 self.assertEqual(struct.pack("!I", 2), record[466])
Filip Varga1f360232020-09-14 11:20:16 +0200469 # maxBIBEntries
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +0500470 self.assertEqual(struct.pack("!I", limit), record[472])
471 return len(data)
Filip Varga1f360232020-09-14 11:20:16 +0200472
Filip Varga1f360232020-09-14 11:20:16 +0200473 def verify_ipfix_bib(self, data, is_create, src_addr):
474 """
475 Verify IPFIX NAT64 BIB create and delete events
476
477 :param data: Decoded IPFIX data records
478 :param is_create: Create event if nonzero value otherwise delete event
479 :param src_addr: IPv6 source address
480 """
481 self.assertEqual(1, len(data))
482 record = data[0]
483 # natEvent
484 if is_create:
485 self.assertEqual(scapy.compat.orb(record[230]), 10)
486 else:
487 self.assertEqual(scapy.compat.orb(record[230]), 11)
488 # sourceIPv6Address
489 self.assertEqual(src_addr, str(ipaddress.IPv6Address(record[27])))
490 # postNATSourceIPv4Address
491 self.assertEqual(self.nat_addr_n, record[225])
492 # protocolIdentifier
493 self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
494 # ingressVRFID
495 self.assertEqual(struct.pack("!I", 0), record[234])
496 # sourceTransportPort
497 self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
498 # postNAPTSourceTransportPort
499 self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
500
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200501 def verify_ipfix_nat64_ses(self, data, is_create, src_addr, dst_addr, dst_port):
Filip Varga1f360232020-09-14 11:20:16 +0200502 """
503 Verify IPFIX NAT64 session create and delete events
504
505 :param data: Decoded IPFIX data records
506 :param is_create: Create event if nonzero value otherwise delete event
507 :param src_addr: IPv6 source address
508 :param dst_addr: IPv4 destination address
509 :param dst_port: destination TCP port
510 """
511 self.assertEqual(1, len(data))
512 record = data[0]
513 # natEvent
514 if is_create:
515 self.assertEqual(scapy.compat.orb(record[230]), 6)
516 else:
517 self.assertEqual(scapy.compat.orb(record[230]), 7)
518 # sourceIPv6Address
519 self.assertEqual(src_addr, str(ipaddress.IPv6Address(record[27])))
520 # destinationIPv6Address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 self.assertEqual(
522 socket.inet_pton(
523 socket.AF_INET6, self.compose_ip6(dst_addr, "64:ff9b::", 96)
524 ),
525 record[28],
526 )
Filip Varga1f360232020-09-14 11:20:16 +0200527 # postNATSourceIPv4Address
528 self.assertEqual(self.nat_addr_n, record[225])
529 # postNATDestinationIPv4Address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200530 self.assertEqual(socket.inet_pton(socket.AF_INET, dst_addr), record[226])
Filip Varga1f360232020-09-14 11:20:16 +0200531 # protocolIdentifier
532 self.assertEqual(IP_PROTOS.tcp, scapy.compat.orb(record[4]))
533 # ingressVRFID
534 self.assertEqual(struct.pack("!I", 0), record[234])
535 # sourceTransportPort
536 self.assertEqual(struct.pack("!H", self.tcp_port_in), record[7])
537 # postNAPTSourceTransportPort
538 self.assertEqual(struct.pack("!H", self.tcp_port_out), record[227])
539 # destinationTransportPort
540 self.assertEqual(struct.pack("!H", dst_port), record[11])
541 # postNAPTDestinationTransportPort
542 self.assertEqual(struct.pack("!H", dst_port), record[228])
543
544 def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200545 message = data.decode("utf-8")
Filip Varga1f360232020-09-14 11:20:16 +0200546 try:
547 message = SyslogMessage.parse(message)
548 except ParseError as e:
549 self.logger.error(e)
550 raise
551 else:
552 self.assertEqual(message.severity, SyslogSeverity.info)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200553 self.assertEqual(message.appname, "NAT")
554 self.assertEqual(message.msgid, "SADD" if is_add else "SDEL")
555 sd_params = message.sd.get("nsess")
Filip Varga1f360232020-09-14 11:20:16 +0200556 self.assertTrue(sd_params is not None)
557 if is_ip6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 self.assertEqual(sd_params.get("IATYP"), "IPv6")
559 self.assertEqual(sd_params.get("ISADDR"), self.pg0.remote_ip6)
Filip Varga1f360232020-09-14 11:20:16 +0200560 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200561 self.assertEqual(sd_params.get("IATYP"), "IPv4")
562 self.assertEqual(sd_params.get("ISADDR"), self.pg0.remote_ip4)
563 self.assertTrue(sd_params.get("SSUBIX") is not None)
564 self.assertEqual(sd_params.get("ISPORT"), "%d" % self.tcp_port_in)
565 self.assertEqual(sd_params.get("XATYP"), "IPv4")
566 self.assertEqual(sd_params.get("XSADDR"), self.nat_addr)
567 self.assertEqual(sd_params.get("XSPORT"), "%d" % self.tcp_port_out)
568 self.assertEqual(sd_params.get("PROTO"), "%d" % IP_PROTOS.tcp)
569 self.assertEqual(sd_params.get("SVLAN"), "0")
570 self.assertEqual(sd_params.get("XDADDR"), self.pg1.remote_ip4)
571 self.assertEqual(sd_params.get("XDPORT"), "%d" % self.tcp_external_port)
Filip Varga1f360232020-09-14 11:20:16 +0200572
573 def compose_ip6(self, ip4, pref, plen):
574 """
575 Compose IPv4-embedded IPv6 addresses
576
577 :param ip4: IPv4 address
578 :param pref: IPv6 prefix
579 :param plen: IPv6 prefix length
580 :returns: IPv4-embedded IPv6 addresses
581 """
582 pref_n = list(socket.inet_pton(socket.AF_INET6, pref))
583 ip4_n = list(socket.inet_pton(socket.AF_INET, ip4))
584 if plen == 32:
585 pref_n[4] = ip4_n[0]
586 pref_n[5] = ip4_n[1]
587 pref_n[6] = ip4_n[2]
588 pref_n[7] = ip4_n[3]
589 elif plen == 40:
590 pref_n[5] = ip4_n[0]
591 pref_n[6] = ip4_n[1]
592 pref_n[7] = ip4_n[2]
593 pref_n[9] = ip4_n[3]
594 elif plen == 48:
595 pref_n[6] = ip4_n[0]
596 pref_n[7] = ip4_n[1]
597 pref_n[9] = ip4_n[2]
598 pref_n[10] = ip4_n[3]
599 elif plen == 56:
600 pref_n[7] = ip4_n[0]
601 pref_n[9] = ip4_n[1]
602 pref_n[10] = ip4_n[2]
603 pref_n[11] = ip4_n[3]
604 elif plen == 64:
605 pref_n[9] = ip4_n[0]
606 pref_n[10] = ip4_n[1]
607 pref_n[11] = ip4_n[2]
608 pref_n[12] = ip4_n[3]
609 elif plen == 96:
610 pref_n[12] = ip4_n[0]
611 pref_n[13] = ip4_n[1]
612 pref_n[14] = ip4_n[2]
613 pref_n[15] = ip4_n[3]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200614 packed_pref_n = b"".join([scapy.compat.chb(x) for x in pref_n])
Filip Varga1f360232020-09-14 11:20:16 +0200615 return socket.inet_ntop(socket.AF_INET6, packed_pref_n)
616
Filip Varga1f360232020-09-14 11:20:16 +0200617 def verify_ipfix_max_sessions(self, data, limit):
618 """
619 Verify IPFIX maximum session entries exceeded event
620
621 :param data: Decoded IPFIX data records
622 :param limit: Number of maximum session entries that can be created.
623 """
624 self.assertEqual(1, len(data))
625 record = data[0]
626 # natEvent
627 self.assertEqual(scapy.compat.orb(record[230]), 13)
628 # natQuotaExceededEvent
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +0500629 self.assertEqual(struct.pack("!I", 1), record[466])
Filip Varga1f360232020-09-14 11:20:16 +0200630 # maxSessionEntries
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +0500631 self.assertEqual(struct.pack("!I", limit), record[471])
632 return len(data)
Filip Varga1f360232020-09-14 11:20:16 +0200633
634 def test_nat64_inside_interface_handles_neighbor_advertisement(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200635 """NAT64 inside interface handles Neighbor Advertisement"""
Filip Varga1f360232020-09-14 11:20:16 +0200636
637 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 self.vapi.nat64_add_del_interface(
639 is_add=1, flags=flags, sw_if_index=self.pg5.sw_if_index
640 )
Filip Varga1f360232020-09-14 11:20:16 +0200641
642 # Try to send ping
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200643 ping = (
644 Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac)
645 / IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6)
646 / ICMPv6EchoRequest()
647 )
Filip Varga1f360232020-09-14 11:20:16 +0200648 pkts = [ping]
649 self.pg5.add_stream(pkts)
650 self.pg_enable_capture(self.pg_interfaces)
651 self.pg_start()
652
653 # Wait for Neighbor Solicitation
654 capture = self.pg5.get_capture(len(pkts))
655 packet = capture[0]
656 try:
Ole Troandbeb56d2023-10-13 09:19:45 +0200657 self.assertEqual(packet[IPv6].src, self.pg5.local_ip6_ll)
Filip Varga1f360232020-09-14 11:20:16 +0200658 self.assertEqual(packet.haslayer(ICMPv6ND_NS), 1)
659 tgt = packet[ICMPv6ND_NS].tgt
660 except:
661 self.logger.error(ppp("Unexpected or invalid packet:", packet))
662 raise
663
664 # Send Neighbor Advertisement
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200665 p = (
666 Ether(dst=self.pg5.local_mac, src=self.pg5.remote_mac)
667 / IPv6(src=self.pg5.remote_ip6, dst=self.pg5.local_ip6)
668 / ICMPv6ND_NA(tgt=tgt)
669 / ICMPv6NDOptDstLLAddr(lladdr=self.pg5.remote_mac)
670 )
Filip Varga1f360232020-09-14 11:20:16 +0200671 pkts = [p]
672 self.pg5.add_stream(pkts)
673 self.pg_enable_capture(self.pg_interfaces)
674 self.pg_start()
675
676 # Try to send ping again
677 pkts = [ping]
678 self.pg5.add_stream(pkts)
679 self.pg_enable_capture(self.pg_interfaces)
680 self.pg_start()
681
682 # Wait for ping reply
683 capture = self.pg5.get_capture(len(pkts))
684 packet = capture[0]
685 try:
686 self.assertEqual(packet[IPv6].src, self.pg5.local_ip6)
687 self.assertEqual(packet[IPv6].dst, self.pg5.remote_ip6)
688 self.assertEqual(packet.haslayer(ICMPv6EchoReply), 1)
689 except:
690 self.logger.error(ppp("Unexpected or invalid packet:", packet))
691 raise
692
693 def test_pool(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200694 """Add/delete address to NAT64 pool"""
695 nat_addr = "1.2.3.4"
Filip Varga1f360232020-09-14 11:20:16 +0200696
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200697 self.vapi.nat64_add_del_pool_addr_range(
698 start_addr=nat_addr, end_addr=nat_addr, vrf_id=0xFFFFFFFF, is_add=1
699 )
Filip Varga1f360232020-09-14 11:20:16 +0200700
701 addresses = self.vapi.nat64_pool_addr_dump()
702 self.assertEqual(len(addresses), 1)
703 self.assertEqual(str(addresses[0].address), nat_addr)
704
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200705 self.vapi.nat64_add_del_pool_addr_range(
706 start_addr=nat_addr, end_addr=nat_addr, vrf_id=0xFFFFFFFF, is_add=0
707 )
Filip Varga1f360232020-09-14 11:20:16 +0200708
709 addresses = self.vapi.nat64_pool_addr_dump()
710 self.assertEqual(len(addresses), 0)
711
712 def test_interface(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200713 """Enable/disable NAT64 feature on the interface"""
Filip Varga1f360232020-09-14 11:20:16 +0200714 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 self.vapi.nat64_add_del_interface(
716 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
717 )
718 self.vapi.nat64_add_del_interface(
719 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
720 )
Filip Varga1f360232020-09-14 11:20:16 +0200721
722 interfaces = self.vapi.nat64_interface_dump()
723 self.assertEqual(len(interfaces), 2)
724 pg0_found = False
725 pg1_found = False
726 for intf in interfaces:
727 if intf.sw_if_index == self.pg0.sw_if_index:
728 self.assertEqual(intf.flags, self.config_flags.NAT_IS_INSIDE)
729 pg0_found = True
730 elif intf.sw_if_index == self.pg1.sw_if_index:
731 self.assertEqual(intf.flags, self.config_flags.NAT_IS_OUTSIDE)
732 pg1_found = True
733 self.assertTrue(pg0_found)
734 self.assertTrue(pg1_found)
735
736 features = self.vapi.cli("show interface features pg0")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 self.assertIn("nat64-in2out", features)
Filip Varga1f360232020-09-14 11:20:16 +0200738 features = self.vapi.cli("show interface features pg1")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200739 self.assertIn("nat64-out2in", features)
Filip Varga1f360232020-09-14 11:20:16 +0200740
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200741 self.vapi.nat64_add_del_interface(
742 is_add=0, flags=flags, sw_if_index=self.pg0.sw_if_index
743 )
744 self.vapi.nat64_add_del_interface(
745 is_add=0, flags=flags, sw_if_index=self.pg1.sw_if_index
746 )
Filip Varga1f360232020-09-14 11:20:16 +0200747
748 interfaces = self.vapi.nat64_interface_dump()
749 self.assertEqual(len(interfaces), 0)
750
751 def test_static_bib(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200752 """Add/delete static BIB entry"""
753 in_addr = "2001:db8:85a3::8a2e:370:7334"
754 out_addr = "10.1.1.3"
Filip Varga1f360232020-09-14 11:20:16 +0200755 in_port = 1234
756 out_port = 5678
757 proto = IP_PROTOS.tcp
758
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200759 self.vapi.nat64_add_del_static_bib(
760 i_addr=in_addr,
761 o_addr=out_addr,
762 i_port=in_port,
763 o_port=out_port,
764 proto=proto,
765 vrf_id=0,
766 is_add=1,
767 )
Filip Varga1f360232020-09-14 11:20:16 +0200768 bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
769 static_bib_num = 0
770 for bibe in bib:
771 if bibe.flags & self.config_flags.NAT_IS_STATIC:
772 static_bib_num += 1
773 self.assertEqual(str(bibe.i_addr), in_addr)
774 self.assertEqual(str(bibe.o_addr), out_addr)
775 self.assertEqual(bibe.i_port, in_port)
776 self.assertEqual(bibe.o_port, out_port)
777 self.assertEqual(static_bib_num, 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200778 bibs = self.statistics.get_counter("/nat64/total-bibs")
Filip Varga1f360232020-09-14 11:20:16 +0200779 self.assertEqual(bibs[0][0], 1)
780
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200781 self.vapi.nat64_add_del_static_bib(
782 i_addr=in_addr,
783 o_addr=out_addr,
784 i_port=in_port,
785 o_port=out_port,
786 proto=proto,
787 vrf_id=0,
788 is_add=0,
789 )
Filip Varga1f360232020-09-14 11:20:16 +0200790 bib = self.vapi.nat64_bib_dump(proto=IP_PROTOS.tcp)
791 static_bib_num = 0
792 for bibe in bib:
793 if bibe.flags & self.config_flags.NAT_IS_STATIC:
794 static_bib_num += 1
795 self.assertEqual(static_bib_num, 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200796 bibs = self.statistics.get_counter("/nat64/total-bibs")
Filip Varga1f360232020-09-14 11:20:16 +0200797 self.assertEqual(bibs[0][0], 0)
798
799 def test_set_timeouts(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200800 """Set NAT64 timeouts"""
Filip Varga1f360232020-09-14 11:20:16 +0200801 # verify default values
802 timeouts = self.vapi.nat64_get_timeouts()
803 self.assertEqual(timeouts.udp, 300)
804 self.assertEqual(timeouts.icmp, 60)
805 self.assertEqual(timeouts.tcp_transitory, 240)
806 self.assertEqual(timeouts.tcp_established, 7440)
807
808 # set and verify custom values
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809 self.vapi.nat64_set_timeouts(
810 udp=200, tcp_established=7450, tcp_transitory=250, icmp=30
811 )
Filip Varga1f360232020-09-14 11:20:16 +0200812 timeouts = self.vapi.nat64_get_timeouts()
813 self.assertEqual(timeouts.udp, 200)
814 self.assertEqual(timeouts.icmp, 30)
815 self.assertEqual(timeouts.tcp_transitory, 250)
816 self.assertEqual(timeouts.tcp_established, 7450)
817
818 def test_dynamic(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200819 """NAT64 dynamic translation test"""
Filip Varga1f360232020-09-14 11:20:16 +0200820 self.tcp_port_in = 6303
821 self.udp_port_in = 6304
822 self.icmp_id_in = 6305
823
824 ses_num_start = self.nat64_get_ses_num()
825
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200826 self.vapi.nat64_add_del_pool_addr_range(
827 start_addr=self.nat_addr,
828 end_addr=self.nat_addr,
829 vrf_id=0xFFFFFFFF,
830 is_add=1,
831 )
Filip Varga1f360232020-09-14 11:20:16 +0200832 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200833 self.vapi.nat64_add_del_interface(
834 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
835 )
836 self.vapi.nat64_add_del_interface(
837 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
838 )
Filip Varga1f360232020-09-14 11:20:16 +0200839
840 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200841 tcpn = self.statistics.get_counter("/nat64/in2out/tcp")[0]
842 udpn = self.statistics.get_counter("/nat64/in2out/udp")[0]
843 icmpn = self.statistics.get_counter("/nat64/in2out/icmp")[0]
844 drops = self.statistics.get_counter("/nat64/in2out/drops")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200845
846 pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
847 self.pg0.add_stream(pkts)
848 self.pg_enable_capture(self.pg_interfaces)
849 self.pg_start()
850 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 self.verify_capture_out(
852 capture, nat_ip=self.nat_addr, dst_ip=self.pg1.remote_ip4
853 )
Filip Varga1f360232020-09-14 11:20:16 +0200854
855 if_idx = self.pg0.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 cnt = self.statistics.get_counter("/nat64/in2out/tcp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200857 self.assertEqual(cnt[if_idx] - tcpn[if_idx], 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 cnt = self.statistics.get_counter("/nat64/in2out/udp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200859 self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200860 cnt = self.statistics.get_counter("/nat64/in2out/icmp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200861 self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 cnt = self.statistics.get_counter("/nat64/in2out/drops")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200863 self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
864
865 # out2in
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200866 tcpn = self.statistics.get_counter("/nat64/out2in/tcp")[0]
867 udpn = self.statistics.get_counter("/nat64/out2in/udp")[0]
868 icmpn = self.statistics.get_counter("/nat64/out2in/icmp")[0]
869 drops = self.statistics.get_counter("/nat64/out2in/drops")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200870
871 pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
872 self.pg1.add_stream(pkts)
873 self.pg_enable_capture(self.pg_interfaces)
874 self.pg_start()
875 capture = self.pg0.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200876 ip = IPv6(src="".join(["64:ff9b::", self.pg1.remote_ip4]))
Filip Varga1f360232020-09-14 11:20:16 +0200877 self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
878
879 if_idx = self.pg1.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200880 cnt = self.statistics.get_counter("/nat64/out2in/tcp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200881 self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200882 cnt = self.statistics.get_counter("/nat64/out2in/udp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200883 self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200884 cnt = self.statistics.get_counter("/nat64/out2in/icmp")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200885 self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200886 cnt = self.statistics.get_counter("/nat64/out2in/drops")[0]
Filip Varga1f360232020-09-14 11:20:16 +0200887 self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
888
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200889 bibs = self.statistics.get_counter("/nat64/total-bibs")
Filip Varga1f360232020-09-14 11:20:16 +0200890 self.assertEqual(bibs[0][0], 3)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200891 sessions = self.statistics.get_counter("/nat64/total-sessions")
Filip Varga1f360232020-09-14 11:20:16 +0200892 self.assertEqual(sessions[0][0], 3)
893
894 # in2out
895 pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
896 self.pg0.add_stream(pkts)
897 self.pg_enable_capture(self.pg_interfaces)
898 self.pg_start()
899 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200900 self.verify_capture_out(
901 capture, nat_ip=self.nat_addr, dst_ip=self.pg1.remote_ip4
902 )
Filip Varga1f360232020-09-14 11:20:16 +0200903
904 # out2in
905 pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
906 self.pg1.add_stream(pkts)
907 self.pg_enable_capture(self.pg_interfaces)
908 self.pg_start()
909 capture = self.pg0.get_capture(len(pkts))
910 self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
911
912 ses_num_end = self.nat64_get_ses_num()
913
914 self.assertEqual(ses_num_end - ses_num_start, 3)
915
916 # tenant with specific VRF
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200917 self.vapi.nat64_add_del_pool_addr_range(
918 start_addr=self.vrf1_nat_addr,
919 end_addr=self.vrf1_nat_addr,
920 vrf_id=self.vrf1_id,
921 is_add=1,
922 )
Filip Varga1f360232020-09-14 11:20:16 +0200923 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200924 self.vapi.nat64_add_del_interface(
925 is_add=1, flags=flags, sw_if_index=self.pg2.sw_if_index
926 )
Filip Varga1f360232020-09-14 11:20:16 +0200927
928 pkts = self.create_stream_in_ip6(self.pg2, self.pg1)
929 self.pg2.add_stream(pkts)
930 self.pg_enable_capture(self.pg_interfaces)
931 self.pg_start()
932 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 self.verify_capture_out(
934 capture, nat_ip=self.vrf1_nat_addr, dst_ip=self.pg1.remote_ip4
935 )
Filip Varga1f360232020-09-14 11:20:16 +0200936
937 pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
938 self.pg1.add_stream(pkts)
939 self.pg_enable_capture(self.pg_interfaces)
940 self.pg_start()
941 capture = self.pg2.get_capture(len(pkts))
942 self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg2.remote_ip6)
943
944 def test_static(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200945 """NAT64 static translation test"""
Filip Varga1f360232020-09-14 11:20:16 +0200946 self.tcp_port_in = 60303
947 self.udp_port_in = 60304
948 self.icmp_id_in = 60305
949 self.tcp_port_out = 60303
950 self.udp_port_out = 60304
951 self.icmp_id_out = 60305
952
953 ses_num_start = self.nat64_get_ses_num()
954
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200955 self.vapi.nat64_add_del_pool_addr_range(
956 start_addr=self.nat_addr,
957 end_addr=self.nat_addr,
958 vrf_id=0xFFFFFFFF,
959 is_add=1,
960 )
Filip Varga1f360232020-09-14 11:20:16 +0200961 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200962 self.vapi.nat64_add_del_interface(
963 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
964 )
965 self.vapi.nat64_add_del_interface(
966 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
967 )
Filip Varga1f360232020-09-14 11:20:16 +0200968
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 self.vapi.nat64_add_del_static_bib(
970 i_addr=self.pg0.remote_ip6,
971 o_addr=self.nat_addr,
972 i_port=self.tcp_port_in,
973 o_port=self.tcp_port_out,
974 proto=IP_PROTOS.tcp,
975 vrf_id=0,
976 is_add=1,
977 )
978 self.vapi.nat64_add_del_static_bib(
979 i_addr=self.pg0.remote_ip6,
980 o_addr=self.nat_addr,
981 i_port=self.udp_port_in,
982 o_port=self.udp_port_out,
983 proto=IP_PROTOS.udp,
984 vrf_id=0,
985 is_add=1,
986 )
987 self.vapi.nat64_add_del_static_bib(
988 i_addr=self.pg0.remote_ip6,
989 o_addr=self.nat_addr,
990 i_port=self.icmp_id_in,
991 o_port=self.icmp_id_out,
992 proto=IP_PROTOS.icmp,
993 vrf_id=0,
994 is_add=1,
995 )
Filip Varga1f360232020-09-14 11:20:16 +0200996
997 # in2out
998 pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
999 self.pg0.add_stream(pkts)
1000 self.pg_enable_capture(self.pg_interfaces)
1001 self.pg_start()
1002 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001003 self.verify_capture_out(
1004 capture, nat_ip=self.nat_addr, dst_ip=self.pg1.remote_ip4, same_port=True
1005 )
Filip Varga1f360232020-09-14 11:20:16 +02001006
1007 # out2in
1008 pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
1009 self.pg1.add_stream(pkts)
1010 self.pg_enable_capture(self.pg_interfaces)
1011 self.pg_start()
1012 capture = self.pg0.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001013 ip = IPv6(src="".join(["64:ff9b::", self.pg1.remote_ip4]))
Filip Varga1f360232020-09-14 11:20:16 +02001014 self.verify_capture_in_ip6(capture, ip[IPv6].src, self.pg0.remote_ip6)
1015
1016 ses_num_end = self.nat64_get_ses_num()
1017
1018 self.assertEqual(ses_num_end - ses_num_start, 3)
1019
Filip Varga1f360232020-09-14 11:20:16 +02001020 def test_session_timeout(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001021 """NAT64 session timeout"""
Filip Varga1f360232020-09-14 11:20:16 +02001022 self.icmp_id_in = 1234
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001023 self.vapi.nat64_add_del_pool_addr_range(
1024 start_addr=self.nat_addr,
1025 end_addr=self.nat_addr,
1026 vrf_id=0xFFFFFFFF,
1027 is_add=1,
1028 )
Filip Varga1f360232020-09-14 11:20:16 +02001029 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001030 self.vapi.nat64_add_del_interface(
1031 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1032 )
1033 self.vapi.nat64_add_del_interface(
1034 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1035 )
1036 self.vapi.nat64_set_timeouts(
1037 udp=300, tcp_established=5, tcp_transitory=5, icmp=5
1038 )
Filip Varga1f360232020-09-14 11:20:16 +02001039
1040 pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
1041 self.pg0.add_stream(pkts)
1042 self.pg_enable_capture(self.pg_interfaces)
1043 self.pg_start()
1044 capture = self.pg1.get_capture(len(pkts))
1045
1046 ses_num_before_timeout = self.nat64_get_ses_num()
1047
BenoƮt Ganne56eccdb2021-08-20 09:18:31 +02001048 self.virtual_sleep(15)
Filip Varga1f360232020-09-14 11:20:16 +02001049
1050 # ICMP and TCP session after timeout
1051 ses_num_after_timeout = self.nat64_get_ses_num()
1052 self.assertEqual(ses_num_before_timeout - ses_num_after_timeout, 2)
1053
1054 def test_icmp_error(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001055 """NAT64 ICMP Error message translation"""
Filip Varga1f360232020-09-14 11:20:16 +02001056 self.tcp_port_in = 6303
1057 self.udp_port_in = 6304
1058 self.icmp_id_in = 6305
1059
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001060 self.vapi.nat64_add_del_pool_addr_range(
1061 start_addr=self.nat_addr,
1062 end_addr=self.nat_addr,
1063 vrf_id=0xFFFFFFFF,
1064 is_add=1,
1065 )
Filip Varga1f360232020-09-14 11:20:16 +02001066 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001067 self.vapi.nat64_add_del_interface(
1068 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1069 )
1070 self.vapi.nat64_add_del_interface(
1071 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1072 )
Filip Varga1f360232020-09-14 11:20:16 +02001073
1074 # send some packets to create sessions
1075 pkts = self.create_stream_in_ip6(self.pg0, self.pg1)
1076 self.pg0.add_stream(pkts)
1077 self.pg_enable_capture(self.pg_interfaces)
1078 self.pg_start()
1079 capture_ip4 = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001080 self.verify_capture_out(
1081 capture_ip4, nat_ip=self.nat_addr, dst_ip=self.pg1.remote_ip4
1082 )
Filip Varga1f360232020-09-14 11:20:16 +02001083
1084 pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
1085 self.pg1.add_stream(pkts)
1086 self.pg_enable_capture(self.pg_interfaces)
1087 self.pg_start()
1088 capture_ip6 = self.pg0.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001089 ip = IPv6(src="".join(["64:ff9b::", self.pg1.remote_ip4]))
1090 self.verify_capture_in_ip6(capture_ip6, ip[IPv6].src, self.pg0.remote_ip6)
Filip Varga1f360232020-09-14 11:20:16 +02001091
1092 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001093 pkts = [
1094 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1095 / IPv6(src=self.pg0.remote_ip6, dst=ip[IPv6].src)
1096 / ICMPv6DestUnreach(code=1)
1097 / packet[IPv6]
1098 for packet in capture_ip6
1099 ]
Filip Varga1f360232020-09-14 11:20:16 +02001100 self.pg0.add_stream(pkts)
1101 self.pg_enable_capture(self.pg_interfaces)
1102 self.pg_start()
1103 capture = self.pg1.get_capture(len(pkts))
1104 for packet in capture:
1105 try:
1106 self.assertEqual(packet[IP].src, self.nat_addr)
1107 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1108 self.assertEqual(packet[ICMP].type, 3)
1109 self.assertEqual(packet[ICMP].code, 13)
1110 inner = packet[IPerror]
1111 self.assertEqual(inner.src, self.pg1.remote_ip4)
1112 self.assertEqual(inner.dst, self.nat_addr)
1113 self.assert_packet_checksums_valid(packet)
1114 if inner.haslayer(TCPerror):
1115 self.assertEqual(inner[TCPerror].dport, self.tcp_port_out)
1116 elif inner.haslayer(UDPerror):
1117 self.assertEqual(inner[UDPerror].dport, self.udp_port_out)
1118 else:
1119 self.assertEqual(inner[ICMPerror].id, self.icmp_id_out)
1120 except:
1121 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1122 raise
1123
1124 # out2in
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001125 pkts = [
1126 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1127 / IP(src=self.pg1.remote_ip4, dst=self.nat_addr)
1128 / ICMP(type=3, code=13)
1129 / packet[IP]
1130 for packet in capture_ip4
1131 ]
Filip Varga1f360232020-09-14 11:20:16 +02001132 self.pg1.add_stream(pkts)
1133 self.pg_enable_capture(self.pg_interfaces)
1134 self.pg_start()
1135 capture = self.pg0.get_capture(len(pkts))
1136 for packet in capture:
1137 try:
1138 self.assertEqual(packet[IPv6].src, ip.src)
1139 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
1140 icmp = packet[ICMPv6DestUnreach]
1141 self.assertEqual(icmp.code, 1)
1142 inner = icmp[IPerror6]
1143 self.assertEqual(inner.src, self.pg0.remote_ip6)
1144 self.assertEqual(inner.dst, ip.src)
1145 self.assert_icmpv6_checksum_valid(packet)
1146 if inner.haslayer(TCPerror):
1147 self.assertEqual(inner[TCPerror].sport, self.tcp_port_in)
1148 elif inner.haslayer(UDPerror):
1149 self.assertEqual(inner[UDPerror].sport, self.udp_port_in)
1150 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001151 self.assertEqual(inner[ICMPv6EchoRequest].id, self.icmp_id_in)
Filip Varga1f360232020-09-14 11:20:16 +02001152 except:
1153 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1154 raise
1155
1156 def test_hairpinning(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001157 """NAT64 hairpinning"""
Filip Varga1f360232020-09-14 11:20:16 +02001158
1159 client = self.pg0.remote_hosts[0]
1160 server = self.pg0.remote_hosts[1]
1161 server_tcp_in_port = 22
1162 server_tcp_out_port = 4022
1163 server_udp_in_port = 23
1164 server_udp_out_port = 4023
1165 client_tcp_in_port = 1234
1166 client_udp_in_port = 1235
1167 client_tcp_out_port = 0
1168 client_udp_out_port = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001169 ip = IPv6(src="".join(["64:ff9b::", self.nat_addr]))
Filip Varga1f360232020-09-14 11:20:16 +02001170 nat_addr_ip6 = ip.src
1171
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001172 self.vapi.nat64_add_del_pool_addr_range(
1173 start_addr=self.nat_addr,
1174 end_addr=self.nat_addr,
1175 vrf_id=0xFFFFFFFF,
1176 is_add=1,
1177 )
Filip Varga1f360232020-09-14 11:20:16 +02001178 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001179 self.vapi.nat64_add_del_interface(
1180 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1181 )
1182 self.vapi.nat64_add_del_interface(
1183 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1184 )
Filip Varga1f360232020-09-14 11:20:16 +02001185
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001186 self.vapi.nat64_add_del_static_bib(
1187 i_addr=server.ip6n,
1188 o_addr=self.nat_addr,
1189 i_port=server_tcp_in_port,
1190 o_port=server_tcp_out_port,
1191 proto=IP_PROTOS.tcp,
1192 vrf_id=0,
1193 is_add=1,
1194 )
1195 self.vapi.nat64_add_del_static_bib(
1196 i_addr=server.ip6n,
1197 o_addr=self.nat_addr,
1198 i_port=server_udp_in_port,
1199 o_port=server_udp_out_port,
1200 proto=IP_PROTOS.udp,
1201 vrf_id=0,
1202 is_add=1,
1203 )
Filip Varga1f360232020-09-14 11:20:16 +02001204
1205 # client to server
1206 pkts = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001207 p = (
1208 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1209 / IPv6(src=client.ip6, dst=nat_addr_ip6)
1210 / TCP(sport=client_tcp_in_port, dport=server_tcp_out_port)
1211 )
Filip Varga1f360232020-09-14 11:20:16 +02001212 pkts.append(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001213 p = (
1214 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1215 / IPv6(src=client.ip6, dst=nat_addr_ip6)
1216 / UDP(sport=client_udp_in_port, dport=server_udp_out_port)
1217 )
Filip Varga1f360232020-09-14 11:20:16 +02001218 pkts.append(p)
1219 self.pg0.add_stream(pkts)
1220 self.pg_enable_capture(self.pg_interfaces)
1221 self.pg_start()
1222 capture = self.pg0.get_capture(len(pkts))
1223 for packet in capture:
1224 try:
1225 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
1226 self.assertEqual(packet[IPv6].dst, server.ip6)
1227 self.assert_packet_checksums_valid(packet)
1228 if packet.haslayer(TCP):
1229 self.assertNotEqual(packet[TCP].sport, client_tcp_in_port)
1230 self.assertEqual(packet[TCP].dport, server_tcp_in_port)
1231 client_tcp_out_port = packet[TCP].sport
1232 else:
1233 self.assertNotEqual(packet[UDP].sport, client_udp_in_port)
1234 self.assertEqual(packet[UDP].dport, server_udp_in_port)
1235 client_udp_out_port = packet[UDP].sport
1236 except:
1237 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1238 raise
1239
1240 # server to client
1241 pkts = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001242 p = (
1243 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1244 / IPv6(src=server.ip6, dst=nat_addr_ip6)
1245 / TCP(sport=server_tcp_in_port, dport=client_tcp_out_port)
1246 )
Filip Varga1f360232020-09-14 11:20:16 +02001247 pkts.append(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001248 p = (
1249 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1250 / IPv6(src=server.ip6, dst=nat_addr_ip6)
1251 / UDP(sport=server_udp_in_port, dport=client_udp_out_port)
1252 )
Filip Varga1f360232020-09-14 11:20:16 +02001253 pkts.append(p)
1254 self.pg0.add_stream(pkts)
1255 self.pg_enable_capture(self.pg_interfaces)
1256 self.pg_start()
1257 capture = self.pg0.get_capture(len(pkts))
1258 for packet in capture:
1259 try:
1260 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
1261 self.assertEqual(packet[IPv6].dst, client.ip6)
1262 self.assert_packet_checksums_valid(packet)
1263 if packet.haslayer(TCP):
1264 self.assertEqual(packet[TCP].sport, server_tcp_out_port)
1265 self.assertEqual(packet[TCP].dport, client_tcp_in_port)
1266 else:
1267 self.assertEqual(packet[UDP].sport, server_udp_out_port)
1268 self.assertEqual(packet[UDP].dport, client_udp_in_port)
1269 except:
1270 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1271 raise
1272
1273 # ICMP error
1274 pkts = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 pkts = [
1276 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1277 / IPv6(src=client.ip6, dst=nat_addr_ip6)
1278 / ICMPv6DestUnreach(code=1)
1279 / packet[IPv6]
1280 for packet in capture
1281 ]
Filip Varga1f360232020-09-14 11:20:16 +02001282 self.pg0.add_stream(pkts)
1283 self.pg_enable_capture(self.pg_interfaces)
1284 self.pg_start()
1285 capture = self.pg0.get_capture(len(pkts))
1286 for packet in capture:
1287 try:
1288 self.assertEqual(packet[IPv6].src, nat_addr_ip6)
1289 self.assertEqual(packet[IPv6].dst, server.ip6)
1290 icmp = packet[ICMPv6DestUnreach]
1291 self.assertEqual(icmp.code, 1)
1292 inner = icmp[IPerror6]
1293 self.assertEqual(inner.src, server.ip6)
1294 self.assertEqual(inner.dst, nat_addr_ip6)
1295 self.assert_packet_checksums_valid(packet)
1296 if inner.haslayer(TCPerror):
1297 self.assertEqual(inner[TCPerror].sport, server_tcp_in_port)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001298 self.assertEqual(inner[TCPerror].dport, client_tcp_out_port)
Filip Varga1f360232020-09-14 11:20:16 +02001299 else:
1300 self.assertEqual(inner[UDPerror].sport, server_udp_in_port)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001301 self.assertEqual(inner[UDPerror].dport, client_udp_out_port)
Filip Varga1f360232020-09-14 11:20:16 +02001302 except:
1303 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1304 raise
1305
1306 def test_prefix(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001307 """NAT64 Network-Specific Prefix"""
Filip Varga1f360232020-09-14 11:20:16 +02001308
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001309 self.vapi.nat64_add_del_pool_addr_range(
1310 start_addr=self.nat_addr,
1311 end_addr=self.nat_addr,
1312 vrf_id=0xFFFFFFFF,
1313 is_add=1,
1314 )
Filip Varga1f360232020-09-14 11:20:16 +02001315 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001316 self.vapi.nat64_add_del_interface(
1317 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1318 )
1319 self.vapi.nat64_add_del_interface(
1320 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1321 )
1322 self.vapi.nat64_add_del_pool_addr_range(
1323 start_addr=self.vrf1_nat_addr,
1324 end_addr=self.vrf1_nat_addr,
1325 vrf_id=self.vrf1_id,
1326 is_add=1,
1327 )
1328 self.vapi.nat64_add_del_interface(
1329 is_add=1, flags=flags, sw_if_index=self.pg2.sw_if_index
1330 )
Filip Varga1f360232020-09-14 11:20:16 +02001331
1332 # Add global prefix
1333 global_pref64 = "2001:db8::"
1334 global_pref64_len = 32
1335 global_pref64_str = "{}/{}".format(global_pref64, global_pref64_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001336 self.vapi.nat64_add_del_prefix(prefix=global_pref64_str, vrf_id=0, is_add=1)
Filip Varga1f360232020-09-14 11:20:16 +02001337
1338 prefix = self.vapi.nat64_prefix_dump()
1339 self.assertEqual(len(prefix), 1)
1340 self.assertEqual(str(prefix[0].prefix), global_pref64_str)
1341 self.assertEqual(prefix[0].vrf_id, 0)
1342
1343 # Add tenant specific prefix
1344 vrf1_pref64 = "2001:db8:122:300::"
1345 vrf1_pref64_len = 56
1346 vrf1_pref64_str = "{}/{}".format(vrf1_pref64, vrf1_pref64_len)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001347 self.vapi.nat64_add_del_prefix(
1348 prefix=vrf1_pref64_str, vrf_id=self.vrf1_id, is_add=1
1349 )
Filip Varga1f360232020-09-14 11:20:16 +02001350
1351 prefix = self.vapi.nat64_prefix_dump()
1352 self.assertEqual(len(prefix), 2)
1353
1354 # Global prefix
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001355 pkts = self.create_stream_in_ip6(
1356 self.pg0, self.pg1, pref=global_pref64, plen=global_pref64_len
1357 )
Filip Varga1f360232020-09-14 11:20:16 +02001358 self.pg0.add_stream(pkts)
1359 self.pg_enable_capture(self.pg_interfaces)
1360 self.pg_start()
1361 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001362 self.verify_capture_out(
1363 capture, nat_ip=self.nat_addr, dst_ip=self.pg1.remote_ip4
1364 )
Filip Varga1f360232020-09-14 11:20:16 +02001365
1366 pkts = self.create_stream_out(self.pg1, dst_ip=self.nat_addr)
1367 self.pg1.add_stream(pkts)
1368 self.pg_enable_capture(self.pg_interfaces)
1369 self.pg_start()
1370 capture = self.pg0.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001371 dst_ip = self.compose_ip6(self.pg1.remote_ip4, global_pref64, global_pref64_len)
Filip Varga1f360232020-09-14 11:20:16 +02001372 self.verify_capture_in_ip6(capture, dst_ip, self.pg0.remote_ip6)
1373
1374 # Tenant specific prefix
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001375 pkts = self.create_stream_in_ip6(
1376 self.pg2, self.pg1, pref=vrf1_pref64, plen=vrf1_pref64_len
1377 )
Filip Varga1f360232020-09-14 11:20:16 +02001378 self.pg2.add_stream(pkts)
1379 self.pg_enable_capture(self.pg_interfaces)
1380 self.pg_start()
1381 capture = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001382 self.verify_capture_out(
1383 capture, nat_ip=self.vrf1_nat_addr, dst_ip=self.pg1.remote_ip4
1384 )
Filip Varga1f360232020-09-14 11:20:16 +02001385
1386 pkts = self.create_stream_out(self.pg1, dst_ip=self.vrf1_nat_addr)
1387 self.pg1.add_stream(pkts)
1388 self.pg_enable_capture(self.pg_interfaces)
1389 self.pg_start()
1390 capture = self.pg2.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001391 dst_ip = self.compose_ip6(self.pg1.remote_ip4, vrf1_pref64, vrf1_pref64_len)
Filip Varga1f360232020-09-14 11:20:16 +02001392 self.verify_capture_in_ip6(capture, dst_ip, self.pg2.remote_ip6)
1393
1394 def test_unknown_proto(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001395 """NAT64 translate packet with unknown protocol"""
Filip Varga1f360232020-09-14 11:20:16 +02001396
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001397 self.vapi.nat64_add_del_pool_addr_range(
1398 start_addr=self.nat_addr,
1399 end_addr=self.nat_addr,
1400 vrf_id=0xFFFFFFFF,
1401 is_add=1,
1402 )
Filip Varga1f360232020-09-14 11:20:16 +02001403 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001404 self.vapi.nat64_add_del_interface(
1405 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1406 )
1407 self.vapi.nat64_add_del_interface(
1408 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1409 )
1410 remote_ip6 = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001411
1412 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001413 p = (
1414 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1415 / IPv6(src=self.pg0.remote_ip6, dst=remote_ip6)
1416 / TCP(sport=self.tcp_port_in, dport=20)
1417 )
Filip Varga1f360232020-09-14 11:20:16 +02001418 self.pg0.add_stream(p)
1419 self.pg_enable_capture(self.pg_interfaces)
1420 self.pg_start()
1421 p = self.pg1.get_capture(1)
1422
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001423 p = (
1424 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1425 / IPv6(src=self.pg0.remote_ip6, dst=remote_ip6, nh=47)
1426 / GRE()
1427 / IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4)
1428 / TCP(sport=1234, dport=1234)
1429 )
Filip Varga1f360232020-09-14 11:20:16 +02001430 self.pg0.add_stream(p)
1431 self.pg_enable_capture(self.pg_interfaces)
1432 self.pg_start()
1433 p = self.pg1.get_capture(1)
1434 packet = p[0]
1435 try:
1436 self.assertEqual(packet[IP].src, self.nat_addr)
1437 self.assertEqual(packet[IP].dst, self.pg1.remote_ip4)
1438 self.assertEqual(packet.haslayer(GRE), 1)
1439 self.assert_packet_checksums_valid(packet)
1440 except:
1441 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1442 raise
1443
1444 # out2in
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001445 p = (
1446 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1447 / IP(src=self.pg1.remote_ip4, dst=self.nat_addr)
1448 / GRE()
1449 / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4)
1450 / TCP(sport=1234, dport=1234)
1451 )
Filip Varga1f360232020-09-14 11:20:16 +02001452 self.pg1.add_stream(p)
1453 self.pg_enable_capture(self.pg_interfaces)
1454 self.pg_start()
1455 p = self.pg0.get_capture(1)
1456 packet = p[0]
1457 try:
1458 self.assertEqual(packet[IPv6].src, remote_ip6)
1459 self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6)
1460 self.assertEqual(packet[IPv6].nh, 47)
1461 except:
1462 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1463 raise
1464
1465 def test_hairpinning_unknown_proto(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001466 """NAT64 translate packet with unknown protocol - hairpinning"""
Filip Varga1f360232020-09-14 11:20:16 +02001467
1468 client = self.pg0.remote_hosts[0]
1469 server = self.pg0.remote_hosts[1]
1470 server_tcp_in_port = 22
1471 server_tcp_out_port = 4022
1472 client_tcp_in_port = 1234
1473 client_tcp_out_port = 1235
1474 server_nat_ip = "10.0.0.100"
1475 client_nat_ip = "10.0.0.110"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001476 server_nat_ip6 = self.compose_ip6(server_nat_ip, "64:ff9b::", 96)
1477 client_nat_ip6 = self.compose_ip6(client_nat_ip, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001478
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001479 self.vapi.nat64_add_del_pool_addr_range(
1480 start_addr=server_nat_ip,
1481 end_addr=client_nat_ip,
1482 vrf_id=0xFFFFFFFF,
1483 is_add=1,
1484 )
Filip Varga1f360232020-09-14 11:20:16 +02001485 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001486 self.vapi.nat64_add_del_interface(
1487 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1488 )
1489 self.vapi.nat64_add_del_interface(
1490 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1491 )
Filip Varga1f360232020-09-14 11:20:16 +02001492
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001493 self.vapi.nat64_add_del_static_bib(
1494 i_addr=server.ip6n,
1495 o_addr=server_nat_ip,
1496 i_port=server_tcp_in_port,
1497 o_port=server_tcp_out_port,
1498 proto=IP_PROTOS.tcp,
1499 vrf_id=0,
1500 is_add=1,
1501 )
Filip Varga1f360232020-09-14 11:20:16 +02001502
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001503 self.vapi.nat64_add_del_static_bib(
1504 i_addr=server.ip6n,
1505 o_addr=server_nat_ip,
1506 i_port=0,
1507 o_port=0,
1508 proto=IP_PROTOS.gre,
1509 vrf_id=0,
1510 is_add=1,
1511 )
Filip Varga1f360232020-09-14 11:20:16 +02001512
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001513 self.vapi.nat64_add_del_static_bib(
1514 i_addr=client.ip6n,
1515 o_addr=client_nat_ip,
1516 i_port=client_tcp_in_port,
1517 o_port=client_tcp_out_port,
1518 proto=IP_PROTOS.tcp,
1519 vrf_id=0,
1520 is_add=1,
1521 )
Filip Varga1f360232020-09-14 11:20:16 +02001522
1523 # client to server
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001524 p = (
1525 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1526 / IPv6(src=client.ip6, dst=server_nat_ip6)
1527 / TCP(sport=client_tcp_in_port, dport=server_tcp_out_port)
1528 )
Filip Varga1f360232020-09-14 11:20:16 +02001529 self.pg0.add_stream(p)
1530 self.pg_enable_capture(self.pg_interfaces)
1531 self.pg_start()
1532 p = self.pg0.get_capture(1)
1533
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001534 p = (
1535 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1536 / IPv6(src=client.ip6, dst=server_nat_ip6, nh=IP_PROTOS.gre)
1537 / GRE()
1538 / IP(src=self.pg2.local_ip4, dst=self.pg2.remote_ip4)
1539 / TCP(sport=1234, dport=1234)
1540 )
Filip Varga1f360232020-09-14 11:20:16 +02001541 self.pg0.add_stream(p)
1542 self.pg_enable_capture(self.pg_interfaces)
1543 self.pg_start()
1544 p = self.pg0.get_capture(1)
1545 packet = p[0]
1546 try:
1547 self.assertEqual(packet[IPv6].src, client_nat_ip6)
1548 self.assertEqual(packet[IPv6].dst, server.ip6)
1549 self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
1550 except:
1551 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1552 raise
1553
1554 # server to client
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001555 p = (
1556 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1557 / IPv6(src=server.ip6, dst=client_nat_ip6, nh=IP_PROTOS.gre)
1558 / GRE()
1559 / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4)
1560 / TCP(sport=1234, dport=1234)
1561 )
Filip Varga1f360232020-09-14 11:20:16 +02001562 self.pg0.add_stream(p)
1563 self.pg_enable_capture(self.pg_interfaces)
1564 self.pg_start()
1565 p = self.pg0.get_capture(1)
1566 packet = p[0]
1567 try:
1568 self.assertEqual(packet[IPv6].src, server_nat_ip6)
1569 self.assertEqual(packet[IPv6].dst, client.ip6)
1570 self.assertEqual(packet[IPv6].nh, IP_PROTOS.gre)
1571 except:
1572 self.logger.error(ppp("Unexpected or invalid packet:", packet))
1573 raise
1574
1575 def test_one_armed_nat64(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001576 """One armed NAT64"""
Filip Varga1f360232020-09-14 11:20:16 +02001577 external_port = 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001578 remote_host_ip6 = self.compose_ip6(self.pg3.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001579
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001580 self.vapi.nat64_add_del_pool_addr_range(
1581 start_addr=self.nat_addr,
1582 end_addr=self.nat_addr,
1583 vrf_id=0xFFFFFFFF,
1584 is_add=1,
1585 )
Filip Varga1f360232020-09-14 11:20:16 +02001586 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001587 self.vapi.nat64_add_del_interface(
1588 is_add=1, flags=flags, sw_if_index=self.pg3.sw_if_index
1589 )
1590 self.vapi.nat64_add_del_interface(
1591 is_add=1, flags=0, sw_if_index=self.pg3.sw_if_index
1592 )
Filip Varga1f360232020-09-14 11:20:16 +02001593
1594 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001595 p = (
1596 Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac)
1597 / IPv6(src=self.pg3.remote_ip6, dst=remote_host_ip6)
1598 / TCP(sport=12345, dport=80)
1599 )
Filip Varga1f360232020-09-14 11:20:16 +02001600 self.pg3.add_stream(p)
1601 self.pg_enable_capture(self.pg_interfaces)
1602 self.pg_start()
1603 capture = self.pg3.get_capture(1)
1604 p = capture[0]
1605 try:
1606 ip = p[IP]
1607 tcp = p[TCP]
1608 self.assertEqual(ip.src, self.nat_addr)
1609 self.assertEqual(ip.dst, self.pg3.remote_ip4)
1610 self.assertNotEqual(tcp.sport, 12345)
1611 external_port = tcp.sport
1612 self.assertEqual(tcp.dport, 80)
1613 self.assert_packet_checksums_valid(p)
1614 except:
1615 self.logger.error(ppp("Unexpected or invalid packet:", p))
1616 raise
1617
1618 # out2in
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001619 p = (
1620 Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac)
1621 / IP(src=self.pg3.remote_ip4, dst=self.nat_addr)
1622 / TCP(sport=80, dport=external_port)
1623 )
Filip Varga1f360232020-09-14 11:20:16 +02001624 self.pg3.add_stream(p)
1625 self.pg_enable_capture(self.pg_interfaces)
1626 self.pg_start()
1627 capture = self.pg3.get_capture(1)
1628 p = capture[0]
1629 try:
1630 ip = p[IPv6]
1631 tcp = p[TCP]
1632 self.assertEqual(ip.src, remote_host_ip6)
1633 self.assertEqual(ip.dst, self.pg3.remote_ip6)
1634 self.assertEqual(tcp.sport, 80)
1635 self.assertEqual(tcp.dport, 12345)
1636 self.assert_packet_checksums_valid(p)
1637 except:
1638 self.logger.error(ppp("Unexpected or invalid packet:", p))
1639 raise
1640
1641 def test_frag_in_order(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001642 """NAT64 translate fragments arriving in order"""
Filip Varga1f360232020-09-14 11:20:16 +02001643 self.tcp_port_in = random.randint(1025, 65535)
1644
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001645 self.vapi.nat64_add_del_pool_addr_range(
1646 start_addr=self.nat_addr,
1647 end_addr=self.nat_addr,
1648 vrf_id=0xFFFFFFFF,
1649 is_add=1,
1650 )
Filip Varga1f360232020-09-14 11:20:16 +02001651 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001652 self.vapi.nat64_add_del_interface(
1653 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1654 )
1655 self.vapi.nat64_add_del_interface(
1656 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1657 )
Filip Varga1f360232020-09-14 11:20:16 +02001658
1659 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001660 data = b"a" * 200
1661 pkts = self.create_stream_frag_ip6(
1662 self.pg0, self.pg1.remote_ip4, self.tcp_port_in, 20, data
1663 )
Filip Varga1f360232020-09-14 11:20:16 +02001664 self.pg0.add_stream(pkts)
1665 self.pg_enable_capture(self.pg_interfaces)
1666 self.pg_start()
1667 frags = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001668 p = self.reass_frags_and_verify(frags, self.nat_addr, self.pg1.remote_ip4)
Filip Varga1f360232020-09-14 11:20:16 +02001669 self.assertEqual(p[TCP].dport, 20)
1670 self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
1671 self.tcp_port_out = p[TCP].sport
1672 self.assertEqual(data, p[Raw].load)
1673
1674 # out2in
1675 data = b"A" * 4 + b"b" * 16 + b"C" * 3
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001676 pkts = self.create_stream_frag(
1677 self.pg1, self.nat_addr, 20, self.tcp_port_out, data
1678 )
Filip Varga1f360232020-09-14 11:20:16 +02001679 self.pg1.add_stream(pkts)
1680 self.pg_enable_capture(self.pg_interfaces)
1681 self.pg_start()
1682 frags = self.pg0.get_capture(len(pkts))
1683 self.logger.debug(ppc("Captured:", frags))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001684 src = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001685 p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
1686 self.assertEqual(p[TCP].sport, 20)
1687 self.assertEqual(p[TCP].dport, self.tcp_port_in)
1688 self.assertEqual(data, p[Raw].load)
1689
1690 def test_reass_hairpinning(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001691 """NAT64 fragments hairpinning"""
1692 data = b"a" * 200
Filip Varga1f360232020-09-14 11:20:16 +02001693 server = self.pg0.remote_hosts[1]
1694 server_in_port = random.randint(1025, 65535)
1695 server_out_port = random.randint(1025, 65535)
1696 client_in_port = random.randint(1025, 65535)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001697 ip = IPv6(src="".join(["64:ff9b::", self.nat_addr]))
Filip Varga1f360232020-09-14 11:20:16 +02001698 nat_addr_ip6 = ip.src
1699
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001700 self.vapi.nat64_add_del_pool_addr_range(
1701 start_addr=self.nat_addr,
1702 end_addr=self.nat_addr,
1703 vrf_id=0xFFFFFFFF,
1704 is_add=1,
1705 )
Filip Varga1f360232020-09-14 11:20:16 +02001706 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001707 self.vapi.nat64_add_del_interface(
1708 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1709 )
1710 self.vapi.nat64_add_del_interface(
1711 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1712 )
Filip Varga1f360232020-09-14 11:20:16 +02001713
1714 # add static BIB entry for server
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001715 self.vapi.nat64_add_del_static_bib(
1716 i_addr=server.ip6n,
1717 o_addr=self.nat_addr,
1718 i_port=server_in_port,
1719 o_port=server_out_port,
1720 proto=IP_PROTOS.tcp,
1721 vrf_id=0,
1722 is_add=1,
1723 )
Filip Varga1f360232020-09-14 11:20:16 +02001724
1725 # send packet from host to server
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001726 pkts = self.create_stream_frag_ip6(
1727 self.pg0, self.nat_addr, client_in_port, server_out_port, data
1728 )
Filip Varga1f360232020-09-14 11:20:16 +02001729 self.pg0.add_stream(pkts)
1730 self.pg_enable_capture(self.pg_interfaces)
1731 self.pg_start()
1732 frags = self.pg0.get_capture(len(pkts))
1733 self.logger.debug(ppc("Captured:", frags))
1734 p = self.reass_frags_and_verify_ip6(frags, nat_addr_ip6, server.ip6)
1735 self.assertNotEqual(p[TCP].sport, client_in_port)
1736 self.assertEqual(p[TCP].dport, server_in_port)
1737 self.assertEqual(data, p[Raw].load)
1738
1739 def test_frag_out_of_order(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001740 """NAT64 translate fragments arriving out of order"""
Filip Varga1f360232020-09-14 11:20:16 +02001741 self.tcp_port_in = random.randint(1025, 65535)
1742
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001743 self.vapi.nat64_add_del_pool_addr_range(
1744 start_addr=self.nat_addr,
1745 end_addr=self.nat_addr,
1746 vrf_id=0xFFFFFFFF,
1747 is_add=1,
1748 )
Filip Varga1f360232020-09-14 11:20:16 +02001749 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001750 self.vapi.nat64_add_del_interface(
1751 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1752 )
1753 self.vapi.nat64_add_del_interface(
1754 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1755 )
Filip Varga1f360232020-09-14 11:20:16 +02001756
1757 # in2out
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001758 data = b"a" * 200
1759 pkts = self.create_stream_frag_ip6(
1760 self.pg0, self.pg1.remote_ip4, self.tcp_port_in, 20, data
1761 )
Filip Varga1f360232020-09-14 11:20:16 +02001762 pkts.reverse()
1763 self.pg0.add_stream(pkts)
1764 self.pg_enable_capture(self.pg_interfaces)
1765 self.pg_start()
1766 frags = self.pg1.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001767 p = self.reass_frags_and_verify(frags, self.nat_addr, self.pg1.remote_ip4)
Filip Varga1f360232020-09-14 11:20:16 +02001768 self.assertEqual(p[TCP].dport, 20)
1769 self.assertNotEqual(p[TCP].sport, self.tcp_port_in)
1770 self.tcp_port_out = p[TCP].sport
1771 self.assertEqual(data, p[Raw].load)
1772
1773 # out2in
1774 data = b"A" * 4 + b"B" * 16 + b"C" * 3
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001775 pkts = self.create_stream_frag(
1776 self.pg1, self.nat_addr, 20, self.tcp_port_out, data
1777 )
Filip Varga1f360232020-09-14 11:20:16 +02001778 pkts.reverse()
1779 self.pg1.add_stream(pkts)
1780 self.pg_enable_capture(self.pg_interfaces)
1781 self.pg_start()
1782 frags = self.pg0.get_capture(len(pkts))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001783 src = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001784 p = self.reass_frags_and_verify_ip6(frags, src, self.pg0.remote_ip6)
1785 self.assertEqual(p[TCP].sport, 20)
1786 self.assertEqual(p[TCP].dport, self.tcp_port_in)
1787 self.assertEqual(data, p[Raw].load)
1788
1789 def test_interface_addr(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001790 """Acquire NAT64 pool addresses from interface"""
Filip Varga1f360232020-09-14 11:20:16 +02001791 self.vapi.nat64_add_del_interface_addr(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001792 is_add=1, sw_if_index=self.pg4.sw_if_index
1793 )
Filip Varga1f360232020-09-14 11:20:16 +02001794
1795 # no address in NAT64 pool
1796 addresses = self.vapi.nat44_address_dump()
1797 self.assertEqual(0, len(addresses))
1798
1799 # configure interface address and check NAT64 address pool
1800 self.pg4.config_ip4()
1801 addresses = self.vapi.nat64_pool_addr_dump()
1802 self.assertEqual(len(addresses), 1)
1803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001804 self.assertEqual(str(addresses[0].address), self.pg4.local_ip4)
Filip Varga1f360232020-09-14 11:20:16 +02001805
1806 # remove interface address and check NAT64 address pool
1807 self.pg4.unconfig_ip4()
1808 addresses = self.vapi.nat64_pool_addr_dump()
1809 self.assertEqual(0, len(addresses))
1810
Klement Sekerab23ffd72021-05-31 16:08:53 +02001811 @unittest.skipUnless(config.extended, "part of extended tests")
Filip Varga1f360232020-09-14 11:20:16 +02001812 def test_ipfix_max_bibs_sessions(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001813 """IPFIX logging maximum session and BIB entries exceeded"""
Filip Varga1f360232020-09-14 11:20:16 +02001814 max_bibs = 1280
1815 max_sessions = 2560
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001816 remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001817
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001818 self.vapi.nat64_add_del_pool_addr_range(
1819 start_addr=self.nat_addr,
1820 end_addr=self.nat_addr,
1821 vrf_id=0xFFFFFFFF,
1822 is_add=1,
1823 )
Filip Varga1f360232020-09-14 11:20:16 +02001824 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001825 self.vapi.nat64_add_del_interface(
1826 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1827 )
1828 self.vapi.nat64_add_del_interface(
1829 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1830 )
Filip Varga1f360232020-09-14 11:20:16 +02001831
1832 pkts = []
1833 src = ""
1834 for i in range(0, max_bibs):
1835 src = "fd01:aa::%x" % (i)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001836 p = (
1837 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1838 / IPv6(src=src, dst=remote_host_ip6)
1839 / TCP(sport=12345, dport=80)
1840 )
Filip Varga1f360232020-09-14 11:20:16 +02001841 pkts.append(p)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001842 p = (
1843 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1844 / IPv6(src=src, dst=remote_host_ip6)
1845 / TCP(sport=12345, dport=22)
1846 )
Filip Varga1f360232020-09-14 11:20:16 +02001847 pkts.append(p)
1848 self.pg0.add_stream(pkts)
1849 self.pg_enable_capture(self.pg_interfaces)
1850 self.pg_start()
1851 self.pg1.get_capture(max_sessions)
1852
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001853 self.vapi.set_ipfix_exporter(
1854 collector_address=self.pg3.remote_ip4,
1855 src_address=self.pg3.local_ip4,
1856 path_mtu=512,
1857 template_interval=10,
1858 )
1859 self.vapi.nat_ipfix_enable_disable(
1860 domain_id=self.ipfix_domain_id, src_port=self.ipfix_src_port, enable=1
1861 )
Filip Varga1f360232020-09-14 11:20:16 +02001862
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001863 p = (
1864 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1865 / IPv6(src=src, dst=remote_host_ip6)
1866 / TCP(sport=12345, dport=25)
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001867 ) * 3
Filip Varga1f360232020-09-14 11:20:16 +02001868 self.pg0.add_stream(p)
1869 self.pg_enable_capture(self.pg_interfaces)
1870 self.pg_start()
1871 self.pg1.assert_nothing_captured()
Filip Varga1f360232020-09-14 11:20:16 +02001872 self.vapi.ipfix_flush()
1873 capture = self.pg3.get_capture(7)
1874 ipfix = IPFIXDecoder()
1875 # first load template
1876 for p in capture:
1877 self.assertTrue(p.haslayer(IPFIX))
1878 self.assertEqual(p[IP].src, self.pg3.local_ip4)
1879 self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
1880 self.assertEqual(p[UDP].sport, self.ipfix_src_port)
1881 self.assertEqual(p[UDP].dport, 4739)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001882 self.assertEqual(p[IPFIX].observationDomainID, self.ipfix_domain_id)
Filip Varga1f360232020-09-14 11:20:16 +02001883 if p.haslayer(Template):
1884 ipfix.add_template(p.getlayer(Template))
1885 # verify events in data set
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001886 event_count = 0
Filip Varga1f360232020-09-14 11:20:16 +02001887 for p in capture:
1888 if p.haslayer(Data):
1889 data = ipfix.decode_data_set(p.getlayer(Set))
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001890 event_count += self.verify_ipfix_max_sessions(data, max_sessions)
1891 self.assertEqual(event_count, 1)
Filip Varga1f360232020-09-14 11:20:16 +02001892
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001893 p = (
1894 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1895 / IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6)
1896 / TCP(sport=12345, dport=80)
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001897 ) * 3
Filip Varga1f360232020-09-14 11:20:16 +02001898 self.pg0.add_stream(p)
1899 self.pg_enable_capture(self.pg_interfaces)
1900 self.pg_start()
1901 self.pg1.assert_nothing_captured()
Filip Varga1f360232020-09-14 11:20:16 +02001902 self.vapi.ipfix_flush()
1903 capture = self.pg3.get_capture(1)
1904 # verify events in data set
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001905 event_count = 0
Filip Varga1f360232020-09-14 11:20:16 +02001906 for p in capture:
1907 self.assertTrue(p.haslayer(IPFIX))
1908 self.assertEqual(p[IP].src, self.pg3.local_ip4)
1909 self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
1910 self.assertEqual(p[UDP].sport, self.ipfix_src_port)
1911 self.assertEqual(p[UDP].dport, 4739)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001912 self.assertEqual(p[IPFIX].observationDomainID, self.ipfix_domain_id)
Filip Varga1f360232020-09-14 11:20:16 +02001913 if p.haslayer(Data):
1914 data = ipfix.decode_data_set(p.getlayer(Set))
Vladislav Grishenkoda34f4a2023-09-14 22:14:38 +05001915 event_count += self.verify_ipfix_max_bibs(data, max_bibs)
1916 self.assertEqual(event_count, 1)
Filip Varga1f360232020-09-14 11:20:16 +02001917
Filip Varga1f360232020-09-14 11:20:16 +02001918 def test_ipfix_bib_ses(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001919 """IPFIX logging NAT64 BIB/session create and delete events"""
Filip Varga1f360232020-09-14 11:20:16 +02001920 self.tcp_port_in = random.randint(1025, 65535)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001921 remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02001922
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001923 self.vapi.nat64_add_del_pool_addr_range(
1924 start_addr=self.nat_addr,
1925 end_addr=self.nat_addr,
1926 vrf_id=0xFFFFFFFF,
1927 is_add=1,
1928 )
Filip Varga1f360232020-09-14 11:20:16 +02001929 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001930 self.vapi.nat64_add_del_interface(
1931 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
1932 )
1933 self.vapi.nat64_add_del_interface(
1934 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
1935 )
1936 self.vapi.set_ipfix_exporter(
1937 collector_address=self.pg3.remote_ip4,
1938 src_address=self.pg3.local_ip4,
1939 path_mtu=512,
1940 template_interval=10,
1941 )
1942 self.vapi.nat_ipfix_enable_disable(
1943 domain_id=self.ipfix_domain_id, src_port=self.ipfix_src_port, enable=1
1944 )
Filip Varga1f360232020-09-14 11:20:16 +02001945
1946 # Create
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001947 p = (
1948 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1949 / IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6)
1950 / TCP(sport=self.tcp_port_in, dport=25)
1951 )
Filip Varga1f360232020-09-14 11:20:16 +02001952 self.pg0.add_stream(p)
1953 self.pg_enable_capture(self.pg_interfaces)
1954 self.pg_start()
1955 p = self.pg1.get_capture(1)
1956 self.tcp_port_out = p[0][TCP].sport
1957 self.vapi.ipfix_flush()
1958 capture = self.pg3.get_capture(8)
1959 ipfix = IPFIXDecoder()
1960 # first load template
1961 for p in capture:
1962 self.assertTrue(p.haslayer(IPFIX))
1963 self.assertEqual(p[IP].src, self.pg3.local_ip4)
1964 self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
1965 self.assertEqual(p[UDP].sport, self.ipfix_src_port)
1966 self.assertEqual(p[UDP].dport, 4739)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001967 self.assertEqual(p[IPFIX].observationDomainID, self.ipfix_domain_id)
Filip Varga1f360232020-09-14 11:20:16 +02001968 if p.haslayer(Template):
1969 ipfix.add_template(p.getlayer(Template))
1970 # verify events in data set
1971 for p in capture:
1972 if p.haslayer(Data):
1973 data = ipfix.decode_data_set(p.getlayer(Set))
1974 if scapy.compat.orb(data[0][230]) == 10:
1975 self.verify_ipfix_bib(data, 1, self.pg0.remote_ip6)
1976 elif scapy.compat.orb(data[0][230]) == 6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001977 self.verify_ipfix_nat64_ses(
1978 data, 1, self.pg0.remote_ip6, self.pg1.remote_ip4, 25
1979 )
Filip Varga1f360232020-09-14 11:20:16 +02001980 else:
1981 self.logger.error(ppp("Unexpected or invalid packet: ", p))
1982
1983 # Delete
1984 self.pg_enable_capture(self.pg_interfaces)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001985 self.vapi.nat64_add_del_pool_addr_range(
1986 start_addr=self.nat_addr,
1987 end_addr=self.nat_addr,
1988 vrf_id=0xFFFFFFFF,
1989 is_add=0,
1990 )
Filip Varga1f360232020-09-14 11:20:16 +02001991 self.vapi.ipfix_flush()
1992 capture = self.pg3.get_capture(2)
1993 # verify events in data set
1994 for p in capture:
1995 self.assertTrue(p.haslayer(IPFIX))
1996 self.assertEqual(p[IP].src, self.pg3.local_ip4)
1997 self.assertEqual(p[IP].dst, self.pg3.remote_ip4)
1998 self.assertEqual(p[UDP].sport, self.ipfix_src_port)
1999 self.assertEqual(p[UDP].dport, 4739)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002000 self.assertEqual(p[IPFIX].observationDomainID, self.ipfix_domain_id)
Filip Varga1f360232020-09-14 11:20:16 +02002001 if p.haslayer(Data):
2002 data = ipfix.decode_data_set(p.getlayer(Set))
2003 if scapy.compat.orb(data[0][230]) == 11:
2004 self.verify_ipfix_bib(data, 0, self.pg0.remote_ip6)
2005 elif scapy.compat.orb(data[0][230]) == 7:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002006 self.verify_ipfix_nat64_ses(
2007 data, 0, self.pg0.remote_ip6, self.pg1.remote_ip4, 25
2008 )
Filip Varga1f360232020-09-14 11:20:16 +02002009 else:
2010 self.logger.error(ppp("Unexpected or invalid packet: ", p))
2011
2012 def test_syslog_sess(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002013 """Test syslog session creation and deletion"""
Filip Varga1f360232020-09-14 11:20:16 +02002014 self.tcp_port_in = random.randint(1025, 65535)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002015 remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4, "64:ff9b::", 96)
Filip Varga1f360232020-09-14 11:20:16 +02002016
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002017 self.vapi.nat64_add_del_pool_addr_range(
2018 start_addr=self.nat_addr,
2019 end_addr=self.nat_addr,
2020 vrf_id=0xFFFFFFFF,
2021 is_add=1,
2022 )
Filip Varga1f360232020-09-14 11:20:16 +02002023 flags = self.config_flags.NAT_IS_INSIDE
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002024 self.vapi.nat64_add_del_interface(
2025 is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index
2026 )
2027 self.vapi.nat64_add_del_interface(
2028 is_add=1, flags=0, sw_if_index=self.pg1.sw_if_index
2029 )
2030 self.vapi.syslog_set_filter(self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
Filip Varga1f360232020-09-14 11:20:16 +02002031 self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
2032
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002033 p = (
2034 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2035 / IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6)
2036 / TCP(sport=self.tcp_port_in, dport=self.tcp_external_port)
2037 )
Filip Varga1f360232020-09-14 11:20:16 +02002038 self.pg0.add_stream(p)
2039 self.pg_enable_capture(self.pg_interfaces)
2040 self.pg_start()
2041 p = self.pg1.get_capture(1)
2042 self.tcp_port_out = p[0][TCP].sport
2043 capture = self.pg3.get_capture(1)
2044 self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
2045
2046 self.pg_enable_capture(self.pg_interfaces)
2047 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002048 self.vapi.nat64_add_del_pool_addr_range(
2049 start_addr=self.nat_addr,
2050 end_addr=self.nat_addr,
2051 vrf_id=0xFFFFFFFF,
2052 is_add=0,
2053 )
Filip Varga1f360232020-09-14 11:20:16 +02002054 capture = self.pg3.get_capture(1)
2055 self.verify_syslog_sess(capture[0][Raw].load, False, True)
2056
2057 def nat64_get_ses_num(self):
2058 """
2059 Return number of active NAT64 sessions.
2060 """
2061 st = self.vapi.nat64_st_dump(proto=255)
2062 return len(st)
2063
2064 def clear_nat64(self):
2065 """
2066 Clear NAT64 configuration.
2067 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002068 self.vapi.nat_ipfix_enable_disable(
2069 domain_id=self.ipfix_domain_id, src_port=self.ipfix_src_port, enable=0
2070 )
Filip Varga1f360232020-09-14 11:20:16 +02002071 self.ipfix_src_port = 4739
2072 self.ipfix_domain_id = 1
2073
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002074 self.vapi.syslog_set_filter(self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
Filip Varga1f360232020-09-14 11:20:16 +02002075
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002076 self.vapi.nat64_set_timeouts(
2077 udp=300, tcp_established=7440, tcp_transitory=240, icmp=60
2078 )
Filip Varga1f360232020-09-14 11:20:16 +02002079
2080 interfaces = self.vapi.nat64_interface_dump()
2081 for intf in interfaces:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002082 self.vapi.nat64_add_del_interface(
2083 is_add=0, flags=intf.flags, sw_if_index=intf.sw_if_index
2084 )
Filip Varga1f360232020-09-14 11:20:16 +02002085
2086 bib = self.vapi.nat64_bib_dump(proto=255)
2087 for bibe in bib:
2088 if bibe.flags & self.config_flags.NAT_IS_STATIC:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002089 self.vapi.nat64_add_del_static_bib(
2090 i_addr=bibe.i_addr,
2091 o_addr=bibe.o_addr,
2092 i_port=bibe.i_port,
2093 o_port=bibe.o_port,
2094 proto=bibe.proto,
2095 vrf_id=bibe.vrf_id,
2096 is_add=0,
2097 )
Filip Varga1f360232020-09-14 11:20:16 +02002098
2099 adresses = self.vapi.nat64_pool_addr_dump()
2100 for addr in adresses:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002101 self.vapi.nat64_add_del_pool_addr_range(
2102 start_addr=addr.address,
2103 end_addr=addr.address,
2104 vrf_id=addr.vrf_id,
2105 is_add=0,
2106 )
Filip Varga1f360232020-09-14 11:20:16 +02002107
2108 prefixes = self.vapi.nat64_prefix_dump()
2109 for prefix in prefixes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002110 self.vapi.nat64_add_del_prefix(
2111 prefix=str(prefix.prefix), vrf_id=prefix.vrf_id, is_add=0
2112 )
Filip Varga1f360232020-09-14 11:20:16 +02002113
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002114 bibs = self.statistics.get_counter("/nat64/total-bibs")
Filip Varga1f360232020-09-14 11:20:16 +02002115 self.assertEqual(bibs[0][0], 0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002116 sessions = self.statistics.get_counter("/nat64/total-sessions")
Filip Varga1f360232020-09-14 11:20:16 +02002117 self.assertEqual(sessions[0][0], 0)
2118
2119
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002120if __name__ == "__main__":
Filip Varga1f360232020-09-14 11:20:16 +02002121 unittest.main(testRunner=VppTestRunner)