diff --git a/miniupnpd/Makefile.linux_nft b/miniupnpd/Makefile.linux_nft index 7e302ce..f490318 100644 --- a/miniupnpd/Makefile.linux_nft +++ b/miniupnpd/Makefile.linux_nft @@ -46,7 +46,8 @@ BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnppinhole.o pcplearndscp.o asyncsendto.o LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o -NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/nfct_get.o netfilter_nft/nftnlrdr_misc.o +NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/nftpinhole.o \ + netfilter_nft/nfct_get.o netfilter_nft/nftnlrdr_misc.o ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) @@ -210,7 +211,7 @@ upnputils.o: miniupnpdtypes.h getroute.h getconnstatus.o: getconnstatus.h getifaddr.h upnppinhole.o: macros.h config.h upnpredirect.h upnpglobalvars.h upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.h -#upnppinhole.o: netfilter/iptpinhole.h +upnppinhole.o: netfilter_nft/nftpinhole.h pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h pcplearndscp.o: pcplearndscp.h asyncsendto.o: asyncsendto.h @@ -222,8 +223,8 @@ 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: miniupnpdtypes.h -netfilter_nft/iptpinhole.o: config.h netfilter_nft/iptpinhole.h upnpglobalvars.h -netfilter_nft/iptpinhole.o: upnppermissions.h config.h miniupnpdtypes.h +netfilter_nft/nftpinhole.o: config.h netfilter_nft/nftpinhole.h upnpglobalvars.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 upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h diff --git a/miniupnpd/netfilter_nft/Makefile b/miniupnpd/netfilter_nft/Makefile index 19846cf..e856269 100644 --- a/miniupnpd/netfilter_nft/Makefile +++ b/miniupnpd/netfilter_nft/Makefile @@ -5,15 +5,15 @@ LIBS = -lnftnl -lmnl ARCH := $(shell uname -m | grep -q "x86_64" && echo 64) -all: test_nfct_get testnftnlrdr +all: test_nfct_get testnftnlrdr testnftpinhole clean: - $(RM) *.o testnftnlcrdr testnftnlpinhole testnftnlrdr_peer \ + $(RM) *.o testnftnlcrdr testnftpinhole testnftnlrdr_peer \ test_nfct_get testnftnlrdr testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o upnpglobalvars.o $(LIBS) -testiptpinhole: testiptpinhole.o iptpinhole.o upnpglobalvars.o $(LIBS) +testnftpinhole: nftpinhole.o nftnlrdr_misc.o testnftpinhole.o upnpglobalvars.o $(LIBS) test_nfct_get: test_nfct_get.o test_nfct_get.o -lmnl -lnetfilter_conntrack @@ -27,7 +27,7 @@ nftnlrdr.o: nftnlrdr.c nftnlrdr.h nftnlrdr_misc.o: nftnlrdr_misc.c -iptpinhole.o: iptpinhole.c iptpinhole.h +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 e548750..93c0d88 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr.c +++ b/miniupnpd/netfilter_nft/nftnlrdr.c @@ -131,10 +131,12 @@ add_redirect_rule2(const char * ifname, d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n", ifname, rhost, eport, iaddr, iport, proto, desc)); + r = rule_set_dnat(NFPROTO_IPV4, ifname, proto, - 0, eport, - inet_addr(iaddr), iport, desc, NULL); - return nft_send_request(r, NFT_MSG_NEWRULE); + 0, eport, + inet_addr(iaddr), iport, desc, NULL); + + return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_REDIRECT); } /* @@ -154,12 +156,13 @@ add_peer_redirect_rule2(const char * ifname, UNUSED(ifname); UNUSED(timestamp); d_printf(("add peer redirect rule2()!\n")); - r = rule_set_snat(NFPROTO_IPV4, proto, - inet_addr(rhost), rport, - inet_addr(eaddr), eport, - inet_addr(iaddr), iport, desc, NULL); - return nft_send_request(r, NFT_MSG_NEWRULE); + r = rule_set_snat(NFPROTO_IPV4, proto, + inet_addr(rhost), rport, + inet_addr(eaddr), eport, + inet_addr(iaddr), iport, desc, NULL); + + return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_PEER); } /* @@ -179,13 +182,16 @@ add_filter_rule2(const char * ifname, d_printf(("add_filter_rule2(%s, %s, %s, %d, %d, %d, %s)\n", ifname, rhost, iaddr, eport, iport, proto, desc)); + if (rhost != NULL && strcmp(rhost, "") != 0) { rhost_addr = inet_addr(rhost); } r = rule_set_filter(NFPROTO_IPV4, ifname, proto, - rhost_addr, inet_addr(iaddr), eport, iport, - desc, 0); - return nft_send_request(r, NFT_MSG_NEWRULE); + rhost_addr, inet_addr(iaddr), + eport, iport, 0, + desc, 0); + + return nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); } /* @@ -213,12 +219,11 @@ delete_filter_rule(const char * ifname, unsigned short port, int proto) struct nftnl_rule *r; UNUSED(ifname); - reflesh_nft_cache(NFPROTO_IPV4); - LIST_FOREACH(p, &head, entry) { + reflesh_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); - /* Todo: send bulk request */ - nft_send_request(r, NFT_MSG_DELRULE); + nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); break; } } @@ -236,37 +241,71 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) struct nftnl_rule *r = NULL; in_addr_t iaddr = 0; uint16_t iport = 0; - extern void print_rule(rule_t *r) ; + extern void print_rule(rule_t *r); d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto)); - reflesh_nft_cache(NFPROTO_IPV4); - LIST_FOREACH(p, &head, entry) { + reflesh_nft_cache_redirect(); + + // Delete Redirect Rule + LIST_FOREACH(p, &head_redirect, entry) { if (p->eport == eport && p->proto == proto && - (p->type == RULE_NAT || p->type == RULE_SNAT)) { + (p->type == RULE_NAT && p->nat_type == NFT_NAT_DNAT)) { iaddr = p->iaddr; iport = p->iport; r = rule_del_handle(p); /* Todo: send bulk request */ - nft_send_request(r, NFT_MSG_DELRULE); + nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT); break; } } - if (iaddr == 0 && iport == 0) { - return -1; + if (iaddr != 0 && iport != 0) { + reflesh_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); + break; + } + } } - reflesh_nft_cache(NFPROTO_IPV4); - LIST_FOREACH(p, &head, entry) { - if (p->eport == iport && - p->iaddr == iaddr && p->type == RULE_FILTER) { + + iaddr = 0; + iport = 0; + + reflesh_nft_cache_peer(); + // Delete Peer Rule + LIST_FOREACH(p, &head_peer, entry) { + if (p->eport == eport && p->proto == proto && + (p->type == RULE_NAT && p->nat_type == NFT_NAT_SNAT)) { + iaddr = p->iaddr; + iport = p->iport; + r = rule_del_handle(p); /* Todo: send bulk request */ - nft_send_request(r, NFT_MSG_DELRULE); + nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER); break; } } + if (iaddr != 0 && iport != 0) { + reflesh_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); + break; + } + } + } + return 0; } @@ -283,56 +322,66 @@ get_peer_rule_by_index(int index, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - int i; struct in_addr addr; char *addr_str; rule_t *r; - UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + UNUSED(timestamp); d_printf(("get_peer_rule_by_index()\n")); - reflesh_nft_cache(NFPROTO_IPV4); - if (peer_cache == NULL) { - return -1; - } + reflesh_nft_cache_peer(); - for (i = 0; peer_cache[i] != NULL; i++) { - if (index == i) { - r = peer_cache[i]; + LIST_FOREACH(r, &head_peer, entry) { + if (r->index == index) { if (ifname != NULL) { if_indextoname(r->ingress_ifidx, ifname); } + if (eport != NULL) { *eport = r->eport; } + if (iaddr != NULL) { addr.s_addr = r->iaddr; addr_str = inet_ntoa(addr); strncpy(iaddr , addr_str, iaddrlen); } + if (iport != NULL) { *iport = r->iport; } + if (proto != NULL) { *proto = r->proto; } + if (rhost != NULL) { addr.s_addr = r->rhost; addr_str = inet_ntoa(addr); strncpy(iaddr , addr_str, rhostlen); } + if (rport != NULL) { *rport = r->rport; } + if (desc != NULL) { strncpy(desc, r->desc, desclen); } + if (packets || bytes) { + if (packets) + *packets = r->packets; + if (bytes) + *bytes = r->bytes; + } + /* * TODO: Implement counter in case of add {nat,filter} */ return 0; } } + return -1; } @@ -369,43 +418,44 @@ get_redirect_rule_by_index(int index, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - int i; struct in_addr addr; char *addr_str; rule_t *r; - UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + UNUSED(timestamp); - d_printf(("get_redirect_rule_by_index()\n")); - reflesh_nft_cache(NFPROTO_IPV4); - if (redirect_cache == NULL) { - return -1; - } + d_printf(("get_redirect_rule_by_index()\n")); + reflesh_nft_cache_redirect(); - for (i = 0; redirect_cache[i] != NULL; i++) { - if (index == i) { - r = redirect_cache[i]; + LIST_FOREACH(r, &head_redirect, entry) { + if (r->index == index) { if (ifname != NULL) { if_indextoname(r->ingress_ifidx, ifname); } + if (eport != NULL) { *eport = r->eport; } + if (iaddr != NULL) { addr.s_addr = r->iaddr; addr_str = inet_ntoa(addr); strncpy(iaddr , addr_str, iaddrlen); } + if (iport != NULL) { *iport = r->iport; } + if (proto != NULL) { *proto = r->proto; } + if (rhost != NULL) { addr.s_addr = r->rhost; addr_str = inet_ntoa(addr); strncpy(iaddr , addr_str, rhostlen); } + if (desc != NULL && r->desc) { strncpy(desc, r->desc, desclen); } @@ -414,12 +464,20 @@ get_redirect_rule_by_index(int index, *timestamp = get_timestamp(*eport, *proto); } + if (packets || bytes) { + if (packets) + *packets = r->packets; + if (bytes) + *bytes = r->bytes; + } + /* * TODO: Implement counter in case of add {nat,filter} */ return 0; } } + return -1; } @@ -438,30 +496,32 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, { rule_t *p; struct in_addr addr; - char *addr_str; UNUSED(nat_chain_name); UNUSED(ifname); UNUSED(iaddrlen); UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + UNUSED(rhost); + UNUSED(rhostlen); - d_printf(("get_nat_redirect_rule()\n")); - reflesh_nft_cache(NFPROTO_IPV4); + reflesh_nft_cache_redirect(); - LIST_FOREACH(p, &head, entry) { + LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && p->eport == eport) { - if (p->rhost && rhost) { - addr.s_addr = p->rhost; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, rhostlen); + if (p->iaddr) { + addr.s_addr = p->iaddr; + inet_ntop(AF_INET, &addr, iaddr, INET_ADDRSTRLEN); } + if (desc != NULL && p->desc) { strncpy(desc, p->desc, desclen); } - *iport = p->iport; + + if (iport) + *iport = p->iport; if(timestamp != NULL) *timestamp = get_timestamp(eport, proto); @@ -486,7 +546,8 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, unsigned short *array; unsigned short *tmp; - d_printf(("get_portmappings_in_range()\n")); + d_printf(("get_portmappings_in_range()\n")); + *number = 0; capacity = 128; array = calloc(capacity, sizeof(unsigned short)); @@ -496,7 +557,9 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, return NULL; } - LIST_FOREACH(p, &head, entry) { + reflesh_nft_cache_redirect(); + + LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && startport <= p->eport && p->eport <= endport) { @@ -539,24 +602,24 @@ update_portmapping(const char * ifname, unsigned short eport, int proto, unsigned short iport, const char * desc, unsigned int timestamp) { - char iaddr[4]; - char iaddr_str[16]; - char rhost[32]; + char iaddr_str[INET_ADDRSTRLEN]; + char rhost[INET_ADDRSTRLEN]; int r; - if (get_redirect_rule(NULL, eport, proto, iaddr, 0, NULL, NULL, 0, rhost, 0, NULL, 0, 0) < 0) + d_printf(("update_portmapping()\n")); + + if (get_redirect_rule(NULL, eport, proto, iaddr_str, INET_ADDRSTRLEN, NULL, NULL, 0, rhost, INET_ADDRSTRLEN, NULL, 0, 0) < 0) return -1; r = delete_redirect_and_filter_rules(eport, proto); if (r < 0) return -1; - inet_ntop(AF_INET, &iaddr, iaddr_str, sizeof(iaddr_str)); - - if(add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto, + if (add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto, desc, timestamp) < 0) return -1; - if(add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0) + + if (add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0) return -1; return 0; @@ -570,13 +633,21 @@ list_redirect_rule(const char * ifname) rule_t *p; UNUSED(ifname); - reflesh_nft_cache(NFPROTO_IPV4); - - LIST_FOREACH(p, &head, entry) { + reflesh_nft_cache_filter(); + LIST_FOREACH(p, &head_filter, entry) { + print_rule(p); + } + + reflesh_nft_cache_redirect(); + LIST_FOREACH(p, &head_redirect, entry) { + print_rule(p); + } + + reflesh_nft_cache_peer(); + LIST_FOREACH(p, &head_peer, entry) { print_rule(p); } - return -1; return 0; } diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.c b/miniupnpd/netfilter_nft/nftnlrdr_misc.c index f709904..a138a42 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.c +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.c @@ -2,7 +2,7 @@ * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2015 Tomofumi Hayashi - * + * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution. */ @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -45,28 +46,30 @@ #define RULE_CACHE_INVALID 0 #define RULE_CACHE_VALID 1 -const char * miniupnpd_nft_nat_chain = "miniupnpd"; -const char * miniupnpd_nft_peer_chain = "miniupnpd-pcp-peer"; -const char * miniupnpd_nft_forward_chain = "miniupnpd"; - static struct mnl_socket *nl = NULL; -struct rule_list head = LIST_HEAD_INITIALIZER(head); -static uint32_t rule_list_validate = RULE_CACHE_INVALID; - -uint32_t rule_list_length = 0; -uint32_t rule_list_peer_length = 0; - -rule_t **redirect_cache; -rule_t **peer_cache; +// FILTER +struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter); +// DNAT +struct rule_list head_redirect = LIST_HEAD_INITIALIZER(head_redirect); +// SNAT +struct rule_list head_peer = LIST_HEAD_INITIALIZER(head_peer); +static uint32_t rule_list_filter_validate = RULE_CACHE_INVALID; +static uint32_t rule_list_redirect_validate = RULE_CACHE_INVALID; +static uint32_t rule_list_peer_validate = RULE_CACHE_INVALID; static const char * get_family_string(uint32_t family) { switch (family) { + case NFPROTO_INET: + return "ipv4/6"; case NFPROTO_IPV4: return "ipv4"; + case NFPROTO_IPV6: + return "ipv6"; } + return "unknown family"; } @@ -79,6 +82,7 @@ get_proto_string(uint32_t proto) case IPPROTO_UDP: return "udp"; } + return "unknown proto"; } @@ -95,11 +99,13 @@ get_verdict_string(uint32_t val) } } -void -print_rule(rule_t *r) +void +print_rule(rule_t *r) { struct in_addr addr; char *iaddr_str = NULL, *rhost_str = NULL, *eaddr_str = NULL; + char iaddr6_str[INET6_ADDRSTRLEN]; + char rhost6_str[INET6_ADDRSTRLEN]; char ifname_buf[IF_NAMESIZE]; switch (r->type) { @@ -120,10 +126,10 @@ print_rule(rule_t *r) printf("%"PRIu64":[%s/%s] iif %s, %s/%s, %d -> " "%s:%d (%s)\n", r->handle, - r->table, r->chain, + r->table, r->chain, if_indextoname(r->ingress_ifidx, ifname_buf), get_family_string(r->family), - get_proto_string(r->proto), r->eport, + get_proto_string(r->proto), r->eport, iaddr_str, r->iport, r->desc); } else if (r->nat_type == NFT_NAT_SNAT) { @@ -135,7 +141,7 @@ print_rule(rule_t *r) r->handle, r->table, r->chain, r->nat_type, r->family, r->ingress_ifidx, eaddr_str, r->eport, - r->proto, iaddr_str, r->iport, + r->proto, iaddr_str, r->iport, rhost_str, r->rport, r->desc); } else { @@ -159,13 +165,26 @@ print_rule(rule_t *r) addr.s_addr = r->rhost; rhost_str = strdupa(inet_ntoa(addr)); } - printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n", - r->handle, r->table, r->chain, - get_family_string(r->family), get_proto_string(r->proto), - rhost_str, - iaddr_str, r->eport, - get_verdict_string(r->filter_action), - r->desc); + inet_ntop(AF_INET6, &r->iaddr6, iaddr6_str, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &r->rhost6, rhost6_str, INET6_ADDRSTRLEN); + + if ( (r->iaddr != 0) || (r->rhost != 0) ) { + printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n", + r->handle, r->table, r->chain, + get_family_string(r->family), get_proto_string(r->proto), + rhost_str, + iaddr_str, r->eport, + get_verdict_string(r->filter_action), + r->desc); + } else { + printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n", + r->handle, r->table, r->chain, + get_family_string(r->family), get_proto_string(r->proto), + rhost6_str, + iaddr6_str, r->eport, + get_verdict_string(r->filter_action), + r->desc); + } break; case RULE_COUNTER: if (r->iaddr != 0) { @@ -178,7 +197,7 @@ print_rule(rule_t *r) } printf("%"PRIu64":[%s/%s] %s/%s, %s:%d: " "packets:%"PRIu64", bytes:%"PRIu64"\n", - r->handle, r->table, r->chain, + r->handle, r->table, r->chain, get_family_string(r->family), get_proto_string(r->proto), iaddr_str, r->eport, r->packets, r->bytes); break; @@ -188,7 +207,7 @@ print_rule(rule_t *r) } static enum rule_reg_type * -get_reg_type_ptr(rule_t *r, uint32_t dreg) +get_reg_type_ptr(rule_t *r, uint32_t dreg) { switch (dreg) { case NFT_REG_1: @@ -201,7 +220,7 @@ get_reg_type_ptr(rule_t *r, uint32_t dreg) } static uint32_t * -get_reg_val_ptr(rule_t *r, uint32_t dreg) +get_reg_val_ptr(rule_t *r, uint32_t dreg) { switch (dreg) { case NFT_REG_1: @@ -314,7 +333,7 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r) r->iport = proto_min_val; } else if (r->nat_type == NFT_NAT_SNAT) { r->eaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg); - if (proto_min_reg == NFT_REG_1) { + if (proto_min_reg == NFT_REG_1) { r->eport = proto_min_val; } } @@ -328,7 +347,7 @@ static inline void parse_rule_payload(struct nftnl_expr *e, rule_t *r) { uint32_t base, dreg, offset, len; - uint32_t *regptr; + uint32_t *regptr; dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); @@ -354,6 +373,22 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r) 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; } case NFT_PAYLOAD_TRANSPORT_HEADER: if (offset == offsetof(struct tcphdr, dest) && @@ -366,7 +401,7 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r) return; } } - syslog(LOG_DEBUG, + syslog(LOG_DEBUG, "Unsupport payload: (dreg:%d, base:%d, offset:%d, len:%d)", dreg, base, offset, len); return; @@ -383,6 +418,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { uint32_t op, sreg; uint16_t *ports; in_addr_t *addrp; + struct in6_addr *addrp6; data_val = (void *)nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &data_len); sreg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); @@ -406,6 +442,12 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { r->reg1_type = RULE_REG_NONE; return; } + case RULE_REG_IP6_SRC_ADDR: + if (data_len == sizeof(struct in6_addr) && op == NFT_CMP_EQ) { + r->rhost6 = *(struct in6_addr *)data_val; + r->reg1_type = RULE_REG_NONE; + return; + } case RULE_REG_IP_DEST_ADDR: if (data_len == sizeof(in_addr_t) && op == NFT_CMP_EQ) { if (r->type == RULE_FILTER) { @@ -416,15 +458,34 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { r->reg1_type = RULE_REG_NONE; return; } + case RULE_REG_IP6_DEST_ADDR: + if (data_len == sizeof(struct in6_addr) && op == NFT_CMP_EQ) { + if (r->type == RULE_FILTER) { + r->iaddr6 = *(struct in6_addr *)data_val; + } else { + r->rhost6 = *(struct in6_addr *)data_val; + } + r->reg1_type = RULE_REG_NONE; + return; + } case RULE_REG_IP_SD_ADDR: - if (data_len == sizeof(in_addr_t) * 2 && op == NFT_CMP_EQ) { + if (data_len == sizeof(in_addr_t) * 2 && op == NFT_CMP_EQ) { addrp = (in_addr_t *)data_val; r->iaddr = addrp[0]; r->rhost = addrp[1]; r->reg1_type = RULE_REG_NONE; return; } + case RULE_REG_IP6_SD_ADDR: + if (data_len == sizeof(struct in6_addr) * 2 && op == NFT_CMP_EQ) { + addrp6 = (struct in6_addr *)data_val; + r->iaddr6 = addrp6[0]; + r->rhost6 = addrp6[1]; + r->reg1_type = RULE_REG_NONE; + return; + } case RULE_REG_IP_PROTO: + case RULE_REG_IP6_PROTO: if (data_len == sizeof(uint8_t) && op == NFT_CMP_EQ) { r->proto = *(uint8_t *)data_val; r->reg1_type = RULE_REG_NONE; @@ -439,7 +500,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { case RULE_REG_TCP_SD_PORT: if (data_len == sizeof(uint16_t) * 2 && op == NFT_CMP_EQ) { ports = (uint16_t *)data_val; - r->iport = ntohs(ports[0]); + r->eport = ntohs(ports[0]); r->rport = ntohs(ports[1]); r->reg1_type = RULE_REG_NONE; return; @@ -447,17 +508,18 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) { default: break; } + syslog(LOG_DEBUG, "Unknown cmp (r1type:%d, data_len:%d, op:%d)", r->reg1_type, data_len, op); + return; } static int -rule_expr_cb(struct nftnl_expr *e, void *data) +rule_expr_cb(struct nftnl_expr *e, void *data) { rule_t *r = data; - const char *attr_name = nftnl_expr_get_str(e, - NFTNL_EXPR_NAME); + const char *attr_name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME); if (strncmp("cmp", attr_name, sizeof("cmp")) == 0) { parse_rule_cmp(e, r); @@ -472,8 +534,9 @@ 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_ERR, "unknown attr: %s\n", attr_name); - } + syslog(LOG_DEBUG, "unknown attr: %s\n", attr_name); + } + return MNL_CB_OK; } @@ -487,9 +550,13 @@ table_cb(const struct nlmsghdr *nlh, void *data) struct nftnl_expr_iter *itr; rule_t *r; char *chain; + char *descr; + int index_filter, index_peer, index_redirect; UNUSED(data); - r = malloc(sizeof(rule_t)); + index_filter = index_peer = index_redirect = 0; + + r = malloc(sizeof(rule_t)); memset(r, 0, sizeof(rule_t)); t = nftnl_rule_alloc(); @@ -504,9 +571,9 @@ table_cb(const struct nlmsghdr *nlh, void *data) } chain = (char *)nftnl_rule_get_data(t, NFTNL_RULE_CHAIN, &len); - if (strcmp(chain, miniupnpd_nft_nat_chain) != 0 && - strcmp(chain, miniupnpd_nft_peer_chain) != 0 && - strcmp(chain, miniupnpd_nft_forward_chain) != 0) { + if (strcmp(chain, miniupnpd_nat_chain) != 0 && + strcmp(chain, miniupnpd_nat_postrouting_chain) != 0 && + strcmp(chain, miniupnpd_forward_chain) != 0) { goto rule_skip; } @@ -515,8 +582,11 @@ table_cb(const struct nlmsghdr *nlh, void *data) r->chain = strdup(chain); r->family = *(uint32_t*)nftnl_rule_get_data(t, NFTNL_RULE_FAMILY, &len); - r->desc = (char *)nftnl_rule_get_data(t, NFTNL_RULE_USERDATA, - &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); @@ -524,9 +594,6 @@ table_cb(const struct nlmsghdr *nlh, void *data) r->type = RULE_NAT; } else if (strcmp(r->table, NFT_TABLE_FILTER) == 0) { r->type = RULE_FILTER; - } - if (strcmp(r->chain, miniupnpd_nft_peer_chain) == 0) { - rule_list_peer_length++; } itr = nftnl_expr_iter_create(t); @@ -537,9 +604,18 @@ table_cb(const struct nlmsghdr *nlh, void *data) if (r->type == RULE_NONE) { free(r); + } else if (strcmp(r->chain, miniupnpd_nat_postrouting_chain) == 0) { + r->index = index_peer; + LIST_INSERT_HEAD(&head_peer, r, entry); + index_peer++; + } else if (strcmp(r->chain, miniupnpd_nat_chain) == 0) { + r->index = index_redirect; + LIST_INSERT_HEAD(&head_redirect, r, entry); + index_redirect++; } else { - LIST_INSERT_HEAD(&head, r, entry); - rule_list_length++; + r->index = index_filter; + LIST_INSERT_HEAD(&head_filter, r, entry); + index_filter++; } rule_skip: @@ -550,66 +626,50 @@ err: } void -reflesh_nft_redirect_cache(void) +reflesh_nft_cache_filter() { - rule_t *p; - int i; - uint32_t len; - if (redirect_cache != NULL) { - free(redirect_cache); - } - len = rule_list_length - rule_list_peer_length; - if (len == 0) { - redirect_cache = NULL; + if (rule_list_filter_validate == RULE_CACHE_VALID) { return; - } - - redirect_cache = (rule_t **)malloc(sizeof(rule_t *) * len); - bzero(redirect_cache, sizeof(rule_t *) * len); - - i = 0; - LIST_FOREACH(p, &head, entry) { - if (strcmp(p->chain, miniupnpd_nft_nat_chain) == 0 && - (p->type == RULE_NAT || p->type == RULE_SNAT)) { - redirect_cache[i] = p; - i++; - } } + reflesh_nft_cache(&head_filter, NFT_TABLE_FILTER, miniupnpd_forward_chain, NFPROTO_INET); + + rule_list_filter_validate = RULE_CACHE_VALID; + return; } void -reflesh_nft_peer_cache(void) +reflesh_nft_cache_peer() { - rule_t *p; - int i; - - if (peer_cache != NULL) { - free(peer_cache); - } - if (rule_list_peer_length == 0) { - peer_cache = NULL; + if (rule_list_peer_validate == RULE_CACHE_VALID) { return; } - peer_cache = (rule_t **)malloc( - sizeof(rule_t *) * rule_list_peer_length); - bzero(peer_cache, sizeof(rule_t *) * rule_list_peer_length); - i = 0; - LIST_FOREACH(p, &head, entry) { - if (strcmp(p->chain, miniupnpd_nft_peer_chain) == 0) { - peer_cache[i] = p; - i++; - } - } + 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(uint32_t family) +reflesh_nft_cache_redirect() +{ + if (rule_list_redirect_validate == RULE_CACHE_VALID) { + return; + } + + 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) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; @@ -618,12 +678,8 @@ reflesh_nft_cache(uint32_t family) rule_t *p1, *p2; int ret; - if (rule_list_validate == RULE_CACHE_VALID) { - return; - } - t = NULL; - p1 = LIST_FIRST(&head); + p1 = LIST_FIRST(head); if (p1 != NULL) { while(p1 != NULL) { p2 = (rule_t *)LIST_NEXT(p1, entry); @@ -640,19 +696,7 @@ reflesh_nft_cache(uint32_t family) p1 = p2; } } - LIST_INIT(&head); - - t = nftnl_rule_alloc(); - if (t == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); - } - - seq = time(NULL); - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, - NLM_F_DUMP, seq); - nftnl_rule_nlmsg_build_payload(nlh, t); - nftnl_rule_free(t); + LIST_INIT(head); if (nl == NULL) { nl = mnl_socket_open(NETLINK_NETFILTER); @@ -668,13 +712,25 @@ reflesh_nft_cache(uint32_t family) } portid = mnl_socket_get_portid(nl); + t = nftnl_rule_alloc(); + if (t == NULL) { + perror("OOM"); + exit(EXIT_FAILURE); + } + + seq = time(NULL); + nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, + NLM_F_DUMP, seq); + nftnl_rule_set(t, NFTNL_RULE_TABLE, table); + nftnl_rule_set(t, NFTNL_RULE_CHAIN, chain); + nftnl_rule_nlmsg_build_payload(nlh, t); + nftnl_rule_free(t); + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { perror("mnl_socket_send"); exit(EXIT_FAILURE); } - rule_list_peer_length = 0; - rule_list_length = 0; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); while (ret > 0) { ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type); @@ -682,21 +738,20 @@ reflesh_nft_cache(uint32_t family) break; ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } + if (ret == -1) { perror("error"); exit(EXIT_FAILURE); } + /* mnl_socket_close(nl); */ - reflesh_nft_peer_cache(); - reflesh_nft_redirect_cache(); - rule_list_validate = RULE_CACHE_VALID; return; } static void expr_add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg, - uint32_t offset, uint32_t len) + uint32_t offset, uint32_t len) { struct nftnl_expr *e; @@ -802,7 +857,7 @@ expr_set_reg_val_u16(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val } static void -expr_set_reg_verdict(struct nftnl_rule *r, uint32_t val) +expr_set_reg_verdict(struct nftnl_rule *r, uint32_t val) { struct nftnl_expr *e; e = nftnl_expr_alloc("immediate"); @@ -831,20 +886,18 @@ expr_add_nat(struct nftnl_rule *r, uint32_t t, uint32_t family, nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_TYPE, t); nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_FAMILY, family); + /* To IP Address */ expr_set_reg_val_u32(r, NFT_REG_1, (uint32_t)addr_min); nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MAX, NFT_REG_1); + /* To Port */ expr_set_reg_val_u16(r, NFT_REG_2, proto_min); - nftnl_expr_set_u16(e, NFTNL_EXPR_NAT_REG_PROTO_MIN, NFT_REG_2); - nftnl_expr_set_u16(e, NFTNL_EXPR_NAT_REG_PROTO_MAX, NFT_REG_2); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MIN, NFT_REG_2); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MAX, NFT_REG_2); nftnl_rule_add_expr(r, e); } - -/* - * Todo: add expr for rhost - */ struct nftnl_rule * rule_set_snat(uint8_t family, uint8_t proto, in_addr_t rhost, unsigned short rport, @@ -854,10 +907,11 @@ rule_set_snat(uint8_t family, uint8_t proto, const char *handle) { struct nftnl_rule *r = NULL; - uint32_t destport; - in_addr_t addr[2]; - uint16_t port[2]; + uint16_t dport, sport; uint32_t descr_len; + #ifdef DEBUG + char buf[8192]; + #endif UNUSED(handle); r = nftnl_rule_alloc(); @@ -867,46 +921,67 @@ rule_set_snat(uint8_t family, uint8_t proto, } nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nft_peer_chain); - if (descr != NULL) { - descr_len = strlen(descr); - nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, - descr, descr_len); - } + nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_postrouting_chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); - addr[0] = ihost; - addr[1] = rhost; - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, saddr), sizeof(uint32_t)*2); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, addr, sizeof(uint32_t)*2); + if (descr != NULL) { + descr_len = strlen(descr); + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + descr, descr_len); + } + /* Destination IP */ expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); + offsetof(struct iphdr, daddr), sizeof(uint32_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &ihost, sizeof(uint32_t)); + + /* Source IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, sizeof(in_addr_t)); + + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, protocol), sizeof(uint8_t)); expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); - port[0] = htons(iport); - port[1] = htons(rport); + /* Source and Destination Port of Protocol */ if (proto == IPPROTO_TCP) { + /* Destination Port */ + dport = htons(iport); expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, source), - sizeof(uint32_t)); - } else if (proto == IPPROTO_UDP) { - expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct udphdr, source), - sizeof(uint32_t)); - } - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, port, sizeof(uint32_t)); + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); - destport = htons(eport); - expr_add_nat(r, NFT_NAT_SNAT, AF_INET, ehost, destport, 0); + /* Source Port */ + sport = htons(rport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, source), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + /* Destination Port */ + dport = htons(iport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + + /* Source Port */ + sport = htons(rport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, source), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); + } + + expr_add_nat(r, NFT_NAT_SNAT, family, ehost, htons(eport), 0); + + #ifdef DEBUG + nftnl_rule_snprintf(buf, sizeof(buf), r, NFTNL_OUTPUT_DEFAULT, 0); + fprintf(stdout, "%s\n", buf); + #endif return r; } -/* - * Todo: add expr for rhost - */ struct nftnl_rule * rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, in_addr_t rhost, unsigned short eport, @@ -919,9 +994,11 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, uint64_t handle_num; uint32_t if_idx; uint32_t descr_len; + #ifdef DEBUG + char buf[8192]; + #endif UNUSED(handle); - UNUSED(rhost); r = nftnl_rule_alloc(); if (r == NULL) { @@ -930,75 +1007,12 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, } nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_NAT); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nft_nat_chain); + nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); + if (descr != NULL) { descr_len = strlen(descr); - nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, - descr, descr_len); - } - - if (handle != NULL) { - handle_num = atoll(handle); - nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num); - } - - if (ifname != NULL) { - if_idx = (uint32_t)if_nametoindex(ifname); - expr_add_meta(r, NFT_META_IIF, NFT_REG_1); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &if_idx, - sizeof(uint32_t)); - } - - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); - - if (proto == IPPROTO_TCP) { - dport = htons(eport); - expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, dest), - sizeof(uint16_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, - sizeof(uint16_t)); - } else if (proto == IPPROTO_UDP) { - dport = htons(eport); - expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct udphdr, dest), - sizeof(uint16_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, - sizeof(uint16_t)); - } - - expr_add_nat(r, NFT_NAT_DNAT, AF_INET, ihost, htons(iport), 0); - - return r; -} - -struct nftnl_rule * -rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, - in_addr_t rhost, in_addr_t iaddr, unsigned short eport, - unsigned short iport, const char *descr, const char *handle) -{ - struct nftnl_rule *r = NULL; - uint16_t dport; - uint64_t handle_num; - uint32_t if_idx; - uint32_t descr_len; - UNUSED(eport); - - r = nftnl_rule_alloc(); - if (r == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); - } - - nftnl_rule_set(r, NFTNL_RULE_TABLE, NFT_TABLE_FILTER); - nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nft_forward_chain); - nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); - if (descr != NULL) { - descr_len = strlen(descr); - nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, descr, descr_len); } @@ -1014,29 +1028,192 @@ rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, sizeof(uint32_t)); } - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, daddr), sizeof(uint32_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &iaddr, sizeof(uint32_t)); - - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); - - dport = htons(iport); - expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, dest), sizeof(uint16_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); - + /* Source IP */ if (rhost != 0) { expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, saddr), - sizeof(in_addr_t)); + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, sizeof(in_addr_t)); + } + + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, protocol), sizeof(uint8_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); + + if (proto == IPPROTO_TCP) { + dport = htons(eport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + dport = htons(eport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + } + + expr_add_nat(r, NFT_NAT_DNAT, family, ihost, htons(iport), 0); + + #ifdef DEBUG + nftnl_rule_snprintf(buf, sizeof(buf), r, NFTNL_OUTPUT_DEFAULT, 0); + fprintf(stdout, "%s\n", buf); + #endif + + return r; +} + +struct nftnl_rule * +rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, + in_addr_t rhost, in_addr_t iaddr, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle) +{ + struct nftnl_rule *r = NULL; + #ifdef DEBUG + char buf[8192]; + #endif + UNUSED(eport); + + r = nftnl_rule_alloc(); + if (r == NULL) { + perror("OOM"); + exit(EXIT_FAILURE); + } + + r = rule_set_filter_common(r, family, ifname, proto, eport, iport, rport, descr, handle); + + /* Destination IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, daddr), sizeof(uint32_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &iaddr, sizeof(uint32_t)); + + /* Source IP */ + if (rhost != 0) { + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, sizeof(in_addr_t)); } + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, protocol), sizeof(uint8_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); + expr_set_reg_verdict(r, NF_ACCEPT); + #ifdef DEBUG + nftnl_rule_snprintf(buf, sizeof(buf), r, NFTNL_OUTPUT_DEFAULT, 0); + fprintf(stdout, "%s\n", buf); + #endif + + return r; +} + +struct nftnl_rule * +rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto, + struct in6_addr *rhost6, struct in6_addr *iaddr6, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle) +{ + struct nftnl_rule *r = NULL; + #ifdef DEBUG + char buf[8192]; + #endif + UNUSED(eport); + + r = nftnl_rule_alloc(); + if (r == NULL) { + perror("OOM"); + exit(EXIT_FAILURE); + } + + r = rule_set_filter_common(r, family, ifname, proto, eport, iport, rport, descr, handle); + + /* Destination IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, daddr), sizeof(struct in6_addr)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, iaddr6, sizeof(struct in6_addr)); + + /* Source IP */ + if (rhost6) { + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, saddr), sizeof(struct in6_addr)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, rhost6, sizeof(struct in6_addr)); + } + + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, nexthdr), sizeof(uint8_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); + + expr_set_reg_verdict(r, NF_ACCEPT); + + #ifdef DEBUG + nftnl_rule_snprintf(buf, sizeof(buf), r, NFTNL_OUTPUT_DEFAULT, 0); + fprintf(stdout, "%s\n", buf); + #endif + + return r; +} + +struct nftnl_rule * +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) +{ + uint16_t dport, sport; + uint64_t handle_num; + uint32_t if_idx; + 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_u32(r, NFTNL_RULE_FAMILY, family); + + if (descr != NULL) { + descr_len = strlen(descr); + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + descr, descr_len); + } + + if (handle != NULL) { + handle_num = atoll(handle); + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num); + } + + if (ifname != NULL) { + if_idx = (uint32_t)if_nametoindex(ifname); + expr_add_meta(r, NFT_META_IIF, NFT_REG_1); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &if_idx, + sizeof(uint32_t)); + } + + /* Destination Port */ + dport = htons(iport); + if (proto == IPPROTO_TCP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, dest), sizeof(uint16_t)); + } + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + + /* Source Port */ + if (rport != 0) { + sport = htons(rport); + if (proto == IPPROTO_TCP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, source), sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, source), sizeof(uint16_t)); + } + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); + } + return r; } @@ -1077,7 +1254,7 @@ nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq) } int -nft_send_request(struct nftnl_rule * rule, uint16_t cmd) +nft_send_request(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain_type) { struct nlmsghdr *nlh; struct mnl_nlmsg_batch *batch; @@ -1085,7 +1262,13 @@ nft_send_request(struct nftnl_rule * rule, uint16_t cmd) uint32_t seq = time(NULL); int ret; - rule_list_validate = RULE_CACHE_INVALID; + 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) { diff --git a/miniupnpd/netfilter_nft/nftnlrdr_misc.h b/miniupnpd/netfilter_nft/nftnlrdr_misc.h index 7f0a981..a097c8c 100644 --- a/miniupnpd/netfilter_nft/nftnlrdr_misc.h +++ b/miniupnpd/netfilter_nft/nftnlrdr_misc.h @@ -10,6 +10,7 @@ #define NFT_TABLE_NAT "nat" #define NFT_TABLE_FILTER "filter" +#define NFT_DESCR_SIZE 1024 enum rule_reg_type { RULE_REG_NONE, @@ -18,7 +19,11 @@ enum rule_reg_type { RULE_REG_IP_SRC_ADDR, RULE_REG_IP_DEST_ADDR, RULE_REG_IP_SD_ADDR, /* source & dest */ + RULE_REG_IP6_SRC_ADDR, + RULE_REG_IP6_DEST_ADDR, + RULE_REG_IP6_SD_ADDR, /* source & dest */ RULE_REG_IP_PROTO, + RULE_REG_IP6_PROTO, RULE_REG_TCP_DPORT, RULE_REG_TCP_SD_PORT, /* source & dest */ RULE_REG_IMM_VAL, @@ -28,11 +33,16 @@ enum rule_reg_type { enum rule_type { RULE_NONE, RULE_NAT, - RULE_SNAT, RULE_FILTER, RULE_COUNTER, }; +enum rule_chain_type { + RULE_CHAIN_FILTER, + RULE_CHAIN_PEER, + RULE_CHAIN_REDIRECT, +}; + typedef struct rule_ { LIST_ENTRY(rule_t) entry; char * table; @@ -47,6 +57,8 @@ typedef struct rule_ { in_addr_t eaddr; in_addr_t iaddr; in_addr_t rhost; + struct in6_addr iaddr6; + struct in6_addr rhost6; uint16_t eport; uint16_t iport; uint16_t rport; @@ -57,16 +69,18 @@ typedef struct rule_ { uint32_t reg2_val; uint64_t packets; uint64_t bytes; - char *desc; + char * desc; + uint32_t desc_len; + int index; } rule_t; LIST_HEAD(rule_list, rule_); -extern struct rule_list head; -extern rule_t **peer_cache; -extern rule_t **redirect_cache; +extern struct rule_list head_filter; +extern struct rule_list head_redirect; +extern struct rule_list head_peer; int -nft_send_request(struct nftnl_rule * rule, uint16_t cmd); +nft_send_request(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, @@ -82,10 +96,21 @@ rule_set_snat(uint8_t family, uint8_t proto, const char *handle); struct nftnl_rule * rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, - in_addr_t rhost, in_addr_t iaddr, unsigned short eport, - unsigned short iport, const char * descr, const char *handle); + in_addr_t rhost, in_addr_t iaddr, + 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(uint32_t family); +rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto, + struct in6_addr *rhost6, struct in6_addr *iaddr6, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle); +struct nftnl_rule * +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 print_rule(rule_t *r); diff --git a/miniupnpd/netfilter_nft/nftpinhole.c b/miniupnpd/netfilter_nft/nftpinhole.c new file mode 100644 index 0000000..527e8b1 --- /dev/null +++ b/miniupnpd/netfilter_nft/nftpinhole.c @@ -0,0 +1,434 @@ +/* $Id: iptpinhole.c,v 1.19 2018/04/22 19:36:58 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012-2018 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../upnputils.h" +#include "nftpinhole.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include "tiny_nf_nat.h" + +#include "../macros.h" +#include "../config.h" +#include "nftnlrdr.h" +#include "../upnpglobalvars.h" + +#include "nftnlrdr_misc.h" + +#ifdef DEBUG +#define d_printf(x) do { printf x; } while (0) +#else +#define d_printf(x) +#endif + +#ifdef ENABLE_UPNPPINHOLE + +static int next_uid = 1; + +#define PINEHOLE_LABEL_FORMAT "pinhole-%d ts-%u: %s" +#define PINEHOLE_LABEL_FORMAT_SKIPDESC "pinhole-%d ts-%u: %*s" + +void init_iptpinhole(void) +{ + return; +} + +void shutdown_iptpinhole(void) +{ + return; +} + +/* +ip saddr ip daddr tcp sport tcp dport +*/ +int add_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, const char * desc, unsigned int timestamp) +{ + int uid, res; + char comment[NFT_DESCR_SIZE]; + + struct nftnl_rule *r = NULL; + struct in6_addr rhost_addr, ihost_addr; + struct in6_addr *rhost_addr_p; + + UNUSED(rem_host); + UNUSED(rem_port); + + uid = next_uid; + + d_printf(("add_pinhole(%s, %s, %s, %d, %d, %d, %s)\n", + ifname, rem_host, int_client, rem_port, int_port, proto, desc)); + + if (rem_host && rem_host[0] != '\0' && rem_host[0] != '*') { + inet_pton(AF_INET6, rem_host, &rhost_addr); + rhost_addr_p = &rhost_addr; + } else { + rhost_addr_p = NULL; + } + + inet_pton(AF_INET6, int_client, &ihost_addr); + + snprintf(comment, NFT_DESCR_SIZE, + PINEHOLE_LABEL_FORMAT, uid, timestamp, desc); + + r = rule_set_filter6(NFPROTO_INET, ifname, proto, + rhost_addr_p, &ihost_addr, + 0, int_port, rem_port, comment, 0); + + res = nft_send_request(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); + + if (res < 0) + return -1; + + if (++next_uid >= 65535) { + next_uid = 1; + } + + return uid; +} + +int +find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp) +{ + rule_t *p; + struct in6_addr saddr; + struct in6_addr daddr; + int uid; + unsigned int ts; + UNUSED(ifname); + + if (rem_host && (rem_host[0] != '\0')) { + inet_pton(AF_INET6, rem_host, &saddr); + } else { + memset(&saddr, 0, sizeof(struct in6_addr)); + } + inet_pton(AF_INET6, int_client, &daddr); + + d_printf(("find_pinhole()\n")); + reflesh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + if ((proto == p->proto) && (rem_port == ntohs(p->rport)) + && (0 == memcmp(&saddr, &p->iaddr6, sizeof(struct in6_addr))) + && (int_port == ntohs(p->eport)) && + (0 == memcmp(&daddr, &p->iaddr6, sizeof(struct in6_addr)))) { + + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + if (timestamp) + *timestamp = ts; + + if (desc) { + char * pd = strchr(p->desc, ':'); + if(pd) { + pd += 2; + strncpy(desc, pd, desc_len); + } + } + + return uid; + } + } + + return -2; /* not found */ +} + +int +delete_pinhole(unsigned short uid) +{ + rule_t *p; + struct nftnl_rule *r; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + + snprintf(label_start, sizeof(label_start), + "pinhole-%hu", uid); + + d_printf(("find_pinhole()\n")); + reflesh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + r = rule_del_handle(p); + nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + return 0; + } + } + + return -2; +} + +int +update_pinhole(unsigned short uid, unsigned int timestamp) +{ + char iaddr[INET6_ADDRSTRLEN]; + char raddr[INET6_ADDRSTRLEN]; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + char desc[NFT_DESCR_SIZE]; + char ifname[IFNAMSIZ]; + char * tmp_p; + uint32_t ext_if_indx; + int proto; + unsigned short iport, rport; + rule_t *p; + + d_printf(("update_pinhole()\n")); + + reflesh_nft_cache_filter(); + + proto = -1; + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + /* Source IP Address */ + inet_ntop(AF_INET6, &p->rhost6, raddr, sizeof(raddr)); + + /* Source Port */ + rport = p->eport; + + /* Destination IP Address */ + inet_ntop(AF_INET6, &p->iaddr6, iaddr, sizeof(iaddr)); + + /* Destination Port */ + iport = p->iport; + + proto = p->proto; + + ext_if_indx = p->ingress_ifidx; + if_indextoname(ext_if_indx, ifname); + + tmp_p = tmp_label; + strsep(&tmp_p, " "); + if (tmp_p) { + strncpy(desc, tmp_p, NFT_DESCR_SIZE); + } else { + desc[0] = '\0'; + } + + break; + } + } + + if (proto == -1) + return -2; + + delete_pinhole(uid); + add_pinhole(ifname, raddr, rport, iaddr, iport, proto, desc, timestamp); + + return 0; +} + +int +get_pinhole_info(unsigned short uid, + char * rem_host, int rem_hostlen, + unsigned short * rem_port, + char * int_client, int int_clientlen, + unsigned short * int_port, + int * proto, char * desc, int desclen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes) +{ + rule_t *p; + unsigned int ts; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + + snprintf(label_start, sizeof(label_start), + "pinhole-%hu", uid); + + d_printf(("get_pinhole_info()\n")); + reflesh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + /* Source IP Address */ + if (rem_host && (rem_host[0] != '\0')) { + if(inet_ntop(AF_INET6, &p->rhost6, rem_host, rem_hostlen) == NULL) + return -1; + } + + /* Source Port */ + if (rem_port) + *rem_port = p->rport; + + /* Destination IP Address */ + if (int_client) { + if(inet_ntop(AF_INET6, &p->iaddr6, int_client, int_clientlen) == NULL) + return -1; + } + + /* Destination Port */ + if (int_port) + *int_port = p->eport; + + if (proto) + *proto = p->proto; + + if (timestamp) { + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC,(int *) &uid, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + *timestamp = ts; + } + + if (desc) + strncpy(desc, p->desc, desclen); + + if (packets || bytes) { + if (packets) + *packets = p->packets; + if (bytes) + *bytes = p->bytes; + } + + break; + } + } + + d_printf(("end_pinhole_info()\n")); + + return 0; +} + +int get_pinhole_uid_by_index(int index) +{ + UNUSED(index); + return -42; +} + +int +clean_pinhole_list(unsigned int * next_timestamp) +{ + rule_t *p; + struct nftnl_rule *r; + time_t current_time; + unsigned int ts; + int uid; + unsigned int min_ts = UINT_MAX; + int min_uid = INT_MAX, max_uid = -1; + int n = 0; + + current_time = upnp_time(); + + d_printf(("clean_pinhole_list()\n")); + reflesh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + if (ts <= (unsigned int)current_time) { + syslog(LOG_INFO, "removing expired pinhole '%s'", p->desc); + r = rule_del_handle(p); + nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + n++; + } else { + if (uid > max_uid) + max_uid = uid; + else if (uid < min_uid) + min_uid = uid; + if (ts < min_ts) + min_ts = ts; + } + } + + if (next_timestamp && (min_ts != UINT_MAX)) + *next_timestamp = min_ts; + + if (max_uid > 0) { + if (((min_uid - 32000) <= next_uid) && (next_uid <= max_uid)) { + next_uid = max_uid + 1; + } + + if (next_uid >= 65535) { + next_uid = 1; + } + } + + return n; /* number of rules removed */ +} + +#endif /* ENABLE_UPNPPINHOLE */ diff --git a/miniupnpd/netfilter_nft/nftpinhole.h b/miniupnpd/netfilter_nft/nftpinhole.h new file mode 100644 index 0000000..d536a27 --- /dev/null +++ b/miniupnpd/netfilter_nft/nftpinhole.h @@ -0,0 +1,43 @@ +/* $Id: nftpinhole.h,v 1.10 2016/01/19 10:03:30 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012-2016 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef NFTPINHOLE_H_INCLUDED +#define NFTPINHOLE_H_INCLUDED + +#ifdef ENABLE_UPNPPINHOLE +#include + +int find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp); + +int add_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, const char *desc, unsigned int timestamp); + +int update_pinhole(unsigned short uid, unsigned int timestamp); + +int delete_pinhole(unsigned short uid); + +int +get_pinhole_info(unsigned short uid, + char * rem_host, int rem_hostlen, unsigned short * rem_port, + char * int_client, int int_clientlen, + unsigned short * int_port, + int * proto, char * desc, int desclen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes); + +int get_pinhole_uid_by_index(int index); + +int clean_pinhole_list(unsigned int * next_timestamp); + +#endif /* ENABLE_UPNPPINHOLE */ + +#endif diff --git a/miniupnpd/netfilter_nft/scripts/nft_delete_chain.sh b/miniupnpd/netfilter_nft/scripts/nft_delete_chain.sh index 97f9fbe..d0e049f 100755 --- a/miniupnpd/netfilter_nft/scripts/nft_delete_chain.sh +++ b/miniupnpd/netfilter_nft/scripts/nft_delete_chain.sh @@ -1,5 +1,5 @@ #! /sbin/nft -f -delete chain nat miniupnpd -delete chain nat miniupnpd-pcp-peer -delete chain filter miniupnpd +delete chain nat MINIUPNPD +delete chain nat MINIUPNPD-POSTROUTING +delete chain filter MINIUPNPD diff --git a/miniupnpd/netfilter_nft/scripts/nft_flush.sh b/miniupnpd/netfilter_nft/scripts/nft_flush.sh index bd6c878..5898d68 100755 --- a/miniupnpd/netfilter_nft/scripts/nft_flush.sh +++ b/miniupnpd/netfilter_nft/scripts/nft_flush.sh @@ -1,5 +1,5 @@ #! /sbin/nft -f -flush chain ip nat miniupnpd -flush chain ip nat miniupnpd-pcp-peer -flush chain ip filter miniupnpd +flush chain ip nat MINIUPNPD +flush chain ip nat MINIUPNPD-POSTROUTING +flush chain inet filter MINIUPNPD diff --git a/miniupnpd/netfilter_nft/scripts/nft_init.sh b/miniupnpd/netfilter_nft/scripts/nft_init.sh index 45b42ea..93e2f5d 100755 --- a/miniupnpd/netfilter_nft/scripts/nft_init.sh +++ b/miniupnpd/netfilter_nft/scripts/nft_init.sh @@ -13,35 +13,35 @@ if [ $nft_nat_exists -eq "1" ]; then fi if [ $nft_filter_exists -eq "1" ]; then echo "create filter" - nft "add table filter" + nft "add table inet filter" fi if [ $nft_mangle_exists -eq "1" ]; then echo "create mangle" nft "add table mangle" fi -nft list chain nat miniupnpd > /dev/null +nft list chain nat MINIUPNPD > /dev/null nft_nat_miniupnpd_exists=$? -nft list chain nat miniupnpd-pcp-peer > /dev/null +nft list chain nat MINIUPNPD-POSTROUTING > /dev/null nft_nat_miniupnpd_pcp_peer_exists=$? -nft list chain filter miniupnpd > /dev/null +nft list chain filter MINIUPNPD > /dev/null nft_filter_miniupnpd_exists=$? -nft list chain mangle miniupnpd > /dev/null +nft list chain mangle MINIUPNPD > /dev/null nft_mangle_miniupnpd_exists=$? if [ $nft_nat_miniupnpd_exists -eq "1" ]; then echo "create chain in nat" - nft "add chain nat miniupnpd" + nft "add chain nat MINIUPNPD" fi if [ $nft_nat_miniupnpd_pcp_peer_exists -eq "1" ]; then echo "create pcp peer chain in nat" - nft "add chain nat miniupnpd-pcp-peer" + nft "add chain nat MINIUPNPD-POSTROUTING" fi if [ $nft_filter_miniupnpd_exists -eq "1" ]; then echo "create chain in filter " - nft "add chain filter miniupnpd" + nft "add chain filter MINIUPNPD" fi if [ $nft_mangle_miniupnpd_exists -eq "1" ]; then echo "create chain in mangle" - nft "add chain mangle miniupnpd" + nft "add chain mangle MINIUPNPD" fi diff --git a/miniupnpd/netfilter_nft/scripts/nft_removeall.sh b/miniupnpd/netfilter_nft/scripts/nft_removeall.sh index 11c38e7..e6fd75c 100755 --- a/miniupnpd/netfilter_nft/scripts/nft_removeall.sh +++ b/miniupnpd/netfilter_nft/scripts/nft_removeall.sh @@ -1,5 +1,5 @@ #! /sbin/nft -f -delete rule nat miniupnpd -delete rule nat miniupnpd-pcp-peer -delete rule filter miniupnpd +delete rule nat MINIUPNPD +delete rule nat MINIUPNPD-POSTROUTING +delete rule filter MINIUPNPD diff --git a/miniupnpd/netfilter_nft/testnftnlrdr.c b/miniupnpd/netfilter_nft/testnftnlrdr.c index efeccb3..1491a70 100644 --- a/miniupnpd/netfilter_nft/testnftnlrdr.c +++ b/miniupnpd/netfilter_nft/testnftnlrdr.c @@ -1,4 +1,4 @@ -/* $Id: testiptcrdr.c,v 1.18 2012/04/24 22:41:53 nanard Exp $ */ +/* $Id: testnftnlrdr.c,v 1.1 2015/04/30 09:05:08 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard diff --git a/miniupnpd/netfilter_nft/testnftpinhole.c b/miniupnpd/netfilter_nft/testnftpinhole.c new file mode 100644 index 0000000..ecc9297 --- /dev/null +++ b/miniupnpd/netfilter_nft/testnftpinhole.c @@ -0,0 +1,27 @@ +/* $Id: testiptpinhole.c,v 1.1 2012/04/26 13:50:48 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include + +#include "../config.h" +#include "nftpinhole.h" +#include "../commonrdr.h" + + +int main(int argc, char * * argv) +{ + int uid; + + openlog("testnftpinhole", LOG_PERROR|LOG_CONS, LOG_LOCAL0); + + uid = add_pinhole("eth0", NULL, 0, "ff::123", 54321, IPPROTO_TCP); + return 0; +} + diff --git a/miniupnpd/netfilter_nft/tiny_nf_nat.h b/miniupnpd/netfilter_nft/tiny_nf_nat.h index f7f5b27..051e2c1 100644 --- a/miniupnpd/netfilter_nft/tiny_nf_nat.h +++ b/miniupnpd/netfilter_nft/tiny_nf_nat.h @@ -1,4 +1,4 @@ -/* $Id: tiny_nf_nat.h,v 1.1 2011/07/30 13:14:36 nanard Exp $ */ +/* $Id: tiny_nf_nat.h,v 1.1 2015/04/30 09:05:08 nanard Exp $ */ /* Only what miniupnpd needs, until linux-libc-dev gains nf_nat.h */ #ifndef TINY_NF_NAT_H