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
|
upnppinhole.o pcplearndscp.o asyncsendto.o
|
||||||
|
|
||||||
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
|
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
|
||||||
NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/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)
|
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||||
|
|
||||||
|
@ -210,7 +211,7 @@ upnputils.o: miniupnpdtypes.h getroute.h
|
||||||
getconnstatus.o: getconnstatus.h getifaddr.h
|
getconnstatus.o: getconnstatus.h getifaddr.h
|
||||||
upnppinhole.o: macros.h config.h upnpredirect.h upnpglobalvars.h
|
upnppinhole.o: macros.h config.h upnpredirect.h upnpglobalvars.h
|
||||||
upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.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: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||||
pcplearndscp.o: pcplearndscp.h
|
pcplearndscp.o: pcplearndscp.h
|
||||||
asyncsendto.o: asyncsendto.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: macros.h config.h netfilter_nft/nftnlrdr.h commonrdr.h
|
||||||
netfilter_nft/nftnlrdr.o: config.h upnpglobalvars.h upnppermissions.h
|
netfilter_nft/nftnlrdr.o: config.h upnpglobalvars.h upnppermissions.h
|
||||||
netfilter_nft/nftnlrdr.o: miniupnpdtypes.h
|
netfilter_nft/nftnlrdr.o: miniupnpdtypes.h
|
||||||
netfilter_nft/iptpinhole.o: config.h netfilter_nft/iptpinhole.h upnpglobalvars.h
|
netfilter_nft/nftpinhole.o: config.h netfilter_nft/nftpinhole.h upnpglobalvars.h
|
||||||
netfilter_nft/iptpinhole.o: upnppermissions.h config.h miniupnpdtypes.h
|
netfilter_nft/nftpinhole.o: upnppermissions.h config.h miniupnpdtypes.h
|
||||||
testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h
|
testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h
|
||||||
testupnpdescgen.o: getifaddr.h
|
testupnpdescgen.o: getifaddr.h
|
||||||
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.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)
|
ARCH := $(shell uname -m | grep -q "x86_64" && echo 64)
|
||||||
|
|
||||||
all: test_nfct_get testnftnlrdr
|
all: test_nfct_get testnftnlrdr testnftpinhole
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) *.o testnftnlcrdr testnftnlpinhole testnftnlrdr_peer \
|
$(RM) *.o testnftnlcrdr testnftpinhole testnftnlrdr_peer \
|
||||||
test_nfct_get testnftnlrdr
|
test_nfct_get testnftnlrdr
|
||||||
|
|
||||||
testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o upnpglobalvars.o $(LIBS)
|
testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o 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
|
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
|
nftnlrdr_misc.o: nftnlrdr_misc.c
|
||||||
|
|
||||||
iptpinhole.o: iptpinhole.c iptpinhole.h
|
nftpinhole.o: nftpinhole.c nftpinhole.h
|
||||||
|
|
||||||
upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h
|
upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h
|
||||||
$(CC) -c -o $@ $<
|
$(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",
|
d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n",
|
||||||
ifname, rhost, eport, iaddr, iport, proto, desc));
|
ifname, rhost, eport, iaddr, iport, proto, desc));
|
||||||
|
|
||||||
r = rule_set_dnat(NFPROTO_IPV4, ifname, proto,
|
r = rule_set_dnat(NFPROTO_IPV4, ifname, proto,
|
||||||
0, eport,
|
0, eport,
|
||||||
inet_addr(iaddr), iport, desc, NULL);
|
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);
|
UNUSED(ifname); UNUSED(timestamp);
|
||||||
|
|
||||||
d_printf(("add peer redirect rule2()!\n"));
|
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",
|
d_printf(("add_filter_rule2(%s, %s, %s, %d, %d, %d, %s)\n",
|
||||||
ifname, rhost, iaddr, eport, iport, proto, desc));
|
ifname, rhost, iaddr, eport, iport, proto, desc));
|
||||||
|
|
||||||
if (rhost != NULL && strcmp(rhost, "") != 0) {
|
if (rhost != NULL && strcmp(rhost, "") != 0) {
|
||||||
rhost_addr = inet_addr(rhost);
|
rhost_addr = inet_addr(rhost);
|
||||||
}
|
}
|
||||||
r = rule_set_filter(NFPROTO_IPV4, ifname, proto,
|
r = rule_set_filter(NFPROTO_IPV4, ifname, proto,
|
||||||
rhost_addr, inet_addr(iaddr), eport, iport,
|
rhost_addr, inet_addr(iaddr),
|
||||||
desc, 0);
|
eport, iport, 0,
|
||||||
return nft_send_request(r, NFT_MSG_NEWRULE);
|
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;
|
struct nftnl_rule *r;
|
||||||
UNUSED(ifname);
|
UNUSED(ifname);
|
||||||
|
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
reflesh_nft_cache_filter();
|
||||||
LIST_FOREACH(p, &head, entry) {
|
LIST_FOREACH(p, &head_filter, entry) {
|
||||||
if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) {
|
if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) {
|
||||||
r = rule_del_handle(p);
|
r = rule_del_handle(p);
|
||||||
/* Todo: send bulk request */
|
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
|
||||||
nft_send_request(r, NFT_MSG_DELRULE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,37 +241,71 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
|
||||||
struct nftnl_rule *r = NULL;
|
struct nftnl_rule *r = NULL;
|
||||||
in_addr_t iaddr = 0;
|
in_addr_t iaddr = 0;
|
||||||
uint16_t iport = 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));
|
d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto));
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
reflesh_nft_cache_redirect();
|
||||||
LIST_FOREACH(p, &head, entry) {
|
|
||||||
|
// Delete Redirect Rule
|
||||||
|
LIST_FOREACH(p, &head_redirect, entry) {
|
||||||
if (p->eport == eport && p->proto == proto &&
|
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;
|
iaddr = p->iaddr;
|
||||||
iport = p->iport;
|
iport = p->iport;
|
||||||
|
|
||||||
r = rule_del_handle(p);
|
r = rule_del_handle(p);
|
||||||
/* Todo: send bulk request */
|
/* Todo: send bulk request */
|
||||||
nft_send_request(r, NFT_MSG_DELRULE);
|
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iaddr == 0 && iport == 0) {
|
if (iaddr != 0 && iport != 0) {
|
||||||
return -1;
|
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) {
|
iaddr = 0;
|
||||||
if (p->eport == iport &&
|
iport = 0;
|
||||||
p->iaddr == iaddr && p->type == RULE_FILTER) {
|
|
||||||
|
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);
|
r = rule_del_handle(p);
|
||||||
/* Todo: send bulk request */
|
/* Todo: send bulk request */
|
||||||
nft_send_request(r, NFT_MSG_DELRULE);
|
nft_send_request(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER);
|
||||||
break;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,56 +322,66 @@ get_peer_rule_by_index(int index,
|
||||||
unsigned int * timestamp,
|
unsigned int * timestamp,
|
||||||
u_int64_t * packets, u_int64_t * bytes)
|
u_int64_t * packets, u_int64_t * bytes)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
char *addr_str;
|
char *addr_str;
|
||||||
rule_t *r;
|
rule_t *r;
|
||||||
UNUSED(timestamp); UNUSED(packets); UNUSED(bytes);
|
UNUSED(timestamp);
|
||||||
|
|
||||||
d_printf(("get_peer_rule_by_index()\n"));
|
d_printf(("get_peer_rule_by_index()\n"));
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
reflesh_nft_cache_peer();
|
||||||
if (peer_cache == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; peer_cache[i] != NULL; i++) {
|
LIST_FOREACH(r, &head_peer, entry) {
|
||||||
if (index == i) {
|
if (r->index == index) {
|
||||||
r = peer_cache[i];
|
|
||||||
if (ifname != NULL) {
|
if (ifname != NULL) {
|
||||||
if_indextoname(r->ingress_ifidx, ifname);
|
if_indextoname(r->ingress_ifidx, ifname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eport != NULL) {
|
if (eport != NULL) {
|
||||||
*eport = r->eport;
|
*eport = r->eport;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iaddr != NULL) {
|
if (iaddr != NULL) {
|
||||||
addr.s_addr = r->iaddr;
|
addr.s_addr = r->iaddr;
|
||||||
addr_str = inet_ntoa(addr);
|
addr_str = inet_ntoa(addr);
|
||||||
strncpy(iaddr , addr_str, iaddrlen);
|
strncpy(iaddr , addr_str, iaddrlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iport != NULL) {
|
if (iport != NULL) {
|
||||||
*iport = r->iport;
|
*iport = r->iport;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
*proto = r->proto;
|
*proto = r->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhost != NULL) {
|
if (rhost != NULL) {
|
||||||
addr.s_addr = r->rhost;
|
addr.s_addr = r->rhost;
|
||||||
addr_str = inet_ntoa(addr);
|
addr_str = inet_ntoa(addr);
|
||||||
strncpy(iaddr , addr_str, rhostlen);
|
strncpy(iaddr , addr_str, rhostlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rport != NULL) {
|
if (rport != NULL) {
|
||||||
*rport = r->rport;
|
*rport = r->rport;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc != NULL) {
|
if (desc != NULL) {
|
||||||
strncpy(desc, r->desc, desclen);
|
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}
|
* TODO: Implement counter in case of add {nat,filter}
|
||||||
*/
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,43 +418,44 @@ get_redirect_rule_by_index(int index,
|
||||||
unsigned int * timestamp,
|
unsigned int * timestamp,
|
||||||
u_int64_t * packets, u_int64_t * bytes)
|
u_int64_t * packets, u_int64_t * bytes)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
char *addr_str;
|
char *addr_str;
|
||||||
rule_t *r;
|
rule_t *r;
|
||||||
UNUSED(timestamp); UNUSED(packets); UNUSED(bytes);
|
UNUSED(timestamp);
|
||||||
|
|
||||||
d_printf(("get_redirect_rule_by_index()\n"));
|
d_printf(("get_redirect_rule_by_index()\n"));
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
reflesh_nft_cache_redirect();
|
||||||
if (redirect_cache == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; redirect_cache[i] != NULL; i++) {
|
LIST_FOREACH(r, &head_redirect, entry) {
|
||||||
if (index == i) {
|
if (r->index == index) {
|
||||||
r = redirect_cache[i];
|
|
||||||
if (ifname != NULL) {
|
if (ifname != NULL) {
|
||||||
if_indextoname(r->ingress_ifidx, ifname);
|
if_indextoname(r->ingress_ifidx, ifname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eport != NULL) {
|
if (eport != NULL) {
|
||||||
*eport = r->eport;
|
*eport = r->eport;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iaddr != NULL) {
|
if (iaddr != NULL) {
|
||||||
addr.s_addr = r->iaddr;
|
addr.s_addr = r->iaddr;
|
||||||
addr_str = inet_ntoa(addr);
|
addr_str = inet_ntoa(addr);
|
||||||
strncpy(iaddr , addr_str, iaddrlen);
|
strncpy(iaddr , addr_str, iaddrlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iport != NULL) {
|
if (iport != NULL) {
|
||||||
*iport = r->iport;
|
*iport = r->iport;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto != NULL) {
|
if (proto != NULL) {
|
||||||
*proto = r->proto;
|
*proto = r->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rhost != NULL) {
|
if (rhost != NULL) {
|
||||||
addr.s_addr = r->rhost;
|
addr.s_addr = r->rhost;
|
||||||
addr_str = inet_ntoa(addr);
|
addr_str = inet_ntoa(addr);
|
||||||
strncpy(iaddr , addr_str, rhostlen);
|
strncpy(iaddr , addr_str, rhostlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc != NULL && r->desc) {
|
if (desc != NULL && r->desc) {
|
||||||
strncpy(desc, r->desc, desclen);
|
strncpy(desc, r->desc, desclen);
|
||||||
}
|
}
|
||||||
|
@ -414,12 +464,20 @@ get_redirect_rule_by_index(int index,
|
||||||
*timestamp = get_timestamp(*eport, *proto);
|
*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}
|
* TODO: Implement counter in case of add {nat,filter}
|
||||||
*/
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,30 +496,32 @@ get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
|
||||||
{
|
{
|
||||||
rule_t *p;
|
rule_t *p;
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
char *addr_str;
|
|
||||||
UNUSED(nat_chain_name);
|
UNUSED(nat_chain_name);
|
||||||
UNUSED(ifname);
|
UNUSED(ifname);
|
||||||
UNUSED(iaddrlen);
|
UNUSED(iaddrlen);
|
||||||
UNUSED(timestamp);
|
UNUSED(timestamp);
|
||||||
UNUSED(packets);
|
UNUSED(packets);
|
||||||
UNUSED(bytes);
|
UNUSED(bytes);
|
||||||
|
UNUSED(rhost);
|
||||||
|
UNUSED(rhostlen);
|
||||||
|
|
||||||
d_printf(("get_nat_redirect_rule()\n"));
|
reflesh_nft_cache_redirect();
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
|
||||||
|
|
||||||
LIST_FOREACH(p, &head, entry) {
|
LIST_FOREACH(p, &head_redirect, entry) {
|
||||||
if (p->proto == proto &&
|
if (p->proto == proto &&
|
||||||
p->eport == eport) {
|
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) {
|
if (desc != NULL && p->desc) {
|
||||||
strncpy(desc, p->desc, desclen);
|
strncpy(desc, p->desc, desclen);
|
||||||
}
|
}
|
||||||
*iport = p->iport;
|
|
||||||
|
if (iport)
|
||||||
|
*iport = p->iport;
|
||||||
|
|
||||||
if(timestamp != NULL)
|
if(timestamp != NULL)
|
||||||
*timestamp = get_timestamp(eport, proto);
|
*timestamp = get_timestamp(eport, proto);
|
||||||
|
@ -486,7 +546,8 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||||
unsigned short *array;
|
unsigned short *array;
|
||||||
unsigned short *tmp;
|
unsigned short *tmp;
|
||||||
|
|
||||||
d_printf(("get_portmappings_in_range()\n"));
|
d_printf(("get_portmappings_in_range()\n"));
|
||||||
|
|
||||||
*number = 0;
|
*number = 0;
|
||||||
capacity = 128;
|
capacity = 128;
|
||||||
array = calloc(capacity, sizeof(unsigned short));
|
array = calloc(capacity, sizeof(unsigned short));
|
||||||
|
@ -496,7 +557,9 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_FOREACH(p, &head, entry) {
|
reflesh_nft_cache_redirect();
|
||||||
|
|
||||||
|
LIST_FOREACH(p, &head_redirect, entry) {
|
||||||
if (p->proto == proto &&
|
if (p->proto == proto &&
|
||||||
startport <= p->eport &&
|
startport <= p->eport &&
|
||||||
p->eport <= endport) {
|
p->eport <= endport) {
|
||||||
|
@ -539,24 +602,24 @@ update_portmapping(const char * ifname, unsigned short eport, int proto,
|
||||||
unsigned short iport, const char * desc,
|
unsigned short iport, const char * desc,
|
||||||
unsigned int timestamp)
|
unsigned int timestamp)
|
||||||
{
|
{
|
||||||
char iaddr[4];
|
char iaddr_str[INET_ADDRSTRLEN];
|
||||||
char iaddr_str[16];
|
char rhost[INET_ADDRSTRLEN];
|
||||||
char rhost[32];
|
|
||||||
int r;
|
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;
|
return -1;
|
||||||
|
|
||||||
r = delete_redirect_and_filter_rules(eport, proto);
|
r = delete_redirect_and_filter_rules(eport, proto);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -1;
|
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)
|
desc, timestamp) < 0)
|
||||||
return -1;
|
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 -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -570,13 +633,21 @@ list_redirect_rule(const char * ifname)
|
||||||
rule_t *p;
|
rule_t *p;
|
||||||
UNUSED(ifname);
|
UNUSED(ifname);
|
||||||
|
|
||||||
reflesh_nft_cache(NFPROTO_IPV4);
|
reflesh_nft_cache_filter();
|
||||||
|
LIST_FOREACH(p, &head_filter, entry) {
|
||||||
LIST_FOREACH(p, &head, 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);
|
print_rule(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* MiniUPnP project
|
* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2015 Tomofumi Hayashi
|
* (c) 2015 Tomofumi Hayashi
|
||||||
*
|
*
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution.
|
* in the LICENCE file provided within the distribution.
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter/nfnetlink.h>
|
#include <linux/netfilter/nfnetlink.h>
|
||||||
#include <linux/netfilter/nf_tables.h>
|
#include <linux/netfilter/nf_tables.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
|
|
||||||
#include <libmnl/libmnl.h>
|
#include <libmnl/libmnl.h>
|
||||||
#include <libnftnl/rule.h>
|
#include <libnftnl/rule.h>
|
||||||
|
@ -45,28 +46,30 @@
|
||||||
#define RULE_CACHE_INVALID 0
|
#define RULE_CACHE_INVALID 0
|
||||||
#define RULE_CACHE_VALID 1
|
#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;
|
static struct mnl_socket *nl = NULL;
|
||||||
struct rule_list head = LIST_HEAD_INITIALIZER(head);
|
// FILTER
|
||||||
static uint32_t rule_list_validate = RULE_CACHE_INVALID;
|
struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter);
|
||||||
|
// DNAT
|
||||||
uint32_t rule_list_length = 0;
|
struct rule_list head_redirect = LIST_HEAD_INITIALIZER(head_redirect);
|
||||||
uint32_t rule_list_peer_length = 0;
|
// SNAT
|
||||||
|
struct rule_list head_peer = LIST_HEAD_INITIALIZER(head_peer);
|
||||||
rule_t **redirect_cache;
|
|
||||||
rule_t **peer_cache;
|
|
||||||
|
|
||||||
|
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 *
|
static const char *
|
||||||
get_family_string(uint32_t family)
|
get_family_string(uint32_t family)
|
||||||
{
|
{
|
||||||
switch (family) {
|
switch (family) {
|
||||||
|
case NFPROTO_INET:
|
||||||
|
return "ipv4/6";
|
||||||
case NFPROTO_IPV4:
|
case NFPROTO_IPV4:
|
||||||
return "ipv4";
|
return "ipv4";
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
return "ipv6";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown family";
|
return "unknown family";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +82,7 @@ get_proto_string(uint32_t proto)
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
return "udp";
|
return "udp";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown proto";
|
return "unknown proto";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,11 +99,13 @@ get_verdict_string(uint32_t val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
print_rule(rule_t *r)
|
print_rule(rule_t *r)
|
||||||
{
|
{
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
char *iaddr_str = NULL, *rhost_str = NULL, *eaddr_str = NULL;
|
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];
|
char ifname_buf[IF_NAMESIZE];
|
||||||
|
|
||||||
switch (r->type) {
|
switch (r->type) {
|
||||||
|
@ -120,10 +126,10 @@ print_rule(rule_t *r)
|
||||||
printf("%"PRIu64":[%s/%s] iif %s, %s/%s, %d -> "
|
printf("%"PRIu64":[%s/%s] iif %s, %s/%s, %d -> "
|
||||||
"%s:%d (%s)\n",
|
"%s:%d (%s)\n",
|
||||||
r->handle,
|
r->handle,
|
||||||
r->table, r->chain,
|
r->table, r->chain,
|
||||||
if_indextoname(r->ingress_ifidx, ifname_buf),
|
if_indextoname(r->ingress_ifidx, ifname_buf),
|
||||||
get_family_string(r->family),
|
get_family_string(r->family),
|
||||||
get_proto_string(r->proto), r->eport,
|
get_proto_string(r->proto), r->eport,
|
||||||
iaddr_str, r->iport,
|
iaddr_str, r->iport,
|
||||||
r->desc);
|
r->desc);
|
||||||
} else if (r->nat_type == NFT_NAT_SNAT) {
|
} else if (r->nat_type == NFT_NAT_SNAT) {
|
||||||
|
@ -135,7 +141,7 @@ print_rule(rule_t *r)
|
||||||
r->handle, r->table, r->chain,
|
r->handle, r->table, r->chain,
|
||||||
r->nat_type, r->family, r->ingress_ifidx,
|
r->nat_type, r->family, r->ingress_ifidx,
|
||||||
eaddr_str, r->eport,
|
eaddr_str, r->eport,
|
||||||
r->proto, iaddr_str, r->iport,
|
r->proto, iaddr_str, r->iport,
|
||||||
rhost_str, r->rport,
|
rhost_str, r->rport,
|
||||||
r->desc);
|
r->desc);
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,13 +165,26 @@ print_rule(rule_t *r)
|
||||||
addr.s_addr = r->rhost;
|
addr.s_addr = r->rhost;
|
||||||
rhost_str = strdupa(inet_ntoa(addr));
|
rhost_str = strdupa(inet_ntoa(addr));
|
||||||
}
|
}
|
||||||
printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n",
|
inet_ntop(AF_INET6, &r->iaddr6, iaddr6_str, INET6_ADDRSTRLEN);
|
||||||
r->handle, r->table, r->chain,
|
inet_ntop(AF_INET6, &r->rhost6, rhost6_str, INET6_ADDRSTRLEN);
|
||||||
get_family_string(r->family), get_proto_string(r->proto),
|
|
||||||
rhost_str,
|
if ( (r->iaddr != 0) || (r->rhost != 0) ) {
|
||||||
iaddr_str, r->eport,
|
printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n",
|
||||||
get_verdict_string(r->filter_action),
|
r->handle, r->table, r->chain,
|
||||||
r->desc);
|
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;
|
break;
|
||||||
case RULE_COUNTER:
|
case RULE_COUNTER:
|
||||||
if (r->iaddr != 0) {
|
if (r->iaddr != 0) {
|
||||||
|
@ -178,7 +197,7 @@ print_rule(rule_t *r)
|
||||||
}
|
}
|
||||||
printf("%"PRIu64":[%s/%s] %s/%s, %s:%d: "
|
printf("%"PRIu64":[%s/%s] %s/%s, %s:%d: "
|
||||||
"packets:%"PRIu64", bytes:%"PRIu64"\n",
|
"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),
|
get_family_string(r->family), get_proto_string(r->proto),
|
||||||
iaddr_str, r->eport, r->packets, r->bytes);
|
iaddr_str, r->eport, r->packets, r->bytes);
|
||||||
break;
|
break;
|
||||||
|
@ -188,7 +207,7 @@ print_rule(rule_t *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum rule_reg_type *
|
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) {
|
switch (dreg) {
|
||||||
case NFT_REG_1:
|
case NFT_REG_1:
|
||||||
|
@ -201,7 +220,7 @@ get_reg_type_ptr(rule_t *r, uint32_t dreg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t *
|
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) {
|
switch (dreg) {
|
||||||
case NFT_REG_1:
|
case NFT_REG_1:
|
||||||
|
@ -314,7 +333,7 @@ parse_rule_nat(struct nftnl_expr *e, rule_t *r)
|
||||||
r->iport = proto_min_val;
|
r->iport = proto_min_val;
|
||||||
} else if (r->nat_type == NFT_NAT_SNAT) {
|
} else if (r->nat_type == NFT_NAT_SNAT) {
|
||||||
r->eaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg);
|
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;
|
r->eport = proto_min_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +347,7 @@ static inline void
|
||||||
parse_rule_payload(struct nftnl_expr *e, rule_t *r)
|
parse_rule_payload(struct nftnl_expr *e, rule_t *r)
|
||||||
{
|
{
|
||||||
uint32_t base, dreg, offset, len;
|
uint32_t base, dreg, offset, len;
|
||||||
uint32_t *regptr;
|
uint32_t *regptr;
|
||||||
|
|
||||||
dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
|
dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
|
||||||
base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE);
|
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)) {
|
len == sizeof(uint8_t)) {
|
||||||
*regptr = RULE_REG_IP_PROTO;
|
*regptr = RULE_REG_IP_PROTO;
|
||||||
return;
|
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:
|
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||||
if (offset == offsetof(struct tcphdr, dest) &&
|
if (offset == offsetof(struct tcphdr, dest) &&
|
||||||
|
@ -366,7 +401,7 @@ parse_rule_payload(struct nftnl_expr *e, rule_t *r)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syslog(LOG_DEBUG,
|
syslog(LOG_DEBUG,
|
||||||
"Unsupport payload: (dreg:%d, base:%d, offset:%d, len:%d)",
|
"Unsupport payload: (dreg:%d, base:%d, offset:%d, len:%d)",
|
||||||
dreg, base, offset, len);
|
dreg, base, offset, len);
|
||||||
return;
|
return;
|
||||||
|
@ -383,6 +418,7 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) {
|
||||||
uint32_t op, sreg;
|
uint32_t op, sreg;
|
||||||
uint16_t *ports;
|
uint16_t *ports;
|
||||||
in_addr_t *addrp;
|
in_addr_t *addrp;
|
||||||
|
struct in6_addr *addrp6;
|
||||||
|
|
||||||
data_val = (void *)nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &data_len);
|
data_val = (void *)nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &data_len);
|
||||||
sreg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG);
|
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;
|
r->reg1_type = RULE_REG_NONE;
|
||||||
return;
|
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:
|
case RULE_REG_IP_DEST_ADDR:
|
||||||
if (data_len == sizeof(in_addr_t) && op == NFT_CMP_EQ) {
|
if (data_len == sizeof(in_addr_t) && op == NFT_CMP_EQ) {
|
||||||
if (r->type == RULE_FILTER) {
|
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;
|
r->reg1_type = RULE_REG_NONE;
|
||||||
return;
|
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:
|
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;
|
addrp = (in_addr_t *)data_val;
|
||||||
r->iaddr = addrp[0];
|
r->iaddr = addrp[0];
|
||||||
r->rhost = addrp[1];
|
r->rhost = addrp[1];
|
||||||
r->reg1_type = RULE_REG_NONE;
|
r->reg1_type = RULE_REG_NONE;
|
||||||
return;
|
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_IP_PROTO:
|
||||||
|
case RULE_REG_IP6_PROTO:
|
||||||
if (data_len == sizeof(uint8_t) && op == NFT_CMP_EQ) {
|
if (data_len == sizeof(uint8_t) && op == NFT_CMP_EQ) {
|
||||||
r->proto = *(uint8_t *)data_val;
|
r->proto = *(uint8_t *)data_val;
|
||||||
r->reg1_type = RULE_REG_NONE;
|
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:
|
case RULE_REG_TCP_SD_PORT:
|
||||||
if (data_len == sizeof(uint16_t) * 2 && op == NFT_CMP_EQ) {
|
if (data_len == sizeof(uint16_t) * 2 && op == NFT_CMP_EQ) {
|
||||||
ports = (uint16_t *)data_val;
|
ports = (uint16_t *)data_val;
|
||||||
r->iport = ntohs(ports[0]);
|
r->eport = ntohs(ports[0]);
|
||||||
r->rport = ntohs(ports[1]);
|
r->rport = ntohs(ports[1]);
|
||||||
r->reg1_type = RULE_REG_NONE;
|
r->reg1_type = RULE_REG_NONE;
|
||||||
return;
|
return;
|
||||||
|
@ -447,17 +508,18 @@ parse_rule_cmp(struct nftnl_expr *e, rule_t *r) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog(LOG_DEBUG, "Unknown cmp (r1type:%d, data_len:%d, op:%d)",
|
syslog(LOG_DEBUG, "Unknown cmp (r1type:%d, data_len:%d, op:%d)",
|
||||||
r->reg1_type, data_len, op);
|
r->reg1_type, data_len, op);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rule_expr_cb(struct nftnl_expr *e, void *data)
|
rule_expr_cb(struct nftnl_expr *e, void *data)
|
||||||
{
|
{
|
||||||
rule_t *r = data;
|
rule_t *r = data;
|
||||||
const char *attr_name = nftnl_expr_get_str(e,
|
const char *attr_name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
|
||||||
NFTNL_EXPR_NAME);
|
|
||||||
|
|
||||||
if (strncmp("cmp", attr_name, sizeof("cmp")) == 0) {
|
if (strncmp("cmp", attr_name, sizeof("cmp")) == 0) {
|
||||||
parse_rule_cmp(e, r);
|
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) {
|
} else if (strncmp("immediate", attr_name, sizeof("immediate")) == 0) {
|
||||||
parse_rule_immediate(e, r);
|
parse_rule_immediate(e, r);
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_ERR, "unknown attr: %s\n", attr_name);
|
syslog(LOG_DEBUG, "unknown attr: %s\n", attr_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MNL_CB_OK;
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,9 +550,13 @@ table_cb(const struct nlmsghdr *nlh, void *data)
|
||||||
struct nftnl_expr_iter *itr;
|
struct nftnl_expr_iter *itr;
|
||||||
rule_t *r;
|
rule_t *r;
|
||||||
char *chain;
|
char *chain;
|
||||||
|
char *descr;
|
||||||
|
int index_filter, index_peer, index_redirect;
|
||||||
UNUSED(data);
|
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));
|
memset(r, 0, sizeof(rule_t));
|
||||||
t = nftnl_rule_alloc();
|
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);
|
chain = (char *)nftnl_rule_get_data(t, NFTNL_RULE_CHAIN, &len);
|
||||||
if (strcmp(chain, miniupnpd_nft_nat_chain) != 0 &&
|
if (strcmp(chain, miniupnpd_nat_chain) != 0 &&
|
||||||
strcmp(chain, miniupnpd_nft_peer_chain) != 0 &&
|
strcmp(chain, miniupnpd_nat_postrouting_chain) != 0 &&
|
||||||
strcmp(chain, miniupnpd_nft_forward_chain) != 0) {
|
strcmp(chain, miniupnpd_forward_chain) != 0) {
|
||||||
goto rule_skip;
|
goto rule_skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,8 +582,11 @@ table_cb(const struct nlmsghdr *nlh, void *data)
|
||||||
r->chain = strdup(chain);
|
r->chain = strdup(chain);
|
||||||
r->family = *(uint32_t*)nftnl_rule_get_data(t, NFTNL_RULE_FAMILY,
|
r->family = *(uint32_t*)nftnl_rule_get_data(t, NFTNL_RULE_FAMILY,
|
||||||
&len);
|
&len);
|
||||||
r->desc = (char *)nftnl_rule_get_data(t, NFTNL_RULE_USERDATA,
|
descr = (char *)nftnl_rule_get_data(t, NFTNL_RULE_USERDATA,
|
||||||
&len);
|
&r->desc_len);
|
||||||
|
if (r->desc_len > 0)
|
||||||
|
r->desc = strdup(descr);
|
||||||
|
|
||||||
r->handle = *(uint32_t*)nftnl_rule_get_data(t,
|
r->handle = *(uint32_t*)nftnl_rule_get_data(t,
|
||||||
NFTNL_RULE_HANDLE,
|
NFTNL_RULE_HANDLE,
|
||||||
&len);
|
&len);
|
||||||
|
@ -524,9 +594,6 @@ table_cb(const struct nlmsghdr *nlh, void *data)
|
||||||
r->type = RULE_NAT;
|
r->type = RULE_NAT;
|
||||||
} else if (strcmp(r->table, NFT_TABLE_FILTER) == 0) {
|
} else if (strcmp(r->table, NFT_TABLE_FILTER) == 0) {
|
||||||
r->type = RULE_FILTER;
|
r->type = RULE_FILTER;
|
||||||
}
|
|
||||||
if (strcmp(r->chain, miniupnpd_nft_peer_chain) == 0) {
|
|
||||||
rule_list_peer_length++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itr = nftnl_expr_iter_create(t);
|
itr = nftnl_expr_iter_create(t);
|
||||||
|
@ -537,9 +604,18 @@ table_cb(const struct nlmsghdr *nlh, void *data)
|
||||||
|
|
||||||
if (r->type == RULE_NONE) {
|
if (r->type == RULE_NONE) {
|
||||||
free(r);
|
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 {
|
} else {
|
||||||
LIST_INSERT_HEAD(&head, r, entry);
|
r->index = index_filter;
|
||||||
rule_list_length++;
|
LIST_INSERT_HEAD(&head_filter, r, entry);
|
||||||
|
index_filter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule_skip:
|
rule_skip:
|
||||||
|
@ -550,66 +626,50 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
reflesh_nft_redirect_cache(void)
|
reflesh_nft_cache_filter()
|
||||||
{
|
{
|
||||||
rule_t *p;
|
|
||||||
int i;
|
|
||||||
uint32_t len;
|
|
||||||
|
|
||||||
if (redirect_cache != NULL) {
|
if (rule_list_filter_validate == RULE_CACHE_VALID) {
|
||||||
free(redirect_cache);
|
|
||||||
}
|
|
||||||
len = rule_list_length - rule_list_peer_length;
|
|
||||||
if (len == 0) {
|
|
||||||
redirect_cache = NULL;
|
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
reflesh_nft_peer_cache(void)
|
reflesh_nft_cache_peer()
|
||||||
{
|
{
|
||||||
rule_t *p;
|
if (rule_list_peer_validate == RULE_CACHE_VALID) {
|
||||||
int i;
|
|
||||||
|
|
||||||
if (peer_cache != NULL) {
|
|
||||||
free(peer_cache);
|
|
||||||
}
|
|
||||||
if (rule_list_peer_length == 0) {
|
|
||||||
peer_cache = NULL;
|
|
||||||
return;
|
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;
|
reflesh_nft_cache(&head_peer, NFT_TABLE_NAT, miniupnpd_nat_postrouting_chain, NFPROTO_IPV4);
|
||||||
LIST_FOREACH(p, &head, entry) {
|
|
||||||
if (strcmp(p->chain, miniupnpd_nft_peer_chain) == 0) {
|
rule_list_peer_validate = RULE_CACHE_VALID;
|
||||||
peer_cache[i] = p;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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];
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||||
struct nlmsghdr *nlh;
|
struct nlmsghdr *nlh;
|
||||||
|
@ -618,12 +678,8 @@ reflesh_nft_cache(uint32_t family)
|
||||||
rule_t *p1, *p2;
|
rule_t *p1, *p2;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (rule_list_validate == RULE_CACHE_VALID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = NULL;
|
t = NULL;
|
||||||
p1 = LIST_FIRST(&head);
|
p1 = LIST_FIRST(head);
|
||||||
if (p1 != NULL) {
|
if (p1 != NULL) {
|
||||||
while(p1 != NULL) {
|
while(p1 != NULL) {
|
||||||
p2 = (rule_t *)LIST_NEXT(p1, entry);
|
p2 = (rule_t *)LIST_NEXT(p1, entry);
|
||||||
|
@ -640,19 +696,7 @@ reflesh_nft_cache(uint32_t family)
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LIST_INIT(&head);
|
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);
|
|
||||||
|
|
||||||
if (nl == NULL) {
|
if (nl == NULL) {
|
||||||
nl = mnl_socket_open(NETLINK_NETFILTER);
|
nl = mnl_socket_open(NETLINK_NETFILTER);
|
||||||
|
@ -668,13 +712,25 @@ reflesh_nft_cache(uint32_t family)
|
||||||
}
|
}
|
||||||
portid = mnl_socket_get_portid(nl);
|
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) {
|
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||||
perror("mnl_socket_send");
|
perror("mnl_socket_send");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
rule_list_peer_length = 0;
|
|
||||||
rule_list_length = 0;
|
|
||||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||||
while (ret > 0) {
|
while (ret > 0) {
|
||||||
ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type);
|
ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type);
|
||||||
|
@ -682,21 +738,20 @@ reflesh_nft_cache(uint32_t family)
|
||||||
break;
|
break;
|
||||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
perror("error");
|
perror("error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mnl_socket_close(nl); */
|
/* mnl_socket_close(nl); */
|
||||||
|
|
||||||
reflesh_nft_peer_cache();
|
|
||||||
reflesh_nft_redirect_cache();
|
|
||||||
rule_list_validate = RULE_CACHE_VALID;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
expr_add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg,
|
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;
|
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
|
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;
|
struct nftnl_expr *e;
|
||||||
e = nftnl_expr_alloc("immediate");
|
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_TYPE, t);
|
||||||
nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_FAMILY, family);
|
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);
|
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_MIN, NFT_REG_1);
|
||||||
nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MAX, 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);
|
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_u32(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_MAX, NFT_REG_2);
|
||||||
|
|
||||||
nftnl_rule_add_expr(r, e);
|
nftnl_rule_add_expr(r, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Todo: add expr for rhost
|
|
||||||
*/
|
|
||||||
struct nftnl_rule *
|
struct nftnl_rule *
|
||||||
rule_set_snat(uint8_t family, uint8_t proto,
|
rule_set_snat(uint8_t family, uint8_t proto,
|
||||||
in_addr_t rhost, unsigned short rport,
|
in_addr_t rhost, unsigned short rport,
|
||||||
|
@ -854,10 +907,11 @@ rule_set_snat(uint8_t family, uint8_t proto,
|
||||||
const char *handle)
|
const char *handle)
|
||||||
{
|
{
|
||||||
struct nftnl_rule *r = NULL;
|
struct nftnl_rule *r = NULL;
|
||||||
uint32_t destport;
|
uint16_t dport, sport;
|
||||||
in_addr_t addr[2];
|
|
||||||
uint16_t port[2];
|
|
||||||
uint32_t descr_len;
|
uint32_t descr_len;
|
||||||
|
#ifdef DEBUG
|
||||||
|
char buf[8192];
|
||||||
|
#endif
|
||||||
UNUSED(handle);
|
UNUSED(handle);
|
||||||
|
|
||||||
r = nftnl_rule_alloc();
|
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_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);
|
||||||
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);
|
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
|
||||||
|
|
||||||
addr[0] = ihost;
|
if (descr != NULL) {
|
||||||
addr[1] = rhost;
|
descr_len = strlen(descr);
|
||||||
expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
|
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
|
||||||
offsetof(struct iphdr, saddr), sizeof(uint32_t)*2);
|
descr, descr_len);
|
||||||
expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, addr, sizeof(uint32_t)*2);
|
}
|
||||||
|
|
||||||
|
/* Destination IP */
|
||||||
expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
|
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));
|
expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t));
|
||||||
|
|
||||||
port[0] = htons(iport);
|
/* Source and Destination Port of Protocol */
|
||||||
port[1] = htons(rport);
|
|
||||||
if (proto == IPPROTO_TCP) {
|
if (proto == IPPROTO_TCP) {
|
||||||
|
/* Destination Port */
|
||||||
|
dport = htons(iport);
|
||||||
expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
|
expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1,
|
||||||
offsetof(struct tcphdr, source),
|
offsetof(struct tcphdr, dest), sizeof(uint16_t));
|
||||||
sizeof(uint32_t));
|
expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_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));
|
|
||||||
|
|
||||||
destport = htons(eport);
|
/* Source Port */
|
||||||
expr_add_nat(r, NFT_NAT_SNAT, AF_INET, ehost, destport, 0);
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Todo: add expr for rhost
|
|
||||||
*/
|
|
||||||
struct nftnl_rule *
|
struct nftnl_rule *
|
||||||
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
in_addr_t rhost, unsigned short eport,
|
in_addr_t rhost, unsigned short eport,
|
||||||
|
@ -919,9 +994,11 @@ rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
uint64_t handle_num;
|
uint64_t handle_num;
|
||||||
uint32_t if_idx;
|
uint32_t if_idx;
|
||||||
uint32_t descr_len;
|
uint32_t descr_len;
|
||||||
|
#ifdef DEBUG
|
||||||
|
char buf[8192];
|
||||||
|
#endif
|
||||||
|
|
||||||
UNUSED(handle);
|
UNUSED(handle);
|
||||||
UNUSED(rhost);
|
|
||||||
|
|
||||||
r = nftnl_rule_alloc();
|
r = nftnl_rule_alloc();
|
||||||
if (r == NULL) {
|
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_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);
|
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
|
||||||
|
|
||||||
if (descr != NULL) {
|
if (descr != NULL) {
|
||||||
descr_len = strlen(descr);
|
descr_len = strlen(descr);
|
||||||
nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
|
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,
|
|
||||||
descr, descr_len);
|
descr, descr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1014,29 +1028,192 @@ rule_set_filter(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
sizeof(uint32_t));
|
sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
|
/* Source IP */
|
||||||
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));
|
|
||||||
|
|
||||||
if (rhost != 0) {
|
if (rhost != 0) {
|
||||||
expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
|
expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
|
||||||
offsetof(struct iphdr, saddr),
|
offsetof(struct iphdr, saddr), sizeof(in_addr_t));
|
||||||
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,
|
expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost,
|
||||||
sizeof(in_addr_t));
|
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);
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1077,7 +1254,7 @@ nft_mnl_batch_put(char *buf, uint16_t type, uint32_t seq)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 nlmsghdr *nlh;
|
||||||
struct mnl_nlmsg_batch *batch;
|
struct mnl_nlmsg_batch *batch;
|
||||||
|
@ -1085,7 +1262,13 @@ nft_send_request(struct nftnl_rule * rule, uint16_t cmd)
|
||||||
uint32_t seq = time(NULL);
|
uint32_t seq = time(NULL);
|
||||||
int ret;
|
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) {
|
if (nl == NULL) {
|
||||||
nl = mnl_socket_open(NETLINK_NETFILTER);
|
nl = mnl_socket_open(NETLINK_NETFILTER);
|
||||||
if (nl == NULL) {
|
if (nl == NULL) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#define NFT_TABLE_NAT "nat"
|
#define NFT_TABLE_NAT "nat"
|
||||||
#define NFT_TABLE_FILTER "filter"
|
#define NFT_TABLE_FILTER "filter"
|
||||||
|
#define NFT_DESCR_SIZE 1024
|
||||||
|
|
||||||
enum rule_reg_type {
|
enum rule_reg_type {
|
||||||
RULE_REG_NONE,
|
RULE_REG_NONE,
|
||||||
|
@ -18,7 +19,11 @@ enum rule_reg_type {
|
||||||
RULE_REG_IP_SRC_ADDR,
|
RULE_REG_IP_SRC_ADDR,
|
||||||
RULE_REG_IP_DEST_ADDR,
|
RULE_REG_IP_DEST_ADDR,
|
||||||
RULE_REG_IP_SD_ADDR, /* source & dest */
|
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_IP_PROTO,
|
||||||
|
RULE_REG_IP6_PROTO,
|
||||||
RULE_REG_TCP_DPORT,
|
RULE_REG_TCP_DPORT,
|
||||||
RULE_REG_TCP_SD_PORT, /* source & dest */
|
RULE_REG_TCP_SD_PORT, /* source & dest */
|
||||||
RULE_REG_IMM_VAL,
|
RULE_REG_IMM_VAL,
|
||||||
|
@ -28,11 +33,16 @@ enum rule_reg_type {
|
||||||
enum rule_type {
|
enum rule_type {
|
||||||
RULE_NONE,
|
RULE_NONE,
|
||||||
RULE_NAT,
|
RULE_NAT,
|
||||||
RULE_SNAT,
|
|
||||||
RULE_FILTER,
|
RULE_FILTER,
|
||||||
RULE_COUNTER,
|
RULE_COUNTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum rule_chain_type {
|
||||||
|
RULE_CHAIN_FILTER,
|
||||||
|
RULE_CHAIN_PEER,
|
||||||
|
RULE_CHAIN_REDIRECT,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct rule_ {
|
typedef struct rule_ {
|
||||||
LIST_ENTRY(rule_t) entry;
|
LIST_ENTRY(rule_t) entry;
|
||||||
char * table;
|
char * table;
|
||||||
|
@ -47,6 +57,8 @@ typedef struct rule_ {
|
||||||
in_addr_t eaddr;
|
in_addr_t eaddr;
|
||||||
in_addr_t iaddr;
|
in_addr_t iaddr;
|
||||||
in_addr_t rhost;
|
in_addr_t rhost;
|
||||||
|
struct in6_addr iaddr6;
|
||||||
|
struct in6_addr rhost6;
|
||||||
uint16_t eport;
|
uint16_t eport;
|
||||||
uint16_t iport;
|
uint16_t iport;
|
||||||
uint16_t rport;
|
uint16_t rport;
|
||||||
|
@ -57,16 +69,18 @@ typedef struct rule_ {
|
||||||
uint32_t reg2_val;
|
uint32_t reg2_val;
|
||||||
uint64_t packets;
|
uint64_t packets;
|
||||||
uint64_t bytes;
|
uint64_t bytes;
|
||||||
char *desc;
|
char * desc;
|
||||||
|
uint32_t desc_len;
|
||||||
|
int index;
|
||||||
} rule_t;
|
} rule_t;
|
||||||
|
|
||||||
LIST_HEAD(rule_list, rule_);
|
LIST_HEAD(rule_list, rule_);
|
||||||
extern struct rule_list head;
|
extern struct rule_list head_filter;
|
||||||
extern rule_t **peer_cache;
|
extern struct rule_list head_redirect;
|
||||||
extern rule_t **redirect_cache;
|
extern struct rule_list head_peer;
|
||||||
|
|
||||||
int
|
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 *
|
struct nftnl_rule *
|
||||||
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
in_addr_t rhost, unsigned short eport,
|
in_addr_t rhost, unsigned short eport,
|
||||||
|
@ -82,10 +96,21 @@ rule_set_snat(uint8_t family, uint8_t proto,
|
||||||
const char *handle);
|
const char *handle);
|
||||||
struct nftnl_rule *
|
struct nftnl_rule *
|
||||||
rule_set_filter(uint8_t family, const char * ifname, uint8_t proto,
|
rule_set_filter(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
in_addr_t rhost, in_addr_t iaddr, unsigned short eport,
|
in_addr_t rhost, in_addr_t iaddr,
|
||||||
unsigned short iport, const char * descr, const char *handle);
|
unsigned short eport, unsigned short iport,
|
||||||
|
unsigned short rport, const char * descr, const char *handle);
|
||||||
struct nftnl_rule *
|
struct nftnl_rule *
|
||||||
rule_del_handle(rule_t *r);
|
rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto,
|
||||||
void
|
struct in6_addr *rhost6, struct in6_addr *iaddr6,
|
||||||
reflesh_nft_cache(uint32_t family);
|
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);
|
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
|
#! /sbin/nft -f
|
||||||
|
|
||||||
delete chain nat miniupnpd
|
delete chain nat MINIUPNPD
|
||||||
delete chain nat miniupnpd-pcp-peer
|
delete chain nat MINIUPNPD-POSTROUTING
|
||||||
delete chain filter miniupnpd
|
delete chain filter MINIUPNPD
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#! /sbin/nft -f
|
#! /sbin/nft -f
|
||||||
|
|
||||||
flush chain ip nat miniupnpd
|
flush chain ip nat MINIUPNPD
|
||||||
flush chain ip nat miniupnpd-pcp-peer
|
flush chain ip nat MINIUPNPD-POSTROUTING
|
||||||
flush chain ip filter miniupnpd
|
flush chain inet filter MINIUPNPD
|
||||||
|
|
|
@ -13,35 +13,35 @@ if [ $nft_nat_exists -eq "1" ]; then
|
||||||
fi
|
fi
|
||||||
if [ $nft_filter_exists -eq "1" ]; then
|
if [ $nft_filter_exists -eq "1" ]; then
|
||||||
echo "create filter"
|
echo "create filter"
|
||||||
nft "add table filter"
|
nft "add table inet filter"
|
||||||
fi
|
fi
|
||||||
if [ $nft_mangle_exists -eq "1" ]; then
|
if [ $nft_mangle_exists -eq "1" ]; then
|
||||||
echo "create mangle"
|
echo "create mangle"
|
||||||
nft "add table mangle"
|
nft "add table mangle"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nft list chain nat miniupnpd > /dev/null
|
nft list chain nat MINIUPNPD > /dev/null
|
||||||
nft_nat_miniupnpd_exists=$?
|
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_nat_miniupnpd_pcp_peer_exists=$?
|
||||||
nft list chain filter miniupnpd > /dev/null
|
nft list chain filter MINIUPNPD > /dev/null
|
||||||
nft_filter_miniupnpd_exists=$?
|
nft_filter_miniupnpd_exists=$?
|
||||||
nft list chain mangle miniupnpd > /dev/null
|
nft list chain mangle MINIUPNPD > /dev/null
|
||||||
nft_mangle_miniupnpd_exists=$?
|
nft_mangle_miniupnpd_exists=$?
|
||||||
|
|
||||||
if [ $nft_nat_miniupnpd_exists -eq "1" ]; then
|
if [ $nft_nat_miniupnpd_exists -eq "1" ]; then
|
||||||
echo "create chain in nat"
|
echo "create chain in nat"
|
||||||
nft "add chain nat miniupnpd"
|
nft "add chain nat MINIUPNPD"
|
||||||
fi
|
fi
|
||||||
if [ $nft_nat_miniupnpd_pcp_peer_exists -eq "1" ]; then
|
if [ $nft_nat_miniupnpd_pcp_peer_exists -eq "1" ]; then
|
||||||
echo "create pcp peer chain in nat"
|
echo "create pcp peer chain in nat"
|
||||||
nft "add chain nat miniupnpd-pcp-peer"
|
nft "add chain nat MINIUPNPD-POSTROUTING"
|
||||||
fi
|
fi
|
||||||
if [ $nft_filter_miniupnpd_exists -eq "1" ]; then
|
if [ $nft_filter_miniupnpd_exists -eq "1" ]; then
|
||||||
echo "create chain in filter "
|
echo "create chain in filter "
|
||||||
nft "add chain filter miniupnpd"
|
nft "add chain filter MINIUPNPD"
|
||||||
fi
|
fi
|
||||||
if [ $nft_mangle_miniupnpd_exists -eq "1" ]; then
|
if [ $nft_mangle_miniupnpd_exists -eq "1" ]; then
|
||||||
echo "create chain in mangle"
|
echo "create chain in mangle"
|
||||||
nft "add chain mangle miniupnpd"
|
nft "add chain mangle MINIUPNPD"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#! /sbin/nft -f
|
#! /sbin/nft -f
|
||||||
|
|
||||||
delete rule nat miniupnpd
|
delete rule nat MINIUPNPD
|
||||||
delete rule nat miniupnpd-pcp-peer
|
delete rule nat MINIUPNPD-POSTROUTING
|
||||||
delete rule filter miniupnpd
|
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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2012 Thomas Bernard
|
* (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 */
|
/* Only what miniupnpd needs, until linux-libc-dev gains nf_nat.h */
|
||||||
|
|
||||||
#ifndef TINY_NF_NAT_H
|
#ifndef TINY_NF_NAT_H
|
||||||
|
|
Loading…
Reference in New Issue