Initial commit to support nftables.

This commit is contained in:
Tomofumi Hayashi 2015-03-11 21:10:25 +09:00
parent eb72ab5330
commit dcf218c452
14 changed files with 2493 additions and 0 deletions

View File

@ -0,0 +1,228 @@
# MiniUPnP project
# (c) 2015 Tomofumi Hayashi
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# Author : Tomofumi Hayashi
# for use with GNU Make
#
# options can be passed to genconfig.sh through CONFIG_OPTIONS :
# $ CONFIG_OPTIONS="--ipv6 --igd2" make -f Makefile.linux
#
# To install use :
# $ DESTDIR=/dummyinstalldir make -f Makefile.linux_nft install
# or :
# $ INSTALLPREFIX=/usr/local make -f Makefile.linux_nft install
# or :
# $ make -f Makefile.linux install
# (default INSTALLPREFIX is /usr)
#
#
CFLAGS = -O -g -DDEBUG
CFLAGS ?= -Os
CFLAGS += -fno-strict-aliasing
CFLAGS += -fno-common
CPPFLAGS += -D_GNU_SOURCE
CFLAGS += -Wall
CFLAGS += -Wextra -Wstrict-prototypes -Wdeclaration-after-statement
#CFLAGS += -Wno-missing-field-initializers
CC ?= gcc
RM = rm -f
INSTALL = install
STRIP ?= strip
PKG_CONFIG ?= pkg-config
CP = cp
INSTALLPREFIX ?= $(PREFIX)/usr
SBININSTALLDIR = $(INSTALLPREFIX)/sbin
ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd
MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
upnpreplyparse.o minixml.o portinuse.o \
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \
upnpevents.o upnputils.o getconnstatus.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
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
PCFILE_FOUND := $(shell $(PKG_CONFIG) --exists libnftnl; echo $$?)
ifeq (${PCFILE_FOUND},0)
CFLAGS += $(shell $(PKG_CONFIG) --cflags libnftnl)
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnftnl)
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libnftnl)
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-other libnftnl)
else
ARCH ?= $(shell uname -m | grep -q "x86_64" && echo 64)
endif # ifdef PCFILE_FOUND
LDLIBS += -lnfnetlink
TEST := $(shell $(PKG_CONFIG) --atleast-version=1.0.2 libnetfilter_conntrack && $(PKG_CONFIG) --atleast-version=1.0.3 libmnl && echo 1)
ifeq ($(TEST),1)
CPPFLAGS += -DUSE_NFCT
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libmnl)
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnetfilter_conntrack)
endif # ($(TEST),1)
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl)
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
testupnppermissions miniupnpdctl testgetifaddr \
testgetroute testasyncsendto testportinuse
.PHONY: all clean install depend genuuid
all: $(EXECUTABLES)
clean:
$(RM) $(ALLOBJS)
$(RM) $(EXECUTABLES)
$(RM) testupnpdescgen.o testgetifstats.o
$(RM) testupnppermissions.o testgetifaddr.o
$(RM) testgetroute.o testasyncsendto.o
$(RM) testportinuse.o
$(RM) miniupnpdctl.o
install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \
netfilter/iptables_init.sh netfilter/iptables_removeall.sh \
netfilter/ip6tables_init.sh netfilter/ip6tables_removeall.sh \
linux/miniupnpd.init.d.script
$(STRIP) miniupnpd
$(INSTALL) -d $(DESTDIR)$(SBININSTALLDIR)
$(INSTALL) miniupnpd $(DESTDIR)$(SBININSTALLDIR)
$(INSTALL) -d $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) netfilter/iptables_init.sh $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) netfilter/iptables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) netfilter/ip6tables_init.sh $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) netfilter/ip6tables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) --mode=0644 -b miniupnpd.conf $(DESTDIR)$(ETCINSTALLDIR)
$(INSTALL) -d $(DESTDIR)$(PREFIX)/etc/init.d
$(INSTALL) linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd
$(INSTALL) -d $(DESTDIR)$(MANINSTALLDIR)
$(INSTALL) --mode=0644 miniupnpd.8 $(DESTDIR)$(MANINSTALLDIR)
gzip -f $(DESTDIR)$(MANINSTALLDIR)/miniupnpd.8
# genuuid is using the uuidgen CLI tool which is part of libuuid
# from the e2fsprogs
# 'cat /proc/sys/kernel/random/uuid' could be also used
genuuid:
ifeq ($(TARGET_OPENWRT),)
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen||uuid) 2>/dev/null`/" miniupnpd.conf
else
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf
endif
miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
testupnpdescgen: $(TESTUPNPDESCGENOBJS)
testgetifstats: testgetifstats.o linux/getifstats.o
testupnppermissions: testupnppermissions.o upnppermissions.o
testgetifaddr: testgetifaddr.o getifaddr.o
testgetroute: testgetroute.o linux/getroute.o upnputils.o
testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \
linux/getroute.o
testportinuse: testportinuse.o portinuse.o getifaddr.o \
netfilter_nft/nftnlrdr.o netfilter_nft/nftnlrdr_misc.o
miniupnpdctl: miniupnpdctl.o
config.h: genconfig.sh VERSION
./genconfig.sh $(CONFIG_OPTIONS)
depend: config.h
makedepend -f$(MAKEFILE_LIST) -Y \
$(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \
testgetifstats.c testupnppermissions.c testgetifaddr.c \
testgetroute.c testasyncsendto.c testportinuse.c \
miniupnpdctl.c 2>/dev/null
# DO NOT DELETE
miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h
miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.h
miniupnpd.o: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h
miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h asyncsendto.h natpmp.h
miniupnpd.o: pcpserver.h commonrdr.h upnputils.h ifacewatcher.h
upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h
upnphttp.o: upnpevents.h upnputils.h
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
upnpsoap.o: macros.h config.h upnpglobalvars.h upnppermissions.h
upnpsoap.o: miniupnpdtypes.h upnphttp.h upnpsoap.h upnpreplyparse.h
upnpsoap.o: upnpredirect.h upnppinhole.h getifaddr.h getifstats.h
upnpsoap.o: getconnstatus.h upnpurns.h
upnpreplyparse.o: upnpreplyparse.h minixml.h
minixml.o: minixml.h
portinuse.o: macros.h config.h upnpglobalvars.h upnppermissions.h
portinuse.o: miniupnpdtypes.h getifaddr.h portinuse.h netfilter_nft/nftnlrdr.h
portinuse.o: commonrdr.h
upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h
upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h portinuse.h
upnpredirect.o: netfilter_nft/nftnlrdr.h commonrdr.h
getifaddr.o: config.h getifaddr.h
daemonize.o: daemonize.h config.h
upnpglobalvars.o: config.h upnpglobalvars.h upnppermissions.h
upnpglobalvars.o: miniupnpdtypes.h upnpdescstrings.h
options.o: config.h options.h upnppermissions.h upnpglobalvars.h
options.o: miniupnpdtypes.h
upnppermissions.o: config.h upnppermissions.h
minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h
minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h
minissdp.o: upnputils.h getroute.h asyncsendto.h codelength.h
natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h
natpmp.o: portinuse.h asyncsendto.h
pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h
pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h
pcpserver.o: getifaddr.h asyncsendto.h pcp_msg_struct.h netfilter_nft/nftnlrdr.h
pcpserver.o: commonrdr.h
upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h
upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h
upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h
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
pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
pcplearndscp.o: pcplearndscp.h
asyncsendto.o: asyncsendto.h
linux/getifstats.o: config.h getifstats.h
linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h
linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
linux/ifacewatcher.o: upnppermissions.h natpmp.h
linux/getroute.o: getroute.h upnputils.h
netfilter_nft/nftnlrdr.o: macros.h config.h netfilter_nft/nftnlrdr.h commonrdr.h
netfilter_nft/nftnlrdr.o: config.h upnpglobalvars.h upnppermissions.h
netfilter_nft/nftnlrdr.o: miniupnpdtypes.h
netfilter_nft/iptpinhole.o: config.h netfilter_nft/iptpinhole.h upnpglobalvars.h
netfilter_nft/iptpinhole.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
upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
testgetifstats.o: getifstats.h
testupnppermissions.o: upnppermissions.h config.h
testgetifaddr.o: config.h getifaddr.h
testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h
testgetroute.o: config.h miniupnpdtypes.h
testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h
testportinuse.o: macros.h config.h portinuse.h
miniupnpdctl.o: macros.h

View File

@ -0,0 +1,33 @@
CFLAGS?=-Wall -g -D_GNU_SOURCE -DDEBUG -Wstrict-prototypes -Wdeclaration-after-statement
CC = gcc
LIBS = -lnftnl -lmnl
ARCH := $(shell uname -m | grep -q "x86_64" && echo 64)
all: test_nfct_get testnftnlrdr
clean:
$(RM) *.o testnftnlcrdr testnftnlpinhole 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)
test_nfct_get: test_nfct_get.o test_nfct_get.o -lmnl -lnetfilter_conntrack
test_nfct_get.o: test_nfct_get.c
testnftnlrdr_peer.o: testnftnlrdr_peer.c
testnftnlrdr_dscp.o: testnftnlrdr_dscp.c
nftnlrdr.o: nftnlrdr.c nftnlrdr.h
nftnlrdr_misc.o: nftnlrdr_misc.c
iptpinhole.o: iptpinhole.c iptpinhole.h
upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h
$(CC) -c -o $@ $<

View File

@ -0,0 +1,258 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <arpa/inet.h>
#ifdef USE_NFCT
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <linux/netfilter/nf_conntrack_tcp.h>
struct data_cb_s
{
struct sockaddr_storage * ext;
uint8_t found;
};
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
struct nf_conntrack *ct;
struct data_cb_s * d = (struct data_cb_s*) data;
struct sockaddr_in* ext4 = (struct sockaddr_in*) d->ext;
ct = nfct_new();
if (ct == NULL)
return MNL_CB_OK;
nfct_nlmsg_parse(nlh, ct);
if (data) {
ext4->sin_addr.s_addr = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST);
ext4->sin_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
}
d->found = 1;
nfct_destroy(ct);
return MNL_CB_OK;
}
int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto,
struct sockaddr_storage* ret_ext)
{
struct mnl_socket *nl;
struct nlmsghdr *nlh;
struct nfgenmsg *nfh;
char buf[MNL_SOCKET_BUFFER_SIZE];
unsigned int seq, portid;
struct nf_conntrack *ct;
int ret;
struct data_cb_s data;
if ((!src)&&(!dst)) {
return 0;
}
if (src->sa_family != dst->sa_family) {
return 0;
}
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
// perror("mnl_socket_open");
goto free_nl;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
// perror("mnl_socket_bind");
goto free_nl;
}
portid = mnl_socket_get_portid(nl);
memset(buf, 0, sizeof(buf));
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
nlh->nlmsg_seq = seq = time(NULL);
nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
nfh->nfgen_family = src->sa_family;
nfh->version = NFNETLINK_V0;
nfh->res_id = 0;
ct = nfct_new();
if (ct == NULL) {
goto free_nl;
}
nfct_set_attr_u8(ct, ATTR_L3PROTO, src->sa_family);
if (src->sa_family == AF_INET) {
struct sockaddr_in *src4 = (struct sockaddr_in *)src;
struct sockaddr_in *dst4 = (struct sockaddr_in *)dst;
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, src4->sin_addr.s_addr);
nfct_set_attr_u32(ct, ATTR_IPV4_DST, dst4->sin_addr.s_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, src4->sin_port);
nfct_set_attr_u16(ct, ATTR_PORT_DST, dst4->sin_port);
} else if (src->sa_family == AF_INET6) {
struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)src;
struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
nfct_set_attr(ct, ATTR_IPV6_SRC, &src6->sin6_addr);
nfct_set_attr(ct, ATTR_IPV6_DST, &dst6->sin6_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, src6->sin6_port);
nfct_set_attr_u16(ct, ATTR_PORT_DST, dst6->sin6_port);
}
nfct_set_attr_u8(ct, ATTR_L4PROTO, proto);
nfct_nlmsg_build(nlh, ct);
ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
if (ret == -1) {
goto free_ct;
}
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
data.ext = ret_ext;
data.found = 0;
while (ret > 0) {
ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &data);
if (ret <= MNL_CB_STOP)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
free_ct:
nfct_destroy(ct);
free_nl:
mnl_socket_close(nl);
return data.found;
}
#else
#define DST "dst="
#define DST_PORT "dport="
#define SRC "src="
#define SRC_PORT "sport="
#define IP_CONNTRACK_LOCATION "/proc/net/ip_conntrack"
#define NF_CONNTRACK_LOCATION "/proc/net/nf_conntrack"
int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto,
struct sockaddr_storage* ret_ext)
{
FILE *f;
int af;
if (!src)
return -2;
af = src->sa_family;
if ((f = fopen(NF_CONNTRACK_LOCATION, "r")) == NULL) {
if ((f = fopen(IP_CONNTRACK_LOCATION, "r")) == NULL) {
printf("could not read info about connections from the kernel, "
"make sure netfilter is enabled in kernel or by modules.\n");
return -1;
}
}
while (!feof(f)) {
char line[256], *str;
memset(line, 0, sizeof(line));
str = fgets(line, sizeof(line), f);
if (line[0] != 0) {
char *token, *saveptr;
int j;
uint8_t src_f, src_port_f, dst_f, dst_port_f;
src_f=src_port_f=dst_f=dst_port_f=0;
for (j = 1; ; j++, str = NULL) {
token = strtok_r(str, " ", &saveptr);
if (token == NULL)
break;
if ((j==2)&&(af!=atoi(token)))
break;
if ((j==4)&&(proto!=atoi(token)))
break;
if (j<=4)
continue;
if (strncmp(token, SRC, sizeof(SRC) - 1) == 0) {
char *srcip = token + sizeof(SRC) - 1;
uint32_t buf[4];
memset(buf,0,sizeof(buf));
if (inet_pton(af, srcip, buf)!=1)
break;
if (af==AF_INET) {
struct sockaddr_in *src4=(struct sockaddr_in*)src;
if (!src_f) {
if (src4->sin_addr.s_addr != buf[0])
break;
src_f = 1;
}
}
}
if (strncmp(token, SRC_PORT, sizeof(SRC_PORT) - 1) == 0) {
char *src_port = token + sizeof(SRC_PORT) - 1;
uint16_t port=atoi(src_port);
if (af==AF_INET) {
struct sockaddr_in *src4=(struct sockaddr_in*)src;
if (!src_port_f) {
if (ntohs(src4->sin_port) != port)
break;
src_port_f = 1;
}
}
}
if (strncmp(token, DST, sizeof(DST) - 1) == 0) {
char *dstip = token + sizeof(DST) - 1;
uint32_t buf[4];
memset(buf,0,sizeof(buf));
if (inet_pton(af, dstip, buf)!=1)
break;
if (af==AF_INET) {
struct sockaddr_in *dst4=(struct sockaddr_in*)dst;
if (!dst_f) {
if (dst4->sin_addr.s_addr != buf[0])
break;
dst_f = 1;
} else {
struct sockaddr_in*ret4=(struct sockaddr_in*)ret_ext;
ret_ext->ss_family = AF_INET;
ret4->sin_addr.s_addr = buf[0];
}
}
}
if (strncmp(token, DST_PORT, sizeof(DST_PORT)-1) == 0) {
char *dst_port = token + sizeof(DST_PORT) - 1;
uint16_t port=atoi(dst_port);
if (af==AF_INET) {
struct sockaddr_in *dst4=(struct sockaddr_in*)dst;
if (!dst_port_f) {
if (ntohs(dst4->sin_port) != port)
break;
dst_port_f = 1;
} else {
struct sockaddr_in*ret4=(struct sockaddr_in*)ret_ext;
ret_ext->ss_family = AF_INET;
ret4->sin_port = htons(port);
}
}
}
}
if (src_f && src_port_f && dst_f && dst_port_f) {
fclose(f);
return 1;
}
}
}
fclose(f);
return 0;
}
#endif

View File

@ -0,0 +1,478 @@
/*
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2015 Tomofumi Hayashi
*
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution.
*/
#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 <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"
/* dummy init and shutdown functions */
int init_redirect(void)
{
return 0;
}
void shutdown_redirect(void)
{
return;
}
int
add_redirect_rule2(const char * ifname,
const char * rhost, unsigned short eport,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp)
{
struct nft_rule *r;
UNUSED(timestamp);
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);
}
/*
* This function submit the rule as following:
* nft add rule nat miniupnpd-pcp-peer ip
* saddr <iaddr> ip daddr <rhost> tcp sport <iport>
* tcp dport <rport> snat <eaddr>:<eport>
*/
int
add_peer_redirect_rule2(const char * ifname,
const char * rhost, unsigned short rport,
const char * eaddr, unsigned short eport,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp)
{
struct nft_rule *r;
UNUSED(ifname); UNUSED(timestamp);
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);
}
/*
* This function submit the rule as following:
* nft add rule filter miniupnpd
* ip daddr <iaddr> tcp dport <iport> accept
*
*/
int
add_filter_rule2(const char * ifname,
const char * rhost, const char * iaddr,
unsigned short eport, unsigned short iport,
int proto, const char * desc)
{
struct nft_rule *r = NULL;
in_addr_t rhost_addr = 0;
if (rhost != NULL) {
rhost_addr = inet_addr(rhost);
}
r = rule_set_filter(NFPROTO_IPV4, ifname, proto,
rhost_addr, inet_addr(iaddr), eport, iport,
desc, 0);
return nft_send_request(r, NFT_MSG_NEWRULE);
}
/*
* add_peer_dscp_rule2() is not supported due to nft does not support
* dscp set.
*/
int
add_peer_dscp_rule2(const char * ifname,
const char * rhost, unsigned short rport,
unsigned char dscp,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp)
{
UNUSED(ifname); UNUSED(rhost); UNUSED(rport);
UNUSED(dscp); UNUSED(iaddr); UNUSED(iport); UNUSED(proto);
UNUSED(desc); UNUSED(timestamp);
syslog(LOG_ERR, "add_peer_dscp_rule2: not supported");
return 0;
}
/*
* Clear all rules corresponding eport/proto
*/
int
delete_redirect_and_filter_rules(unsigned short eport, int proto)
{
rule_t *p;
struct nft_rule *r = NULL;
in_addr_t iaddr = 0;
uint16_t iport = 0;
extern void print_rule(rule_t *r) ;
printf("delete_redirect_and_filter_rules(%d %d)\n", eport, proto);
reflesh_nft_cache(NFPROTO_IPV4);
LIST_FOREACH(p, &head, entry) {
if (p->eport == eport && p->proto == proto &&
(p->type == RULE_NAT || p->type == RULE_SNAT)) {
iaddr = p->iaddr;
iport = p->iport;
r = rule_del_handle(p);
/* Todo: send bulk request */
nft_send_request(r, NFT_MSG_DELRULE);
}
}
if (iaddr == 0 && iport == 0) {
return -1;
}
reflesh_nft_cache(NFPROTO_IPV4);
LIST_FOREACH(p, &head, 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);
}
}
return 0;
}
/*
* get peer by index as array.
* return -1 when not found.
*/
int
get_peer_rule_by_index(int index,
char * ifname, unsigned short * eport,
char * iaddr, int iaddrlen, unsigned short * iport,
int * proto, char * desc, int desclen,
char * rhost, int rhostlen, unsigned short * rport,
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);
printf("get_peer_rule_by_index()\n");
reflesh_nft_cache(NFPROTO_IPV4);
for (i = 0; peer_cache[i] != NULL; i++) {
if (index == i) {
r = peer_cache[i];
if (ifname != NULL) {
if_indextoname(r->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);
}
/*
* TODO: Implement counter in case of add {nat,filter}
*/
return 0;
}
}
return -1;
}
/*
* get_redirect_rule()
* returns -1 if the rule is not found
*/
int
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
char * iaddr, int iaddrlen, unsigned short * iport,
char * desc, int desclen,
char * rhost, int rhostlen,
unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes)
{
return get_nat_redirect_rule(NFT_TABLE_NAT,
ifname, eport, proto,
iaddr, iaddrlen, iport,
desc, desclen,
rhost, rhostlen,
timestamp, packets, bytes);
}
/*
* get_redirect_rule_by_index()
* return -1 when the rule was not found
*/
int
get_redirect_rule_by_index(int index,
char * ifname, unsigned short * eport,
char * iaddr, int iaddrlen, unsigned short * iport,
int * proto, char * desc, int desclen,
char * rhost, int rhostlen,
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);
printf("get_redirect_rule_by_index()\n");
reflesh_nft_cache(NFPROTO_IPV4);
for (i = 0; redirect_cache[i] != NULL; i++) {
if (index == i) {
r = redirect_cache[i];
if (ifname != NULL) {
if_indextoname(r->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);
}
/*
* TODO: Implement counter in case of add {nat,filter}
*/
return 0;
}
}
return -1;
}
/*
* return -1 not found.
* return 0 found
*/
int
get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
unsigned short eport, int proto,
char * iaddr, int iaddrlen, unsigned short * iport,
char * desc, int desclen,
char * rhost, int rhostlen,
unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes)
{
rule_t *p;
struct in_addr addr;
char *addr_str;
UNUSED(nat_chain_name);
UNUSED(ifname);
UNUSED(iaddrlen);
UNUSED(timestamp);
UNUSED(packets);
UNUSED(bytes);
printf("get_nat_redirect_rule()\n");
reflesh_nft_cache(NFPROTO_IPV4);
LIST_FOREACH(p, &head, 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 (desc != NULL && p->desc) {
strncpy(desc, p->desc, desclen);
}
*iport = p->iport;
return 0;
}
}
return -1;
}
/*
* return an (malloc'ed) array of "external" port for which there is
* a port mapping. number is the size of the array
*/
unsigned short *
get_portmappings_in_range(unsigned short startport, unsigned short endport,
int proto, unsigned int * number)
{
uint32_t capacity;
rule_t *p;
unsigned short *array;
unsigned short *tmp;
printf("get_portmappings_in_range()\n");
*number = 0;
capacity = 128;
array = calloc(capacity, sizeof(unsigned short));
if (array == NULL) {
syslog(LOG_ERR, "get_portmappings_in_range(): calloc error");
return NULL;
}
LIST_FOREACH(p, &head, entry) {
if (p->proto == proto &&
startport <= p->eport &&
p->eport <= endport) {
if (*number >= capacity) {
tmp = realloc(array,
sizeof(unsigned short)*capacity);
if (tmp == NULL) {
syslog(LOG_ERR,
"get_portmappings_in_range(): "
"realloc(%u) error",
(unsigned)sizeof(unsigned short)*capacity);
*number = 0;
free(array);
return NULL;
}
array = tmp;
}
array[*number] = p->eport;
(*number)++;
}
}
return array;
}
/* for debug */
/* read the "filter" and "nat" tables */
int
list_redirect_rule(const char * ifname)
{
rule_t *p;
UNUSED(ifname);
reflesh_nft_cache(NFPROTO_IPV4);
LIST_FOREACH(p, &head, entry) {
print_rule(p);
}
return -1;
return 0;
}
#if 0
/* delete_rule_and_commit() :
* subfunction used in delete_redirect_and_filter_rules() */
static int
delete_rule_and_commit(unsigned int index, IPTC_HANDLE h,
const char * miniupnpd_chain,
const char * logcaller)
{
/* TODO: Implement it */
}
/* TODO: Implement it */
static void
print_iface(const char * iface, const unsigned char * mask, int invert)
{
unsigned i;
if(mask[0] == 0)
return;
if(invert)
printf("! ");
for(i=0; i<IFNAMSIZ; i++)
{
if(mask[i])
{
if(iface[i])
putchar(iface[i]);
}
else
{
if(iface[i-1])
putchar('+');
break;
}
}
return ;
}
#ifdef DEBUG
static void
printip(uint32_t ip)
{
printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
(ip >> 8) & 0xff, ip & 0xff);
}
#endif
#endif /* if 0 */

View File

@ -0,0 +1,84 @@
/*
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2015 Tomofumi Hayashi
*
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution.
*/
#ifndef NFTNLRDR_H_INCLUDED
#define NFTNLRDR_H_INCLUDED
#include "../commonrdr.h"
int init_redirect(void);
void shutdown_redirect(void);
int
add_redirect_rule2(const char * ifname,
const char * rhost, unsigned short eport,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp);
int
add_peer_redirect_rule2(const char * ifname,
const char * rhost, unsigned short rport,
const char * eaddr, unsigned short eport,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp);
int
add_filter_rule2(const char * ifname,
const char * rhost, const char * iaddr,
unsigned short eport, unsigned short iport,
int proto, const char * desc);
int
delete_redirect_and_filter_rules(unsigned short eport, int proto);
int
add_peer_dscp_rule2(const char * ifname,
const char * rhost, unsigned short rport,
unsigned char dscp,
const char * iaddr, unsigned short iport, int proto,
const char * desc, unsigned int timestamp);
int
get_peer_rule_by_index(int index,
char * ifname, unsigned short * eport,
char * iaddr, int iaddrlen, unsigned short * iport,
int * proto, char * desc, int desclen,
char * rhost, int rhostlen, unsigned short * rport,
unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes);
int
get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
unsigned short eport, int proto,
char * iaddr, int iaddrlen, unsigned short * iport,
char * desc, int desclen,
char * rhost, int rhostlen,
unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes);
int
get_redirect_rule_by_index(int index,
char * ifname, unsigned short * eport,
char * iaddr, int iaddrlen, unsigned short * iport,
int * proto, char * desc, int desclen,
char * rhost, int rhostlen,
unsigned int * timestamp,
u_int64_t * packets, u_int64_t * bytes);
unsigned short *
get_portmappings_in_range(unsigned short startport, unsigned short endport,
int proto, unsigned int * number);
/* in nfct_get.c */
int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto,
struct sockaddr* ret_ext);
/* for debug */
int
list_redirect_rule(const char * ifname);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
/*
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2015 Tomofumi Hayashi
*
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution.
*/
#include <sys/queue.h>
#define NFT_TABLE_NAT "nat"
#define NFT_TABLE_FILTER "filter"
enum rule_reg_type {
RULE_REG_NONE,
RULE_REG_IIF,
RULE_REG_IP_SRC_ADDR,
RULE_REG_IP_DEST_ADDR,
RULE_REG_IP_SD_ADDR, /* source & dest */
RULE_REG_IP_PROTO,
RULE_REG_TCP_DPORT,
RULE_REG_TCP_SD_PORT, /* source & dest */
RULE_REG_IMM_VAL,
RULE_REG_MAX,
};
enum rule_type {
RULE_NONE,
RULE_NAT,
RULE_SNAT,
RULE_FILTER,
RULE_COUNTER,
};
typedef struct rule_ {
LIST_ENTRY(rule_t) entry;
char * table;
char * chain;
uint64_t handle;
enum rule_type type;
uint32_t nat_type;
uint32_t filter_action;
uint32_t family;
uint32_t ifidx;
in_addr_t eaddr;
in_addr_t iaddr;
in_addr_t rhost;
uint16_t eport;
uint16_t iport;
uint16_t rport;
uint8_t proto;
enum rule_reg_type reg1_type;
enum rule_reg_type reg2_type;
uint32_t reg1_val;
uint32_t reg2_val;
uint64_t packets;
uint64_t bytes;
char *desc;
} rule_t;
LIST_HEAD(rule_list, rule_);
extern struct rule_list head;
extern rule_t **peer_cache;
extern rule_t **redirect_cache;
int
nft_send_request(struct nft_rule * rule, uint16_t cmd);
struct nft_rule *
rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto,
in_addr_t rhost, unsigned short eport,
in_addr_t ihost, uint32_t iport,
const char *descr,
const char *handle);
struct nft_rule *
rule_set_snat(uint8_t family, uint8_t proto,
in_addr_t rhost, unsigned short rport,
in_addr_t ehost, unsigned short eport,
in_addr_t ihost, unsigned short iport,
const char *descr,
const char *handle);
struct nft_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 nft_rule *
rule_del_handle(rule_t *r);
void
reflesh_nft_cache(uint32_t family);
void print_rule(rule_t *r);

View File

@ -0,0 +1,5 @@
#! /sbin/nft -f
delete chain nat miniupnpd
delete chain nat miniupnpd-pcp-peer
delete chain filter miniupnpd

View File

@ -0,0 +1,5 @@
#! /sbin/nft -f
flush chain ip nat miniupnpd
flush chain ip nat miniupnpd-pcp-peer
flush chain ip filter miniupnpd

View File

@ -0,0 +1,51 @@
#! /bin/sh
nft list table nat > /dev/null
nft_nat_exists=$?
nft list table filter > /dev/null
nft_filter_exists=$?
nft list table mangle > /dev/null
nft_mangle_exists=$?
if [ $nft_nat_exists -eq "1" ]; then
echo "create nat"
nft "add table nat"
fi
if [ $nft_filter_exists -eq "1" ]; then
echo "create filter"
nft "add table 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_nat_miniupnpd_exists=$?
nft list chain nat miniupnpd-pcp-peer > /dev/null
nft_nat_miniupnpd_pcp_peer_exists=$?
nft list chain filter miniupnpd > /dev/null
nft_filter_miniupnpd_exists=$?
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 { \
type nat hook prerouting priority -200 ; }"
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 { \
type nat hook postrouting priority -300 ; }"
fi
if [ $nft_filter_miniupnpd_exists -eq "1" ]; then
echo "create chain in filter "
nft "add chain filter miniupnpd { \
type nat hook forward priority -200 ; }"
fi
if [ $nft_mangle_miniupnpd_exists -eq "1" ]; then
echo "create chain in mangle"
nft "add chain mangle miniupnpd { \
type nat hook prerouting priority -100 ; }"
fi

View File

@ -0,0 +1,5 @@
#! /sbin/nft -f
delete rule nat miniupnpd
delete rule nat miniupnpd-pcp-peer
delete rule filter miniupnpd

View File

@ -0,0 +1,50 @@
#include "nfct_get.c"
int main(int argc, char *argv[])
{
struct sockaddr_storage src, dst, ext;
char buff[INET6_ADDRSTRLEN];
if (argc!=5)
return 0;
if (1 != inet_pton(AF_INET, argv[1],
&((struct sockaddr_in*)&src)->sin_addr)) {
if (1 != inet_pton(AF_INET6, argv[1],
&((struct sockaddr_in6*) &src)->sin6_addr)) {
perror("bad input param");
} else {
((struct sockaddr_in6*)(&src))->sin6_port = htons(atoi(argv[2]));
src.ss_family = AF_INET6;
}
} else {
((struct sockaddr_in*)(&src))->sin_port = htons(atoi(argv[2]));
src.ss_family = AF_INET;
}
if (1 != inet_pton(AF_INET, argv[3],
&((struct sockaddr_in*)&dst)->sin_addr)) {
if (1 != inet_pton(AF_INET6, argv[3],
&((struct sockaddr_in6*) &dst)->sin6_addr)) {
perror("bad input param");
} else {
((struct sockaddr_in6*)(&dst))->sin6_port = htons(atoi(argv[4]));
dst.ss_family = AF_INET6;
}
} else {
((struct sockaddr_in*)(&dst))->sin_port = htons(atoi(argv[4]));
dst.ss_family = AF_INET;
}
if (get_nat_ext_addr((struct sockaddr*)&src, (struct sockaddr*)&dst,
IPPROTO_TCP, &ext)) {
printf("Ext address %s:%d\n",
inet_ntop(src.ss_family,
&((struct sockaddr_in*)&ext)->sin_addr,
buff, sizeof(buff)),
ntohs(((struct sockaddr_in*)(&ext))->sin_port));
} else {
printf("no entry\n");
}
return 0;
}

View File

@ -0,0 +1,91 @@
/* $Id: testiptcrdr.c,v 1.18 2012/04/24 22:41:53 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-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 "nftnlrdr.h"
#include "../commonrdr.h"
#ifndef PRIu64
#define PRIu64 "llu"
#endif
static int
add_filter_rule(int proto, const char * rhost,
const char * iaddr, unsigned short iport)
{
return add_filter_rule2(NULL, rhost, iaddr, 0, iport, proto, NULL);
}
static int
addnatrule(int proto, unsigned short eport,
const char * iaddr, unsigned short iport,
const char * rhost)
{
return add_redirect_rule2(NULL, rhost, eport, iaddr, iport, proto, NULL, 0);
}
int
main(int argc, char ** argv)
{
unsigned short eport, iport;
const char * iaddr;
if(argc<4) {
printf("Usage %s <ext_port> <internal_ip> <internal_port>\n", argv[0]);
return -1;
}
openlog("testnftnlrdr", LOG_PERROR|LOG_CONS, LOG_LOCAL0);
eport = (unsigned short)atoi(argv[1]);
iaddr = argv[2];
iport = (unsigned short)atoi(argv[3]);
printf("trying to redirect port %hu to %s:%hu\n", eport, iaddr, iport);
if(addnatrule(IPPROTO_TCP, eport, iaddr, iport, NULL) < 0) {
printf("addnatrule() failed!\n");
return -1;
}
if(add_filter_rule(IPPROTO_TCP, NULL, iaddr, iport) < 0) {
printf("add_filter_rule() failed!\n");
return -1;
}
/* test */
{
unsigned short p1, p2;
char addr[16];
int proto2;
char desc[256];
char rhost[256];
unsigned int timestamp;
u_int64_t packets, bytes;
desc[0] = '\0';
printf("test0\n");
if(get_redirect_rule_by_index(0, "", &p1,
addr, sizeof(addr), &p2,
&proto2, desc, sizeof(desc),
rhost, sizeof(rhost),
&timestamp,
&packets, &bytes) < 0)
{
printf("rule not found\n");
}
else
{
printf("redirected port %hu to %s:%hu proto %d packets=%" PRIu64 " bytes=%" PRIu64 "\n",
p1, addr, p2, proto2, packets, bytes);
}
printf("test\n");
}
printf("trying to list nat rules :\n");
list_redirect_rule(argv[1]);
printf("deleting\n");
delete_redirect_and_filter_rules(eport, IPPROTO_TCP);
return 0;
}

View File

@ -0,0 +1,37 @@
/* $Id: tiny_nf_nat.h,v 1.1 2011/07/30 13:14:36 nanard Exp $ */
/* Only what miniupnpd needs, until linux-libc-dev gains nf_nat.h */
#ifndef TINY_NF_NAT_H
#define TINY_NF_NAT_H
#include <linux/types.h>
#define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
#define IP_NAT_RANGE_PROTO_RANDOM 4
#define IP_NAT_RANGE_PERSISTENT 8
union nf_conntrack_man_proto {
__be16 all;
struct { __be16 port; } tcp;
struct { __be16 port; } udp;
struct { __be16 id; } icmp;
struct { __be16 port; } dccp;
struct { __be16 port; } sctp;
struct { __be16 key; } gre;
};
struct nf_nat_range {
unsigned int flags;
__be32 min_ip, max_ip;
union nf_conntrack_man_proto min, max;
};
struct nf_nat_multi_range_compat {
unsigned int rangesize;
struct nf_nat_range range[1];
};
#define nf_nat_multi_range nf_nat_multi_range_compat
#endif /*TINY_NF_NAT_H*/