Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119064275
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:45 AM (5 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4641778
Default Alt Text
(31 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment