Page MenuHomeVyOS Platform

No OneTemporary

Size
31 KB
Referenced Files
None
Subscribers
None
diff --git a/interface-definitions/include/nat-rule.xml.i b/interface-definitions/include/nat-rule.xml.i
index 8f2029388..7b3b8804e 100644
--- a/interface-definitions/include/nat-rule.xml.i
+++ b/interface-definitions/include/nat-rule.xml.i
@@ -1,294 +1,321 @@
<!-- include start from nat-rule.xml.i -->
<tagNode name="rule">
<properties>
<help>Rule number for NAT</help>
<valueHelp>
<format>u32:1-999999</format>
<description>Number of NAT rule</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-999999"/>
</constraint>
<constraintErrorMessage>NAT rule number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
#include <include/generic-description.xml.i>
<node name="destination">
<properties>
<help>NAT destination parameters</help>
</properties>
<children>
#include <include/nat-address.xml.i>
#include <include/nat-port.xml.i>
#include <include/firewall/source-destination-group.xml.i>
</children>
</node>
#include <include/generic-disable-node.xml.i>
#include <include/nat-exclude.xml.i>
<leafNode name="log">
<properties>
<help>NAT rule logging</help>
<valueless/>
</properties>
</leafNode>
+ <leafNode name="packet-type">
+ <properties>
+ <help>Packet type</help>
+ <completionHelp>
+ <list>broadcast host multicast other</list>
+ </completionHelp>
+ <valueHelp>
+ <format>broadcast</format>
+ <description>Match broadcast packet type</description>
+ </valueHelp>
+ <valueHelp>
+ <format>host</format>
+ <description>Match host packet type, addressed to local host</description>
+ </valueHelp>
+ <valueHelp>
+ <format>multicast</format>
+ <description>Match multicast packet type</description>
+ </valueHelp>
+ <valueHelp>
+ <format>other</format>
+ <description>Match packet addressed to another host</description>
+ </valueHelp>
+ <constraint>
+ <regex>(broadcast|host|multicast|other)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
<leafNode name="protocol">
<properties>
<help>Protocol to NAT</help>
<completionHelp>
<list>all ip hopopt icmp igmp ggp ipencap st tcp egp igp pup udp tcp_udp hmp xns-idp rdp iso-tp4 dccp xtp ddp idpr-cmtp ipv6 ipv6-route ipv6-frag idrp rsvp gre esp ah skip ipv6-icmp ipv6-nonxt ipv6-opts rspf vmtp eigrp ospf ax.25 ipip etherip encap 99 pim ipcomp vrrp l2tp isis sctp fc mobility-header udplite mpls-in-ip manet hip shim6 wesp rohc</list>
</completionHelp>
<valueHelp>
<format>all</format>
<description>All IP protocols</description>
</valueHelp>
<valueHelp>
<format>ip</format>
<description>Internet Protocol, pseudo protocol number</description>
</valueHelp>
<valueHelp>
<format>hopopt</format>
<description>IPv6 Hop-by-Hop Option [RFC1883]</description>
</valueHelp>
<valueHelp>
<format>icmp</format>
<description>internet control message protocol</description>
</valueHelp>
<valueHelp>
<format>igmp</format>
<description>Internet Group Management</description>
</valueHelp>
<valueHelp>
<format>ggp</format>
<description>gateway-gateway protocol</description>
</valueHelp>
<valueHelp>
<format>ipencap</format>
<description>IP encapsulated in IP (officially IP)</description>
</valueHelp>
<valueHelp>
<format>st</format>
<description>ST datagram mode</description>
</valueHelp>
<valueHelp>
<format>tcp</format>
<description>transmission control protocol</description>
</valueHelp>
<valueHelp>
<format>egp</format>
<description>exterior gateway protocol</description>
</valueHelp>
<valueHelp>
<format>igp</format>
<description>any private interior gateway (Cisco)</description>
</valueHelp>
<valueHelp>
<format>pup</format>
<description>PARC universal packet protocol</description>
</valueHelp>
<valueHelp>
<format>udp</format>
<description>user datagram protocol</description>
</valueHelp>
<valueHelp>
<format>tcp_udp</format>
<description>Both TCP and UDP</description>
</valueHelp>
<valueHelp>
<format>hmp</format>
<description>host monitoring protocol</description>
</valueHelp>
<valueHelp>
<format>xns-idp</format>
<description>Xerox NS IDP</description>
</valueHelp>
<valueHelp>
<format>rdp</format>
<description>"reliable datagram" protocol</description>
</valueHelp>
<valueHelp>
<format>iso-tp4</format>
<description>ISO Transport Protocol class 4 [RFC905]</description>
</valueHelp>
<valueHelp>
<format>dccp</format>
<description>Datagram Congestion Control Prot. [RFC4340]</description>
</valueHelp>
<valueHelp>
<format>xtp</format>
<description>Xpress Transfer Protocol</description>
</valueHelp>
<valueHelp>
<format>ddp</format>
<description>Datagram Delivery Protocol</description>
</valueHelp>
<valueHelp>
<format>idpr-cmtp</format>
<description>IDPR Control Message Transport</description>
</valueHelp>
<valueHelp>
<format>Ipv6</format>
<description>Internet Protocol, version 6</description>
</valueHelp>
<valueHelp>
<format>ipv6-route</format>
<description>Routing Header for IPv6</description>
</valueHelp>
<valueHelp>
<format>ipv6-frag</format>
<description>Fragment Header for IPv6</description>
</valueHelp>
<valueHelp>
<format>idrp</format>
<description>Inter-Domain Routing Protocol</description>
</valueHelp>
<valueHelp>
<format>rsvp</format>
<description>Reservation Protocol</description>
</valueHelp>
<valueHelp>
<format>gre</format>
<description>General Routing Encapsulation</description>
</valueHelp>
<valueHelp>
<format>esp</format>
<description>Encap Security Payload [RFC2406]</description>
</valueHelp>
<valueHelp>
<format>ah</format>
<description>Authentication Header [RFC2402]</description>
</valueHelp>
<valueHelp>
<format>skip</format>
<description>SKIP</description>
</valueHelp>
<valueHelp>
<format>ipv6-icmp</format>
<description>ICMP for IPv6</description>
</valueHelp>
<valueHelp>
<format>ipv6-nonxt</format>
<description>No Next Header for IPv6</description>
</valueHelp>
<valueHelp>
<format>ipv6-opts</format>
<description>Destination Options for IPv6</description>
</valueHelp>
<valueHelp>
<format>rspf</format>
<description>Radio Shortest Path First (officially CPHB)</description>
</valueHelp>
<valueHelp>
<format>vmtp</format>
<description>Versatile Message Transport</description>
</valueHelp>
<valueHelp>
<format>eigrp</format>
<description>Enhanced Interior Routing Protocol (Cisco)</description>
</valueHelp>
<valueHelp>
<format>ospf</format>
<description>Open Shortest Path First IGP</description>
</valueHelp>
<valueHelp>
<format>ax.25</format>
<description>AX.25 frames</description>
</valueHelp>
<valueHelp>
<format>ipip</format>
<description>IP-within-IP Encapsulation Protocol</description>
</valueHelp>
<valueHelp>
<format>etherip</format>
<description>Ethernet-within-IP Encapsulation [RFC3378]</description>
</valueHelp>
<valueHelp>
<format>encap</format>
<description>Yet Another IP encapsulation [RFC1241]</description>
</valueHelp>
<valueHelp>
<format>99</format>
<description>Any private encryption scheme</description>
</valueHelp>
<valueHelp>
<format>pim</format>
<description>Protocol Independent Multicast</description>
</valueHelp>
<valueHelp>
<format>ipcomp</format>
<description>IP Payload Compression Protocol</description>
</valueHelp>
<valueHelp>
<format>vrrp</format>
<description>Virtual Router Redundancy Protocol [RFC5798]</description>
</valueHelp>
<valueHelp>
<format>l2tp</format>
<description>Layer Two Tunneling Protocol [RFC2661]</description>
</valueHelp>
<valueHelp>
<format>isis</format>
<description>IS-IS over IPv4</description>
</valueHelp>
<valueHelp>
<format>sctp</format>
<description>Stream Control Transmission Protocol</description>
</valueHelp>
<valueHelp>
<format>fc</format>
<description>Fibre Channel</description>
</valueHelp>
<valueHelp>
<format>mobility-header</format>
<description>Mobility Support for IPv6 [RFC3775]</description>
</valueHelp>
<valueHelp>
<format>udplite</format>
<description>UDP-Lite [RFC3828]</description>
</valueHelp>
<valueHelp>
<format>mpls-in-ip</format>
<description>MPLS-in-IP [RFC4023]</description>
</valueHelp>
<valueHelp>
<format>manet</format>
<description>MANET Protocols [RFC5498]</description>
</valueHelp>
<valueHelp>
<format>hip</format>
<description>Host Identity Protocol</description>
</valueHelp>
<valueHelp>
<format>shim6</format>
<description>Shim6 Protocol</description>
</valueHelp>
<valueHelp>
<format>wesp</format>
<description>Wrapped Encapsulating Security Payload</description>
</valueHelp>
<valueHelp>
<format>rohc</format>
<description>Robust Header Compression</description>
</valueHelp>
<valueHelp>
<format>u32:0-255</format>
<description>IP protocol number</description>
</valueHelp>
<constraint>
<validator name="ip-protocol"/>
</constraint>
</properties>
<defaultValue>all</defaultValue>
</leafNode>
<node name="source">
<properties>
<help>NAT source parameters</help>
</properties>
<children>
#include <include/nat-address.xml.i>
#include <include/nat-port.xml.i>
#include <include/firewall/source-destination-group.xml.i>
</children>
</node>
</children>
</tagNode>
<!-- include end -->
diff --git a/python/vyos/nat.py b/python/vyos/nat.py
index 8a311045a..53fd7fb33 100644
--- a/python/vyos/nat.py
+++ b/python/vyos/nat.py
@@ -1,241 +1,244 @@
#!/usr/bin/env python3
#
# Copyright (C) 2022 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from vyos.template import is_ip_network
from vyos.util import dict_search_args
from vyos.template import bracketize_ipv6
def parse_nat_rule(rule_conf, rule_id, nat_type, ipv6=False):
output = []
ip_prefix = 'ip6' if ipv6 else 'ip'
log_prefix = ('DST' if nat_type == 'destination' else 'SRC') + f'-NAT-{rule_id}'
log_suffix = ''
if ipv6:
log_prefix = log_prefix.replace("NAT-", "NAT66-")
ignore_type_addr = False
translation_str = ''
if 'inbound_interface' in rule_conf:
ifname = rule_conf['inbound_interface']
if ifname != 'any':
output.append(f'iifname "{ifname}"')
if 'outbound_interface' in rule_conf:
ifname = rule_conf['outbound_interface']
if ifname != 'any':
output.append(f'oifname "{ifname}"')
if 'protocol' in rule_conf and rule_conf['protocol'] != 'all':
protocol = rule_conf['protocol']
if protocol == 'tcp_udp':
protocol = '{ tcp, udp }'
output.append(f'meta l4proto {protocol}')
+ if 'packet_type' in rule_conf:
+ output.append(f'pkttype ' + rule_conf['packet_type'])
+
if 'exclude' in rule_conf:
translation_str = 'return'
log_suffix = '-EXCL'
elif 'translation' in rule_conf:
translation_prefix = nat_type[:1]
translation_output = [f'{translation_prefix}nat']
addr = dict_search_args(rule_conf, 'translation', 'address')
port = dict_search_args(rule_conf, 'translation', 'port')
if addr and is_ip_network(addr):
if not ipv6:
map_addr = dict_search_args(rule_conf, nat_type, 'address')
translation_output.append(f'{ip_prefix} prefix to {ip_prefix} {translation_prefix}addr map {{ {map_addr} : {addr} }}')
ignore_type_addr = True
else:
translation_output.append(f'prefix to {addr}')
elif addr == 'masquerade':
if port:
addr = f'{addr} to '
translation_output = [addr]
log_suffix = '-MASQ'
else:
translation_output.append('to')
if addr:
addr = bracketize_ipv6(addr)
translation_output.append(addr)
options = []
addr_mapping = dict_search_args(rule_conf, 'translation', 'options', 'address_mapping')
port_mapping = dict_search_args(rule_conf, 'translation', 'options', 'port_mapping')
if addr_mapping == 'persistent':
options.append('persistent')
if port_mapping and port_mapping != 'none':
options.append(port_mapping)
translation_str = " ".join(translation_output) + (f':{port}' if port else '')
if options:
translation_str += f' {",".join(options)}'
for target in ['source', 'destination']:
if target not in rule_conf:
continue
side_conf = rule_conf[target]
prefix = target[:1]
addr = dict_search_args(side_conf, 'address')
if addr and not (ignore_type_addr and target == nat_type):
operator = ''
if addr[:1] == '!':
operator = '!='
addr = addr[1:]
output.append(f'{ip_prefix} {prefix}addr {operator} {addr}')
addr_prefix = dict_search_args(side_conf, 'prefix')
if addr_prefix and ipv6:
operator = ''
if addr_prefix[:1] == '!':
operator = '!='
addr_prefix = addr[1:]
output.append(f'ip6 {prefix}addr {operator} {addr_prefix}')
port = dict_search_args(side_conf, 'port')
if port:
protocol = rule_conf['protocol']
if protocol == 'tcp_udp':
protocol = 'th'
operator = ''
if port[:1] == '!':
operator = '!='
port = port[1:]
output.append(f'{protocol} {prefix}port {operator} {{ {port} }}')
if 'group' in side_conf:
group = side_conf['group']
if 'address_group' in group and not (ignore_type_addr and target == nat_type):
group_name = group['address_group']
operator = ''
if group_name[0] == '!':
operator = '!='
group_name = group_name[1:]
output.append(f'{ip_prefix} {prefix}addr {operator} @A_{group_name}')
# Generate firewall group domain-group
elif 'domain_group' in group and not (ignore_type_addr and target == nat_type):
group_name = group['domain_group']
operator = ''
if group_name[0] == '!':
operator = '!='
group_name = group_name[1:]
output.append(f'{ip_prefix} {prefix}addr {operator} @D_{group_name}')
elif 'network_group' in group and not (ignore_type_addr and target == nat_type):
group_name = group['network_group']
operator = ''
if group_name[0] == '!':
operator = '!='
group_name = group_name[1:]
output.append(f'{ip_prefix} {prefix}addr {operator} @N_{group_name}')
if 'mac_group' in group:
group_name = group['mac_group']
operator = ''
if group_name[0] == '!':
operator = '!='
group_name = group_name[1:]
output.append(f'ether {prefix}addr {operator} @M_{group_name}')
if 'port_group' in group:
proto = rule_conf['protocol']
group_name = group['port_group']
if proto == 'tcp_udp':
proto = 'th'
operator = ''
if group_name[0] == '!':
operator = '!='
group_name = group_name[1:]
output.append(f'{proto} {prefix}port {operator} @P_{group_name}')
output.append('counter')
if 'log' in rule_conf:
output.append(f'log prefix "[{log_prefix}{log_suffix}]"')
if translation_str:
output.append(translation_str)
output.append(f'comment "{log_prefix}"')
return " ".join(output)
def parse_nat_static_rule(rule_conf, rule_id, nat_type):
output = []
log_prefix = ('STATIC-DST' if nat_type == 'destination' else 'STATIC-SRC') + f'-NAT-{rule_id}'
log_suffix = ''
ignore_type_addr = False
translation_str = ''
if 'inbound_interface' in rule_conf:
ifname = rule_conf['inbound_interface']
ifprefix = 'i' if nat_type == 'destination' else 'o'
if ifname != 'any':
output.append(f'{ifprefix}ifname "{ifname}"')
if 'exclude' in rule_conf:
translation_str = 'return'
log_suffix = '-EXCL'
elif 'translation' in rule_conf:
translation_prefix = nat_type[:1]
translation_output = [f'{translation_prefix}nat']
addr = dict_search_args(rule_conf, 'translation', 'address')
map_addr = dict_search_args(rule_conf, 'destination', 'address')
if nat_type == 'source':
addr, map_addr = map_addr, addr # Swap
if addr and is_ip_network(addr):
translation_output.append(f'ip prefix to ip {translation_prefix}addr map {{ {map_addr} : {addr} }}')
ignore_type_addr = True
elif addr:
translation_output.append(f'to {addr}')
options = []
addr_mapping = dict_search_args(rule_conf, 'translation', 'options', 'address_mapping')
port_mapping = dict_search_args(rule_conf, 'translation', 'options', 'port_mapping')
if addr_mapping == 'persistent':
options.append('persistent')
if port_mapping and port_mapping != 'none':
options.append(port_mapping)
if options:
translation_output.append(",".join(options))
translation_str = " ".join(translation_output)
prefix = nat_type[:1]
addr = dict_search_args(rule_conf, 'translation' if nat_type == 'source' else nat_type, 'address')
if addr and not ignore_type_addr:
output.append(f'ip {prefix}addr {addr}')
output.append('counter')
if translation_str:
output.append(translation_str)
if 'log' in rule_conf:
output.append(f'log prefix "[{log_prefix}{log_suffix}]"')
output.append(f'comment "{log_prefix}"')
return " ".join(output)
diff --git a/smoketest/scripts/cli/test_nat.py b/smoketest/scripts/cli/test_nat.py
index 9f4e3b831..1f2b777a8 100755
--- a/smoketest/scripts/cli/test_nat.py
+++ b/smoketest/scripts/cli/test_nat.py
@@ -1,234 +1,235 @@
#!/usr/bin/env python3
#
# Copyright (C) 2020-2022 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jmespath
import json
import os
import unittest
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
from vyos.util import dict_search
base_path = ['nat']
src_path = base_path + ['source']
dst_path = base_path + ['destination']
static_path = base_path + ['static']
nftables_nat_config = '/run/nftables_nat.conf'
nftables_static_nat_conf = '/run/nftables_static-nat-rules.nft'
class TestNAT(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestNAT, cls).setUpClass()
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
self.assertFalse(os.path.exists(nftables_nat_config))
self.assertFalse(os.path.exists(nftables_static_nat_conf))
def verify_nftables(self, nftables_search, table, inverse=False, args=''):
nftables_output = cmd(f'sudo nft {args} list table {table}')
for search in nftables_search:
matched = False
for line in nftables_output.split("\n"):
if all(item in line for item in search):
matched = True
break
self.assertTrue(not matched if inverse else matched, msg=search)
def wait_for_domain_resolver(self, table, set_name, element, max_wait=10):
# Resolver no longer blocks commit, need to wait for daemon to populate set
count = 0
while count < max_wait:
code = run(f'sudo nft get element {table} {set_name} {{ {element} }}')
if code == 0:
return True
count += 1
sleep(1)
return False
def test_snat(self):
rules = ['100', '110', '120', '130', '200', '210', '220', '230']
outbound_iface_100 = 'eth0'
outbound_iface_200 = 'eth1'
nftables_search = ['jump VYOS_PRE_SNAT_HOOK']
for rule in rules:
network = f'192.168.{rule}.0/24'
# depending of rule order we check either for source address for NAT
# or configured destination address for NAT
if int(rule) < 200:
self.cli_set(src_path + ['rule', rule, 'source', 'address', network])
self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_100])
self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
nftables_search.append([f'saddr {network}', f'oifname "{outbound_iface_100}"', 'masquerade'])
else:
self.cli_set(src_path + ['rule', rule, 'destination', 'address', network])
self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface_200])
self.cli_set(src_path + ['rule', rule, 'exclude'])
nftables_search.append([f'daddr {network}', f'oifname "{outbound_iface_200}"', 'return'])
self.cli_commit()
self.verify_nftables(nftables_search, 'ip vyos_nat')
def test_snat_groups(self):
address_group = 'smoketest_addr'
address_group_member = '192.0.2.1'
rule = '100'
outbound_iface = 'eth0'
self.cli_set(['firewall', 'group', 'address-group', address_group, 'address', address_group_member])
self.cli_set(src_path + ['rule', rule, 'source', 'group', 'address-group', address_group])
self.cli_set(src_path + ['rule', rule, 'outbound-interface', outbound_iface])
self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
self.cli_commit()
nftables_search = [
[f'set A_{address_group}'],
[f'elements = {{ {address_group_member} }}'],
[f'ip saddr @A_{address_group}', f'oifname "{outbound_iface}"', 'masquerade']
]
self.verify_nftables(nftables_search, 'ip vyos_nat')
self.cli_delete(['firewall'])
def test_dnat(self):
rules = ['100', '110', '120', '130', '200', '210', '220', '230']
inbound_iface_100 = 'eth0'
inbound_iface_200 = 'eth1'
inbound_proto_100 = 'udp'
inbound_proto_200 = 'tcp'
nftables_search = ['jump VYOS_PRE_DNAT_HOOK']
for rule in rules:
port = f'10{rule}'
self.cli_set(dst_path + ['rule', rule, 'source', 'port', port])
self.cli_set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1'])
self.cli_set(dst_path + ['rule', rule, 'translation', 'port', port])
rule_search = [f'dnat to 192.0.2.1:{port}']
if int(rule) < 200:
self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_100])
self.cli_set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_100])
rule_search.append(f'{inbound_proto_100} sport {port}')
rule_search.append(f'iifname "{inbound_iface_100}"')
else:
self.cli_set(dst_path + ['rule', rule, 'protocol', inbound_proto_200])
self.cli_set(dst_path + ['rule', rule, 'inbound-interface', inbound_iface_200])
rule_search.append(f'iifname "{inbound_iface_200}"')
nftables_search.append(rule_search)
self.cli_commit()
self.verify_nftables(nftables_search, 'ip vyos_nat')
def test_snat_required_translation_address(self):
# T2813: Ensure translation address is specified
rule = '5'
self.cli_set(src_path + ['rule', rule, 'source', 'address', '192.0.2.0/24'])
# check validate() - outbound-interface must be defined
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(src_path + ['rule', rule, 'outbound-interface', 'eth0'])
# check validate() - translation address not specified
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(src_path + ['rule', rule, 'translation', 'address', 'masquerade'])
self.cli_commit()
def test_dnat_negated_addresses(self):
# T3186: negated addresses are not accepted by nftables
rule = '1000'
self.cli_set(dst_path + ['rule', rule, 'destination', 'address', '!192.0.2.1'])
self.cli_set(dst_path + ['rule', rule, 'destination', 'port', '53'])
self.cli_set(dst_path + ['rule', rule, 'inbound-interface', 'eth0'])
self.cli_set(dst_path + ['rule', rule, 'protocol', 'tcp_udp'])
self.cli_set(dst_path + ['rule', rule, 'source', 'address', '!192.0.2.1'])
self.cli_set(dst_path + ['rule', rule, 'translation', 'address', '192.0.2.1'])
self.cli_set(dst_path + ['rule', rule, 'translation', 'port', '53'])
self.cli_commit()
def test_nat_no_rules(self):
# T3206: deleting all rules but keep the direction 'destination' or
# 'source' resulteds in KeyError: 'rule'.
#
# Test that both 'nat destination' and 'nat source' nodes can exist
# without any rule
self.cli_set(src_path)
self.cli_set(dst_path)
self.cli_set(static_path)
self.cli_commit()
def test_dnat_without_translation_address(self):
self.cli_set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
self.cli_set(dst_path + ['rule', '1', 'destination', 'port', '443'])
self.cli_set(dst_path + ['rule', '1', 'protocol', 'tcp'])
+ self.cli_set(dst_path + ['rule', '1', 'packet-type', 'host'])
self.cli_set(dst_path + ['rule', '1', 'translation', 'port', '443'])
self.cli_commit()
nftables_search = [
- ['iifname "eth1"', 'tcp dport 443', 'dnat to :443']
+ ['iifname "eth1"', 'tcp dport 443', 'pkttype host', 'dnat to :443']
]
self.verify_nftables(nftables_search, 'ip vyos_nat')
def test_static_nat(self):
dst_addr_1 = '10.0.1.1'
translate_addr_1 = '192.168.1.1'
dst_addr_2 = '203.0.113.0/24'
translate_addr_2 = '192.0.2.0/24'
ifname = 'eth0'
self.cli_set(static_path + ['rule', '10', 'destination', 'address', dst_addr_1])
self.cli_set(static_path + ['rule', '10', 'inbound-interface', ifname])
self.cli_set(static_path + ['rule', '10', 'translation', 'address', translate_addr_1])
self.cli_set(static_path + ['rule', '20', 'destination', 'address', dst_addr_2])
self.cli_set(static_path + ['rule', '20', 'inbound-interface', ifname])
self.cli_set(static_path + ['rule', '20', 'translation', 'address', translate_addr_2])
self.cli_commit()
nftables_search = [
[f'iifname "{ifname}"', f'ip daddr {dst_addr_1}', f'dnat to {translate_addr_1}'],
[f'oifname "{ifname}"', f'ip saddr {translate_addr_1}', f'snat to {dst_addr_1}'],
[f'iifname "{ifname}"', f'dnat ip prefix to ip daddr map {{ {dst_addr_2} : {translate_addr_2} }}'],
[f'oifname "{ifname}"', f'snat ip prefix to ip saddr map {{ {translate_addr_2} : {dst_addr_2} }}']
]
self.verify_nftables(nftables_search, 'ip vyos_static_nat')
if __name__ == '__main__':
unittest.main(verbosity=2)

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:45 AM (2 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4641778
Default Alt Text
(31 KB)

Event Timeline