From 75bdb777cfa7b62aba1d8ae8fcd081abef775d2e Mon Sep 17 00:00:00 2001 From: Paul Chambers Date: Mon, 30 Sep 2019 00:12:08 -0700 Subject: [PATCH] rework nft-specific globals, create & destroy tables/chains at init & shutdown --- miniupnpd/Makefile.linux_nft | 11 +- miniupnpd/commonrdr.h | 16 + miniupnpd/miniupnpd.c | 16 +- miniupnpd/netfilter_nft/Makefile | 6 +- miniupnpd/netfilter_nft/nftnlrdr.c | 170 +++++-- miniupnpd/netfilter_nft/nftnlrdr.h | 1 + miniupnpd/netfilter_nft/nftnlrdr_misc.c | 579 +++++++++++++++--------- miniupnpd/netfilter_nft/nftnlrdr_misc.h | 32 +- miniupnpd/upnpglobalvars.c | 2 +- miniupnpd/upnpglobalvars.h | 2 +- 10 files changed, 567 insertions(+), 268 deletions(-) diff --git a/miniupnpd/Makefile.linux_nft b/miniupnpd/Makefile.linux_nft index 45cd2ed..0d6d546 100644 --- a/miniupnpd/Makefile.linux_nft +++ b/miniupnpd/Makefile.linux_nft @@ -41,11 +41,10 @@ MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8 BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.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 \ - upnpevents.o upnputils.o getconnstatus.o \ - upnpstun.o \ - upnppinhole.o pcplearndscp.o asyncsendto.o + upnpglobalvars.o upnpevents.o upnputils.o getconnstatus.o \ + upnpstun.o upnppinhole.o pcplearndscp.o asyncsendto.o LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.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/getroute.o: getroute.h upnputils.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/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 testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h testupnpdescgen.o: getifaddr.h diff --git a/miniupnpd/commonrdr.h b/miniupnpd/commonrdr.h index 61352e4..f04b53f 100644 --- a/miniupnpd/commonrdr.h +++ b/miniupnpd/commonrdr.h @@ -64,4 +64,20 @@ update_portmapping_desc_timestamp(const char * ifname, unsigned short eport, int proto, 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 diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 3f09e81..4871c3c 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1267,6 +1267,17 @@ init(int argc, char * * argv, struct runtime_vars * v) break; #endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */ #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: miniupnpd_forward_chain = ary_options[i].value; break; @@ -1276,7 +1287,8 @@ init(int argc, char * * argv, struct runtime_vars * v) case UPNPNATPOSTCHAIN: miniupnpd_nat_postrouting_chain = ary_options[i].value; break; -#endif /* USE_NETFILTER */ +#endif /* else USE_NFTABLES */ +#endif /* USE_NETFILTER */ case UPNPNOTIFY_INTERVAL: v->notify_interval = atoi(ary_options[i].value); break; @@ -2901,6 +2913,8 @@ shutdown: freeoptions(); #endif + shutdown_redirect(); + return 0; } diff --git a/miniupnpd/netfilter_nft/Makefile b/miniupnpd/netfilter_nft/Makefile index e856269..a41ace5 100644 --- a/miniupnpd/netfilter_nft/Makefile +++ b/miniupnpd/netfilter_nft/Makefile @@ -11,9 +11,9 @@ clean: $(RM) *.o testnftnlcrdr testnftpinhole testnftnlrdr_peer \ 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 @@ -29,5 +29,3 @@ nftnlrdr_misc.o: nftnlrdr_misc.c nftpinhole.o: nftpinhole.c nftpinhole.h -upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h - $(CC) -c -o $@ $< diff --git a/miniupnpd/netfilter_nft/nftnlrdr.c b/miniupnpd/netfilter_nft/nftnlrdr.c index 18f939c..3ac4ce5 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr.c +++ b/miniupnpd/netfilter_nft/nftnlrdr.c @@ -20,14 +20,18 @@ #include #include #include +#include #include #include +#include #include #include #include +#include +#include #include #include @@ -35,8 +39,8 @@ #include "../macros.h" #include "../config.h" +#include "../commonrdr.h" #include "nftnlrdr.h" -#include "../upnpglobalvars.h" #include "nftnlrdr_misc.h" @@ -56,15 +60,123 @@ struct timestamp_entry { static struct timestamp_entry * timestamp_list = NULL; -/* dummy init and shutdown functions */ -int init_redirect(void) -{ - return 0; +#define NAT_CHAIN_TYPE "nat" +#define FILTER_CHAIN_TYPE "filter" + +/* 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) -{ - return; +void +shutdown_redirect(void) { + 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 @@ -136,7 +248,7 @@ add_redirect_rule2(const char * ifname, 0, eport, 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(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, 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; UNUSED(ifname); - reflesh_nft_cache_filter(); + refresh_nft_cache_filter(); LIST_FOREACH(p, &head_filter, entry) { if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) { 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; } } @@ -243,7 +355,7 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) uint16_t iport = 0; d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto)); - reflesh_nft_cache_redirect(); + refresh_nft_cache_redirect(); // Delete Redirect Rule 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); /* 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; } } if (iaddr != 0 && iport != 0) { - reflesh_nft_cache_filter(); + refresh_nft_cache_filter(); // Delete Forward Rule LIST_FOREACH(p, &head_filter, entry) { if (p->eport == iport && p->iaddr == iaddr && p->type == RULE_FILTER) { r = rule_del_handle(p); /* 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; } } @@ -276,7 +388,7 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) iaddr = 0; iport = 0; - reflesh_nft_cache_peer(); + refresh_nft_cache_peer(); // Delete Peer Rule LIST_FOREACH(p, &head_peer, entry) { 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); /* 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; } } if (iaddr != 0 && iport != 0) { - reflesh_nft_cache_filter(); + refresh_nft_cache_filter(); // Delete Forward Rule LIST_FOREACH(p, &head_filter, entry) { if (p->eport == iport && p->iaddr == iaddr && p->type == RULE_FILTER) { r = rule_del_handle(p); /* 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; } } @@ -327,7 +439,7 @@ get_peer_rule_by_index(int index, UNUSED(timestamp); d_printf(("get_peer_rule_by_index()\n")); - reflesh_nft_cache_peer(); + refresh_nft_cache_peer(); LIST_FOREACH(r, &head_peer, entry) { if (r->index == index) { @@ -396,7 +508,7 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, unsigned int * timestamp, 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, iaddr, iaddrlen, iport, desc, desclen, @@ -423,7 +535,7 @@ get_redirect_rule_by_index(int index, UNUSED(timestamp); d_printf(("get_redirect_rule_by_index()\n")); - reflesh_nft_cache_redirect(); + refresh_nft_cache_redirect(); LIST_FOREACH(r, &head_redirect, entry) { if (r->index == index) { @@ -504,7 +616,7 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, UNUSED(rhost); UNUSED(rhostlen); - reflesh_nft_cache_redirect(); + refresh_nft_cache_redirect(); LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && @@ -556,7 +668,7 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, return NULL; } - reflesh_nft_cache_redirect(); + refresh_nft_cache_redirect(); LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && @@ -636,17 +748,17 @@ list_redirect_rule(const char * ifname) rule_t *p; UNUSED(ifname); - reflesh_nft_cache_filter(); + refresh_nft_cache_filter(); LIST_FOREACH(p, &head_filter, entry) { print_rule(p); } - reflesh_nft_cache_redirect(); + refresh_nft_cache_redirect(); LIST_FOREACH(p, &head_redirect, entry) { print_rule(p); } - reflesh_nft_cache_peer(); + refresh_nft_cache_peer(); LIST_FOREACH(p, &head_peer, entry) { print_rule(p); } diff --git a/miniupnpd/netfilter_nft/nftnlrdr.h b/miniupnpd/netfilter_nft/nftnlrdr.h index b9e547f..a8076b9 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr.h +++ b/miniupnpd/netfilter_nft/nftnlrdr.h @@ -11,6 +11,7 @@ #define NFTNLRDR_H_INCLUDED #include "../commonrdr.h" + int init_redirect(void); void shutdown_redirect(void); diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.c b/miniupnpd/netfilter_nft/nftnlrdr_misc.c index d2b8c26..a66df8b 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.c +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.c @@ -32,12 +32,16 @@ #include #include +#include +#include #include #include +#include "../commonrdr.h" #include "nftnlrdr_misc.h" #include "../macros.h" -#include "../upnpglobalvars.h" + +#define DEBUG 1 #ifdef DEBUG #define d_printf(x) do { printf x; } while (0) @@ -45,10 +49,30 @@ #define d_printf(x) #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_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 uint32_t nl_seq = 0; + // FILTER struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter); // 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; } } else { - syslog(LOG_ERR, "%s: unknown reg:%d", "set_reg", dreg); + log_error("unknown reg:%d", dreg); } 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); - return; } static inline void @@ -284,8 +307,6 @@ parse_rule_counter(struct nftnl_expr *e, rule_t *r) r->type = RULE_COUNTER; r->bytes = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); r->packets = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); - - return; } 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); enum rule_reg_type reg_type; + /* ToDo: body of both cases are identical - bug? */ switch (key) { case NFT_META_IIF: reg_type = RULE_REG_IIF; set_reg(r, dreg, reg_type, 0); - return ; - + break; case NFT_META_OIF: reg_type = RULE_REG_IIF; 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 @@ -328,7 +348,7 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r) if (addr_min_reg != addr_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)); @@ -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_2, RULE_REG_NONE, 0); - return; } static inline void @@ -364,53 +383,45 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r) if (offset == offsetof(struct iphdr, daddr) && len == sizeof(in_addr_t)) { *regptr = RULE_REG_IP_DEST_ADDR; - return; } else if (offset == offsetof(struct iphdr, saddr) && len == sizeof(in_addr_t)) { *regptr = RULE_REG_IP_SRC_ADDR; - return; } else if (offset == offsetof(struct iphdr, saddr) && len == sizeof(in_addr_t) * 2) { *regptr = RULE_REG_IP_SD_ADDR; - return; } else if (offset == offsetof(struct iphdr, protocol) && len == sizeof(uint8_t)) { *regptr = RULE_REG_IP_PROTO; - return; } else if (offset == offsetof(struct ipv6hdr, nexthdr) && len == sizeof(uint8_t)) { *regptr = RULE_REG_IP6_PROTO; - return; } else if (offset == offsetof(struct ipv6hdr, daddr) && len == sizeof(struct in6_addr)) { *regptr = RULE_REG_IP6_DEST_ADDR; - return; } else if (offset == offsetof(struct ipv6hdr, saddr) && len == sizeof(struct in6_addr)) { *regptr = RULE_REG_IP6_SRC_ADDR; - return; } else if (offset == offsetof(struct ipv6hdr, saddr) && len == sizeof(struct in6_addr) * 2) { *regptr = RULE_REG_IP6_SD_ADDR; - return; } break; case NFT_PAYLOAD_TRANSPORT_HEADER: if (offset == offsetof(struct tcphdr, dest) && len == sizeof(uint16_t)) { *regptr = RULE_REG_TCP_DPORT; - return; } else if (offset == offsetof(struct tcphdr, source) && len == sizeof(uint16_t) * 2) { *regptr = RULE_REG_TCP_SD_PORT; - return; } 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); 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; } @@ -509,7 +520,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { } break; 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); /* return early - don't modify r->reg1_type */ return; @@ -538,7 +549,7 @@ rule_expr_cb(struct nftnl_expr *e, void *data) } else if (strncmp("immediate", attr_name, sizeof("immediate")) == 0) { parse_rule_immediate(e, r); } else { - syslog(LOG_DEBUG, "unknown attr: %s\n", attr_name); + log_debug("unknown attr: %s\n", attr_name); } return MNL_CB_OK; @@ -548,6 +559,7 @@ rule_expr_cb(struct nftnl_expr *e, void *data) static int table_cb(const struct nlmsghdr *nlh, void *data) { + int result = MNL_CB_OK; struct nftnl_rule *t; uint32_t len; struct nftnl_expr *expr; @@ -562,130 +574,118 @@ table_cb(const struct nlmsghdr *nlh, void *data) r = malloc(sizeof(rule_t)); - memset(r, 0, sizeof(rule_t)); - t = nftnl_rule_alloc(); - if (t == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); - goto err; + if (r == NULL) { + log_error("out of memory: %m"); + } else { + memset(r, 0, sizeof(rule_t)); + 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); + } + } } - - 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; + return result; } void -reflesh_nft_cache_filter() -{ - - if (rule_list_filter_validate == RULE_CACHE_VALID) { - return; +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); + rule_list_filter_validate = RULE_CACHE_VALID; } - - reflesh_nft_cache(&head_filter, NFT_TABLE_FILTER, miniupnpd_forward_chain, NFPROTO_INET); - - rule_list_filter_validate = RULE_CACHE_VALID; - - return; } void -reflesh_nft_cache_peer() -{ - if (rule_list_peer_validate == RULE_CACHE_VALID) { - return; +refresh_nft_cache_peer(void) { + if (rule_list_peer_validate != RULE_CACHE_VALID) { + refresh_nft_cache(&head_peer, nft_table4, nft_postrouting_chain, NFPROTO_IPV4); + 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 -reflesh_nft_cache_redirect() +refresh_nft_cache_redirect(void) { - if (rule_list_redirect_validate == RULE_CACHE_VALID) { - return; + if (rule_list_redirect_validate != RULE_CACHE_VALID) { + 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 -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; - int ret; - t = NULL; p1 = LIST_FIRST(head); if (p1 != NULL) { - while(p1 != NULL) { + while (p1 != NULL) { p2 = (rule_t *)LIST_NEXT(p1, entry); if (p1->desc != NULL) { free(p1->desc); @@ -701,16 +701,28 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32 } } 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) { nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { - syslog(LOG_ERR, "%s: mnl_socket_open() FAILED: %m", "reflesh_nft_cache()"); + log_error("mnl_socket_open() FAILED: %m"); return; } 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; } } @@ -718,7 +730,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32 t = nftnl_rule_alloc(); if (t == NULL) { - syslog(LOG_ERR, "%s: nftnl_rule_alloc() FAILED", "reflesh_nft_cache()"); + log_error("nftnl_rule_alloc() FAILED"); return; } @@ -731,7 +743,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32 nftnl_rule_free(t); 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; } @@ -744,7 +756,7 @@ reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32 } 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); */ @@ -760,7 +772,7 @@ expr_add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg, e = nftnl_expr_alloc("payload"); 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; } @@ -781,7 +793,7 @@ expr_add_bitwise(struct nftnl_rule *r, uint32_t sreg, uint32_t dreg, e = nftnl_expr_alloc("bitwise"); 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; } @@ -803,7 +815,7 @@ expr_add_cmp(struct nftnl_rule *r, uint32_t sreg, uint32_t op, e = nftnl_expr_alloc("cmp"); 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; } @@ -821,7 +833,7 @@ expr_add_meta(struct nftnl_rule *r, uint32_t meta_key, uint32_t dreg) e = nftnl_expr_alloc("meta"); 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; } @@ -837,7 +849,7 @@ expr_set_reg_val_u32(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val struct nftnl_expr *e; e = nftnl_expr_alloc("immediate"); 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; } 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; e = nftnl_expr_alloc("immediate"); 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; } 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; e = nftnl_expr_alloc("immediate"); 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; } 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"); 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; } @@ -919,12 +931,12 @@ rule_set_snat(uint8_t family, uint8_t proto, r = nftnl_rule_alloc(); if (r == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); + log_error("nftnl_rule_alloc() FAILED"); return NULL; } - nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_postrouting_chain); + nftnl_rule_set(r, NFTNL_RULE_TABLE, family == NFPROTO_IPV6 ? nft_table6 : nft_table4); + nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_postrouting_chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); if (descr != NULL) { @@ -1005,12 +1017,12 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, r = nftnl_rule_alloc(); if (r == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); + log_error("nftnl_rule_alloc() FAILED"); return NULL; } - nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_chain); + nftnl_rule_set(r, NFTNL_RULE_TABLE, family == NFPROTO_IPV6 ? nft_table6 : nft_table4); + nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_prerouting_chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); if (descr != NULL) { @@ -1079,7 +1091,7 @@ rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, r = nftnl_rule_alloc(); if (r == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); + log_error("nftnl_rule_alloc() FAILED"); return NULL; } @@ -1127,7 +1139,7 @@ rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto, r = nftnl_rule_alloc(); if (r == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); + log_error("nftnl_rule_alloc() FAILED"); return NULL; } @@ -1171,8 +1183,8 @@ rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname uint32_t descr_len; UNUSED(eport); - nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_FILTER); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_forward_chain); + nftnl_rule_set(r, NFTNL_RULE_TABLE, nft_table); + nftnl_rule_set(r, NFTNL_RULE_CHAIN, nft_forward_chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); if (descr != NULL) { @@ -1227,7 +1239,7 @@ rule_del_handle(rule_t *rule) r = nftnl_rule_alloc(); if (r == NULL) { - syslog(LOG_ERR, "nftnl_rule_alloc() FAILED"); + log_error("nftnl_rule_alloc() FAILED"); return NULL; } @@ -1257,75 +1269,204 @@ nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq) } 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 mnl_nlmsg_batch *batch; 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) { - nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - syslog(LOG_ERR, "%s: mnl_socket_open() FAILED: %m", "nft_send_request()"); - return -1; - } + batch = start_batch(buf, sizeof(buf)); + if (batch != NULL) + { + switch (chain_type) { + 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) { - syslog(LOG_ERR, "%s: mnl_socket_bind() FAILED: %m", "nft_send_request()"); - return -1; - } - } + nftnl_rule_nlmsg_build_payload(nlh, rule); + nftnl_rule_free(rule); - batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); + result = send_batch(batch); + } - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), - NFNL_MSG_BATCH_BEGIN, seq++); - mnl_nlmsg_batch_next(batch); - - 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, - seq++); - - nftnl_rule_nlmsg_build_payload(nlh, rule); - nftnl_rule_free(rule); - mnl_nlmsg_batch_next(batch); - - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, - seq++); - mnl_nlmsg_batch_next(batch); - - ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), - mnl_nlmsg_batch_size(batch)); - if (ret == -1) { - syslog(LOG_ERR, "%s: mnl_socket_sendto() FAILED: %m", "nft_send_request()"); - return -1; - } - - mnl_nlmsg_batch_stop(batch); - - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - syslog(LOG_ERR, "%s: mnl_socket_recvfrom() FAILED: %m", "nft_send_request()"); - return -1; - } - - ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); - if (ret < 0) { - syslog(LOG_ERR, "%s: mnl_cb_run() FAILED: %m", "nft_send_request()"); - return -1; - } - - /* mnl_socket_close(nl); */ - return 0; + return result; } + +int +table_op( enum nf_tables_msg_types op, uint16_t family, const char * name) +{ + int result; + struct nlmsghdr *nlh; + struct mnl_nlmsg_batch *batch; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + struct nftnl_table *table; + + log_error("(%d, %d, %s)", op, family, name); + + table = nftnl_table_alloc(); + if (table == NULL) { + log_error("out of memory: %m"); + result = -1; + } else { + nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family); + nftnl_table_set_str(table, NFTNL_TABLE_NAME, name); + + batch = start_batch( buf, sizeof(buf)); + if (batch == NULL) { + log_error("out of memory: %m"); + result = -2; + } else { + nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + op, family, + (op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK, + nl_seq++); + nftnl_table_nlmsg_build_payload(nlh, table); + + result = send_batch(batch); + } + nftnl_table_free(table); + } + return result; +} + +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; +} \ No newline at end of file diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.h b/miniupnpd/netfilter_nft/nftnlrdr_misc.h index d24959d..ecd2c2a 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.h +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.h @@ -8,8 +8,13 @@ */ #include -#define NFT_TABLE_NAT "nat" -#define NFT_TABLE_FILTER "filter" +extern const char * nft_table; +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 enum rule_reg_type { @@ -80,7 +85,7 @@ extern struct rule_list head_redirect; extern struct rule_list head_peer; 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 * rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, 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, unsigned short rport, const char *descr, const char *handle); struct nftnl_rule *rule_del_handle(rule_t *r); -void reflesh_nft_cache_filter(void); -void reflesh_nft_cache_redirect(void); -void reflesh_nft_cache_peer(void); -void reflesh_nft_cache(struct rule_list *head, char *table, const char *chain, uint32_t family); +void refresh_nft_cache_filter(void); +void refresh_nft_cache_redirect(void); +void refresh_nft_cache_peer(void); +void refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family); 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); diff --git a/miniupnpd/upnpglobalvars.c b/miniupnpd/upnpglobalvars.c index c970c06..ca63b52 100644 --- a/miniupnpd/upnpglobalvars.c +++ b/miniupnpd/upnpglobalvars.c @@ -109,7 +109,7 @@ const char * queue = 0; const char * tag = 0; #endif -#ifdef USE_NETFILTER +#ifdef USE_IPTABLES /* chain names to use in the nat and filter tables. */ /* iptables -t nat -N MINIUPNPD diff --git a/miniupnpd/upnpglobalvars.h b/miniupnpd/upnpglobalvars.h index ec34e0e..1b08fe7 100644 --- a/miniupnpd/upnpglobalvars.h +++ b/miniupnpd/upnpglobalvars.h @@ -142,7 +142,7 @@ extern const char * queue; extern const char * tag; #endif -#ifdef USE_NETFILTER +#ifdef USE_IPTABLES extern const char * miniupnpd_nat_chain; extern const char * miniupnpd_nat_postrouting_chain; extern const char * miniupnpd_forward_chain;