Skip to content
Permalink
Browse files

Revert NAT removal

This seems to not work right on older kernel versions
  • Loading branch information
RalfJung committed Feb 1, 2020
1 parent 3c5ecb6 commit a461a11495579d3f95c485a295285564c20d6bb4
@@ -15,7 +15,6 @@ install:
- sudo modprobe l2tp_netlink
- sudo modprobe l2tp_ip
- sudo modprobe l2tp_eth
# Newer versions of the broker don't need the following but keep it around for cross-version testing
- sudo modprobe nf_conntrack
- sudo modprobe nf_conntrack_netlink
- sudo iptables -t nat -L >/dev/null
@@ -23,7 +23,6 @@ vNEXT
probes.
* Improve client behavior on broker failure, and decrease some reconnect
timeouts.
* Removed dependency on Netfilter.

.. _`installation chapter in the Tunneldigger documentation`: https://tunneldigger.readthedocs.io/en/latest/server.html#installation

@@ -7,8 +7,16 @@ port=53,123,8942
interface=lo
; Maximum number of tunnels that will be allowed by the broker
max_tunnels=1024
; Tunnel port base. This port is not visible to clients, but must be free on the server.
; This port is used by the actual l2tp tunnel, but tunneldigger sets up NAT rules so that clients
; can keep using the control port.
port_base=20000
; Tunnel id base
tunnel_id_base=100
; Namespace (for running multiple brokers); note that you must also
; configure disjunct ports, and tunnel identifiers in order for
; namespacing to work
namespace=default
; Reject connections if there are less than N seconds since the last connection.
; Can be less than a second (e.g., 0.1).
connection_rate_limit=10
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from setuptools import find_packages, setup

VERSION = '0.4.0.dev1'
VERSION = '0.3.0'

setup(
name='tunneldigger-broker',
@@ -14,7 +14,7 @@
url='https://github.com/wlanslovenija/tunneldigger',
license='AGPLv3',
package_dir={'': 'src'},
packages=find_packages(where='src'),
packages=find_packages(where='src', exclude=['_ffi_src', '_ffi_src.*']),
package_data={},
classifiers=[
'Development Status :: 4 - Beta',
@@ -25,5 +25,16 @@
],
include_package_data=True,
zip_safe=False,
setup_requires=[
'cffi>=1.4.1',
],
install_requires=[
'netfilter>=0.6.2',
'cffi>=1.4.1',
],
extras_require={},
cffi_modules=[
'src/_ffi_src/build_conntrack.py:ffibuilder',
],
ext_package='tunneldigger_broker._ffi',
)
No changes.
@@ -0,0 +1,122 @@


from cffi import FFI

ffibuilder = FFI()
ffibuilder.set_source(
'_conntrack',
'''
#include <sys/types.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
''',
libraries=[
'nfnetlink',
'netfilter_conntrack',
],
)

ffibuilder.cdef('''
typedef unsigned char u_int8_t;
typedef unsigned short int u_int16_t;
typedef unsigned int u_int32_t;
enum {
CONNTRACK,
...
};
enum nf_conntrack_msg_type {
NFCT_T_UNKNOWN,
NFCT_T_NEW,
NFCT_T_UPDATE,
NFCT_T_DESTROY,
NFCT_T_ALL,
NFCT_T_ERROR,
...
};
enum {
NFCT_CB_FAILURE,
NFCT_CB_STOP,
NFCT_CB_CONTINUE,
NFCT_CB_STOLEN,
...
};
enum nf_conntrack_query {
NFCT_Q_CREATE,
NFCT_Q_UPDATE,
NFCT_Q_DESTROY,
NFCT_Q_GET,
NFCT_Q_FLUSH,
NFCT_Q_DUMP,
NFCT_Q_DUMP_RESET,
NFCT_Q_CREATE_UPDATE,
...
};
enum nf_conntrack_attr {
ATTR_L3PROTO,
ATTR_L4PROTO,
ATTR_IPV4_SRC,
ATTR_IPV4_DST,
ATTR_IPV6_SRC,
ATTR_IPV6_DST,
ATTR_PORT_SRC,
ATTR_PORT_DST,
...
};
enum {
NFCT_CMP_ALL,
NFCT_CMP_MASK,
...
};
typedef int nfct_callback(enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data);
struct nf_conntrack* nfct_new();
void nfct_destroy(struct nf_conntrack *ct);
struct nfct_handle* nfct_open(u_int8_t subsys_id, unsigned int subscriptions);
int nfct_close(struct nfct_handle * cth);
int nfct_fd(struct nfct_handle *cth);
int nfct_catch(struct nfct_handle *h);
int nfct_callback_register(struct nfct_handle *h,
enum nf_conntrack_msg_type type,
nfct_callback *cb,
void *data);
int nfct_query(struct nfct_handle *h,
const enum nf_conntrack_query qt,
const void *data);
int nfct_cmp(const struct nf_conntrack *ct1,
const struct nf_conntrack *ct2,
unsigned int flags);
void nfct_set_attr_u8(struct nf_conntrack *ct,
const enum nf_conntrack_attr type,
uint8_t value);
void nfct_set_attr_u16(struct nf_conntrack *ct,
const enum nf_conntrack_attr type,
uint16_t value);
void nfct_set_attr_u32(struct nf_conntrack *ct,
const enum nf_conntrack_attr type,
uint32_t value);
void nfct_set_attr_u64(struct nf_conntrack *ct,
const enum nf_conntrack_attr type,
uint64_t value);
extern "Python" int query_callback(enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data);
''')

if __name__ == '__main__':
ffibuilder.compile(verbose=True)
No changes.
@@ -3,6 +3,10 @@
import time
import traceback

from . import conntrack
import netfilter.table
import netfilter.rule

from . import l2tp, protocol, network, tunnel as td_tunnel

# Logger.
@@ -19,6 +23,8 @@ def __init__(
hook_manager,
max_tunnels,
tunnel_id_base,
tunnel_port_base,
namespace,
connection_rate_limit,
pmtu_fixed,
log_ip_addresses,
@@ -29,12 +35,16 @@ def __init__(
:param hook_manager: Hook manager
:param max_tunnels: Maximum number of tunnels to allow
:param tunnel_id_base: Base local tunnel identifier
:param tunnel_port_base: Base local tunnel port
:param namespace: Netfilter namespace to use
"""

self.hook_manager = hook_manager
self.max_tunnels = max_tunnels
self.tunnel_id_base = tunnel_id_base
self.tunnel_ids = set(range(tunnel_id_base, tunnel_id_base + max_tunnels))
self.tunnel_port_base = tunnel_port_base
self.namespace = namespace
self.tunnels = {}
self.last_tunnel_created = None
self.connection_rate_limit = connection_rate_limit
@@ -93,7 +103,7 @@ def create_tunnel(self, broker, address, uuid, remote_tunnel_id, client_features
try:
tunnel = td_tunnel.Tunnel(
broker=broker,
address=broker.address,
address=(broker.address[0], self.tunnel_port_base + tunnel_id),
endpoint=address,
uuid=uuid,
tunnel_id=tunnel_id,
@@ -139,6 +149,45 @@ def destroy_tunnel(self, tunnel):
del self.tunnels[tunnel.tunnel_id]

def initialize(self):
"""
Sets up netfilter rules so new packets to the same port are redirected
into the per-tunnel socket.
"""

prerouting_chain = "L2TP_PREROUTING_%s" % self.namespace
postrouting_chain = "L2TP_POSTROUTING_%s" % self.namespace
nat = netfilter.table.Table('nat')
self.rule_prerouting_jmp = netfilter.rule.Rule(jump=prerouting_chain)
self.rule_postrouting_jmp = netfilter.rule.Rule(jump=postrouting_chain)

try:
nat.flush_chain(prerouting_chain)
nat.delete_chain(prerouting_chain)
except netfilter.table.IptablesError:
pass

try:
nat.flush_chain(postrouting_chain)
nat.delete_chain(postrouting_chain)
except netfilter.table.IptablesError:
pass

nat.create_chain(prerouting_chain)
nat.create_chain(postrouting_chain)
try:
nat.delete_rule('PREROUTING', self.rule_prerouting_jmp)
except netfilter.table.IptablesError:
pass
nat.prepend_rule('PREROUTING', self.rule_prerouting_jmp)

try:
nat.delete_rule('POSTROUTING', self.rule_postrouting_jmp)
except netfilter.table.IptablesError:
pass
nat.prepend_rule('POSTROUTING', self.rule_postrouting_jmp)

# Initialize connection tracking manager.
self.conntrack = conntrack.ConnectionManager()
# Initialize netlink.
self.netlink = l2tp.NetlinkInterface()

@@ -155,8 +204,8 @@ def initialize(self):

def close(self):
"""
Shuts down all managed tunnels. The tunnel manager instance
should not be used after calling this method.
Shuts down all managed tunnels and restores netfilter state. The tunnel
manager instance should not be used after calling this method.
"""

for tunnel in list(self.tunnels.values()):
@@ -165,6 +214,16 @@ def close(self):
except:
traceback.print_exc()

# Restore netfilter rules.
nat = netfilter.table.Table('nat')
nat.delete_rule('PREROUTING', self.rule_prerouting_jmp)
nat.delete_rule('POSTROUTING', self.rule_postrouting_jmp)
nat.flush_chain('L2TP_PREROUTING_%s' % self.namespace)
nat.flush_chain('L2TP_POSTROUTING_%s' % self.namespace)
nat.delete_chain('L2TP_PREROUTING_%s' % self.namespace)
nat.delete_chain('L2TP_POSTROUTING_%s' % self.namespace)

del self.conntrack
del self.netlink


@@ -186,8 +245,13 @@ def __init__(self, address, interface, tunnel_manager):

self.tunnel_manager = tunnel_manager
self.hook_manager = tunnel_manager.hook_manager
self.conntrack = tunnel_manager.conntrack
self.netlink = tunnel_manager.netlink

# Clear out the connection tracking tables.
self.conntrack.killall(proto=socket.IPPROTO_UDP, src=self.address[0])
self.conntrack.killall(proto=socket.IPPROTO_UDP, dst=self.address[0])

def get_tunnel_manager(self):
"""
Returns the tunnel manager for this broker.

0 comments on commit a461a11

Please sign in to comment.
You can’t perform that action at this time.