rework nft-specific globals, create & destroy tables/chains at init & shutdown

This commit is contained in:
Paul Chambers 2019-09-30 00:12:08 -07:00
parent d5773600f9
commit 75bdb777cf
10 changed files with 567 additions and 268 deletions

View File

@ -41,11 +41,10 @@ MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
upnpreplyparse.o minixml.o portinuse.o \ upnpreplyparse.o minixml.o portinuse.o \
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ upnpredirect.o getifaddr.o daemonize.o \
options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \
upnpevents.o upnputils.o getconnstatus.o \ upnpglobalvars.o upnpevents.o upnputils.o getconnstatus.o \
upnpstun.o \ upnpstun.o upnppinhole.o pcplearndscp.o asyncsendto.o
upnppinhole.o pcplearndscp.o asyncsendto.o
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/nftpinhole.o \ NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/nftpinhole.o \
@ -233,9 +232,9 @@ linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
linux/ifacewatcher.o: upnppermissions.h natpmp.h linux/ifacewatcher.o: upnppermissions.h natpmp.h
linux/getroute.o: getroute.h upnputils.h linux/getroute.o: getroute.h upnputils.h
netfilter_nft/nftnlrdr.o: macros.h config.h netfilter_nft/nftnlrdr.h commonrdr.h netfilter_nft/nftnlrdr.o: macros.h config.h netfilter_nft/nftnlrdr.h commonrdr.h
netfilter_nft/nftnlrdr.o: config.h upnpglobalvars.h upnppermissions.h netfilter_nft/nftnlrdr.o: config.h upnppermissions.h
netfilter_nft/nftnlrdr.o: miniupnpdtypes.h netfilter_nft/nftnlrdr.o: miniupnpdtypes.h
netfilter_nft/nftpinhole.o: config.h netfilter_nft/nftpinhole.h upnpglobalvars.h netfilter_nft/nftpinhole.o: config.h netfilter_nft/nftpinhole.h
netfilter_nft/nftpinhole.o: upnppermissions.h config.h miniupnpdtypes.h netfilter_nft/nftpinhole.o: upnppermissions.h config.h miniupnpdtypes.h
testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h
testupnpdescgen.o: getifaddr.h testupnpdescgen.o: getifaddr.h

View File

@ -64,4 +64,20 @@ update_portmapping_desc_timestamp(const char * ifname,
unsigned short eport, int proto, unsigned short eport, int proto,
const char * desc, unsigned int timestamp); const char * desc, unsigned int timestamp);
#ifdef USE_NFTABLES
/* only provided by nftables implementation at the moment */
typedef enum {
TABLE_NAME,
TABLE4_NAME,
TABLE6_NAME,
NAT_CHAIN_NAME,
NAT_POSTROUTING_CHAIN_NAME,
FORWARD_CHAIN_NAME,
} rdr_name_type;
int set_rdr_name( rdr_name_type param, const char * string );
#endif
#endif #endif

View File

@ -1267,6 +1267,17 @@ init(int argc, char * * argv, struct runtime_vars * v)
break; break;
#endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */ #endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */
#ifdef USE_NETFILTER #ifdef USE_NETFILTER
#ifdef USE_NFTABLES
case UPNPFORWARDCHAIN:
set_rdr_name(FORWARD_CHAIN_NAME, ary_options[i].value);
break;
case UPNPNATCHAIN:
set_rdr_name(NAT_CHAIN_NAME, ary_options[i].value);
break;
case UPNPNATPOSTCHAIN:
set_rdr_name(NAT_POSTROUTING_CHAIN_NAME, ary_options[i].value);
break;
#else
case UPNPFORWARDCHAIN: case UPNPFORWARDCHAIN:
miniupnpd_forward_chain = ary_options[i].value; miniupnpd_forward_chain = ary_options[i].value;
break; break;
@ -1276,7 +1287,8 @@ init(int argc, char * * argv, struct runtime_vars * v)
case UPNPNATPOSTCHAIN: case UPNPNATPOSTCHAIN:
miniupnpd_nat_postrouting_chain = ary_options[i].value; miniupnpd_nat_postrouting_chain = ary_options[i].value;
break; break;
#endif /* USE_NETFILTER */ #endif /* else USE_NFTABLES */
#endif /* USE_NETFILTER */
case UPNPNOTIFY_INTERVAL: case UPNPNOTIFY_INTERVAL:
v->notify_interval = atoi(ary_options[i].value); v->notify_interval = atoi(ary_options[i].value);
break; break;
@ -2901,6 +2913,8 @@ shutdown:
freeoptions(); freeoptions();
#endif #endif
shutdown_redirect();
return 0; return 0;
} }

View File

@ -11,9 +11,9 @@ clean:
$(RM) *.o testnftnlcrdr testnftpinhole testnftnlrdr_peer \ $(RM) *.o testnftnlcrdr testnftpinhole testnftnlrdr_peer \
test_nfct_get testnftnlrdr test_nfct_get testnftnlrdr
testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o upnpglobalvars.o $(LIBS) testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o $(LIBS)
testnftpinhole: nftpinhole.o nftnlrdr_misc.o testnftpinhole.o upnpglobalvars.o $(LIBS) testnftpinhole: nftpinhole.o nftnlrdr_misc.o testnftpinhole.o $(LIBS)
test_nfct_get: test_nfct_get.o test_nfct_get.o -lmnl -lnetfilter_conntrack test_nfct_get: test_nfct_get.o test_nfct_get.o -lmnl -lnetfilter_conntrack
@ -29,5 +29,3 @@ nftnlrdr_misc.o: nftnlrdr_misc.c
nftpinhole.o: nftpinhole.c nftpinhole.h nftpinhole.o: nftpinhole.c nftpinhole.h
upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h
$(CC) -c -o $@ $<

View File

@ -20,14 +20,18 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <net/if.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <libmnl/libmnl.h> #include <libmnl/libmnl.h>
#include <libnftnl/table.h>
#include <libnftnl/chain.h>
#include <libnftnl/rule.h> #include <libnftnl/rule.h>
#include <libnftnl/expr.h> #include <libnftnl/expr.h>
@ -35,8 +39,8 @@
#include "../macros.h" #include "../macros.h"
#include "../config.h" #include "../config.h"
#include "../commonrdr.h"
#include "nftnlrdr.h" #include "nftnlrdr.h"
#include "../upnpglobalvars.h"
#include "nftnlrdr_misc.h" #include "nftnlrdr_misc.h"
@ -56,15 +60,123 @@ struct timestamp_entry {
static struct timestamp_entry * timestamp_list = NULL; static struct timestamp_entry * timestamp_list = NULL;
/* dummy init and shutdown functions */ #define NAT_CHAIN_TYPE "nat"
int init_redirect(void) #define FILTER_CHAIN_TYPE "filter"
{
return 0; /* init and shutdown functions */
int
init_redirect(void) {
int result;
/* 'inet' family */
result = table_op(NFT_MSG_NEWTABLE, NFPROTO_INET, nft_table);
if (result == 0) {
result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_INET, nft_table,
nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER);
}
/* 'ip' family */
if (result == 0) {
result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV4, nft_table4);
}
if (result == 0) {
result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table4,
nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
}
if (result == 0) {
result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table4,
nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
}
/* 'ip6' family */
if (result == 0) {
result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV6, nft_table6);
}
if (result == 0) {
result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table6,
nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
}
if (result == 0) {
result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table6,
nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
}
return result;
} }
void shutdown_redirect(void) void
{ shutdown_redirect(void) {
return; int result;
/* 'inet' family */
result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_INET, nft_table,
nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER);
if (result == 0) {
result = table_op(NFT_MSG_DELTABLE, NFPROTO_INET, nft_table);
}
/* 'ip' family */
result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table4,
nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
if (result == 0) {
result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table4,
nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
}
if (result == 0) {
result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV4, nft_table4);
}
/* 'ip6' family */
if (result == 0) {
result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table6,
nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
}
if (result == 0) {
result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table6,
nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
}
if (result == 0) {
result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV6, nft_table6);
}
finish_batch();
}
/**
* used by the core to override default chain names if specified in config file
* @param param which string to set
* @param string the new name to use. Do not dispose after setting (i.e. use strdup if not static).
* @return 0 if successful
*/
int
set_rdr_name(rdr_name_type param, const char *string) {
if (string == NULL || strlen(string) > 30) {
return -1;
}
switch (param) {
case TABLE_NAME:
nft_table = string;
break;
case TABLE4_NAME:
nft_table4 = string;
break;
case TABLE6_NAME:
nft_table6 = string;
break;
case NAT_CHAIN_NAME:
nft_prerouting_chain = string;
break;
case NAT_POSTROUTING_CHAIN_NAME:
nft_postrouting_chain = string;
break;
case FORWARD_CHAIN_NAME:
nft_forward_chain = string;
break;
default:
syslog(LOG_ERR, "tried to set invalid string parameter: %d", param);
return -2;
}
return 0;
} }
static unsigned int static unsigned int
@ -136,7 +248,7 @@ add_redirect_rule2(const char * ifname,
0, eport, 0, eport,
inet_addr(iaddr), iport, desc, NULL); inet_addr(iaddr), iport, desc, NULL);
return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_REDIRECT); return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_REDIRECT);
} }
/* /*
@ -162,7 +274,7 @@ add_peer_redirect_rule2(const char * ifname,
inet_addr(eaddr), eport, inet_addr(eaddr), eport,
inet_addr(iaddr), iport, desc, NULL); inet_addr(iaddr), iport, desc, NULL);
return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_PEER); return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_PEER);
} }
/* /*
@ -191,7 +303,7 @@ add_filter_rule2(const char * ifname,
eport, iport, 0, eport, iport, 0,
desc, 0); desc, 0);
return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER);
} }
/* /*
@ -219,11 +331,11 @@ delete_filter_rule(const char * ifname, unsigned short port, int proto)
struct nftnl_rule *r; struct nftnl_rule *r;
UNUSED(ifname); UNUSED(ifname);
reflesh_nft_cache_filter(); refresh_nft_cache_filter();
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) { if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
break; break;
} }
} }
@ -243,7 +355,7 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
uint16_t iport = 0; uint16_t iport = 0;
d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto)); d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto));
reflesh_nft_cache_redirect(); refresh_nft_cache_redirect();
// Delete Redirect Rule // Delete Redirect Rule
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
@ -254,20 +366,20 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT);
break; break;
} }
} }
if (iaddr != 0 && iport != 0) { if (iaddr != 0 && iport != 0) {
reflesh_nft_cache_filter(); refresh_nft_cache_filter();
// Delete Forward Rule // Delete Forward Rule
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == iport && if (p->eport == iport &&
p->iaddr == iaddr && p->type == RULE_FILTER) { p->iaddr == iaddr && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
break; break;
} }
} }
@ -276,7 +388,7 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
iaddr = 0; iaddr = 0;
iport = 0; iport = 0;
reflesh_nft_cache_peer(); refresh_nft_cache_peer();
// Delete Peer Rule // Delete Peer Rule
LIST_FOREACH(p, &head_peer, entry) { LIST_FOREACH(p, &head_peer, entry) {
if (p->eport == eport && p->proto == proto && if (p->eport == eport && p->proto == proto &&
@ -286,20 +398,20 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER);
break; break;
} }
} }
if (iaddr != 0 && iport != 0) { if (iaddr != 0 && iport != 0) {
reflesh_nft_cache_filter(); refresh_nft_cache_filter();
// Delete Forward Rule // Delete Forward Rule
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
if (p->eport == iport && if (p->eport == iport &&
p->iaddr == iaddr && p->type == RULE_FILTER) { p->iaddr == iaddr && p->type == RULE_FILTER) {
r = rule_del_handle(p); r = rule_del_handle(p);
/* Todo: send bulk request */ /* Todo: send bulk request */
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
break; break;
} }
} }
@ -327,7 +439,7 @@ get_peer_rule_by_index(int index,
UNUSED(timestamp); UNUSED(timestamp);
d_printf(("get_peer_rule_by_index()\n")); d_printf(("get_peer_rule_by_index()\n"));
reflesh_nft_cache_peer(); refresh_nft_cache_peer();
LIST_FOREACH(r, &head_peer, entry) { LIST_FOREACH(r, &head_peer, entry) {
if (r->index == index) { if (r->index == index) {
@ -396,7 +508,7 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto,
unsigned int * timestamp, unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes) u_int64_t * packets, u_int64_t * bytes)
{ {
return get_nat_redirect_rule(NFT_TABLE_NAT, return get_nat_redirect_rule(nft_prerouting_chain,
ifname, eport, proto, ifname, eport, proto,
iaddr, iaddrlen, iport, iaddr, iaddrlen, iport,
desc, desclen, desc, desclen,
@ -423,7 +535,7 @@ get_redirect_rule_by_index(int index,
UNUSED(timestamp); UNUSED(timestamp);
d_printf(("get_redirect_rule_by_index()\n")); d_printf(("get_redirect_rule_by_index()\n"));
reflesh_nft_cache_redirect(); refresh_nft_cache_redirect();
LIST_FOREACH(r, &head_redirect, entry) { LIST_FOREACH(r, &head_redirect, entry) {
if (r->index == index) { if (r->index == index) {
@ -504,7 +616,7 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
UNUSED(rhost); UNUSED(rhost);
UNUSED(rhostlen); UNUSED(rhostlen);
reflesh_nft_cache_redirect(); refresh_nft_cache_redirect();
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
if (p->proto == proto && if (p->proto == proto &&
@ -556,7 +668,7 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
return NULL; return NULL;
} }
reflesh_nft_cache_redirect(); refresh_nft_cache_redirect();
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
if (p->proto == proto && if (p->proto == proto &&
@ -636,17 +748,17 @@ list_redirect_rule(const char * ifname)
rule_t *p; rule_t *p;
UNUSED(ifname); UNUSED(ifname);
reflesh_nft_cache_filter(); refresh_nft_cache_filter();
LIST_FOREACH(p, &head_filter, entry) { LIST_FOREACH(p, &head_filter, entry) {
print_rule(p); print_rule(p);
} }
reflesh_nft_cache_redirect(); refresh_nft_cache_redirect();
LIST_FOREACH(p, &head_redirect, entry) { LIST_FOREACH(p, &head_redirect, entry) {
print_rule(p); print_rule(p);
} }
reflesh_nft_cache_peer(); refresh_nft_cache_peer();
LIST_FOREACH(p, &head_peer, entry) { LIST_FOREACH(p, &head_peer, entry) {
print_rule(p); print_rule(p);
} }

View File

@ -11,6 +11,7 @@
#define NFTNLRDR_H_INCLUDED #define NFTNLRDR_H_INCLUDED
#include "../commonrdr.h" #include "../commonrdr.h"
int init_redirect(void); int init_redirect(void);
void shutdown_redirect(void); void shutdown_redirect(void);

View File

@ -32,12 +32,16 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <libmnl/libmnl.h> #include <libmnl/libmnl.h>
#include <libnftnl/table.h>
#include <libnftnl/chain.h>
#include <libnftnl/rule.h> #include <libnftnl/rule.h>
#include <libnftnl/expr.h> #include <libnftnl/expr.h>
#include "../commonrdr.h"
#include "nftnlrdr_misc.h" #include "nftnlrdr_misc.h"
#include "../macros.h" #include "../macros.h"
#include "../upnpglobalvars.h"
#define DEBUG 1
#ifdef DEBUG #ifdef DEBUG
#define d_printf(x) do { printf x; } while (0) #define d_printf(x) do { printf x; } while (0)
@ -45,10 +49,30 @@
#define d_printf(x) #define d_printf(x)
#endif #endif
#if defined(DEBUG) && (__STDC_VERSION__ >= 199901L) && (__GNUC__ >= 3)
/* disambiguate log messages by adding position in source. GNU C99 or later. Pesky trailing comma... */
#define log_error( msg, ...) syslog(LOG_ERR, "%s[%d]: " msg, __func__, __LINE__, ##__VA_ARGS__ )
#define log_debug( msg, ...) syslog(LOG_DEBUG, "%s[%d]: " msg, __func__, __LINE__, ##__VA_ARGS__ )
#else
/* original style */
#define log_error(args...) syslog(LOG_ERR, args)
#define log_debug(args...) syslog(LOG_DEBUG, args)
#endif
#define RULE_CACHE_INVALID 0 #define RULE_CACHE_INVALID 0
#define RULE_CACHE_VALID 1 #define RULE_CACHE_VALID 1
const char * nft_table = "miniupnpd";
const char * nft_table4 = "miniupnpd4";
const char * nft_table6 = "miniupnpd6";
const char * nft_prerouting_chain = "prerouting";
const char * nft_postrouting_chain = "postrouting";
const char * nft_forward_chain = "forward";
static struct mnl_socket *nl = NULL; static struct mnl_socket *nl = NULL;
static uint32_t nl_seq = 0;
// FILTER // FILTER
struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter); struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter);
// DNAT // DNAT
@ -254,7 +278,7 @@ set_reg (rule_t *r, uint32_t dreg, enum rule_reg_type type, uint32_t val)
r->filter_action = val; r->filter_action = val;
} }
} else { } else {
syslog(LOG_ERR, "%s: unknown reg:%d", "set_reg", dreg); log_error("unknown reg:%d", dreg);
} }
return ; return ;
} }
@ -275,7 +299,6 @@ parse_rule_immediate(struct nftnl_expr *e, rule_t *r)
} }
set_reg(r, dreg, RULE_REG_IMM_VAL, reg_val); set_reg(r, dreg, RULE_REG_IMM_VAL, reg_val);
return;
} }
static inline void static inline void
@ -284,8 +307,6 @@ parse_rule_counter(struct nftnl_expr *e, rule_t *r)
r->type = RULE_COUNTER; r->type = RULE_COUNTER;
r->bytes = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); r->bytes = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES);
r->packets = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); r->packets = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS);
return;
} }
static inline void static inline void
@ -295,21 +316,20 @@ parse_rule_meta(struct nftnl_expr *e, rule_t *r)
uint32_t dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); uint32_t dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
enum rule_reg_type reg_type; enum rule_reg_type reg_type;
/* ToDo: body of both cases are identical - bug? */
switch (key) { switch (key) {
case NFT_META_IIF: case NFT_META_IIF:
reg_type = RULE_REG_IIF; reg_type = RULE_REG_IIF;
set_reg(r, dreg, reg_type, 0); set_reg(r, dreg, reg_type, 0);
return ; break;
case NFT_META_OIF: case NFT_META_OIF:
reg_type = RULE_REG_IIF; reg_type = RULE_REG_IIF;
set_reg(r, dreg, reg_type, 0); set_reg(r, dreg, reg_type, 0);
return ; break;
default:
log_debug("parse_rule_meta :Not support key %d\n", key);
break;
} }
syslog(LOG_DEBUG, "parse_rule_meta :Not support key %d\n", key);
return;
} }
static inline void static inline void
@ -328,7 +348,7 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r)
if (addr_min_reg != addr_max_reg || if (addr_min_reg != addr_max_reg ||
proto_min_reg != proto_max_reg) { proto_min_reg != proto_max_reg) {
syslog(LOG_ERR, "Unsupport proto/addr range for NAT"); log_error( "Unsupport proto/addr range for NAT");
} }
proto_min_val = htons((uint16_t)*get_reg_val_ptr(r, proto_min_reg)); proto_min_val = htons((uint16_t)*get_reg_val_ptr(r, proto_min_reg));
@ -344,7 +364,6 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r)
set_reg(r, NFT_REG_1, RULE_REG_NONE, 0); set_reg(r, NFT_REG_1, RULE_REG_NONE, 0);
set_reg(r, NFT_REG_2, RULE_REG_NONE, 0); set_reg(r, NFT_REG_2, RULE_REG_NONE, 0);
return;
} }
static inline void static inline void
@ -364,53 +383,45 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r)
if (offset == offsetof(struct iphdr, daddr) && if (offset == offsetof(struct iphdr, daddr) &&
len == sizeof(in_addr_t)) { len == sizeof(in_addr_t)) {
*regptr = RULE_REG_IP_DEST_ADDR; *regptr = RULE_REG_IP_DEST_ADDR;
return;
} else if (offset == offsetof(struct iphdr, saddr) && } else if (offset == offsetof(struct iphdr, saddr) &&
len == sizeof(in_addr_t)) { len == sizeof(in_addr_t)) {
*regptr = RULE_REG_IP_SRC_ADDR; *regptr = RULE_REG_IP_SRC_ADDR;
return;
} else if (offset == offsetof(struct iphdr, saddr) && } else if (offset == offsetof(struct iphdr, saddr) &&
len == sizeof(in_addr_t) * 2) { len == sizeof(in_addr_t) * 2) {
*regptr = RULE_REG_IP_SD_ADDR; *regptr = RULE_REG_IP_SD_ADDR;
return;
} else if (offset == offsetof(struct iphdr, protocol) && } else if (offset == offsetof(struct iphdr, protocol) &&
len == sizeof(uint8_t)) { len == sizeof(uint8_t)) {
*regptr = RULE_REG_IP_PROTO; *regptr = RULE_REG_IP_PROTO;
return;
} else if (offset == offsetof(struct ipv6hdr, nexthdr) && } else if (offset == offsetof(struct ipv6hdr, nexthdr) &&
len == sizeof(uint8_t)) { len == sizeof(uint8_t)) {
*regptr = RULE_REG_IP6_PROTO; *regptr = RULE_REG_IP6_PROTO;
return;
} else if (offset == offsetof(struct ipv6hdr, daddr) && } else if (offset == offsetof(struct ipv6hdr, daddr) &&
len == sizeof(struct in6_addr)) { len == sizeof(struct in6_addr)) {
*regptr = RULE_REG_IP6_DEST_ADDR; *regptr = RULE_REG_IP6_DEST_ADDR;
return;
} else if (offset == offsetof(struct ipv6hdr, saddr) && } else if (offset == offsetof(struct ipv6hdr, saddr) &&
len == sizeof(struct in6_addr)) { len == sizeof(struct in6_addr)) {
*regptr = RULE_REG_IP6_SRC_ADDR; *regptr = RULE_REG_IP6_SRC_ADDR;
return;
} else if (offset == offsetof(struct ipv6hdr, saddr) && } else if (offset == offsetof(struct ipv6hdr, saddr) &&
len == sizeof(struct in6_addr) * 2) { len == sizeof(struct in6_addr) * 2) {
*regptr = RULE_REG_IP6_SD_ADDR; *regptr = RULE_REG_IP6_SD_ADDR;
return;
} }
break; break;
case NFT_PAYLOAD_TRANSPORT_HEADER: case NFT_PAYLOAD_TRANSPORT_HEADER:
if (offset == offsetof(struct tcphdr, dest) && if (offset == offsetof(struct tcphdr, dest) &&
len == sizeof(uint16_t)) { len == sizeof(uint16_t)) {
*regptr = RULE_REG_TCP_DPORT; *regptr = RULE_REG_TCP_DPORT;
return;
} else if (offset == offsetof(struct tcphdr, source) && } else if (offset == offsetof(struct tcphdr, source) &&
len == sizeof(uint16_t) * 2) { len == sizeof(uint16_t) * 2) {
*regptr = RULE_REG_TCP_SD_PORT; *regptr = RULE_REG_TCP_SD_PORT;
return;
} }
break; break;
default:
syslog(LOG_DEBUG,
"Unsupported payload: (dreg:%d, base:%d, offset:%d, len:%d)",
dreg, base, offset, len);
break;
} }
syslog(LOG_DEBUG,
"Unsupport payload: (dreg:%d, base:%d, offset:%d, len:%d)",
dreg, base, offset, len);
return;
} }
/* /*
@ -436,7 +447,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) {
sreg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); sreg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
if (sreg != NFT_REG_1) { if (sreg != NFT_REG_1) {
syslog(LOG_ERR, "parse_rule_cmp: Unsupport reg:%d", sreg); log_error( "parse_rule_cmp: Unsupport reg:%d", sreg);
return; return;
} }
@ -509,7 +520,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) {
} }
break; break;
default: default:
syslog(LOG_DEBUG, "Unknown cmp (r1type:%d, data_len:%d, op:%d)", log_debug("Unknown cmp (r1type:%d, data_len:%d, op:%d)",
r->reg1_type, data_len, op); r->reg1_type, data_len, op);
/* return early - don't modify r->reg1_type */ /* return early - don't modify r->reg1_type */
return; return;
@ -538,7 +549,7 @@ rule_expr_cb(struct nftnl_expr *e, void *data)
} else if (strncmp("immediate", attr_name, sizeof("immediate")) == 0) { } else if (strncmp("immediate", attr_name, sizeof("immediate")) == 0) {
parse_rule_immediate(e, r); parse_rule_immediate(e, r);
} else { } else {
syslog(LOG_DEBUG, "unknown attr: %s\n", attr_name); log_debug("unknown attr: %s\n", attr_name);
} }
return MNL_CB_OK; return MNL_CB_OK;
@ -548,6 +559,7 @@ rule_expr_cb(struct nftnl_expr *e, void *data)
static int static int
table_cb(const struct nlmsghdr *nlh, void *data) table_cb(const struct nlmsghdr *nlh, void *data)
{ {
int result = MNL_CB_OK;
struct nftnl_rule *t; struct nftnl_rule *t;
uint32_t len; uint32_t len;
struct nftnl_expr *expr; struct nftnl_expr *expr;
@ -562,130 +574,118 @@ table_cb(const struct nlmsghdr *nlh, void *data)
r = malloc(sizeof(rule_t)); r = malloc(sizeof(rule_t));
memset(r, 0, sizeof(rule_t)); if (r == NULL) {
t = nftnl_rule_alloc(); log_error("out of memory: %m");
if (t == NULL) { } else {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); memset(r, 0, sizeof(rule_t));
goto err; t = nftnl_rule_alloc();
if (t == NULL) {
log_error("nftnl_rule_alloc() FAILED");
} else {
if (nftnl_rule_nlmsg_parse(nlh, t) < 0) {
log_error("nftnl_rule_nlmsg_parse FAILED");
} else {
chain = (char *) nftnl_rule_get_data(t, NFTNL_RULE_CHAIN, &len);
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0 ||
strcmp(chain, nft_forward_chain) == 0) {
r->table = strdup(
(char *) nftnl_rule_get_data(t, NFTNL_RULE_TABLE, &len));
r->chain = strdup(chain);
r->family = *(uint32_t *) nftnl_rule_get_data(t, NFTNL_RULE_FAMILY,
&len);
descr = (char *) nftnl_rule_get_data(t, NFTNL_RULE_USERDATA,
&r->desc_len);
if (r->desc_len > 0)
r->desc = strdup(descr);
r->handle = *(uint32_t *) nftnl_rule_get_data(t,
NFTNL_RULE_HANDLE,
&len);
r->type = RULE_NONE;
if (strcmp(chain, nft_prerouting_chain) == 0 ||
strcmp(chain, nft_postrouting_chain) == 0) {
r->type = RULE_NAT;
} else if (strcmp(chain, nft_forward_chain) == 0) {
r->type = RULE_FILTER;
}
itr = nftnl_expr_iter_create(t);
while ((expr = nftnl_expr_iter_next(itr)) != NULL) {
rule_expr_cb(expr, r);
}
switch (r->type) {
case RULE_NAT:
switch (r->nat_type) {
case NFT_NAT_SNAT:
r->index = index_peer;
LIST_INSERT_HEAD(&head_peer, r, entry);
index_peer++;
break;
case NFT_NAT_DNAT:
r->index = index_redirect;
LIST_INSERT_HEAD(&head_redirect, r, entry);
index_redirect++;
break;
}
break;
case RULE_FILTER:
r->index = index_filter;
LIST_INSERT_HEAD(&head_filter, r, entry);
index_filter++;
break;
default:
free(r);
break;
}
}
nftnl_rule_free(t);
}
}
} }
return result;
if (nftnl_rule_nlmsg_parse(nlh, t) < 0) {
syslog(LOG_ERR, "nftnl_rule_nlmsg_parse FAILED");
goto err_free;
}
chain = (char *)nftnl_rule_get_data(t, NFTNL_RULE_CHAIN, &len);
if (strcmp(chain, miniupnpd_nat_chain) != 0 &&
strcmp(chain, miniupnpd_nat_postrouting_chain) != 0 &&
strcmp(chain, miniupnpd_forward_chain) != 0) {
goto rule_skip;
}
r->table = strdup(
(char *)nftnl_rule_get_data(t, NFTNL_RULE_TABLE, &len));
r->chain = strdup(chain);
r->family = *(uint32_t*)nftnl_rule_get_data(t, NFTNL_RULE_FAMILY,
&len);
descr = (char *)nftnl_rule_get_data(t, NFTNL_RULE_USERDATA,
&r->desc_len);
if (r->desc_len > 0)
r->desc = strdup(descr);
r->handle = *(uint32_t*)nftnl_rule_get_data(t,
NFTNL_RULE_HANDLE,
&len);
if (strcmp(r->table, NFT_TABLE_NAT) == 0) {
r->type = RULE_NAT;
} else if (strcmp(r->table, NFT_TABLE_FILTER) == 0) {
r->type = RULE_FILTER;
}
itr = nftnl_expr_iter_create(t);
while ((expr = nftnl_expr_iter_next(itr)) != NULL) {
rule_expr_cb(expr, r);
}
if (r->type == RULE_NONE) {
free(r);
} else if (r->type == RULE_NAT && r->nat_type == NFT_NAT_SNAT) {
r->index = index_peer;
LIST_INSERT_HEAD(&head_peer, r, entry);
index_peer++;
} else if (r->type == RULE_NAT && r->nat_type == NFT_NAT_DNAT) {
r->index = index_redirect;
LIST_INSERT_HEAD(&head_redirect, r, entry);
index_redirect++;
} else if (r->type == RULE_FILTER) {
r->index = index_filter;
LIST_INSERT_HEAD(&head_filter, r, entry);
index_filter++;
}
rule_skip:
err_free:
nftnl_rule_free(t);
err:
return MNL_CB_OK;
} }
void void
reflesh_nft_cache_filter() refresh_nft_cache_filter(void) {
{ if (rule_list_filter_validate != RULE_CACHE_VALID) {
refresh_nft_cache(&head_filter, nft_table4, nft_forward_chain, NFPROTO_INET);
if (rule_list_filter_validate == RULE_CACHE_VALID) { rule_list_filter_validate = RULE_CACHE_VALID;
return;
} }
reflesh_nft_cache(&head_filter, NFT_TABLE_FILTER, miniupnpd_forward_chain, NFPROTO_INET);
rule_list_filter_validate = RULE_CACHE_VALID;
return;
} }
void void
reflesh_nft_cache_peer() refresh_nft_cache_peer(void) {
{ if (rule_list_peer_validate != RULE_CACHE_VALID) {
if (rule_list_peer_validate == RULE_CACHE_VALID) { refresh_nft_cache(&head_peer, nft_table4, nft_postrouting_chain, NFPROTO_IPV4);
return; rule_list_peer_validate = RULE_CACHE_VALID;
} }
reflesh_nft_cache(&head_peer, NFT_TABLE_NAT, miniupnpd_nat_postrouting_chain, NFPROTO_IPV4);
rule_list_peer_validate = RULE_CACHE_VALID;
return;
} }
void void
reflesh_nft_cache_redirect() refresh_nft_cache_redirect(void)
{ {
if (rule_list_redirect_validate == RULE_CACHE_VALID) { if (rule_list_redirect_validate != RULE_CACHE_VALID) {
return; refresh_nft_cache(&head_redirect, nft_table4, nft_prerouting_chain, NFPROTO_IPV4);
rule_list_redirect_validate = RULE_CACHE_VALID;
} }
reflesh_nft_cache(&head_redirect, NFT_TABLE_NAT, miniupnpd_nat_chain, NFPROTO_IPV4);
rule_list_redirect_validate = RULE_CACHE_VALID;
return;
} }
void void
reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32_t family) flush_nft_cache(struct rule_list *head)
{ {
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
uint32_t portid, seq, type = NFTNL_OUTPUT_DEFAULT;
struct nftnl_rule *t;
rule_t *p1, *p2; rule_t *p1, *p2;
int ret;
t = NULL;
p1 = LIST_FIRST(head); p1 = LIST_FIRST(head);
if (p1 != NULL) { if (p1 != NULL) {
while(p1 != NULL) { while (p1 != NULL) {
p2 = (rule_t *)LIST_NEXT(p1, entry); p2 = (rule_t *)LIST_NEXT(p1, entry);
if (p1->desc != NULL) { if (p1->desc != NULL) {
free(p1->desc); free(p1->desc);
@ -701,16 +701,28 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32
} }
} }
LIST_INIT(head); LIST_INIT(head);
}
void
refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
uint32_t portid, seq, type = NFTNL_OUTPUT_DEFAULT;
struct nftnl_rule *t;
int ret;
flush_nft_cache(head);
if (nl == NULL) { if (nl == NULL) {
nl = mnl_socket_open(NETLINK_NETFILTER); nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) { if (nl == NULL) {
syslog(LOG_ERR, "%s: mnl_socket_open() FAILED: %m", "reflesh_nft_cache()"); log_error("mnl_socket_open() FAILED: %m");
return; return;
} }
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
syslog(LOG_ERR, "%s: mnl_socket_bind() FAILED: %m", "reflesh_nft_cache()"); log_error("mnl_socket_bind() FAILED: %m");
return; return;
} }
} }
@ -718,7 +730,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32
t = nftnl_rule_alloc(); t = nftnl_rule_alloc();
if (t == NULL) { if (t == NULL) {
syslog(LOG_ERR, "%s: nftnl_rule_alloc() FAILED", "reflesh_nft_cache()"); log_error("nftnl_rule_alloc() FAILED");
return; return;
} }
@ -731,7 +743,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32
nftnl_rule_free(t); nftnl_rule_free(t);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
syslog(LOG_ERR, "%s: mnl_socket_sendto() FAILED: %m", "reflesh_nft_cache()"); log_error("mnl_socket_sendto() FAILED: %m");
return; return;
} }
@ -744,7 +756,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32
} }
if (ret == -1) { if (ret == -1) {
syslog(LOG_ERR, "%s: mnl_socket_recvfrom() FAILED: %m", "reflesh_nft_cache()"); log_error("mnl_socket_recvfrom() FAILED: %m");
} }
/* mnl_socket_close(nl); */ /* mnl_socket_close(nl); */
@ -760,7 +772,7 @@ expr_add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg,
e = nftnl_expr_alloc("payload"); e = nftnl_expr_alloc("payload");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_add_payload()", "payload"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "payload");
return; return;
} }
@ -781,7 +793,7 @@ expr_add_bitwise(struct nftnl_rule *r, uint32_t sreg, uint32_t dreg,
e = nftnl_expr_alloc("bitwise"); e = nftnl_expr_alloc("bitwise");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_add_bitwise()", "bitwise"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "expr_add_bitwise()", "bitwise");
return; return;
} }
@ -803,7 +815,7 @@ expr_add_cmp(struct nftnl_rule *r, uint32_t sreg, uint32_t op,
e = nftnl_expr_alloc("cmp"); e = nftnl_expr_alloc("cmp");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_add_cmp()", "cmp"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "cmp");
return; return;
} }
@ -821,7 +833,7 @@ expr_add_meta(struct nftnl_rule *r, uint32_t meta_key, uint32_t dreg)
e = nftnl_expr_alloc("meta"); e = nftnl_expr_alloc("meta");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_add_meta()", "meta"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "meta");
return; return;
} }
@ -837,7 +849,7 @@ expr_set_reg_val_u32(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val
struct nftnl_expr *e; struct nftnl_expr *e;
e = nftnl_expr_alloc("immediate"); e = nftnl_expr_alloc("immediate");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_set_reg_val_u32()", "immediate"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate");
return; return;
} }
nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg); nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg);
@ -851,7 +863,7 @@ expr_set_reg_val_u16(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val
struct nftnl_expr *e; struct nftnl_expr *e;
e = nftnl_expr_alloc("immediate"); e = nftnl_expr_alloc("immediate");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_set_reg_val_u16()", "immediate"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate");
return; return;
} }
nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg); nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg);
@ -865,7 +877,7 @@ expr_set_reg_verdict(struct nftnl_rule *r, uint32_t val)
struct nftnl_expr *e; struct nftnl_expr *e;
e = nftnl_expr_alloc("immediate"); e = nftnl_expr_alloc("immediate");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_set_reg_verdict()", "immediate"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate");
return; return;
} }
nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT); nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
@ -882,7 +894,7 @@ expr_add_nat(struct nftnl_rule *r, uint32_t t, uint32_t family,
e = nftnl_expr_alloc("nat"); e = nftnl_expr_alloc("nat");
if (e == NULL) { if (e == NULL) {
syslog(LOG_ERR, "%s: nftnl_expr_alloc(\"%s\") FAILED", "expr_add_nat()", "nat"); log_error("nftnl_expr_alloc(\"%s\") FAILED", "nat");
return; return;
} }
@ -919,12 +931,12 @@ rule_set_snat(uint8_t family, uint8_t proto,
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) { if (r == NULL) {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); log_error("nftnl_rule_alloc() FAILED");
return NULL; return NULL;
} }
nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); nftnl_rule_set(r, NFTNL_RULE_TABLE, family == NFPROTO_IPV6 ? nft_table6 : nft_table4);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_postrouting_chain); nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_postrouting_chain);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
if (descr != NULL) { if (descr != NULL) {
@ -1005,12 +1017,12 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) { if (r == NULL) {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); log_error("nftnl_rule_alloc() FAILED");
return NULL; return NULL;
} }
nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); nftnl_rule_set(r, NFTNL_RULE_TABLE, family == NFPROTO_IPV6 ? nft_table6 : nft_table4);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_chain); nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_prerouting_chain);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
if (descr != NULL) { if (descr != NULL) {
@ -1079,7 +1091,7 @@ rule_set_filter(uint8_t family, const char * ifname, uint8_t proto,
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) { if (r == NULL) {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); log_error("nftnl_rule_alloc() FAILED");
return NULL; return NULL;
} }
@ -1127,7 +1139,7 @@ rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto,
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) { if (r == NULL) {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); log_error("nftnl_rule_alloc() FAILED");
return NULL; return NULL;
} }
@ -1171,8 +1183,8 @@ rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname
uint32_t descr_len; uint32_t descr_len;
UNUSED(eport); UNUSED(eport);
nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_FILTER); nftnl_rule_set(r, NFTNL_RULE_TABLE, nft_table);
nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_forward_chain); nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_forward_chain);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
if (descr != NULL) { if (descr != NULL) {
@ -1227,7 +1239,7 @@ rule_del_handle(rule_t *rule)
r = nftnl_rule_alloc(); r = nftnl_rule_alloc();
if (r == NULL) { if (r == NULL) {
syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); log_error("nftnl_rule_alloc() FAILED");
return NULL; return NULL;
} }
@ -1257,75 +1269,204 @@ nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq)
} }
int int
nft_send_request(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain_type) nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain_type)
{ {
int result = -1;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch; struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE]; char buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq = time(NULL);
int ret;
if (chain_type == RULE_CHAIN_FILTER)
rule_list_filter_validate = RULE_CACHE_INVALID;
else if (chain_type == RULE_CHAIN_PEER)
rule_list_peer_validate = RULE_CACHE_INVALID;
else if (chain_type == RULE_CHAIN_REDIRECT)
rule_list_redirect_validate = RULE_CACHE_INVALID;
if (nl == NULL) { batch = start_batch(buf, sizeof(buf));
nl = mnl_socket_open(NETLINK_NETFILTER); if (batch != NULL)
if (nl == NULL) { {
syslog(LOG_ERR, "%s: mnl_socket_open() FAILED: %m", "nft_send_request()"); switch (chain_type) {
return -1; case RULE_CHAIN_FILTER:
} rule_list_filter_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_PEER:
rule_list_peer_validate = RULE_CACHE_INVALID;
break;
case RULE_CHAIN_REDIRECT:
rule_list_redirect_validate = RULE_CACHE_INVALID;
break;
}
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
cmd,
nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY),
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
nl_seq++);
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { nftnl_rule_nlmsg_build_payload(nlh, rule);
syslog(LOG_ERR, "%s: mnl_socket_bind() FAILED: %m", "nft_send_request()"); nftnl_rule_free(rule);
return -1;
}
}
batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); result = send_batch(batch);
}
nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), return result;
NFNL_MSG_BATCH_BEGIN, seq++); }
mnl_nlmsg_batch_next(batch);
int
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), table_op( enum nf_tables_msg_types op, uint16_t family, const char * name)
cmd, {
nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY), int result;
NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, struct nlmsghdr *nlh;
seq++); struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE];
nftnl_rule_nlmsg_build_payload(nlh, rule);
nftnl_rule_free(rule); struct nftnl_table *table;
mnl_nlmsg_batch_next(batch);
log_error("(%d, %d, %s)", op, family, name);
nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END,
seq++); table = nftnl_table_alloc();
mnl_nlmsg_batch_next(batch); if (table == NULL) {
log_error("out of memory: %m");
ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), result = -1;
mnl_nlmsg_batch_size(batch)); } else {
if (ret == -1) { nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
syslog(LOG_ERR, "%s: mnl_socket_sendto() FAILED: %m", "nft_send_request()"); nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
return -1;
} batch = start_batch( buf, sizeof(buf));
if (batch == NULL) {
mnl_nlmsg_batch_stop(batch); log_error("out of memory: %m");
result = -2;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } else {
if (ret == -1) { nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
syslog(LOG_ERR, "%s: mnl_socket_recvfrom() FAILED: %m", "nft_send_request()"); op, family,
return -1; (op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK,
} nl_seq++);
nftnl_table_nlmsg_build_payload(nlh, table);
ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
if (ret < 0) { result = send_batch(batch);
syslog(LOG_ERR, "%s: mnl_cb_run() FAILED: %m", "nft_send_request()"); }
return -1; nftnl_table_free(table);
} }
return result;
/* mnl_socket_close(nl); */ }
return 0;
int
chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table,
const char * name, const char * type, uint32_t hooknum, signed int priority )
{
int result = -1;
struct nlmsghdr *nlh;
struct mnl_nlmsg_batch *batch;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_chain *chain;
log_error("(%d, %d, %s, %s, %s, %d, %d)", op, family, table, name, type, hooknum, priority);
chain = nftnl_chain_alloc();
if (chain == NULL) {
log_error("out of memory: %m");
result = -2;
} else {
nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
nftnl_chain_set_s32(chain, NFTNL_CHAIN_PRIO, priority);
batch = start_batch( buf, sizeof(buf));
if (batch == NULL) {
log_error("out of memory: %m");
result = -3;
} else {
nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
op, family,
(op == NFT_MSG_NEWCHAIN ? NLM_F_CREATE : 0) | NLM_F_ACK,
nl_seq++);
if (nlh == NULL)
{
log_error("failed to build header: %m");
result = -4;
} else {
nftnl_chain_nlmsg_build_payload(nlh, chain);
result = send_batch(batch);
}
}
nftnl_chain_free(chain);
}
return result;
}
struct mnl_nlmsg_batch *
start_batch( char *buf, size_t buf_size)
{
struct mnl_nlmsg_batch *batch;
nl_seq = time(NULL);
if (nl == NULL) {
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
log_error("mnl_socket_open() FAILED: %m");
return NULL;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
log_error("mnl_socket_bind() FAILED: %m");
return NULL;
}
}
batch = mnl_nlmsg_batch_start(buf, buf_size);
if (batch != NULL) {
nft_mnl_batch_put(mnl_nlmsg_batch_current(batch),
NFNL_MSG_BATCH_BEGIN, nl_seq++);
mnl_nlmsg_batch_next(batch);
}
return batch;
}
int
send_batch(struct mnl_nlmsg_batch * batch)
{
int ret;
char buf[MNL_SOCKET_BUFFER_SIZE];
mnl_nlmsg_batch_next(batch);
nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END,
nl_seq++);
mnl_nlmsg_batch_next(batch);
if (nl == NULL) {
log_error("netlink not connected");
return -1;
} else {
ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch));
if (ret == -1) {
log_error("mnl_socket_sendto() FAILED: %m");
return -2;
}
mnl_nlmsg_batch_stop(batch);
do {
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret == -1) {
log_error("mnl_socket_recvfrom() FAILED: %m");
return -3;
} else if (ret > 0) {
ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL);
if (ret == -1) {
log_error("mnl_cb_run() FAILED: %m");
return -4;
}
}
} while (ret > 0);
}
/* mnl_socket_close(nl); */
return 0;
}
void
finish_batch(void)
{
mnl_socket_close(nl);
nl = NULL;
} }

View File

@ -8,8 +8,13 @@
*/ */
#include <sys/queue.h> #include <sys/queue.h>
#define NFT_TABLE_NAT "nat" extern const char * nft_table;
#define NFT_TABLE_FILTER "filter" extern const char * nft_table4;
extern const char * nft_table6;
extern const char * nft_prerouting_chain;
extern const char * nft_postrouting_chain;
extern const char * nft_forward_chain;
#define NFT_DESCR_SIZE 1024 #define NFT_DESCR_SIZE 1024
enum rule_reg_type { enum rule_reg_type {
@ -80,7 +85,7 @@ extern struct rule_list head_redirect;
extern struct rule_list head_peer; extern struct rule_list head_peer;
int int
nft_send_request(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type type); nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type type);
struct nftnl_rule * struct nftnl_rule *
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
in_addr_t rhost, unsigned short eport, in_addr_t rhost, unsigned short eport,
@ -109,8 +114,21 @@ rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname
uint8_t proto, unsigned short eport, unsigned short iport, uint8_t proto, unsigned short eport, unsigned short iport,
unsigned short rport, const char *descr, const char *handle); unsigned short rport, const char *descr, const char *handle);
struct nftnl_rule *rule_del_handle(rule_t *r); struct nftnl_rule *rule_del_handle(rule_t *r);
void reflesh_nft_cache_filter(void); void refresh_nft_cache_filter(void);
void reflesh_nft_cache_redirect(void); void refresh_nft_cache_redirect(void);
void reflesh_nft_cache_peer(void); void refresh_nft_cache_peer(void);
void reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32_t family); void refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family);
void print_rule(rule_t *r); void print_rule(rule_t *r);
int
table_op(enum nf_tables_msg_types op, uint16_t family, const char * name);
int
chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table,
const char * name, const char * type, uint32_t hooknum, signed int priority );
struct mnl_nlmsg_batch *
start_batch( char *buf, size_t buf_size);
int
send_batch(struct mnl_nlmsg_batch * batch);
void
finish_batch(void);

View File

@ -109,7 +109,7 @@ const char * queue = 0;
const char * tag = 0; const char * tag = 0;
#endif #endif
#ifdef USE_NETFILTER #ifdef USE_IPTABLES
/* chain names to use in the nat and filter tables. */ /* chain names to use in the nat and filter tables. */
/* iptables -t nat -N MINIUPNPD /* iptables -t nat -N MINIUPNPD

View File

@ -142,7 +142,7 @@ extern const char * queue;
extern const char * tag; extern const char * tag;
#endif #endif
#ifdef USE_NETFILTER #ifdef USE_IPTABLES
extern const char * miniupnpd_nat_chain; extern const char * miniupnpd_nat_chain;
extern const char * miniupnpd_nat_postrouting_chain; extern const char * miniupnpd_nat_postrouting_chain;
extern const char * miniupnpd_forward_chain; extern const char * miniupnpd_forward_chain;