This commit fixes IPv4 and adds IPv6 pinhole to nftables.
Signed-off-by: Sven Auhagen <sven.auhagen@voleatech.de>
This commit is contained in:
parent
765156b04a
commit
00ff23c428
|
@ -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
|
||||
|
|
|
@ -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 $@ $<
|
||||
|
|
|
@ -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);
|
||||
|
||||
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);
|
||||
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,
|
||||
rhost_addr, inet_addr(iaddr),
|
||||
eport, iport, 0,
|
||||
desc, 0);
|
||||
return nft_send_request(r, NFT_MSG_NEWRULE);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -239,33 +244,67 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
|
|||
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;
|
||||
}
|
||||
reflesh_nft_cache(NFPROTO_IPV4);
|
||||
LIST_FOREACH(p, &head, entry) {
|
||||
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);
|
||||
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, 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;
|
||||
}
|
||||
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,29 +496,31 @@ 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);
|
||||
}
|
||||
|
||||
if (iport)
|
||||
*iport = p->iport;
|
||||
|
||||
if(timestamp != NULL)
|
||||
|
@ -487,6 +547,7 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
|||
unsigned short *tmp;
|
||||
|
||||
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,23 +602,23 @@ 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,
|
||||
desc, timestamp) < 0)
|
||||
return -1;
|
||||
|
||||
if (add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
#include <linux/ipv6.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <libnftnl/rule.h>
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -100,6 +104,8 @@ 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) {
|
||||
|
@ -159,6 +165,10 @@ print_rule(rule_t *r)
|
|||
addr.s_addr = r->rhost;
|
||||
rhost_str = strdupa(inet_ntoa(addr));
|
||||
}
|
||||
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),
|
||||
|
@ -166,6 +176,15 @@ print_rule(rule_t *r)
|
|||
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) {
|
||||
|
@ -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) &&
|
||||
|
@ -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,6 +458,16 @@ 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) {
|
||||
addrp = (in_addr_t *)data_val;
|
||||
|
@ -424,7 +476,16 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) {
|
|||
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,8 +508,10 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -456,8 +519,7 @@ static int
|
|||
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,8 +550,12 @@ 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);
|
||||
|
||||
index_filter = index_peer = index_redirect = 0;
|
||||
|
||||
r = malloc(sizeof(rule_t));
|
||||
|
||||
memset(r, 0, sizeof(rule_t));
|
||||
|
@ -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);
|
||||
|
@ -525,9 +595,6 @@ table_cb(const struct nlmsghdr *nlh, void *data)
|
|||
} 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);
|
||||
reflesh_nft_cache(&head_filter, NFT_TABLE_FILTER, miniupnpd_forward_chain, NFPROTO_INET);
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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,15 +738,14 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
nftnl_rule_set(r, NFTNL_RULE_CHAIN, miniupnpd_nat_postrouting_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);
|
||||
}
|
||||
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
|
||||
|
||||
addr[0] = ihost;
|
||||
addr[1] = rhost;
|
||||
/* Destination IP */
|
||||
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);
|
||||
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,8 +1007,9 @@ 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,
|
||||
|
@ -950,6 +1028,14 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
|||
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));
|
||||
|
@ -957,34 +1043,35 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
|||
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));
|
||||
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));
|
||||
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);
|
||||
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, 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 *r = NULL;
|
||||
uint16_t dport;
|
||||
uint64_t handle_num;
|
||||
uint32_t if_idx;
|
||||
uint32_t descr_len;
|
||||
#ifdef DEBUG
|
||||
char buf[8192];
|
||||
#endif
|
||||
UNUSED(eport);
|
||||
|
||||
r = nftnl_rule_alloc();
|
||||
|
@ -993,9 +1080,98 @@ rule_set_filter(uint8_t family, const char * ifname, uint8_t proto,
|
|||
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_nft_forward_chain);
|
||||
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,
|
||||
|
@ -1014,28 +1190,29 @@ 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));
|
||||
|
||||
/* 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));
|
||||
|
||||
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));
|
||||
/* 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));
|
||||
}
|
||||
|
||||
expr_set_reg_verdict(r, NF_ACCEPT);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
@ -58,15 +70,17 @@ typedef struct rule_ {
|
|||
uint64_t packets;
|
||||
uint64_t bytes;
|
||||
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);
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../upnputils.h"
|
||||
#include "nftpinhole.h"
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <libnftnl/rule.h>
|
||||
#include <libnftnl/expr.h>
|
||||
|
||||
#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 <rem_host> ip daddr <int_client> tcp sport <rem_port> tcp dport <int_port>
|
||||
*/
|
||||
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 */
|
|
@ -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 <sys/types.h>
|
||||
|
||||
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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue