Changes in sonic-buildimage to support the NAT feature (#3494)

* Changes in sonic-buildimage for the NAT feature
- Docker for NAT
- installing the required tools iptables and conntrack for nat

Signed-off-by: kiran.kella@broadcom.com

* Add redis-tools dependencies in the docker nat compilation

* Addressed review comments

* add natsyncd to warm-boot finalizer list

* addressed review comments

* using swsscommon.DBConnector instead of swsssdk.SonicV2Connector

* Enable NAT application in docker-sonic-vs
This commit is contained in:
Kiran Kumar Kella 2020-01-30 07:10:43 +05:30 committed by GitHub
parent 5383e2c765
commit 97165a0d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 636 additions and 3 deletions

View File

@ -277,7 +277,8 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in
cgroup-tools \
ipmitool \
ndisc6 \
makedumpfile
makedumpfile \
conntrack
if [[ $CONFIGURED_ARCH == amd64 ]]; then

View File

@ -0,0 +1,46 @@
{% from "dockers/dockerfile-macros.j2" import install_debian_packages, copy_files %}
FROM docker-config-engine-stretch
ARG docker_container_name
RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf
RUN echo
## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive
## Install redis-tools dependencies
## TODO: implicitly install dependencies
RUN apt-get update \
&& apt-get install -f -y \
libdbus-1-3 \
libdaemon0 \
libjansson4 \
libpython2.7 \
libatomic1 \
libjemalloc1 \
liblua5.1-0 \
lua-bitop \
lua-cjson \
libelf1 \
libmnl0 \
bridge-utils \
conntrack
{% if docker_nat_debs.strip() -%}
# Copy locally-built Debian package dependencies
{{copy_files ("debs/", docker_nat_debs.split(' '), "/debs/") }}
# Install locally-built Debian packages and implicitly install their dependencies
{{ install_debian_packages(docker_nat_debs.split(' ')) }}
{%- endif %}
COPY ["start.sh", "/usr/bin/"]
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["restore_nat_entries.py", "/usr/bin/"]
RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y
RUN rm -rf /debs
ENTRYPOINT ["/usr/bin/supervisord"]

View File

@ -0,0 +1,5 @@
#!/bin/bash
# -t option needed only for shell, not for commands
docker exec -i nat natctl "$@"

View File

@ -0,0 +1,104 @@
#!/usr/bin/env python
""""
Description: restore_nat_entries.py -- restoring nat entries table into kernel during system warm reboot.
The script is started by supervisord in nat docker when the docker is started.
It does not do anything in case neither system nor nat warm restart is enabled.
In case nat warm restart enabled only, it sets the stateDB flag so natsyncd can continue
the reconciation process.
In case system warm reboot is enabled, it will try to restore the nat entries table into kernel
, then it sets the stateDB flag for natsyncd to continue the
reconciliation process.
"""
import sys
import subprocess
from swsscommon import swsscommon
import logging
import logging.handlers
import re
import os
WARM_BOOT_FILE_DIR = '/var/warmboot/nat/'
NAT_WARM_BOOT_FILE = 'nat_entries.dump'
IP_PROTO_TCP = '6'
MATCH_CONNTRACK_ENTRY = '^(\w+)\s+(\d+).*src=([\d.]+)\s+dst=([\d.]+)\s+sport=(\d+)\s+dport=(\d+).*src=([\d.]+)\s+dst=([\d.]+)\s+sport=(\d+)\s+dport=(\d+)'
REDIS_SOCK = "/var/run/redis/redis.sock"
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.handlers.SysLogHandler(address = '/dev/log')
logger.addHandler(handler)
def add_nat_conntrack_entry_in_kernel(ipproto, srcip, dstip, srcport, dstport, natsrcip, natdstip, natsrcport, natdstport):
# pyroute2 doesn't have support for adding conntrack entries via netlink yet. So, invoking the conntrack utility to add the entries.
state = ''
if (ipproto == IP_PROTO_TCP):
state = ' --state ESTABLISHED '
ctcmd = 'conntrack -I -n ' + natdstip + ':' + natdstport + ' -g ' + natsrcip + ':' + natsrcport + \
' --protonum ' + ipproto + state + ' --timeout 600 --src ' + srcip + ' --sport ' + srcport + \
' --dst ' + dstip + ' --dport ' + dstport + ' -u ASSURED'
subprocess.call(ctcmd, shell=True)
logger.info("Restored NAT entry: {}".format(ctcmd))
# Set the statedb "NAT_RESTORE_TABLE|Flags", so natsyncd can start reconciliation
def set_statedb_nat_restore_done():
statedb = swsscommon.DBConnector(swsscommon.STATE_DB, REDIS_SOCK, 0)
tbl = swsscommon.Table(statedb, "NAT_RESTORE_TABLE")
fvs = swsscommon.FieldValuePairs([("restored", "true")])
tbl.set("Flags", fvs)
return
# This function is to restore the kernel nat entries based on the saved nat entries.
def restore_update_kernel_nat_entries(filename):
# Read the entries from nat_entries.dump file and add them to kernel
conntrack_match_pattern = re.compile(r'{}'.format(MATCH_CONNTRACK_ENTRY))
with open(filename, 'r') as fp:
for line in fp:
ctline = conntrack_match_pattern.findall(line)
if not ctline:
continue
cmdargs = list(ctline.pop(0))
proto = cmdargs.pop(0)
if proto not in ('tcp', 'udp'):
continue
add_nat_conntrack_entry_in_kernel(*cmdargs)
def main():
logger.info("restore_nat_entries service is started")
# Use warmstart python binding to check warmstart information
warmstart = swsscommon.WarmStart()
warmstart.initialize("natsyncd", "nat")
warmstart.checkWarmStart("natsyncd", "nat", False)
# if swss or system warm reboot not enabled, don't run
if not warmstart.isWarmStart():
logger.info("restore_nat_entries service is skipped as warm restart not enabled")
return
# NAT restart not system warm reboot, set statedb directly
if not warmstart.isSystemWarmRebootEnabled():
set_statedb_nat_restore_done()
logger.info("restore_nat_entries service is done as system warm reboot not enabled")
return
# Program the nat conntrack entries in the kernel by reading the
# entries from nat_entries.dump
try:
restore_update_kernel_nat_entries(WARM_BOOT_FILE_DIR + NAT_WARM_BOOT_FILE)
except Exception as e:
logger.exception(str(e))
sys.exit(1)
# Remove the dump file after restoration
os.remove(WARM_BOOT_FILE_DIR + NAT_WARM_BOOT_FILE)
# set statedb to signal other processes like natsyncd
set_statedb_nat_restore_done()
logger.info("restore_nat_entries service is done for system warmreboot")
return
if __name__ == '__main__':
main()

15
dockers/docker-nat/start.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
rm -f /var/run/rsyslogd.pid
rm -f /var/run/nat/*
mkdir -p /var/warmboot/nat
supervisorctl start rsyslogd
supervisorctl start natmgrd
supervisorctl start natsyncd
supervisorctl start restore_nat_entries

View File

@ -0,0 +1,47 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true
[program:start.sh]
command=/usr/bin/start.sh
priority=1
autostart=true
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:rsyslogd]
command=/usr/sbin/rsyslogd -n
priority=2
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:natmgrd]
command=/usr/bin/natmgrd
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:natsyncd]
command=/usr/bin/natsyncd
priority=4
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:restore_nat_entries]
command=/usr/bin/restore_nat_entries.py
priority=5
autostart=false
autorestart=false
startsecs=0
startretries=0
stdout_logfile=syslog
stderr_logfile=syslog

View File

@ -20,7 +20,8 @@ RUN apt-get update && \
tcpdump \
libelf1 \
libmnl0 \
bridge-utils
bridge-utils \
conntrack
{% if ( CONFIGURED_ARCH == "armhf" or CONFIGURED_ARCH == "arm64" ) %}
## Fix for gcc/python not found in arm docker

View File

@ -0,0 +1,15 @@
[Unit]
Description=NAT container
Requires=updategraph.service swss.service
After=updategraph.service swss.service syncd.service
Before=ntp-config.service
[Service]
User={{ sonicadmin_user }}
ExecStartPre=/usr/bin/{{docker_container_name}}.sh start
ExecStart=/usr/bin/{{docker_container_name}}.sh wait
ExecStop=/usr/bin/{{docker_container_name}}.sh stop
[Install]
WantedBy=multi-user.target swss.service

View File

@ -81,6 +81,10 @@ sudo mkdir -p $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/ifupdown2_*.deb || \
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
# Install ipables (and its dependencies via 'apt-get -y install -f')
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/iptables_*.deb || \
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
# Install dependencies for SONiC config engine
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install \
python-dev \

View File

@ -3,7 +3,7 @@
VERBOSE=no
# Check components
COMP_LIST="orchagent neighsyncd bgp"
COMP_LIST="orchagent neighsyncd bgp natsyncd"
EXP_STATE="reconciled"
ASSISTANT_SCRIPT="/usr/bin/neighbor_advertiser"

View File

@ -70,6 +70,10 @@ supervisorctl start vxlanmgrd
supervisorctl start sflowmgrd
supervisorctl start natmgrd
supervisorctl start natsyncd
# Start arp_update when VLAN exists
VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'`
if [ "$VLAN" != "" ]; then

View File

@ -188,3 +188,19 @@ autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:natmgrd]
command=/usr/bin/natmgrd
priority=23
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
[program:natsyncd]
command=/usr/bin/natsyncd
priority=24
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

30
rules/docker-nat.mk Normal file
View File

@ -0,0 +1,30 @@
# docker image for nat
DOCKER_NAT_STEM = docker-nat
DOCKER_NAT = $(DOCKER_NAT_STEM).gz
DOCKER_NAT_DBG = $(DOCKER_NAT_STEM)-$(DBG_IMAGE_MARK).gz
$(DOCKER_NAT)_PATH = $(DOCKERS_PATH)/$(DOCKER_NAT_STEM)
$(DOCKER_NAT)_DEPENDS += $(SWSS) $(REDIS_TOOLS) $(IPTABLESIP4TC) $(IPTABLESIP6TC) $(IPTABLESIPTC) $(IPXTABLES12) $(IPTABLES)
$(DOCKER_NAT)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS)
$(DOCKER_NAT)_DBG_DEPENDS += $(SWSS_DBG) $(LIBSWSSCOMMON_DBG)
$(DOCKER_NAT)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES)
$(DOCKER_NAT)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH)
SONIC_DOCKER_IMAGES += $(DOCKER_NAT)
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_NAT)
SONIC_STRETCH_DOCKERS += $(DOCKER_NAT)
SONIC_DOCKER_DBG_IMAGES += $(DOCKER_NAT_DBG)
SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_NAT_DBG)
SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_NAT_DBG)
$(DOCKER_NAT)_CONTAINER_NAME = nat
$(DOCKER_NAT)_RUN_OPT += --net=host --privileged -t
$(DOCKER_NAT)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
$(DOCKER_NAT)_RUN_OPT += -v /host/warmboot:/var/warmboot
$(DOCKER_NAT)_BASE_IMAGE_FILES += natctl:/usr/bin/natctl

27
rules/iptables.mk Normal file
View File

@ -0,0 +1,27 @@
# iptables package
IPTABLES_VERSION = 1.6.0+snapshot20161117
IPTABLES_VERSION_SUFFIX = 6
IPTABLES_VERSION_FULL = $(IPTABLES_VERSION)-$(IPTABLES_VERSION_SUFFIX)
IPTABLES = iptables_$(IPTABLES_VERSION_FULL)_amd64.deb
$(IPTABLES)_SRC_PATH = $(SRC_PATH)/iptables
SONIC_MAKE_DEBS += $(IPTABLES)
SONIC_STRETCH_DEBS += $(IPTABLES)
IPTABLESIP4TC = libip4tc0_$(IPTABLES_VERSION_FULL)_amd64.deb
$(eval $(call add_derived_package,$(IPTABLES),$(IPTABLESIP4TC)))
IPTABLESIP6TC = libip6tc0_$(IPTABLES_VERSION_FULL)_amd64.deb
$(eval $(call add_derived_package,$(IPTABLES),$(IPTABLESIP6TC)))
IPTABLESIPTC = libiptc0_$(IPTABLES_VERSION_FULL)_amd64.deb
$(eval $(call add_derived_package,$(IPTABLES),$(IPTABLESIPTC)))
IPXTABLES12 = libxtables12_$(IPTABLES_VERSION_FULL)_amd64.deb
$(eval $(call add_derived_package,$(IPTABLES),$(IPXTABLES12)))
# Export these variables so they can be used in a sub-make
export IPTABLES_VERSION
export IPTABLES_VERSION_FULL
export IPTABLES

View File

@ -294,6 +294,9 @@ RUN apt-get update && apt-get install -y \
libselinux1-dev \
# For kdump-tools
liblzo2-dev \
# For iptables
libnetfilter-conntrack-dev \
libnftnl-dev \
# For SAI3.7
libprotobuf-dev \
# For DHCP Monitor tool

47
src/iptables/Makefile Normal file
View File

@ -0,0 +1,47 @@
.ONESHELL:
SHELL = /bin/bash
.SHELLFLAGS += -e
MAIN_TARGET = $(IPTABLES)
DERIVED_TARGETS = libip4tc0_$(IPTABLES_VERSION_FULL)_amd64.deb \
libip6tc0_$(IPTABLES_VERSION_FULL)_amd64.deb \
libiptc0_$(IPTABLES_VERSION_FULL)_amd64.deb \
libxtables12_$(IPTABLES_VERSION_FULL)_amd64.deb
IPTABLES_URL = http://deb.debian.org/debian/pool/main/i/iptables
DSC_FILE = iptables_$(IPTABLES_VERSION_FULL).dsc
ORIG_FILE = iptables_$(IPTABLES_VERSION).orig.tar.bz2
DEBIAN_FILE = iptables_$(IPTABLES_VERSION_FULL).debian.tar.xz
DSC_FILE_URL = $(IPTABLES_URL)/$(DSC_FILE)
ORIG_FILE_URL = $(IPTABLES_URL)/$(ORIG_FILE)
DEBIAN_FILE_URL = $(IPTABLES_URL)/$(DEBIAN_FILE)
$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
# Remove any stale files
rm -rf ./iptables-$(IPTABLES_VERSION)
# Get iptables release
wget -NO "$(DSC_FILE)" $(DSC_FILE_URL)
wget -NO "$(ORIG_FILE)" $(ORIG_FILE_URL)
wget -NO "$(DEBIAN_FILE)" $(DEBIAN_FILE_URL)
dpkg-source -x iptables_$(IPTABLES_VERSION_FULL).dsc
pushd iptables-$(IPTABLES_VERSION)
git init
git add -f *
git commit -m "unmodified iptables source"
# Apply patches
stg init
stg import -s ../patch/series
# Build source and Debian packages
dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS)
popd
# Move the newly-built .deb packages to the destination directory
mv $(DERIVED_TARGETS) $* $(DEST)/
$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET)

View File

@ -0,0 +1,267 @@
From 92f5aee7372748845f11b7a10d880f968769e860 Mon Sep 17 00:00:00 2001
From: Kiran Kella <kiran.kella@broadcom.com>
Date: Wed, 7 Aug 2019 07:22:42 -0700
Subject: [PATCH] Passing fullcone option for SNAT and DNAT
---
extensions/libipt_DNAT.c | 22 +++++++++++++++++++++-
extensions/libipt_MASQUERADE.c | 21 ++++++++++++++++++++-
extensions/libipt_SNAT.c | 22 +++++++++++++++++++++-
3 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
index a14d16f..4bfab98 100644
--- a/extensions/libipt_DNAT.c
+++ b/extensions/libipt_DNAT.c
@@ -8,14 +8,20 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
+/* Temporarily defining here, need to be picked up from the
+ * new kernel header linux/netfilter/nf_nat.h */
+#define NF_NAT_RANGE_FULLCONE (1 << 5)
+
enum {
O_TO_DEST = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_DEST, /* hidden flag */
+ O_FULLCONE,
F_TO_DEST = 1 << O_TO_DEST,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_DEST = 1 << O_X_TO_DEST,
+ F_FULLCONE = 1 << O_FULLCONE
};
/* Dest NAT data consists of a multi-range, indicating where to map
@@ -32,7 +38,7 @@ static void DNAT_help(void)
"DNAT target options:\n"
" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map destination to.\n"
-"[--random] [--persistent]\n");
+"[--random] [--persistent] [--fullcone]\n");
}
static const struct xt_option_entry DNAT_opts[] = {
@@ -40,6 +46,7 @@ static const struct xt_option_entry DNAT_opts[] = {
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
+ {.name = "fullcone", .id = O_FULLCONE, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -185,10 +192,14 @@ static void DNAT_parse(struct xt_option_call *cb)
static void DNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_DEST | F_RANDOM;
+ static const unsigned int c = F_FULLCONE;
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
if ((cb->xflags & f) == f)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
+
+ if ((cb->xflags & c) == c)
+ mr->range[0].flags |= NF_NAT_RANGE_FULLCONE;
}
static void print_range(const struct nf_nat_ipv4_range *r)
@@ -224,6 +235,8 @@ static void DNAT_print(const void *ip, const struct xt_entry_target *target,
printf(" random");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE)
+ printf(" fullcone");
}
}
@@ -239,6 +252,8 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target)
printf(" --random");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE)
+ printf(" --fullcone");
}
}
@@ -282,6 +297,11 @@ static int DNAT_xlate(struct xt_xlate *xl,
sep = ",";
xt_xlate_add(xl, "%spersistent", sep);
}
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%sfullcone", sep);
+ }
}
return 1;
diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c
index b7b5fc7..88ff650 100644
--- a/extensions/libipt_MASQUERADE.c
+++ b/extensions/libipt_MASQUERADE.c
@@ -8,9 +8,15 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
+/* Temporarily defining here, need to be picked up from the
+ * new kernel header linux/netfilter/nf_nat.h */
+#define NF_NAT_RANGE_FULLCONE (1 << 5)
+
enum {
O_TO_PORTS = 0,
O_RANDOM,
+ O_RANDOM_FULLY,
+ O_FULLCONE
};
static void MASQUERADE_help(void)
@@ -20,12 +26,15 @@ static void MASQUERADE_help(void)
" --to-ports <port>[-<port>]\n"
" Port (range) to map to.\n"
" --random\n"
-" Randomize source port.\n");
+" Randomize source port.\n"
+" --fullcone\n"
+" Do fullcone NAT mapping.\n");
}
static const struct xt_option_entry MASQUERADE_opts[] = {
{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "fullcone", .id = O_FULLCONE, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -97,6 +106,9 @@ static void MASQUERADE_parse(struct xt_option_call *cb)
case O_RANDOM:
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
+ case O_FULLCONE:
+ mr->range[0].flags |= NF_NAT_RANGE_FULLCONE;
+ break;
}
}
@@ -116,6 +128,8 @@ MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
+ if (r->flags & NF_NAT_RANGE_FULLCONE)
+ printf(" fullcone");
}
static void
@@ -132,6 +146,8 @@ MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
+ if (r->flags & NF_NAT_RANGE_FULLCONE)
+ printf(" --fullcone");
}
static int MASQUERADE_xlate(struct xt_xlate *xl,
@@ -153,6 +169,9 @@ static int MASQUERADE_xlate(struct xt_xlate *xl,
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
xt_xlate_add(xl, "random ");
+ if (r->flags & NF_NAT_RANGE_FULLCONE)
+ xt_xlate_add(xl, "fullcone ");
+
return 1;
}
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
index e92d811..9634ba9 100644
--- a/extensions/libipt_SNAT.c
+++ b/extensions/libipt_SNAT.c
@@ -8,16 +8,22 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
+/* Temporarily defining here, need to be picked up from the
+ * new kernel header linux/netfilter/nf_nat.h */
+#define NF_NAT_RANGE_FULLCONE (1 << 5)
+
enum {
O_TO_SRC = 0,
O_RANDOM,
O_RANDOM_FULLY,
O_PERSISTENT,
O_X_TO_SRC,
+ O_FULLCONE,
F_TO_SRC = 1 << O_TO_SRC,
F_RANDOM = 1 << O_RANDOM,
F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
F_X_TO_SRC = 1 << O_X_TO_SRC,
+ F_FULLCONE = 1 << O_FULLCONE
};
/* Source NAT data consists of a multi-range, indicating where to map
@@ -34,7 +40,7 @@ static void SNAT_help(void)
"SNAT target options:\n"
" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map source to.\n"
-"[--random] [--random-fully] [--persistent]\n");
+"[--random] [--random-fully] [--persistent] [--fullcone]\n");
}
static const struct xt_option_entry SNAT_opts[] = {
@@ -43,6 +49,7 @@ static const struct xt_option_entry SNAT_opts[] = {
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
+ {.name = "fullcone", .id = O_FULLCONE, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -189,12 +196,15 @@ static void SNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_SRC | F_RANDOM;
static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY;
+ static const unsigned int c = F_TO_SRC | F_FULLCONE;
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
if ((cb->xflags & f) == f)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
if ((cb->xflags & r) == r)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
+ if ((cb->xflags & c) == c)
+ mr->range[0].flags |= NF_NAT_RANGE_FULLCONE;
}
static void print_range(const struct nf_nat_ipv4_range *r)
@@ -232,6 +242,8 @@ static void SNAT_print(const void *ip, const struct xt_entry_target *target,
printf(" random-fully");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE)
+ printf(" fullcone");
}
}
@@ -249,6 +261,8 @@ static void SNAT_save(const void *ip, const struct xt_entry_target *target)
printf(" --random-fully");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE)
+ printf(" --fullcone");
}
}
@@ -299,6 +313,12 @@ static int SNAT_xlate(struct xt_xlate *xl,
sep = ",";
xt_xlate_add(xl, "%spersistent", sep);
}
+ if (info->mr.range[i].flags & NF_NAT_RANGE_FULLCONE) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%sfullcone", sep);
+ sep_need = true;
+ }
}
return 1;
--
2.18.0

View File

@ -0,0 +1 @@
0001-Passing-fullcone-option-for-SNAT-and-DNAT.patch