Page MenuHomeVyOS Platform

No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None
diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl
index 340ab3678..343807e79 100644
--- a/data/templates/firewall/nftables-nat.tmpl
+++ b/data/templates/firewall/nftables-nat.tmpl
@@ -1,43 +1,54 @@
#!/usr/sbin/nft -f
# Start with a "clean" NAT table
flush table nat
+{% for rule in init_deinit -%}
+# Add or remove conntrack helper rules for NAT operation-
+{{ rule }}
+{% endfor %}
+
add chain ip raw NAT_CONNTRACK
-add rule ip raw PREROUTING position 25 counter jump VYATTA_CT_HELPER
-add rule ip raw PREROUTING position 17 counter jump NAT_CONNTRACK
-add rule ip raw OUTPUT position 26 counter jump VYATTA_CT_HELPER
-add rule ip raw OUTPUT position 21 counter jump NAT_CONNTRACK
+
+# insert rule after VYATTA_CT_IGNORE
+add rule ip raw PREROUTING position {{ pre_ct_ignore }} counter jump VYATTA_CT_HELPER
+# insert rule after VYATTA_CT_PREROUTING_HOOK
+add rule ip raw PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
+# insert rule after VYATTA_CT_IGNORE
+add rule ip raw OUTPUT position {{ out_ct_ignore }} counter jump VYATTA_CT_HELPER
+# insert rule after VYATTA_CT_PREROUTING_HOOK
+add rule ip raw OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
+
add rule ip raw NAT_CONNTRACK counter accept
{% for r in destination -%}
{% if r.protocol == 'tcp_udp' %}
{# Special handling for protocol tcp_udp which is represented as two individual rules #}
add rule ip nat PREROUTING iifname "{{ r.interface_in }}" tcp dport { {{ r.dest_port }} } counter dnat to {{ r.translation_address }}{{ ":" + r.translation_port if r.translation_port }} comment "DST-NAT-{{ r.number }} tcp_udp"
add rule ip nat PREROUTING iifname "{{ r.interface_in }}" udp dport { {{ r.dest_port }} } counter dnat to {{ r.translation_address }}{{ ":" + r.translation_port if r.translation_port }} comment "DST-NAT-{{ r.number }} tcp_udp"
{% else %}
add rule ip nat PREROUTING iifname "{{ r.interface_in }}" {{ r.protocol }} dport { {{ r.dest_port }} } counter dnat to {{ r.translation_address }}{{ ":" + r.translation_port if r.translation_port }} comment "DST-NAT-{{ r.number }}"
{% endif %}
{% endfor %}
{% for r in source -%}
{% if r.log %}
{% if r.exclude %}
{% set value = 'EXCL' %}
{% elif r.translation_address == 'masquerade' %}
{% set value = 'MASQ' %}
{% endif %}
add rule ip nat POSTROUTING oifname "{{ r.interface_out }}" ip saddr {{ r.source_address }} counter log prefix "[NAT-SRC-{{ r.number }}-{{ value }}]" comment "SRC-NAT-{{ r.number }}"
{% endif %}
{% if r.exclude %}
{% set value = 'return' %}
{% elif r.translation_address == 'masquerade' %}
{% set value = 'masquerade' %}
{% else %}
{% set value = 'snat to ' + r.translation_address %}
{% endif %}
add rule ip nat POSTROUTING oifname "{{ r.interface_out }}" ip saddr {{ r.source_address }} counter {{ value }} comment "SRC-NAT-{{ r.number }}"
{% endfor %}
diff --git a/debian/control b/debian/control
index 2aaca13ba..609f46e4d 100644
--- a/debian/control
+++ b/debian/control
@@ -1,111 +1,111 @@
Source: vyos-1x
Section: contrib/net
Priority: extra
Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
Build-Depends: debhelper (>= 9),
quilt,
python3,
python3-setuptools,
quilt,
python3-lxml,
python3-nose,
python3-coverage,
whois,
fakeroot,
libvyosconfig0 (>= 0.0.7)
Standards-Version: 3.9.6
Package: vyos-1x
Architecture: all
Depends: python3,
${python3:Depends},
python3-netifaces,
python3-jinja2,
python3-pystache,
python3-psutil,
python3-tabulate,
python3-six,
python3-isc-dhcp-leases,
python3-hurry.filesize,
python3-vici (>= 5.7.2),
python3-flask,
python3-waitress,
python3-netaddr,
python3-zmq,
cron,
easy-rsa,
ipaddrcheck,
tcpdump,
tshark,
isc-dhcp-client,
bmon,
hvinfo,
file,
lsscsi,
pciutils,
usbutils,
procps,
snmp, snmpd,
openssh-server,
ntp,
ntpdate,
iputils-arping,
libvyosconfig0,
beep,
isc-dhcp-server,
isc-dhcp-relay,
keepalived (>=2.0.5),
wireguard,
tftpd-hpa,
igmpproxy,
accel-ppp,
mdns-repeater,
udp-broadcast-relay,
pdns-recursor,
lcdproc,
lcdproc-extra-drivers,
openvpn,
openvpn-auth-ldap,
openvpn-auth-radius,
libpam-radius-auth (>= 1.5.0),
mtr-tiny,
telnet,
traceroute,
vyos-qat-kernel-modules,
vyos-qat-utilities,
ssl-cert,
nginx-light,
lldpd,
iperf,
iperf3,
frr,
radvd,
dbus,
usb-modeswitch,
hostapd (>= 0.6.8),
wpasupplicant (>= 0.6.7),
iw,
crda,
wireless-regdb,
pmacct (>= 1.6.0),
python3-certbot-nginx,
pppoe,
salt-minion,
vyos-utils,
- nftables,
+ nftables (>= 0.9.3),
conntrack,
${shlibs:Depends},
${misc:Depends}
Description: VyOS configuration scripts and data
VyOS configuration scripts, interface definitions, and everything
Package: vyos-1x-vmware
Architecture: amd64 i386
Depends:
${misc:Depends},
${shlibs:Depends},
vyos-1x,
open-vm-tools
Description: VyOS configuration scripts and data for VMware
Adds configuration files required for VyOS running on VMware hosts.
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index 2e866fdf4..128e2469c 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -1,159 +1,198 @@
#!/usr/bin/env python3
#
# Copyright (C) 2020 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 json
import os
from copy import deepcopy
from sys import exit
from netifaces import interfaces
from vyos.config import Config
-from vyos.util import call
from vyos.template import render
+from vyos.util import call, cmd
from vyos import ConfigError
default_config_data = {
- 'source': [],
- 'destination': []
+ 'prerouting_ct_helper': '',
+ 'prerouting_ct_conntrack': '',
+ 'output_ct_helper': '',
+ 'output_ct_conntrack': '',
+ 'destination': [],
+ 'source': []
}
iptables_nat_config = '/tmp/vyos-nat-rules.nft'
def _check_kmod():
+ """ load required Kernel modules """
modules = ['nft_nat', 'nft_chain_nat_ipv4']
for module in modules:
if not os.path.exists(f'/sys/module/{module}'):
if call(f'modprobe {module}') != 0:
raise ConfigError(f'Loading Kernel module {module} failed')
+
+def get_handler(chain, target):
+ """ Get handler number of given chain/target combination. Handler is
+ required when adding NAT/Conntrack helper targets """
+ tmp = json.loads(cmd('nft -j list table raw'))
+ for rule in tmp.get('nftables'):
+ # We're only interested in rules - not chains
+ if not 'rule' in rule.keys():
+ continue
+
+ # Search for chain of interest
+ if rule['rule']['chain'] == chain:
+ for expr in rule['rule']['expr']:
+ # We're only interested in jump targets
+ if not 'jump' in expr.keys():
+ continue
+
+ # Search for target of interest
+ if expr['jump']['target'] == target:
+ return rule['rule']['handle']
+
+ return None
+
+
def parse_source_destination(conf, source_dest):
""" Common wrapper to read in both NAT source and destination CLI """
tmp = []
base_level = ['nat', source_dest]
conf.set_level(base_level)
for number in conf.list_nodes(['rule']):
rule = {
'description': '',
'dest_address': '',
'dest_port': '',
'disable': False,
'exclude': False,
'interface_in': '',
'interface_out': '',
'log': False,
'protocol': '',
'number': number,
'source_address': '',
'source_port': '',
'translation_address': '',
'translation_port': ''
}
conf.set_level(base_level + ['rule', number])
if conf.exists(['description']):
rule['description'] = conf.return_value(['description'])
if conf.exists(['destination', 'address']):
rule['dest_address'] = conf.return_value(['destination', 'address'])
if conf.exists(['destination', 'port']):
rule['dest_port'] = conf.return_value(['destination', 'port'])
if conf.exists(['disable']):
rule['disable'] = True
if conf.exists(['exclude']):
rule['exclude'] = True
if conf.exists(['inbound-interface']):
rule['interface_in'] = conf.return_value(['inbound-interface'])
if conf.exists(['outbound-interface']):
rule['interface_out'] = conf.return_value(['outbound-interface'])
if conf.exists(['log']):
rule['log'] = True
if conf.exists(['protocol']):
rule['protocol'] = conf.return_value(['protocol'])
if conf.exists(['source', 'address']):
rule['source_address'] = conf.return_value(['source', 'address'])
if conf.exists(['source', 'port']):
rule['source_port'] = conf.return_value(['source', 'port'])
if conf.exists(['translation', 'address']):
rule['translation_address'] = conf.return_value(['translation', 'address'])
if conf.exists(['translation', 'port']):
rule['translation_port'] = conf.return_value(['translation', 'port'])
tmp.append(rule)
return tmp
def get_config():
nat = deepcopy(default_config_data)
conf = Config()
if not conf.exists(['nat']):
return None
else:
conf.set_level(['nat'])
+ nat['pre_ct_ignore'] = get_handler('PREROUTING', 'VYATTA_CT_IGNORE')
+ nat['pre_ct_conntrack'] = get_handler('PREROUTING', 'VYATTA_CT_PREROUTING_HOOK')
+ nat['out_ct_ignore'] = get_handler('OUTPUT', 'VYATTA_CT_IGNORE')
+ nat['out_ct_conntrack'] = get_handler('OUTPUT', 'VYATTA_CT_OUTPUT_HOOK')
+
# use a common wrapper function to read in the source / destination
# tree from the config - thus we do not need to replicate almost the
# same code :-)
for tgt in ['source', 'destination']:
nat[tgt] = parse_source_destination(conf, tgt)
return nat
def verify(nat):
if not nat:
return None
+ if not (nat['pre_ct_ignore'] or nat['pre_ct_conntrack'] or nat['out_ct_ignore'] or nat['out_ct_conntrack']):
+ raise Exception('could not determine nftable ruleset handlers')
+
for rule in nat['source']:
interface = rule['interface_out']
if interface and interface not in interfaces():
print(f'NAT configuration warning: interface {interface} does not exist on this system')
return None
def generate(nat):
if not nat:
return None
render(iptables_nat_config, 'firewall/nftables-nat.tmpl', nat, trim_blocks=True, permission=0o755)
+
return None
def apply(nat):
if not nat:
return None
call(f'{iptables_nat_config}')
return None
if __name__ == '__main__':
try:
_check_kmod()
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 26, 12:23 PM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4285128
Default Alt Text
(11 KB)

Event Timeline