nft-fullcone: init OpenWrt package

Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
This commit is contained in:
Syrone Wong 2022-04-09 01:31:10 +08:00
commit 90834e19a0
7 changed files with 2335 additions and 0 deletions

45
Makefile Normal file
View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2018 Chion Tang <tech@chionlab.moe>
# Original xt_FULLCONENAT and related iptables extension author
# Copyright (c) 2019-2022 GitHub/llccd Twitter/@gNodeB
# Added IPv6 support for xt_FULLCONENAT and ip6tables extension
# Ported to recent kernel versions
# Copyright (c) 2022 Syrone Wong <wong.syrone@gmail.com>
# Massively rewrite the whole module, split the original code into library and nftables 'fullcone' expression module
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=nft-fullcone
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/nft-fullcone
SUBMENU:=Netfilter Extensions
DEPENDS:=@IPV6 +kmod-nft-core +kmod-nf-conntrack +kmod-nf-conntrack6
TITLE:=nftables fullcone expression support
FILES:= $(PKG_BUILD_DIR)/nft_fullcone.ko
KCONFIG:= CONFIG_NFT_FULLCONE=y CONFIG_NF_NAT=y CONFIG_NF_NAT_IPV6=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y
PROVIDES:=$(PKG_NAME)
AUTOLOAD:=$(call AutoProbe,nft_fullcone)
endef
define KernelPackage/nft-fullcone/Description
Kernel module adds the fullcone expression that you can use
to perform NAT in the RFC3489-compatible full cone SNAT flavour.
Currently only UDP traffic is supported for full-cone NAT.
For other protos FULLCONENAT is equivalent to MASQUERADE.
endef
# make use of all CPUs
define Build/Compile
+$(MAKE) $(PKG_JOBS) $(KERNEL_MAKEOPTS) \
M="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(BUILDFLAGS)" \
$(if $(CONFIG_IPv6),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM",) \
modules
endef
$(eval $(call KernelPackage,nft-fullcone))

18
src/Kconfig Normal file
View File

@ -0,0 +1,18 @@
#
# Nftables/netfilter fullcone expression support
#
config NFT_FULLCONE
depends on NF_CONNTRACK
depends on NF_NAT
tristate "Netfilter nf_tables fullcone support"
help
This options adds the "fullcone" expression that you can use
to perform NAT in the RFC3489-compatible full cone SNAT flavour.
Currently only UDP traffic is supported for full-cone NAT.
For other protos FULLCONENAT is equivalent to MASQUERADE.
To compile this code as a module, choose M here: the module will be
called nft_fullcone.
If unsure, say N.

29
src/Lindent Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# original
#PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
# use wide screen in 21th century
PARAM="-npro -kr -i8 -ts8 -sob -l120 -ss -ncs -cp1"
RES=$(indent --version | cut -d' ' -f3)
if [ "$RES" = "" ]; then
exit 1
fi
V1=$(echo $RES | cut -d'.' -f1)
V2=$(echo $RES | cut -d'.' -f2)
V3=$(echo $RES | cut -d'.' -f3)
if [ $V1 -gt 2 ]; then
PARAM="$PARAM -il0"
elif [ $V1 -eq 2 ]; then
if [ $V2 -gt 2 ]; then
PARAM="$PARAM -il0"
elif [ $V2 -eq 2 ]; then
if [ $V3 -ge 10 ]; then
PARAM="$PARAM -il0"
fi
fi
fi
indent $PARAM "$@"

18
src/Makefile Normal file
View File

@ -0,0 +1,18 @@
#
# Makefile for Nftables/netfilter fullcone expression support.
#
# module name, should not have the same name as src file names
TARGET = nft_fullcone
obj-m += $(TARGET).o
$(TARGET)-objs := \
nf_nat_fullcone.o \
nft_ext_fullcone.o
# product
ccflags-y += -Werror -Wall
# develop
#ccflags-y += -Wall -Wno-unused-function

1611
src/nf_nat_fullcone.c Normal file

File diff suppressed because it is too large Load Diff

156
src/nf_nat_fullcone.h Normal file
View File

@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Nftables NAT extension: fullcone expression support library header
*
* Copyright (c) 2018 Chion Tang <tech@chionlab.moe>
* Original xt_FULLCONENAT and related iptables extension author
* Copyright (c) 2019-2022 GitHub/llccd Twitter/@gNodeB
* Added IPv6 support for xt_FULLCONENAT and ip6tables extension
* Ported to recent kernel versions
* Copyright (c) 2022 Syrone Wong <wong.syrone@gmail.com>
* Massively rewrite the whole module, split the original code into library and nftables 'fullcone' expression module
*/
#ifndef _NF_NAT_FULLCONE_H_
#define _NF_NAT_FULLCONE_H_
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/list.h>
#include <linux/inetdevice.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#ifndef NF_NAT_RANGE_PROTO_RANDOM_FULLY
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
static inline int nf_ct_netns_get(struct net *net, u8 nfproto)
{
return 0;
}
static inline void nf_ct_netns_put(struct net *net, u8 nfproto)
{
}
#endif
/**
* enum nft_fullcone_attributes - nf_tables fullcone expression netlink attributes
*
* @NFTA_FULLCONE_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
* @NFTA_FULLCONE_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
* @NFTA_FULLCONE_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
*/
enum nft_fullcone_attributes {
NFTA_FULLCONE_UNSPEC,
NFTA_FULLCONE_REG_PROTO_MIN,
NFTA_FULLCONE_REG_PROTO_MAX,
NFTA_FULLCONE_FLAGS,
__NFTA_FULLCONE_MAX
};
#define NFTA_FULLCONE_MAX (__NFTA_FULLCONE_MAX - 1)
/* fullcone specific data structures */
struct nat_mapping_original_tuple {
struct nf_conntrack_tuple tuple;
struct list_head node;
};
struct nat_mapping {
uint16_t port; /* external source port */
__be32 addr; /* external source ip address */
__be32 int_addr; /* internal source ip address */
uint16_t int_port; /* internal source port */
int refer_count; /* how many references linked to this mapping
* aka. length of original_tuple_list */
struct list_head original_tuple_list;
struct hlist_node node_by_ext_port;
struct hlist_node node_by_int_src;
};
#if IS_ENABLED(CONFIG_NF_NAT_IPV6) || (IS_ENABLED(CONFIG_IPV6) && LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0))
struct nat_mapping6 {
uint16_t port; /* external source port */
union nf_inet_addr addr; /* external source ip address */
union nf_inet_addr int_addr; /* internal source ip address */
uint16_t int_port; /* internal source port */
int refer_count; /* how many references linked to this mapping
* aka. length of original_tuple_list */
struct list_head original_tuple_list;
struct hlist_node node_by_ext_port;
struct hlist_node node_by_int_src;
};
#endif
struct tuple_list {
struct nf_conntrack_tuple tuple_original;
struct nf_conntrack_tuple tuple_reply;
struct list_head list;
};
/* fullcone specific data structures end */
// NOTE: declaration listed here must use EXPORT_SYMBOL_*
unsigned int nf_nat_fullcone_ipv4(struct sk_buff *skb, unsigned int hooknum,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 *range,
#else
struct nf_nat_range *range,
#endif
const struct net_device *out);
unsigned int nf_nat_fullcone_ipv6(struct sk_buff *skb, unsigned int hooknum,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 *range,
#else
struct nf_nat_range *range,
#endif
const struct net_device *out);
void nf_nat_fullcone_handle_dying_tuples(void);
void nf_nat_fullcone_destroy_mappings(void);
void nf_nat_fullcone_dying_tuple_list_add(struct list_head *new_dying);
/*
* For [FUTURE] usage
*
* from https://elixir.bootlin.com/linux/v5.15.32/source/net/netfilter/xt_nat.c#L37
static void xt_nat_convert_range(struct nf_nat_range2 *dst,
const struct nf_nat_ipv4_range *src)
{
memset(&dst->min_addr, 0, sizeof(dst->min_addr));
memset(&dst->max_addr, 0, sizeof(dst->max_addr));
// base_proto is nf_nat_range2 specific
memset(&dst->base_proto, 0, sizeof(dst->base_proto));
dst->flags = src->flags;
dst->min_addr.ip = src->min_ip;
dst->max_addr.ip = src->max_ip;
dst->min_proto = src->min;
dst->max_proto = src->max;
}
*
*/
#endif /*_NF_NAT_FULLCONE_H_ */

458
src/nft_ext_fullcone.c Normal file
View File

@ -0,0 +1,458 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Nftables NAT extension: fullcone expression support
*
* Copyright (c) 2018 Chion Tang <tech@chionlab.moe>
* Original xt_FULLCONENAT and related iptables extension author
* Copyright (c) 2019-2022 GitHub/llccd Twitter/@gNodeB
* Added IPv6 support for xt_FULLCONENAT and ip6tables extension
* Ported to recent kernel versions
* Copyright (c) 2022 Syrone Wong <wong.syrone@gmail.com>
* Massively rewrite the whole module, split the original code into library and nftables 'fullcone' expression module
*/
#define pr_fmt(fmt) "fullcone " KBUILD_MODNAME ": " fmt
#define NF_FULLCONE_WORKQUEUE_NAME "fullcone " KBUILD_MODNAME ": wq"
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_nat.h>
#include <linux/workqueue.h>
#include "nf_nat_fullcone.h"
static void nft_fullcone_set_regs(const struct nft_expr *expr, const struct nft_regs *regs,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 *range);
#else
struct nf_nat_range *range);
#endif
#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
struct notifier_block ct_event_notifier;
#else
struct nf_ct_event_notifier ct_event_notifier;
#endif
static DEFINE_MUTEX(nf_ct_net_event_lock);
int ct_event_notifier_registered = 0;
int module_refer_count = 0;
static void gc_worker(struct work_struct *work);
static struct workqueue_struct *wq __read_mostly = NULL;
static DECLARE_DELAYED_WORK(gc_worker_wk, gc_worker);
static void gc_worker(struct work_struct *work)
{
nf_nat_fullcone_handle_dying_tuples();
}
struct nft_fullcone {
u32 flags;
u8 sreg_proto_min;
u8 sreg_proto_max;
};
static const struct nla_policy nft_fullcone_policy[NFTA_FULLCONE_MAX + 1] = {
[NFTA_FULLCONE_FLAGS] = {.type = NLA_U32 },
[NFTA_FULLCONE_REG_PROTO_MIN] = {.type = NLA_U32 },
[NFTA_FULLCONE_REG_PROTO_MAX] = {.type = NLA_U32 },
};
/* conntrack destroy event callback function */
#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
static int ct_event_cb(struct notifier_block *this, unsigned long events, void *ptr)
{
struct nf_ct_event *item = ptr;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
static int ct_event_cb(unsigned int events, const struct nf_ct_event *item)
{
#else
static int ct_event_cb(unsigned int events, struct nf_ct_event *item)
{
#endif
struct nf_conn *ct;
struct nf_conntrack_tuple *ct_tuple_reply, *ct_tuple_original;
uint8_t protonum;
struct tuple_list *dying_tuple_item;
ct = item->ct;
/* we handle only conntrack destroy events */
if (ct == NULL || !(events & (1 << IPCT_DESTROY))) {
return 0;
}
ct_tuple_original = &(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
ct_tuple_reply = &(ct->tuplehash[IP_CT_DIR_REPLY].tuple);
protonum = (ct_tuple_original->dst).protonum;
if (protonum != IPPROTO_UDP) {
return 0;
}
dying_tuple_item = kmalloc(sizeof(struct tuple_list), GFP_ATOMIC);
if (dying_tuple_item == NULL) {
pr_debug("warning: ct_event_cb(): kmalloc failed.\n");
return 0;
}
memcpy(&(dying_tuple_item->tuple_original), ct_tuple_original, sizeof(struct nf_conntrack_tuple));
memcpy(&(dying_tuple_item->tuple_reply), ct_tuple_reply, sizeof(struct nf_conntrack_tuple));
nf_nat_fullcone_dying_tuple_list_add(&(dying_tuple_item->list));
if (wq != NULL)
queue_delayed_work(wq, &gc_worker_wk, msecs_to_jiffies(100));
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) && !defined(CONFIG_NF_CONNTRACK_CHAIN_EVENTS)
static int exp_event_cb(unsigned int events, const struct nf_exp_event *item)
{
return 0;
}
#endif
static int nft_fullcone_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **data)
{
int err;
err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
if (err < 0)
return err;
// TODO: check hooks
return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_POST_ROUTING));
}
static int nft_fullcone_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr *const tb[])
{
int err;
int register_ct_notifier_ret = 0;
err = nf_ct_netns_get(ctx->net, ctx->family);
mutex_lock(&nf_ct_net_event_lock);
module_refer_count++;
pr_debug("nft_fullcone_init(): module_refer_count is now %d\n", module_refer_count);
if (module_refer_count == 1) {
#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
ct_event_notifier.notifier_call = ct_event_cb;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
ct_event_notifier.ct_event = ct_event_cb;
ct_event_notifier.exp_event = exp_event_cb;
#else
ct_event_notifier.fcn = ct_event_cb;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) && !defined(CONFIG_NF_CONNTRACK_CHAIN_EVENTS)
if (!READ_ONCE(ctx->net->ct.nf_conntrack_event_cb)) {
nf_conntrack_register_notifier(ctx->net, &ct_event_notifier);
}
#else
register_ct_notifier_ret = nf_conntrack_register_notifier(ctx->net, &ct_event_notifier);
#endif
if (register_ct_notifier_ret) {
/* non-zero means failure */
pr_warn("failed to register a conntrack notifier. Disable active GC for mappings.\n");
} else {
ct_event_notifier_registered = 1;
pr_debug("nft_fullcone_init(): ct_event_notifier registered\n");
}
}
mutex_unlock(&nf_ct_net_event_lock);
return err;
}
static int nft_fullcone_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_fullcone *priv = nft_expr_priv(expr);
if (priv->flags != 0 && nla_put_be32(skb, NFTA_FULLCONE_FLAGS, htonl(priv->flags)))
goto nla_put_failure;
if (priv->sreg_proto_min) {
if (nft_dump_register(skb, NFTA_FULLCONE_REG_PROTO_MIN,
priv->sreg_proto_min) ||
nft_dump_register(skb, NFTA_FULLCONE_REG_PROTO_MAX, priv->sreg_proto_max))
goto nla_put_failure;
}
return 0;
nla_put_failure:
return -1;
}
/* nft_fullcone_set_regs sets nft_regs from nft_expr fullcone specific private data */
static void nft_fullcone_set_regs(const struct nft_expr *expr, const struct nft_regs *regs,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 *range
#else
struct nf_nat_range *range
#endif
)
{
// private data connected via nft_expr_type.ops <==> nft_expr_ops.type
// private data type from nft_expr_type.{policy,maxattr,ops}
// private data size from nft_expr_ops.size
struct nft_fullcone *priv = nft_expr_priv(expr);
range->flags = priv->flags;
if (priv->sreg_proto_min) {
range->min_proto.all = (__force __be16)
nft_reg_load16(&regs->data[priv->sreg_proto_min]);
range->max_proto.all = (__force __be16)
nft_reg_load16(&regs->data[priv->sreg_proto_max]);
}
}
static void nft_fullcone_ipv4_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 range;
#else
struct nf_nat_range range;
#endif
memset(&range, 0, sizeof(range));
nft_fullcone_set_regs(expr, regs, &range);
regs->verdict.code = nf_nat_fullcone_ipv4(pkt->skb, nft_hook(pkt), &range, nft_out(pkt));
}
static void nft_fullcone_common_destory(const struct nft_ctx *ctx)
{
mutex_lock(&nf_ct_net_event_lock);
module_refer_count--;
pr_debug("nft_fullcone_common_destory(): module_refer_count is now %d\n", module_refer_count);
if (module_refer_count == 0) {
if (ct_event_notifier_registered) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) && !defined(CONFIG_NF_CONNTRACK_CHAIN_EVENTS)
nf_conntrack_unregister_notifier(ctx->net);
#else
nf_conntrack_unregister_notifier(ctx->net, &ct_event_notifier);
#endif
ct_event_notifier_registered = 0;
pr_debug("nft_fullcone_common_destory(): ct_event_notifier unregistered\n");
}
}
mutex_unlock(&nf_ct_net_event_lock);
}
static void nft_fullcone_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
{
nft_fullcone_common_destory(ctx);
nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
}
static struct nft_expr_type nft_fullcone_ipv4_type;
static const struct nft_expr_ops nft_fullcone_ipv4_ops = {
.type = &nft_fullcone_ipv4_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_fullcone)),
.eval = nft_fullcone_ipv4_eval,
.init = nft_fullcone_init,
.destroy = nft_fullcone_ipv4_destroy,
.dump = nft_fullcone_dump,
.validate = nft_fullcone_validate,
};
static struct nft_expr_type nft_fullcone_ipv4_type __read_mostly = {
.family = NFPROTO_IPV4,
.name = "fullcone",
.ops = &nft_fullcone_ipv4_ops,
.policy = nft_fullcone_policy,
.maxattr = NFTA_FULLCONE_MAX,
.owner = THIS_MODULE,
};
#ifdef CONFIG_NF_TABLES_IPV6
static void nft_fullcone_ipv6_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 range;
#else
struct nf_nat_range range;
#endif
memset(&range, 0, sizeof(range));
nft_fullcone_set_regs(expr, regs, &range);
regs->verdict.code = nf_nat_fullcone_ipv6(pkt->skb, nft_hook(pkt), &range, nft_out(pkt));
}
static void nft_fullcone_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
{
nft_fullcone_common_destory(ctx);
nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
}
static struct nft_expr_type nft_fullcone_ipv6_type;
static const struct nft_expr_ops nft_fullcone_ipv6_ops = {
.type = &nft_fullcone_ipv6_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_fullcone)),
.eval = nft_fullcone_ipv6_eval,
.init = nft_fullcone_init,
.destroy = nft_fullcone_ipv6_destroy,
.dump = nft_fullcone_dump,
.validate = nft_fullcone_validate,
};
static struct nft_expr_type nft_fullcone_ipv6_type __read_mostly = {
.family = NFPROTO_IPV6,
.name = "fullcone",
.ops = &nft_fullcone_ipv6_ops,
.policy = nft_fullcone_policy,
.maxattr = NFTA_FULLCONE_MAX,
.owner = THIS_MODULE,
};
static int __init nft_fullcone_module_init_ipv6(void)
{
return nft_register_expr(&nft_fullcone_ipv6_type);
}
static void nft_fullcone_module_exit_ipv6(void)
{
nft_unregister_expr(&nft_fullcone_ipv6_type);
}
#else
static inline int nft_fullcone_module_init_ipv6(void)
{
return 0;
}
static inline void nft_fullcone_module_exit_ipv6(void)
{
}
#endif
#ifdef CONFIG_NF_TABLES_INET
static void nft_fullcone_inet_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt)
{
switch (nft_pf(pkt)) {
case NFPROTO_IPV4:
return nft_fullcone_ipv4_eval(expr, regs, pkt);
case NFPROTO_IPV6:
return nft_fullcone_ipv6_eval(expr, regs, pkt);
}
WARN_ON_ONCE(1);
}
static void nft_fullcone_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
{
nft_fullcone_common_destory(ctx);
nf_ct_netns_put(ctx->net, NFPROTO_INET);
}
static struct nft_expr_type nft_fullcone_inet_type;
static const struct nft_expr_ops nft_fullcone_inet_ops = {
.type = &nft_fullcone_inet_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_fullcone)),
.eval = nft_fullcone_inet_eval,
.init = nft_fullcone_init,
.destroy = nft_fullcone_inet_destroy,
.dump = nft_fullcone_dump,
.validate = nft_fullcone_validate,
};
static struct nft_expr_type nft_fullcone_inet_type __read_mostly = {
.family = NFPROTO_INET,
.name = "fullcone",
.ops = &nft_fullcone_inet_ops,
.policy = nft_fullcone_policy,
.maxattr = NFTA_FULLCONE_MAX,
.owner = THIS_MODULE,
};
static int __init nft_fullcone_module_init_inet(void)
{
return nft_register_expr(&nft_fullcone_inet_type);
}
static void nft_fullcone_module_exit_inet(void)
{
nft_unregister_expr(&nft_fullcone_inet_type);
}
#else
static inline int nft_fullcone_module_init_inet(void)
{
return 0;
}
static inline void nft_fullcone_module_exit_inet(void)
{
}
#endif
static int __init nft_fullcone_module_init(void)
{
int ret;
ret = nft_fullcone_module_init_ipv6();
if (ret < 0)
return ret;
ret = nft_fullcone_module_init_inet();
if (ret < 0) {
nft_fullcone_module_exit_ipv6();
return ret;
}
ret = nft_register_expr(&nft_fullcone_ipv4_type);
if (ret < 0) {
nft_fullcone_module_exit_inet();
nft_fullcone_module_exit_ipv6();
return ret;
}
wq = create_singlethread_workqueue(NF_FULLCONE_WORKQUEUE_NAME);
if (wq == NULL) {
pr_err("failed to create workqueue %s\n", NF_FULLCONE_WORKQUEUE_NAME);
}
return ret;
}
static void __exit nft_fullcone_module_exit(void)
{
nft_fullcone_module_exit_ipv6();
nft_fullcone_module_exit_inet();
nft_unregister_expr(&nft_fullcone_ipv4_type);
if (wq) {
cancel_delayed_work_sync(&gc_worker_wk);
flush_workqueue(wq);
destroy_workqueue(wq);
}
nf_nat_fullcone_handle_dying_tuples();
nf_nat_fullcone_destroy_mappings();
}
module_init(nft_fullcone_module_init);
module_exit(nft_fullcone_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Syrone Wong <wong.syrone@gmail.com>");
MODULE_ALIAS_NFT_EXPR("fullcone");
MODULE_DESCRIPTION("Netfilter nftables fullcone expression support of RFC3489 full cone NAT");