Add initial PCP support
This commit is contained in:
parent
87a7f05be6
commit
9e1ffd5cd9
|
@ -45,12 +45,12 @@ MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8
|
|||
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||
upnpreplyparse.o minixml.o \
|
||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o\
|
||||
upnpevents.o upnputils.o getconnstatus.o \
|
||||
upnppinhole.o
|
||||
upnppinhole.o pcplearndscp.o
|
||||
|
||||
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
|
||||
NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o
|
||||
NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.o
|
||||
|
||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||
|
||||
|
@ -69,10 +69,9 @@ CFLAGS += -DIPTABLES_143
|
|||
endif
|
||||
|
||||
CFLAGS += $(shell pkg-config --cflags libiptc)
|
||||
LIBS += $(shell pkg-config --libs-only-l libiptc)
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libiptc)
|
||||
LDFLAGS += $(shell pkg-config --libs-only-L libiptc)
|
||||
LDFLAGS += $(shell pkg-config --libs-only-other libiptc)
|
||||
|
||||
else
|
||||
|
||||
ifeq "$(wildcard /etc/gentoo-release )" ""
|
||||
|
@ -140,6 +139,13 @@ endif # ifdef PCFILE_FOUND
|
|||
|
||||
LIBS += -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)
|
||||
CFLAGS += -DUSE_NFCT
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libmnl)
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libnetfilter_conntrack)
|
||||
endif # ($(TEST),1)
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
|
@ -216,7 +222,7 @@ 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 natpmp.h commonrdr.h
|
||||
miniupnpd.o: upnputils.h ifacewatcher.h
|
||||
miniupnpd.o: upnputils.h ifacewatcher.h pcpserver.h pcplearndscp.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
|
||||
|
@ -234,15 +240,18 @@ upnpredirect.o: netfilter/iptcrdr.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
|
||||
upnpglobalvars.o: miniupnpdtypes.h pcplearndscp.h
|
||||
options.o: config.h options.h upnppermissions.h upnpglobalvars.h
|
||||
options.o: miniupnpdtypes.h
|
||||
options.o: miniupnpdtypes.h pcplearndscp.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 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
|
||||
pcpserver.o: macros.h config.h pcpserver.h pcp_msg_struct.h upnpglobalvars.h
|
||||
pcpserver.o: upnpredirect.h
|
||||
pcplearndscp.o: config.h pcplearndscp.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
|
||||
|
|
|
@ -12,12 +12,19 @@ case "$argv" in
|
|||
--igd2) IGD2=1 ;;
|
||||
--strict) STRICT=1 ;;
|
||||
--leasefile) LEASEFILE=1 ;;
|
||||
--pcp) PCP=1 ;;
|
||||
--pcp-peer)
|
||||
PCP=1
|
||||
PCP_PEER=1
|
||||
;;
|
||||
--help|-h)
|
||||
echo "Usage : $0 [options]"
|
||||
echo " --ipv6 enable IPv6"
|
||||
echo " --igd2 build an IGDv2 instead of an IGDv1"
|
||||
echo " --strict be more strict regarding compliance with UPnP specifications"
|
||||
echo " --leasefile enable lease file"
|
||||
echo " --pcp enable PCP"
|
||||
echo " --pcp-peer enable PCP PEER operation"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
|
@ -325,6 +332,31 @@ echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFI
|
|||
echo "#define ENABLE_NATPMP" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
if [ -n "$PCP" ]; then
|
||||
echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_PCP" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
else
|
||||
echo "/* Uncomment the following line to enable PCP operations */" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_PCP*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
fi
|
||||
|
||||
echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE}
|
||||
if [ -n "$PCP_PEER" ]; then
|
||||
echo "/* Comment the following line to disable PCP PEER operation */" >> ${CONFIGFILE}
|
||||
echo "#define PCP_PEER" >> ${CONFIGFILE}
|
||||
else
|
||||
echo "/* Uncomment the following line to enable PCP PEER operation */" >> ${CONFIGFILE}
|
||||
echo "/*#define PCP_PEER*/" >> ${CONFIGFILE}
|
||||
fi
|
||||
echo "#ifdef PCP_PEER" >> ${CONFIGFILE}
|
||||
echo "/*#define PCP_FLOWP*/" >> ${CONFIGFILE}
|
||||
echo "#endif //PCP_PEER" >> ${CONFIGFILE}
|
||||
echo "/*#define PCP_SADSCP*/" >> ${CONFIGFILE}
|
||||
echo "#endif //ENABLE_PCP" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
echo "/* Uncomment the following line to enable generation of" >> ${CONFIGFILE}
|
||||
echo " * filter rules with pf */" >> ${CONFIGFILE}
|
||||
echo "/*#define PF_ENABLE_FILTER_RULES*/">> ${CONFIGFILE}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "getifaddr.h"
|
||||
#if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6)
|
||||
#if defined(USE_GETIFADDRS) || defined(ENABLE_IPV6) || defined(ENABLE_PCP)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
|
@ -118,6 +118,56 @@ getifaddr(const char * ifname, char * buf, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PCP
|
||||
int getifaddr_in6(const char * ifname, struct in6_addr * addr){
|
||||
struct ifaddrs * ifap;
|
||||
struct ifaddrs * ife;
|
||||
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
if(getifaddrs(&ifap)<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifaddrs: %m");
|
||||
return -1;
|
||||
}
|
||||
for(ife = ifap; ife; ife = ife->ifa_next)
|
||||
{
|
||||
int found = 0;
|
||||
/* skip other interfaces if one was specified */
|
||||
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||
continue;
|
||||
if(ife->ifa_addr == NULL)
|
||||
continue;
|
||||
switch(ife->ifa_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
addr->s6_addr32[0]=0;
|
||||
addr->s6_addr32[1]=0;
|
||||
addr->s6_addr32[2]=htonl(0xffff);
|
||||
addr->s6_addr32[3]=((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr;
|
||||
//inet_ntop(ife->ifa_addr->sa_family,
|
||||
// &((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
||||
// buf, len);
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if(!IN6_IS_ADDR_LOOPBACK(&addr->s6_addr32)
|
||||
&& !IN6_IS_ADDR_LINKLOCAL(&addr->s6_addr32)) {
|
||||
memcpy(addr->s6_addr32, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, sizeof(addr->s6_addr32));
|
||||
found = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
int
|
||||
find_ipv6_addr(const char * ifname,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define GETIFADDR_H_INCLUDED
|
||||
|
||||
struct in_addr;
|
||||
struct in6_addr;
|
||||
|
||||
/* getifaddr()
|
||||
* take a network interface name and write the
|
||||
|
@ -18,6 +19,9 @@ int
|
|||
getifaddr(const char * ifname, char * buf, int len,
|
||||
struct in_addr * addr, struct in_addr * mask);
|
||||
|
||||
int
|
||||
getifaddr_in6(const char * ifname, struct in6_addr* addr);
|
||||
|
||||
/* find a non link local IP v6 address for the interface.
|
||||
* if ifname is NULL, look for all interfaces */
|
||||
int
|
||||
|
|
|
@ -65,6 +65,11 @@
|
|||
#include "upnpevents.h"
|
||||
#ifdef ENABLE_NATPMP
|
||||
#include "natpmp.h"
|
||||
#ifdef ENABLE_PCP
|
||||
#include "pcpserver.h"
|
||||
#else
|
||||
#define PCP_MAX_LEN 32
|
||||
#endif
|
||||
#endif
|
||||
#include "commonrdr.h"
|
||||
#include "upnputils.h"
|
||||
|
@ -838,6 +843,20 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
/*enablenatpmp = atoi(ary_options[i].value);*/
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_PCP
|
||||
case UPNPPCPMINLIFETIME:
|
||||
min_lifetime = atoi(ary_options[i].value);
|
||||
if (min_lifetime > 120 ) {
|
||||
min_lifetime = 120;
|
||||
}
|
||||
break;
|
||||
case UPNPPCPMAXLIFETIME:
|
||||
max_lifetime = atoi(ary_options[i].value);
|
||||
if (max_lifetime > 86400 ) {
|
||||
max_lifetime = 86400;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef PF_ENABLE_FILTER_RULES
|
||||
case UPNPQUICKRULES:
|
||||
if(strcmp(ary_options[i].value, "no") == 0)
|
||||
|
@ -865,6 +884,12 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
optionsfile);
|
||||
}
|
||||
}
|
||||
/* if lifetimes ae inverse*/
|
||||
if (min_lifetime >= max_lifetime) {
|
||||
fprintf(stderr, "Minimum lifetime (%lu) is greater than or equal to maximum lifetime (%lu).\n", min_lifetime, max_lifetime);
|
||||
fprintf(stderr, "Check your configuration file.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* DISABLE_CONFIG_FILE */
|
||||
|
||||
|
@ -1362,7 +1387,11 @@ main(int argc, char * * argv)
|
|||
|
||||
syslog(LOG_INFO, "Starting%s%swith external interface %s",
|
||||
#ifdef ENABLE_NATPMP
|
||||
#ifdef ENABLE_PCP
|
||||
GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP/PCP " : " ",
|
||||
#else
|
||||
GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP " : " ",
|
||||
#endif
|
||||
#else
|
||||
" ",
|
||||
#endif
|
||||
|
@ -1443,12 +1472,21 @@ main(int argc, char * * argv)
|
|||
if(GETFLAG(ENABLENATPMPMASK))
|
||||
{
|
||||
if(OpenAndConfNATPMPSockets(snatpmp) < 0)
|
||||
#ifdef ENABLE_PCP
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open sockets for NAT-PMP/PCP.");
|
||||
} else {
|
||||
syslog(LOG_NOTICE, "Listening for NAT-PMP/PCP traffic on port %u",
|
||||
NATPMP_PORT);
|
||||
}
|
||||
#else
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open sockets for NAT PMP.");
|
||||
} else {
|
||||
syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
|
||||
NATPMP_PORT);
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
ScanNATPMPforExpiration();
|
||||
#endif
|
||||
|
@ -1763,7 +1801,26 @@ main(int argc, char * * argv)
|
|||
{
|
||||
if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset))
|
||||
{
|
||||
ProcessIncomingNATPMPPacket(snatpmp[i]);
|
||||
unsigned char msg_buff[PCP_MAX_LEN];
|
||||
struct sockaddr_in senderaddr;
|
||||
int len;
|
||||
memset(msg_buff, 0, PCP_MAX_LEN);
|
||||
len = ReceiveNATPMPOrPCPPacket(snatpmp[i], &senderaddr,
|
||||
msg_buff, sizeof(msg_buff));
|
||||
if (len < 1)
|
||||
continue;
|
||||
#ifdef ENABLE_PCP
|
||||
if (msg_buff[0]==0) { // version equals to 0 -> means NAT-PMP
|
||||
ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len,
|
||||
&senderaddr);
|
||||
} else { // everything else can be PCP
|
||||
ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len,
|
||||
&senderaddr);
|
||||
}
|
||||
|
||||
#else
|
||||
ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len, &senderaddr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,11 @@ enable_natpmp=yes
|
|||
# enable UPNP support (default is yes)
|
||||
enable_upnp=yes
|
||||
|
||||
# configure minimal and maximal lifetime of the port mapping in seconds
|
||||
# 120s and 86400s (24h) are suggested values from PCP-base
|
||||
min_lifetime=120
|
||||
max_lifetime=86400
|
||||
|
||||
# chain names for netfilter (not used for pf or ipf).
|
||||
# default is MINIUPNPD for both
|
||||
#upnp_forward_chain=forwardUPnP
|
||||
|
|
|
@ -118,20 +118,21 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr
|
|||
#endif
|
||||
}
|
||||
|
||||
/** read the request from the socket, process it and then send the
|
||||
* response back.
|
||||
/*
|
||||
* Receives NATPMP and PCP packets and stores them in msg_buff.
|
||||
* The sender information is stored in senderaddr.
|
||||
* Returns number of bytes recevied, even if number is negative.
|
||||
*/
|
||||
void ProcessIncomingNATPMPPacket(int s)
|
||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr,
|
||||
unsigned char *msg_buff, size_t msg_buff_size)
|
||||
{
|
||||
unsigned char req[32]; /* request udp packet */
|
||||
unsigned char resp[32]; /* response udp packet */
|
||||
int resplen;
|
||||
struct sockaddr_in senderaddr;
|
||||
socklen_t senderaddrlen = sizeof(senderaddr);
|
||||
|
||||
socklen_t senderaddrlen = sizeof(*senderaddr);
|
||||
int n;
|
||||
char senderaddrstr[16];
|
||||
n = recvfrom(s, req, sizeof(req), 0,
|
||||
(struct sockaddr *)&senderaddr, &senderaddrlen);
|
||||
|
||||
n = recvfrom(s, msg_buff, msg_buff_size, 0,
|
||||
(struct sockaddr *)senderaddr, &senderaddrlen);
|
||||
|
||||
if(n<0) {
|
||||
/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
|
||||
* other errors : log to LOG_ERR */
|
||||
|
@ -140,14 +141,34 @@ void ProcessIncomingNATPMPPacket(int s)
|
|||
errno != EINTR) {
|
||||
syslog(LOG_ERR, "recvfrom(natpmp): %m");
|
||||
}
|
||||
return;
|
||||
return n;
|
||||
}
|
||||
if(!inet_ntop(AF_INET, &senderaddr.sin_addr,
|
||||
senderaddrstr, sizeof(senderaddrstr))) {
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/** read the request from the socket, process it and then send the
|
||||
* response back.
|
||||
*/
|
||||
void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
||||
struct sockaddr_in *senderaddr)
|
||||
{
|
||||
unsigned char *req=msg_buff; /* request udp packet */
|
||||
unsigned char resp[32]; /* response udp packet */
|
||||
int resplen;
|
||||
//struct sockaddr_in senderaddr;
|
||||
//socklen_t senderaddrlen = sizeof(senderaddr);
|
||||
int n = len;
|
||||
char senderaddrstr[16];
|
||||
|
||||
if(!inet_ntop(AF_INET, &senderaddr->sin_addr,
|
||||
senderaddrstr, sizeof(senderaddrstr))) {
|
||||
syslog(LOG_ERR, "inet_ntop(natpmp): %m");
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
|
||||
senderaddrstr, ntohs(senderaddr.sin_port), n);
|
||||
senderaddrstr, ntohs(senderaddr->sin_port), n);
|
||||
|
||||
if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
|
||||
syslog(LOG_WARNING, "discarding NAT-PMP request (too short) %dBytes",
|
||||
n);
|
||||
|
@ -172,7 +193,7 @@ void ProcessIncomingNATPMPPacket(int s)
|
|||
} else switch(req[1]) {
|
||||
case 0: /* Public address request */
|
||||
syslog(LOG_INFO, "NAT-PMP public address request");
|
||||
FillPublicAddressResponse(resp, senderaddr.sin_addr.s_addr);
|
||||
FillPublicAddressResponse(resp, senderaddr->sin_addr.s_addr);
|
||||
resplen = 12;
|
||||
break;
|
||||
case 1: /* UDP port mapping request */
|
||||
|
@ -244,7 +265,7 @@ void ProcessIncomingNATPMPPacket(int s)
|
|||
}
|
||||
eport = 0; /* to indicate correct removing of port mapping */
|
||||
} else if(iport==0
|
||||
|| !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr.sin_addr, iport)) {
|
||||
|| !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) {
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
} else do {
|
||||
r = get_redirect_rule(ext_if_name, eport, proto,
|
||||
|
@ -306,7 +327,7 @@ void ProcessIncomingNATPMPPacket(int s)
|
|||
resp[3] = 5; /* Unsupported OPCODE */
|
||||
}
|
||||
n = sendto(s, resp, resplen, 0,
|
||||
(struct sockaddr *)&senderaddr, sizeof(senderaddr));
|
||||
(struct sockaddr *)senderaddr, sizeof(*senderaddr));
|
||||
if(n<0) {
|
||||
syslog(LOG_ERR, "sendto(natpmp): %m");
|
||||
} else if(n<resplen) {
|
||||
|
|
|
@ -20,7 +20,11 @@
|
|||
|
||||
int OpenAndConfNATPMPSockets(int * sockets);
|
||||
|
||||
void ProcessIncomingNATPMPPacket(int s);
|
||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr,
|
||||
unsigned char *msg_buff, size_t msg_buff_size);
|
||||
|
||||
void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
||||
struct sockaddr_in *senderaddr);
|
||||
|
||||
#if 0
|
||||
int ScanNATPMPforExpiration(void);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# $Id: Makefile,v 1.6 2012/04/26 13:50:48 nanard Exp $
|
||||
CFLAGS?=-Wall -g -D_GNU_SOURCE -DDEBUG -Wstrict-prototypes -Wdeclaration-after-statement -ansi
|
||||
CFLAGS?=-Wall -g -D_GNU_SOURCE -DDEBUG -Wstrict-prototypes -Wdeclaration-after-statement
|
||||
CC = gcc
|
||||
|
||||
#LIBS = -liptc
|
||||
|
@ -38,15 +38,32 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
all: iptcrdr.o testiptcrdr iptpinhole.o testiptpinhole
|
||||
LIBS += /lib/libip4tc.so /lib/libip6tc.so
|
||||
|
||||
all: iptcrdr.o testiptcrdr iptpinhole.o \
|
||||
testiptcrdr_peer testiptcrdr_dscp test_nfct_get
|
||||
# testiptpinhole
|
||||
|
||||
clean:
|
||||
$(RM) *.o testiptcrdr testiptpinhole
|
||||
$(RM) *.o testiptcrdr testiptpinhole testiptcrdr_peer test_nfct_get \
|
||||
testiptcrdr_dscp
|
||||
|
||||
testiptcrdr: testiptcrdr.o iptcrdr.o upnpglobalvars.o $(LIBS)
|
||||
testiptcrdr: testiptcrdr.o upnpglobalvars.o $(LIBS)
|
||||
|
||||
testiptcrdr_peer: testiptcrdr_peer.o upnpglobalvars.o $(LIBS)
|
||||
|
||||
testiptcrdr_dscp: testiptcrdr_dscp.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
|
||||
|
||||
testiptcrdr_peer.o: testiptcrdr_peer.c
|
||||
|
||||
testiptcrdr_dscp.o: testiptcrdr_dscp.c
|
||||
|
||||
iptcrdr.o: iptcrdr.c iptcrdr.h
|
||||
|
||||
iptpinhole.o: iptpinhole.c iptpinhole.h
|
||||
|
|
|
@ -5,6 +5,9 @@ IPTABLES=/sbin/iptables
|
|||
#display all chains relative to miniupnpd
|
||||
$IPTABLES -v -n -t nat -L PREROUTING
|
||||
$IPTABLES -v -n -t nat -L MINIUPNPD
|
||||
$IPTABLES -v -n -t nat -L POSTROUTING
|
||||
$IPTABLES -v -n -t nat -L MINIUPNPD-PCP-PEER
|
||||
$IPTABLES -v -n -t mangle -L MINIUPNPD
|
||||
$IPTABLES -v -n -t filter -L FORWARD
|
||||
$IPTABLES -v -n -t filter -L MINIUPNPD
|
||||
|
||||
|
|
|
@ -4,5 +4,7 @@ IPTABLES=/sbin/iptables
|
|||
|
||||
#flush all rules owned by miniupnpd
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
$IPTABLES -t nat -F MINIUPNPD-PCP-PEER
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
$IPTABLES -t mangle -F MINIUPNPD
|
||||
|
||||
|
|
|
@ -13,8 +13,15 @@ $IPTABLES -t nat -N MINIUPNPD
|
|||
#$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -A PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
|
||||
#adding the MINIUPNPD chain for mangle
|
||||
$IPTABLES -t mangle -N MINIUPNPD
|
||||
$IPTABLES -t mangle -A PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
|
||||
#adding the MINIUPNPD chain for filter
|
||||
$IPTABLES -t filter -N MINIUPNPD
|
||||
#adding the rule to MINIUPNPD
|
||||
$IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
|
||||
#adding the MINIUPNPD chain for nat
|
||||
$IPTABLES -t nat -N MINIUPNPD-PCP-PEER
|
||||
$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j MINIUPNPD-PCP-PEER
|
||||
|
|
|
@ -13,9 +13,19 @@ $IPTABLES -t nat -F MINIUPNPD
|
|||
$IPTABLES -t nat -D PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t nat -X MINIUPNPD
|
||||
|
||||
#removing the MINIUPNPD chain for mangle
|
||||
$IPTABLES -t mangle -F MINIUPNPD
|
||||
$IPTABLES -t mangle -D PREROUTING -i $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t mangle -X MINIUPNPD
|
||||
|
||||
#removing the MINIUPNPD chain for filter
|
||||
$IPTABLES -t filter -F MINIUPNPD
|
||||
#adding the rule to MINIUPNPD
|
||||
$IPTABLES -t filter -D FORWARD -i $EXTIF ! -o $EXTIF -j MINIUPNPD
|
||||
$IPTABLES -t filter -X MINIUPNPD
|
||||
|
||||
#removing the MINIUPNPD-PCP-PEER chain for nat
|
||||
$IPTABLES -t nat -F MINIUPNPD-PCP-PEER
|
||||
#removing the rule to MINIUPNPD-PCP-PEER
|
||||
$IPTABLES -t nat -D POSTROUTING -o $EXTIF -j MINIUPNPD-PCP-PEER
|
||||
$IPTABLES -t nat -X MINIUPNPD-PCP-PEER
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/xt_DSCP.h>
|
||||
#include <libiptc/libiptc.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
@ -71,6 +72,17 @@ static int
|
|||
add_filter_rule(int proto, const char * rhost,
|
||||
const char * iaddr, unsigned short iport);
|
||||
|
||||
static int
|
||||
addpeernatrule(int proto,
|
||||
const char * eaddr, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * rhost, unsigned short rport);
|
||||
|
||||
static int
|
||||
addpeerdscprule(int proto, unsigned char dscp,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * rhost, unsigned short rport);
|
||||
|
||||
/* dummy init and shutdown functions */
|
||||
int init_redirect(void)
|
||||
{
|
||||
|
@ -215,6 +227,41 @@ add_redirect_rule2(const char * ifname,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* add_redirect_rule2() */
|
||||
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 r;
|
||||
UNUSED(ifname);
|
||||
|
||||
r = addpeernatrule(proto, eaddr, eport, iaddr, iport, rhost, rport);
|
||||
if(r >= 0)
|
||||
add_redirect_desc(eport, proto, desc, timestamp);
|
||||
return r;
|
||||
}
|
||||
|
||||
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 r;
|
||||
UNUSED(ifname);
|
||||
UNUSED(desc);
|
||||
UNUSED(timestamp);
|
||||
|
||||
r = addpeerdscprule(proto, dscp, iaddr, iport, rhost, rport);
|
||||
/* if(r >= 0)
|
||||
add_redirect_desc(dscp, proto, desc, timestamp); */
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
add_filter_rule2(const char * ifname,
|
||||
const char * rhost, const char * iaddr,
|
||||
|
@ -417,6 +464,120 @@ get_redirect_rule_by_index(int index,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* get_peer_rule_by_index()
|
||||
* return -1 when the rule was 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 r = -1;
|
||||
#if USE_INDEX_FROM_DESC_LIST && 0
|
||||
r = get_redirect_desc_by_index(index, eport, proto,
|
||||
desc, desclen, timestamp);
|
||||
if (r==0)
|
||||
{
|
||||
r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport,
|
||||
0, 0, packets, bytes);
|
||||
}
|
||||
#else
|
||||
int i = 0;
|
||||
IPTC_HANDLE h;
|
||||
const struct ipt_entry * e;
|
||||
const struct ipt_entry_target * target;
|
||||
const struct ip_nat_multi_range * mr;
|
||||
const struct ipt_entry_match *match;
|
||||
UNUSED(ifname);
|
||||
|
||||
h = iptc_init("nat");
|
||||
if(!h)
|
||||
{
|
||||
syslog(LOG_ERR, "get_peer_rule_by_index() : "
|
||||
"iptc_init() failed : %s",
|
||||
iptc_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if(!iptc_is_chain(miniupnpd_peer_chain, h))
|
||||
{
|
||||
syslog(LOG_ERR, "chain %s not found", miniupnpd_peer_chain);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef IPTABLES_143
|
||||
for(e = iptc_first_rule(miniupnpd_peer_chain, h);
|
||||
e;
|
||||
e = iptc_next_rule(e, h))
|
||||
#else
|
||||
for(e = iptc_first_rule(miniupnpd_peer_chain, &h);
|
||||
e;
|
||||
e = iptc_next_rule(e, &h))
|
||||
#endif
|
||||
{
|
||||
if(i==index)
|
||||
{
|
||||
*proto = e->ip.proto;
|
||||
match = (const struct ipt_entry_match *)&e->elems;
|
||||
if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
|
||||
{
|
||||
const struct ipt_tcp * info;
|
||||
info = (const struct ipt_tcp *)match->data;
|
||||
if (rport)
|
||||
*rport = info->dpts[0];
|
||||
if (iport)
|
||||
*iport = info->spts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct ipt_udp * info;
|
||||
info = (const struct ipt_udp *)match->data;
|
||||
if (rport)
|
||||
*rport = info->dpts[0];
|
||||
if (iport)
|
||||
*iport = info->spts[0];
|
||||
}
|
||||
target = (void *)e + e->target_offset;
|
||||
mr = (const struct ip_nat_multi_range *)&target->data[0];
|
||||
*eport = ntohs(mr->range[0].min.all);
|
||||
get_redirect_desc(*eport, *proto, desc, desclen, timestamp);
|
||||
if(packets)
|
||||
*packets = e->counters.pcnt;
|
||||
if(bytes)
|
||||
*bytes = e->counters.bcnt;
|
||||
/* rhost */
|
||||
if(rhost && rhostlen > 0) {
|
||||
if(e->ip.dst.s_addr) {
|
||||
snprintip(rhost, rhostlen, ntohl(e->ip.dst.s_addr));
|
||||
} else {
|
||||
rhost[0] = '\0';
|
||||
}
|
||||
}
|
||||
if(iaddr && iaddrlen > 0) {
|
||||
if(e->ip.src.s_addr) {
|
||||
snprintip(iaddr, iaddrlen, ntohl(e->ip.src.s_addr));
|
||||
} else {
|
||||
rhost[0] = '\0';
|
||||
}
|
||||
}
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(h)
|
||||
#ifdef IPTABLES_143
|
||||
iptc_free(h);
|
||||
#else
|
||||
iptc_free(&h);
|
||||
#endif
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
/* delete_rule_and_commit() :
|
||||
* subfunction used in delete_redirect_and_filter_rules() */
|
||||
static int
|
||||
|
@ -459,7 +620,7 @@ delete_rule_and_commit(unsigned int index, IPTC_HANDLE h,
|
|||
int
|
||||
delete_redirect_and_filter_rules(unsigned short eport, int proto)
|
||||
{
|
||||
int r = -1;
|
||||
int r = -1, r2 = -1;
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
IPTC_HANDLE h;
|
||||
|
@ -576,22 +737,134 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto)
|
|||
if(iaddr != e->ip.dst.s_addr)
|
||||
continue;
|
||||
index = i;
|
||||
syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);
|
||||
r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
|
||||
h = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);
|
||||
r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
|
||||
}
|
||||
if(h)
|
||||
#ifdef IPTABLES_143
|
||||
iptc_free(h);
|
||||
#else
|
||||
iptc_free(&h);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*delete PEER rule*/
|
||||
if((h = iptc_init("nat")))
|
||||
{
|
||||
i = 0;
|
||||
/* we must find the right index for the filter rule */
|
||||
#ifdef IPTABLES_143
|
||||
for(e = iptc_first_rule(miniupnpd_peer_chain, h);
|
||||
e;
|
||||
e = iptc_next_rule(e, h), i++)
|
||||
#else
|
||||
for(e = iptc_first_rule(miniupnpd_peer_chain, &h);
|
||||
e;
|
||||
e = iptc_next_rule(e, &h), i++)
|
||||
#endif
|
||||
{
|
||||
if(proto==e->ip.proto)
|
||||
{
|
||||
target = (void *)e + e->target_offset;
|
||||
mr = (const struct ip_nat_multi_range *)&target->data[0];
|
||||
if (eport != ntohs(mr->range[0].min.all)) {
|
||||
continue;
|
||||
}
|
||||
iaddr = e->ip.src.s_addr;
|
||||
match = (const struct ipt_entry_match *)&e->elems;
|
||||
if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
|
||||
{
|
||||
const struct ipt_tcp * info;
|
||||
info = (const struct ipt_tcp *)match->data;
|
||||
iport = info->spts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct ipt_udp * info;
|
||||
info = (const struct ipt_udp *)match->data;
|
||||
iport = info->dpts[0];
|
||||
}
|
||||
|
||||
index = i;
|
||||
syslog(LOG_INFO, "Trying to delete peer rule at index %u", index);
|
||||
r2 = delete_rule_and_commit(index, h, miniupnpd_peer_chain, "delete_peer_rule");
|
||||
h = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(h)
|
||||
#ifdef IPTABLES_143
|
||||
iptc_free(h);
|
||||
#else
|
||||
iptc_free(&h);
|
||||
#endif
|
||||
/*delete DSCP rule*/
|
||||
if((r2==0)&&(h = iptc_init("mangle")))
|
||||
{
|
||||
i = 0;
|
||||
index = -1;
|
||||
/* we must find the right index for the filter rule */
|
||||
#ifdef IPTABLES_143
|
||||
for(e = iptc_first_rule(miniupnpd_nat_chain, h);
|
||||
e;
|
||||
e = iptc_next_rule(e, h), i++)
|
||||
#else
|
||||
for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
|
||||
e;
|
||||
e = iptc_next_rule(e, &h), i++)
|
||||
#endif
|
||||
{
|
||||
if(proto==e->ip.proto)
|
||||
{
|
||||
match = (const struct ipt_entry_match *)&e->elems;
|
||||
/*syslog(LOG_DEBUG, "filter rule #%u: %s %s",
|
||||
i, match->u.user.name, inet_ntoa(e->ip.dst));*/
|
||||
if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
|
||||
{
|
||||
const struct ipt_tcp * info;
|
||||
info = (const struct ipt_tcp *)match->data;
|
||||
if(iport != info->spts[0])
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct ipt_udp * info;
|
||||
info = (const struct ipt_udp *)match->data;
|
||||
if(iport != info->spts[0])
|
||||
continue;
|
||||
}
|
||||
if(iaddr != e->ip.src.s_addr)
|
||||
continue;
|
||||
index = i;
|
||||
syslog(LOG_INFO, "Trying to delete dscp rule at index %u", index);
|
||||
r2 = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_dscp_rule");
|
||||
h = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (h)
|
||||
#ifdef IPTABLES_143
|
||||
iptc_free(h);
|
||||
#else
|
||||
iptc_free(&h);
|
||||
#endif
|
||||
}
|
||||
|
||||
del_redirect_desc(eport, proto);
|
||||
return r;
|
||||
return r*r2;
|
||||
}
|
||||
|
||||
/* ==================================== */
|
||||
/* TODO : add the -m state --state NEW,ESTABLISHED,RELATED
|
||||
* only for the filter rule */
|
||||
static struct ipt_entry_match *
|
||||
get_tcp_match(unsigned short dport)
|
||||
get_tcp_match(unsigned short dport, unsigned short sport)
|
||||
{
|
||||
struct ipt_entry_match *match;
|
||||
struct ipt_tcp * tcpinfo;
|
||||
|
@ -602,15 +875,25 @@ get_tcp_match(unsigned short dport)
|
|||
match->u.match_size = size;
|
||||
strncpy(match->u.user.name, "tcp", sizeof(match->u.user.name));
|
||||
tcpinfo = (struct ipt_tcp *)match->data;
|
||||
tcpinfo->spts[0] = 0; /* all source ports */
|
||||
tcpinfo->spts[1] = 0xFFFF;
|
||||
tcpinfo->dpts[0] = dport; /* specified destination port */
|
||||
tcpinfo->dpts[1] = dport;
|
||||
if (sport == 0) {
|
||||
tcpinfo->spts[0] = 0; /* all source ports */
|
||||
tcpinfo->spts[1] = 0xFFFF;
|
||||
} else {
|
||||
tcpinfo->spts[0] = sport; /* specified source port */
|
||||
tcpinfo->spts[1] = sport;
|
||||
}
|
||||
if (dport == 0) {
|
||||
tcpinfo->dpts[0] = 0; /* all destination ports */
|
||||
tcpinfo->dpts[1] = 0xFFFF;
|
||||
} else {
|
||||
tcpinfo->dpts[0] = dport; /* specified destination port */
|
||||
tcpinfo->dpts[1] = dport;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
static struct ipt_entry_match *
|
||||
get_udp_match(unsigned short dport)
|
||||
get_udp_match(unsigned short dport, unsigned short sport)
|
||||
{
|
||||
struct ipt_entry_match *match;
|
||||
struct ipt_udp * udpinfo;
|
||||
|
@ -621,10 +904,20 @@ get_udp_match(unsigned short dport)
|
|||
match->u.match_size = size;
|
||||
strncpy(match->u.user.name, "udp", sizeof(match->u.user.name));
|
||||
udpinfo = (struct ipt_udp *)match->data;
|
||||
udpinfo->spts[0] = 0; /* all source ports */
|
||||
udpinfo->spts[1] = 0xFFFF;
|
||||
udpinfo->dpts[0] = dport; /* specified destination port */
|
||||
udpinfo->dpts[1] = dport;
|
||||
if (sport == 0) {
|
||||
udpinfo->spts[0] = 0; /* all source ports */
|
||||
udpinfo->spts[1] = 0xFFFF;
|
||||
} else {
|
||||
udpinfo->spts[0] = sport; /* specified source port */
|
||||
udpinfo->spts[1] = sport;
|
||||
}
|
||||
if (dport == 0) {
|
||||
udpinfo->dpts[0] = 0; /* all destination ports */
|
||||
udpinfo->dpts[1] = 0xFFFF;
|
||||
} else {
|
||||
udpinfo->dpts[0] = dport; /* specified destination port */
|
||||
udpinfo->dpts[1] = dport;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
|
@ -652,6 +945,48 @@ get_dnat_target(const char * daddr, unsigned short dport)
|
|||
return target;
|
||||
}
|
||||
|
||||
static struct ipt_entry_target *
|
||||
get_snat_target(const char * saddr, unsigned short sport)
|
||||
{
|
||||
struct ipt_entry_target * target;
|
||||
struct ip_nat_multi_range * mr;
|
||||
struct ip_nat_range * range;
|
||||
size_t size;
|
||||
|
||||
size = IPT_ALIGN(sizeof(struct ipt_entry_target))
|
||||
+ IPT_ALIGN(sizeof(struct ip_nat_multi_range));
|
||||
target = calloc(1, size);
|
||||
target->u.target_size = size;
|
||||
strncpy(target->u.user.name, "SNAT", sizeof(target->u.user.name));
|
||||
/* one ip_nat_range already included in ip_nat_multi_range */
|
||||
mr = (struct ip_nat_multi_range *)&target->data[0];
|
||||
mr->rangesize = 1;
|
||||
range = &mr->range[0];
|
||||
range->min_ip = range->max_ip = inet_addr(saddr);
|
||||
range->flags |= IP_NAT_RANGE_MAP_IPS;
|
||||
range->min.all = range->max.all = htons(sport);
|
||||
range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
|
||||
return target;
|
||||
}
|
||||
|
||||
static struct ipt_entry_target *
|
||||
get_dscp_target(unsigned char dscp)
|
||||
{
|
||||
struct ipt_entry_target * target;
|
||||
struct xt_DSCP_info * di;
|
||||
size_t size;
|
||||
|
||||
size = IPT_ALIGN(sizeof(struct ipt_entry_target))
|
||||
+ IPT_ALIGN(sizeof(struct xt_DSCP_info));
|
||||
target = calloc(1, size);
|
||||
target->u.target_size = size;
|
||||
strncpy(target->u.user.name, "DSCP", sizeof(target->u.user.name));
|
||||
/* one ip_nat_range already included in ip_nat_multi_range */
|
||||
di = (struct xt_DSCP_info *)&target->data[0];
|
||||
di->dscp=dscp;
|
||||
return target;
|
||||
}
|
||||
|
||||
/* iptc_init_verify_and_append()
|
||||
* return 0 on success, -1 on failure */
|
||||
static int
|
||||
|
@ -739,11 +1074,11 @@ addnatrule(int proto, unsigned short eport,
|
|||
e->ip.proto = proto;
|
||||
if(proto == IPPROTO_TCP)
|
||||
{
|
||||
match = get_tcp_match(eport);
|
||||
match = get_tcp_match(eport, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = get_udp_match(eport);
|
||||
match = get_udp_match(eport, 0);
|
||||
}
|
||||
e->nfcache = NFC_IP_DST_PT;
|
||||
target = get_dnat_target(iaddr, iport);
|
||||
|
@ -771,6 +1106,126 @@ addnatrule(int proto, unsigned short eport,
|
|||
free(e);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* iptables -t nat -A MINIUPNPD-PCP-PEER -s iaddr -d rhost
|
||||
* -p proto --sport iport --dport rport -j SNAT
|
||||
* --to-source ext_ip:eport */
|
||||
static int
|
||||
addpeernatrule(int proto,
|
||||
const char * eaddr, unsigned short eport,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * rhost, unsigned short rport)
|
||||
{
|
||||
int r = 0;
|
||||
struct ipt_entry * e;
|
||||
struct ipt_entry_match *match = NULL;
|
||||
struct ipt_entry_target *target = NULL;
|
||||
|
||||
e = calloc(1, sizeof(struct ipt_entry));
|
||||
e->ip.proto = proto;
|
||||
/* TODO: Fill port matches and SNAT */
|
||||
if(proto == IPPROTO_TCP)
|
||||
{
|
||||
match = get_tcp_match(rport, iport);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = get_udp_match(rport, iport);
|
||||
}
|
||||
e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT;
|
||||
target = get_snat_target(eaddr, eport);
|
||||
e->nfcache |= NFC_UNKNOWN;
|
||||
e = realloc(e, sizeof(struct ipt_entry)
|
||||
+ match->u.match_size
|
||||
+ target->u.target_size);
|
||||
memcpy(e->elems, match, match->u.match_size);
|
||||
memcpy(e->elems + match->u.match_size, target, target->u.target_size);
|
||||
e->target_offset = sizeof(struct ipt_entry)
|
||||
+ match->u.match_size;
|
||||
e->next_offset = sizeof(struct ipt_entry)
|
||||
+ match->u.match_size
|
||||
+ target->u.target_size;
|
||||
|
||||
/* internal host */
|
||||
if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*")))
|
||||
{
|
||||
e->ip.src.s_addr = inet_addr(iaddr);
|
||||
e->ip.smsk.s_addr = INADDR_NONE;
|
||||
}
|
||||
/* remote host */
|
||||
if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
|
||||
{
|
||||
e->ip.dst.s_addr = inet_addr(rhost);
|
||||
e->ip.dmsk.s_addr = INADDR_NONE;
|
||||
}
|
||||
|
||||
r = iptc_init_verify_and_append("nat", miniupnpd_peer_chain, e, "addpeernatrule()");
|
||||
free(target);
|
||||
free(match);
|
||||
free(e);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* iptables -t mangle -A MINIUPNPD -s iaddr -d rhost
|
||||
* -p proto --sport iport --dport rport -j DSCP
|
||||
* --set-dscp 0xXXXX */
|
||||
static int
|
||||
addpeerdscprule(int proto, unsigned char dscp,
|
||||
const char * iaddr, unsigned short iport,
|
||||
const char * rhost, unsigned short rport)
|
||||
{
|
||||
int r = 0;
|
||||
struct ipt_entry * e;
|
||||
struct ipt_entry_match *match = NULL;
|
||||
struct ipt_entry_target *target = NULL;
|
||||
|
||||
e = calloc(1, sizeof(struct ipt_entry));
|
||||
e->ip.proto = proto;
|
||||
/* TODO: Fill port matches and SNAT */
|
||||
if(proto == IPPROTO_TCP)
|
||||
{
|
||||
match = get_tcp_match(rport, iport);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = get_udp_match(rport, iport);
|
||||
}
|
||||
e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT;
|
||||
target = get_dscp_target(dscp);
|
||||
e->nfcache |= NFC_UNKNOWN;
|
||||
e = realloc(e, sizeof(struct ipt_entry)
|
||||
+ match->u.match_size
|
||||
+ target->u.target_size);
|
||||
memcpy(e->elems, match, match->u.match_size);
|
||||
memcpy(e->elems + match->u.match_size, target, target->u.target_size);
|
||||
e->target_offset = sizeof(struct ipt_entry)
|
||||
+ match->u.match_size;
|
||||
e->next_offset = sizeof(struct ipt_entry)
|
||||
+ match->u.match_size
|
||||
+ target->u.target_size;
|
||||
|
||||
/* internal host */
|
||||
if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*")))
|
||||
{
|
||||
e->ip.src.s_addr = inet_addr(iaddr);
|
||||
e->ip.smsk.s_addr = INADDR_NONE;
|
||||
}
|
||||
/* remote host */
|
||||
if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*")))
|
||||
{
|
||||
e->ip.dst.s_addr = inet_addr(rhost);
|
||||
e->ip.dmsk.s_addr = INADDR_NONE;
|
||||
}
|
||||
|
||||
r = iptc_init_verify_and_append("mangle", miniupnpd_nat_chain, e,
|
||||
"addpeerDSCPrule()");
|
||||
free(target);
|
||||
free(match);
|
||||
free(e);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* ================================= */
|
||||
static struct ipt_entry_target *
|
||||
get_accept_target(void)
|
||||
|
@ -800,11 +1255,11 @@ add_filter_rule(int proto, const char * rhost,
|
|||
e->ip.proto = proto;
|
||||
if(proto == IPPROTO_TCP)
|
||||
{
|
||||
match = get_tcp_match(iport);
|
||||
match = get_tcp_match(iport,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = get_udp_match(iport);
|
||||
match = get_udp_match(iport,0);
|
||||
}
|
||||
e->nfcache = NFC_IP_DST_PT;
|
||||
e->ip.dst.s_addr = inet_addr(iaddr);
|
||||
|
|
|
@ -16,6 +16,13 @@ add_redirect_rule2(const char * ifname,
|
|||
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,
|
||||
|
@ -25,6 +32,24 @@ add_filter_rule2(const char * ifname,
|
|||
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_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto,
|
||||
struct sockaddr* ret_ext);
|
||||
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);
|
||||
|
||||
/* for debug */
|
||||
int
|
||||
list_redirect_rule(const char * ifname);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "iptcrdr.h"
|
||||
#include "iptcrdr.c"
|
||||
#include "../commonrdr.h"
|
||||
|
||||
#ifndef PRIu64
|
||||
|
@ -30,13 +30,11 @@ main(int argc, char ** argv)
|
|||
eport = (unsigned short)atoi(argv[1]);
|
||||
iaddr = argv[2];
|
||||
iport = (unsigned short)atoi(argv[3]);
|
||||
#if 0
|
||||
printf("trying to redirect port %hu to %s:%hu\n", eport, iaddr, iport);
|
||||
if(addnatrule(IPPROTO_TCP, eport, iaddr, iport) < 0)
|
||||
if(addnatrule(IPPROTO_TCP, eport, iaddr, iport, NULL) < 0)
|
||||
return -1;
|
||||
if(add_filter_rule(IPPROTO_TCP, iaddr, iport) < 0)
|
||||
if(add_filter_rule(IPPROTO_TCP, NULL, iaddr, iport) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
/* test */
|
||||
{
|
||||
unsigned short p1, p2;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* $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 "iptcrdr.h"
|
||||
#include "../commonrdr.h"
|
||||
#include "iptcrdr.c"
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
unsigned char dscp;
|
||||
unsigned short iport, rport;
|
||||
const char * iaddr, *rhost;
|
||||
printf("Usage %s <dscp> <internal_ip> <internal_port> <peer_ip> <peer_port>\n", argv[0]);
|
||||
|
||||
if(argc<6)
|
||||
return -1;
|
||||
openlog("testiptcrdr_peer", LOG_PERROR|LOG_CONS, LOG_LOCAL0);
|
||||
dscp = (unsigned short)atoi(argv[1]);
|
||||
iaddr = argv[2];
|
||||
iport = (unsigned short)atoi(argv[3]);
|
||||
rhost = argv[4];
|
||||
rport = (unsigned short)atoi(argv[5]);
|
||||
#if 1
|
||||
if(addpeerdscprule(IPPROTO_TCP, dscp, iaddr, iport, rhost, rport) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
/* 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';
|
||||
if(get_redirect_rule_by_index(0, "", &p1,
|
||||
addr, sizeof(addr), &p2,
|
||||
&proto2, desc, sizeof(desc),
|
||||
rhost, sizeof(rhost),
|
||||
×tamp,
|
||||
&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("trying to list nat rules :\n");
|
||||
list_redirect_rule(argv[1]);
|
||||
printf("deleting\n");
|
||||
// delete_redirect_and_filter_rules(eport, IPPROTO_TCP);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* $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 "iptcrdr.h"
|
||||
#include "../commonrdr.h"
|
||||
#include "iptcrdr.c"
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 "llu"
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char ** argv)
|
||||
{
|
||||
unsigned short eport, iport, rport;
|
||||
const char * eaddr, *iaddr, *rhost;
|
||||
printf("Usage %s <ext_ip> <ext_port> <internal_ip> <internal_port> <peer_ip> <peer_port>\n", argv[0]);
|
||||
|
||||
if(argc<6)
|
||||
return -1;
|
||||
openlog("testiptcrdr_peer", LOG_PERROR|LOG_CONS, LOG_LOCAL0);
|
||||
eaddr = argv[1];
|
||||
eport = (unsigned short)atoi(argv[2]);
|
||||
iaddr = argv[3];
|
||||
iport = (unsigned short)atoi(argv[4]);
|
||||
rhost = argv[5];
|
||||
rport = (unsigned short)atoi(argv[6]);
|
||||
#if 1
|
||||
printf("trying to redirect port %hu to %s:%hu\n", eport, iaddr, iport);
|
||||
if(addpeernatrule(IPPROTO_TCP, eaddr, eport, iaddr, iport, rhost, rport) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
/* 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';
|
||||
if(get_redirect_rule_by_index(0, "", &p1,
|
||||
addr, sizeof(addr), &p2,
|
||||
&proto2, desc, sizeof(desc),
|
||||
rhost, sizeof(rhost),
|
||||
×tamp,
|
||||
&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("trying to list nat rules :\n");
|
||||
list_redirect_rule(argv[1]);
|
||||
printf("deleting\n");
|
||||
delete_redirect_and_filter_rules(eport, IPPROTO_TCP);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@
|
|||
#include "config.h"
|
||||
#include "options.h"
|
||||
#include "upnppermissions.h"
|
||||
#ifdef PCP_SADSCP
|
||||
#include "pcplearndscp.h"
|
||||
#endif // PCP_SADSPC
|
||||
#include "upnpglobalvars.h"
|
||||
|
||||
#ifndef DISABLE_CONFIG_FILE
|
||||
|
@ -47,6 +50,10 @@ static const struct {
|
|||
#endif
|
||||
#ifdef ENABLE_NATPMP
|
||||
{ UPNPENABLENATPMP, "enable_natpmp"},
|
||||
#endif
|
||||
#ifdef ENABLE_PCP
|
||||
{ UPNPPCPMINLIFETIME, "min_lifetime"},
|
||||
{ UPNPPCPMAXLIFETIME, "max_lifetime"},
|
||||
#endif
|
||||
{ UPNPENABLE, "enable_upnp"},
|
||||
#ifdef USE_PF
|
||||
|
@ -147,6 +154,33 @@ readoptionsfile(const char * fname)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
#ifdef PCP_SADSCP
|
||||
/* check for DSCP values configuration */
|
||||
if(0 == memcmp(name, "set_learn_dscp", sizeof("set_learn_dscp")-1) )
|
||||
{
|
||||
tmp = realloc(dscp_values_list, sizeof(struct dscp_values) * (num_dscp_values+1));
|
||||
if(tmp == NULL)
|
||||
{
|
||||
fprintf(stderr, "memory allocation error. DSCP line in file %s line %d\n",
|
||||
fname, linenum);
|
||||
}
|
||||
else
|
||||
{
|
||||
dscp_values_list = tmp;
|
||||
/* parse the rule */
|
||||
if(read_learn_dscp_line(dscp_values_list + num_dscp_values, name) >= 0)
|
||||
{
|
||||
num_dscp_values++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "parsing error file %s line %d : %s\n",
|
||||
fname, linenum, name);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif //PCP_SADSCP
|
||||
if(!(equals = strchr(name, '=')))
|
||||
{
|
||||
fprintf(stderr, "parsing error file %s line %d : %s\n",
|
||||
|
@ -248,6 +282,21 @@ freeoptions(void)
|
|||
upnppermlist = NULL;
|
||||
num_upnpperm = 0;
|
||||
}
|
||||
#ifdef PCP_SADSCP
|
||||
if(dscp_values_list)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < num_dscp_values; i++) {
|
||||
if (dscp_values_list[i].app_name) {
|
||||
free(dscp_values_list[i].app_name);
|
||||
dscp_values_list[i].app_name = NULL;
|
||||
}
|
||||
}
|
||||
free(dscp_values_list);
|
||||
dscp_values_list = NULL;
|
||||
num_dscp_values = 0;
|
||||
}
|
||||
#endif //PCP_SADSCP
|
||||
}
|
||||
|
||||
#endif /* DISABLE_CONFIG_FILE */
|
||||
|
|
|
@ -32,6 +32,8 @@ enum upnpconfigoptions {
|
|||
UPNPCLEANTHRESHOLD, /* clean_ruleset_threshold */
|
||||
UPNPCLEANINTERVAL, /* clean_ruleset_interval */
|
||||
UPNPENABLENATPMP, /* enable_natpmp */
|
||||
UPNPPCPMINLIFETIME, /* minimum lifetime for PCP mapping */
|
||||
UPNPPCPMAXLIFETIME, /* maximum lifetime for PCP mapping */
|
||||
#ifdef USE_NETFILTER
|
||||
UPNPFORWARDCHAIN,
|
||||
UPNPNATCHAIN,
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/* $Id: pcp_msg_struct.h $ */
|
||||
/* MiniUPnP project
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Peter Tatrai
|
||||
|
||||
Copyright (c) 2013 by Cisco Systems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define PCP_OPCODE_ANNOUNCE 0
|
||||
#define PCP_OPCODE_MAP 1
|
||||
#define PCP_OPCODE_PEER 2
|
||||
#ifdef PCP_SADSCP
|
||||
#define PCP_OPCODE_SADSCP 3
|
||||
#endif
|
||||
|
||||
/* Possible response codes sent by server, as a result of client request*/
|
||||
#define PCP_SUCCESS 0
|
||||
|
||||
#define PCP_ERR_UNSUPP_VERSION 1
|
||||
/** The version number at the start of the PCP Request
|
||||
* header is not recognized by this PCP server. This is a long
|
||||
* lifetime error. This document describes PCP version 2.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_NOT_AUTHORIZED 2
|
||||
/**The requested operation is disabled for this PCP
|
||||
* client, or the PCP client requested an operation that cannot be
|
||||
* fulfilled by the PCP server's security policy. This is a long
|
||||
* lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_MALFORMED_REQUEST 3
|
||||
/**The request could not be successfully parsed.
|
||||
* This is a long lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_UNSUPP_OPCODE 4
|
||||
/** Unsupported Opcode. This is a long lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_UNSUPP_OPTION 5
|
||||
/**Unsupported Option. This error only occurs if the
|
||||
* Option is in the mandatory-to-process range. This is a long
|
||||
* lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_MALFORMED_OPTION 6
|
||||
/**Malformed Option (e.g., appears too many times,
|
||||
* invalid length). This is a long lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_NETWORK_FAILURE 7
|
||||
/**The PCP server or the device it controls are
|
||||
* experiencing a network failure of some sort (e.g., has not
|
||||
* obtained an External IP address). This is a short lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_NO_RESOURCES 8
|
||||
/**Request is well-formed and valid, but the server has
|
||||
* insufficient resources to complete the requested operation at this
|
||||
* time. For example, the NAT device cannot create more mappings at
|
||||
* this time, is short of CPU cycles or memory, or is unable to
|
||||
* handle the request due to some other temporary condition. The
|
||||
* same request may succeed in the future. This is a system-wide
|
||||
* error, different from USER_EX_QUOTA. This can be used as a catch-
|
||||
* all error, should no other error message be suitable. This is a
|
||||
* short lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_UNSUPP_PROTOCOL 9
|
||||
/**Unsupported transport protocol, e.g. SCTP in a
|
||||
* NAT that handles only UDP and TCP. This is a long lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_USER_EX_QUOTA 10
|
||||
/** This attempt to create a new mapping would exceed
|
||||
* this subscriber's port quota. This is a short lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_CANNOT_PROVIDE_EXTERNAL 11
|
||||
/** The suggested external port and/or
|
||||
* external address cannot be provided. This error MUST only be
|
||||
* returned for:
|
||||
* * MAP requests that included the PREFER_FAILURE Option
|
||||
* (normal MAP requests will return an available external port)
|
||||
* * MAP requests for the SCTP protocol (PREFER_FAILURE is implied)
|
||||
* * PEER requests
|
||||
*/
|
||||
|
||||
#define PCP_ERR_ADDRESS_MISMATCH 12
|
||||
/** The source IP address of the request packet does
|
||||
* not match the contents of the PCP Client's IP Address field, due
|
||||
* to an unexpected NAT on the path between the PCP client and the
|
||||
* PCP-controlled NAT or firewall. This is a long lifetime error.
|
||||
*/
|
||||
|
||||
#define PCP_ERR_EXCESSIVE_REMOTE_PEERS 13
|
||||
/** The PCP server was not able to create the
|
||||
* filters in this request. This result code MUST only be returned
|
||||
* if the MAP request contained the FILTER Option. See Section 13.3
|
||||
* for processing information. This is a long lifetime error.
|
||||
*/
|
||||
|
||||
typedef enum pcp_options {
|
||||
PCP_OPTION_3RD_PARTY = 1,
|
||||
PCP_OPTION_PREF_FAIL = 2,
|
||||
PCP_OPTION_FILTER = 3,
|
||||
#ifdef PCP_FLOWP
|
||||
PCP_OPTION_FLOW_PRIORITY = 4, /*TODO: change it to correct value*/
|
||||
#endif
|
||||
} pcp_options_t;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4200)
|
||||
#endif // WIN32
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* PCP common request header*/
|
||||
typedef struct pcp_request {
|
||||
uint8_t ver;
|
||||
uint8_t r_opcode;
|
||||
uint16_t reserved;
|
||||
uint32_t req_lifetime;
|
||||
uint32_t ip[4]; /* ipv4 will be represented
|
||||
by the ipv4 mapped ipv6 */
|
||||
uint8_t next_data[0];
|
||||
} pcp_request_t;
|
||||
|
||||
/* PCP common response header*/
|
||||
typedef struct pcp_response {
|
||||
uint8_t ver;
|
||||
uint8_t r_opcode; /* R indicates Request (0) or Response (1)
|
||||
Opcode is 7 bit value specifying operation MAP or PEER */
|
||||
uint8_t reserved; /* reserved bits, must be 0 on transmission and must be ignored on reception */
|
||||
uint8_t result_code; /* */
|
||||
uint32_t lifetime; /* an unsigned 32-bit integer, in seconds {0, 2^32-1}*/
|
||||
uint32_t epochtime; /* epoch indicates how long has PCP server had its current mappings
|
||||
it increases by 1 every second */
|
||||
uint32_t reserved1[3];/* For requests that were successfully parsed this must be sent as 0 */
|
||||
uint8_t next_data[0];
|
||||
} pcp_response_t;
|
||||
|
||||
|
||||
typedef struct pcp_options_hdr {
|
||||
uint8_t code; /* Most significant bit indicates if this option is mandatory (0) or optional (1) */
|
||||
uint8_t reserved; /* MUST be set to 0 on transmission and MUST be ignored on reception */
|
||||
uint16_t len; /* indicates the length of the enclosed data in octets (see RFC) */
|
||||
uint8_t next_data[0]; /* */
|
||||
} pcp_options_hdr_t;
|
||||
|
||||
/* same for both request and response */
|
||||
typedef struct pcp_map_v2 {
|
||||
uint32_t nonce[3];
|
||||
uint8_t protocol;
|
||||
uint8_t reserved[3];
|
||||
uint16_t int_port;
|
||||
uint16_t ext_port;
|
||||
uint32_t ext_ip[4]; /* ipv4 will be represented
|
||||
by the ipv4 mapped ipv6 */
|
||||
uint8_t next_data[0];
|
||||
} pcp_map_v2_t;
|
||||
|
||||
/* same for both request and response */
|
||||
typedef struct pcp_map_v1 {
|
||||
uint8_t protocol;
|
||||
uint8_t reserved[3];
|
||||
uint16_t int_port;
|
||||
uint16_t ext_port;
|
||||
uint32_t ext_ip[4]; /* ipv4 will be represented
|
||||
by the ipv4 mapped ipv6 */
|
||||
uint8_t next_data[0];
|
||||
} pcp_map_v1_t;
|
||||
|
||||
/* same for both request and response */
|
||||
typedef struct pcp_peer_v1 {
|
||||
uint8_t protocol;
|
||||
uint8_t reserved[3];
|
||||
uint16_t int_port;
|
||||
uint16_t ext_port;
|
||||
uint32_t ext_ip[4]; /* ipv4 will be represented
|
||||
by the ipv4 mapped ipv6 */
|
||||
uint16_t peer_port;
|
||||
uint16_t reserved1;
|
||||
uint32_t peer_ip[4];
|
||||
uint8_t next_data[0];
|
||||
} pcp_peer_v1_t;
|
||||
|
||||
/* same for both request and response */
|
||||
typedef struct pcp_peer_v2 {
|
||||
uint32_t nonce[3];
|
||||
uint8_t protocol;
|
||||
uint8_t reserved[3];
|
||||
uint16_t int_port;
|
||||
uint16_t ext_port;
|
||||
uint32_t ext_ip[4]; /* ipv4 will be represented
|
||||
by the ipv4 mapped ipv6 */
|
||||
uint16_t peer_port;
|
||||
uint16_t reserved1;
|
||||
uint32_t peer_ip[4];
|
||||
uint8_t next_data[0];
|
||||
} pcp_peer_v2_t;
|
||||
|
||||
#ifdef PCP_SADSCP
|
||||
typedef struct pcp_sadscp_req {
|
||||
uint32_t nonce[3];
|
||||
uint8_t tolerance_fields;
|
||||
uint8_t app_name_length;
|
||||
char app_name[0];
|
||||
} pcp_sadscp_req_t;
|
||||
|
||||
typedef struct pcp_sadscp_resp {
|
||||
uint32_t nonce[3];
|
||||
#define PCP_SADSCP_MASK ((1<<6)-1)
|
||||
uint8_t a_r_dscp_value;
|
||||
uint8_t reserved[3];
|
||||
} pcp_sadscp_resp_t;
|
||||
#endif
|
||||
|
||||
typedef struct pcp_prefer_fail_option {
|
||||
uint8_t option;
|
||||
uint8_t reserved;
|
||||
uint16_t len;
|
||||
uint8_t next_data[0];
|
||||
} pcp_prefer_fail_option_t;
|
||||
|
||||
typedef struct pcp_3rd_party_option{
|
||||
uint8_t option;
|
||||
uint8_t reserved;
|
||||
uint16_t len;
|
||||
uint32_t ip[4];
|
||||
uint8_t next_data[0];
|
||||
} pcp_3rd_party_option_t;
|
||||
|
||||
#ifdef PCP_FLOWP
|
||||
typedef struct pcp_flow_priority_option{
|
||||
uint8_t option;
|
||||
uint8_t reserved;
|
||||
uint16_t len;
|
||||
uint8_t dscp_up;
|
||||
uint8_t dscp_down;
|
||||
#define PCP_DSCP_MASK ((1<<6)-1)
|
||||
uint8_t reserved2;
|
||||
/* most significant bit is used for response */
|
||||
uint8_t response_bit;
|
||||
uint8_t next_data[0];
|
||||
} pcp_flow_priority_option_t;
|
||||
#endif
|
||||
|
||||
typedef struct pcp_filter_option {
|
||||
uint8_t option;
|
||||
uint8_t reserved1;
|
||||
uint16_t len;
|
||||
uint8_t reserved2;
|
||||
uint8_t prefix_len;
|
||||
uint16_t peer_port;
|
||||
uint32_t peer_ip[4];
|
||||
}pcp_filter_option_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning (pop)
|
||||
#endif // WIN32
|
|
@ -0,0 +1,298 @@
|
|||
/* $Id: pcplearndscp.c $ */
|
||||
/* MiniUPnP project
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Miroslav Bagljas
|
||||
|
||||
Copyright (c) 2013 by Cisco Systems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "upnpglobalvars.h"
|
||||
#include "pcplearndscp.h"
|
||||
|
||||
#ifdef PCP_SADSCP
|
||||
|
||||
void
|
||||
print_dscp(void) {
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i < num_dscp_values; i++){
|
||||
syslog(LOG_DEBUG, "Appname %*.s, del %d, loss %d, jitter %d, dscp %d",
|
||||
dscp_values_list[i].app_name_len,
|
||||
dscp_values_list[i].app_name, dscp_values_list[i].delay,
|
||||
dscp_values_list[i].loss, dscp_values_list[i].jitter,
|
||||
dscp_values_list[i].dscp_value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
read_learn_dscp_line(struct dscp_values *dscpvalues, char *p)
|
||||
{
|
||||
char * q;
|
||||
size_t len;
|
||||
unsigned int sizeof_first_token = sizeof("set_learn_dscp") - 1;
|
||||
int af_value;
|
||||
int cs_value;
|
||||
|
||||
/* first token: (set_learn_dscp) skip it */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(0 == memcmp(p, "set_learn_dscp", sizeof_first_token))
|
||||
{
|
||||
p += sizeof_first_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
|
||||
/* second token: name of the application */
|
||||
// if
|
||||
if(!(*p == '"'))
|
||||
return -1;
|
||||
p++;
|
||||
for(q = p; !(*q == '"'); q++);
|
||||
len = q - p;
|
||||
if (len != 0) {
|
||||
dscpvalues->app_name = strndup(p, len);
|
||||
} else {
|
||||
dscpvalues->app_name = NULL;
|
||||
}
|
||||
dscpvalues->app_name_len = len;
|
||||
p = q + 1;
|
||||
|
||||
/* third token: delay */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p))
|
||||
goto exit_err_and_cleanup;
|
||||
for(q = p; isdigit(*q); q++);
|
||||
if(isspace(*q))
|
||||
{
|
||||
*q = '\0';
|
||||
dscpvalues->delay = (unsigned char)atoi(p);
|
||||
if (dscpvalues->delay >= 3) {
|
||||
fprintf(stderr, "Wrong delay value %d in \n", dscpvalues->delay);
|
||||
fprintf(stderr, "Delay can be from set {0,1,2} 0=low delay, 1=medium delay, 2=high delay\n");
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
p = q + 1;
|
||||
|
||||
/* fourth token: loss */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p))
|
||||
goto exit_err_and_cleanup;
|
||||
|
||||
for(q = p; isdigit(*q); q++);
|
||||
if(isspace(*q))
|
||||
{
|
||||
*q = '\0';
|
||||
dscpvalues->loss = (unsigned char)atoi(p);
|
||||
if (dscpvalues->loss >= 3) {
|
||||
fprintf(stderr, "Wrong loss value %d \n", dscpvalues->loss);
|
||||
fprintf(stderr, "Delay can be from set {0,1,2} 0=low loss, 1=medium loss, 2=high loss\n");
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
p = q + 1;
|
||||
|
||||
/* fifth token: jitter */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p))
|
||||
goto exit_err_and_cleanup;
|
||||
for(q = p; isdigit(*q); q++);
|
||||
if(isspace(*q))
|
||||
{
|
||||
*q = '\0';
|
||||
dscpvalues->jitter = (unsigned char)atoi(p);
|
||||
if (dscpvalues->jitter >= 3) {
|
||||
fprintf(stderr, "Wrong jitter value %d \n", dscpvalues->jitter);
|
||||
fprintf(stderr, "Delay can be from set {0,1,2} 0=low jitter, 1=medium jitter, 2=high jitter \n");
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
p = q + 1;
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
/*{
|
||||
}*/
|
||||
p = q + 1;
|
||||
|
||||
/* sixth token: DSCP value */
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if(!isdigit(*p) && !( toupper(*p) == 'A' && toupper(*(p+1)) == 'F') &&
|
||||
!( toupper(*p) == 'C' && toupper(*(p+1)) == 'S') &&
|
||||
!( toupper(*p) == 'E' && toupper(*(p+1)) == 'F')
|
||||
)
|
||||
goto exit_err_and_cleanup;
|
||||
// for(q = p; isdigit(*q) || (toupper(*q) == 'A') || (toupper(*q) == 'F'); q++);
|
||||
for(q = p; isdigit(*q) || isalpha(*q); q++);
|
||||
if(isspace(*q) || *q == '\0')
|
||||
{
|
||||
*q = '\0';
|
||||
if (toupper(*p) == 'A' && toupper(*(p+1)) == 'F'){
|
||||
p = p+2;
|
||||
if (*p == '\0') {
|
||||
dscpvalues->dscp_value = 0;
|
||||
}
|
||||
else if (!isdigit(*p)) {
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
else {
|
||||
af_value = atoi(p);
|
||||
switch(af_value) {
|
||||
case 11:
|
||||
dscpvalues->dscp_value = 10;
|
||||
break;
|
||||
case 12:
|
||||
dscpvalues->dscp_value = 12;
|
||||
break;
|
||||
case 13:
|
||||
dscpvalues->dscp_value = 14;
|
||||
break;
|
||||
case 21:
|
||||
dscpvalues->dscp_value = 18;
|
||||
break;
|
||||
case 22:
|
||||
dscpvalues->dscp_value = 20;
|
||||
break;
|
||||
case 23:
|
||||
dscpvalues->dscp_value = 22;
|
||||
break;
|
||||
case 31:
|
||||
dscpvalues->dscp_value = 26;
|
||||
break;
|
||||
case 32:
|
||||
dscpvalues->dscp_value = 28;
|
||||
break;
|
||||
case 33:
|
||||
dscpvalues->dscp_value = 30;
|
||||
break;
|
||||
case 41:
|
||||
dscpvalues->dscp_value = 34;
|
||||
break;
|
||||
case 42:
|
||||
dscpvalues->dscp_value = 36;
|
||||
break;
|
||||
case 43:
|
||||
dscpvalues->dscp_value = 38;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown AF value %u \n", af_value);
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (toupper(*p) == 'C' && toupper(*(p+1)) == 'S'){
|
||||
p=p+2;
|
||||
if (*p == '\0') {
|
||||
dscpvalues->dscp_value = 0;
|
||||
}
|
||||
else if (!isdigit(*p)) {
|
||||
fprintf(stderr, "Not digit after CS but %c \n", *p);
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
else {
|
||||
cs_value = atoi(p);
|
||||
switch(cs_value) {
|
||||
case 1:
|
||||
dscpvalues->dscp_value = 8;
|
||||
break;
|
||||
case 2:
|
||||
dscpvalues->dscp_value = 16;
|
||||
break;
|
||||
case 3:
|
||||
dscpvalues->dscp_value = 24;
|
||||
break;
|
||||
case 4:
|
||||
dscpvalues->dscp_value = 32;
|
||||
break;
|
||||
case 5:
|
||||
dscpvalues->dscp_value = 40;
|
||||
break;
|
||||
case 6:
|
||||
dscpvalues->dscp_value = 48;
|
||||
break;
|
||||
case 7:
|
||||
dscpvalues->dscp_value = 56;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown CS value %d \n", cs_value);
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (toupper(*p) == 'E' && toupper(*(p+1)) == 'F'){
|
||||
dscpvalues->dscp_value = 46;
|
||||
}
|
||||
else {
|
||||
dscpvalues->dscp_value = (unsigned char)atoi(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_err_and_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_err_and_cleanup:
|
||||
free(dscpvalues->app_name);
|
||||
dscpvalues->app_name = NULL;
|
||||
dscpvalues->app_name_len = 0;
|
||||
return -1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/* $Id: pcplearndscp.h $ */
|
||||
/* MiniUPnP project
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Miroslav Bagljas
|
||||
|
||||
Copyright (c) 2013 by Cisco Systems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PCPLEARNDSCP_H_INCLUDED
|
||||
#define PCPLEARNDSCP_H_INCLUDED
|
||||
|
||||
struct dscp_values {
|
||||
char *app_name;
|
||||
unsigned int app_name_len;
|
||||
unsigned char delay;
|
||||
unsigned char loss;
|
||||
unsigned char jitter;
|
||||
unsigned char dscp_value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// #set_learn_dscp "Webex" 1 1 1 34
|
||||
int
|
||||
read_learn_dscp_line(struct dscp_values *dscpvalues, char *p);
|
||||
|
||||
#endif // PCPLEARNDSCP_H_INCLUDED
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
/* $Id: pcpserver.h $ */
|
||||
/* MiniUPnP project
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Peter Tatrai
|
||||
|
||||
Copyright (c) 2013 by Cisco Systems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PCPSERVER_H_INCLUDED
|
||||
#define PCPSERVER_H_INCLUDED
|
||||
|
||||
#define PCP_MIN_LEN 24
|
||||
#define PCP_MAX_LEN 1100
|
||||
|
||||
/*
|
||||
* returns 0 upon success 1 otherwise
|
||||
*/
|
||||
int ProcessIncomingPCPPacket(int s, unsigned char *msg_buff, int len, \
|
||||
struct sockaddr_in *senderaddr);
|
||||
|
||||
#endif /* PCPSERVER_H_INCLUDED */
|
|
@ -32,6 +32,9 @@ unsigned long upstream_bitrate = 0;
|
|||
/* startup time */
|
||||
time_t startup_time = 0;
|
||||
|
||||
unsigned long int min_lifetime = 120;
|
||||
unsigned long int max_lifetime = 86400;
|
||||
|
||||
int runtime_flags = 0;
|
||||
|
||||
const char * pidfilename = "/var/run/miniupnpd.pid";
|
||||
|
@ -61,6 +64,10 @@ unsigned int nextnatpmptoclean_timestamp = 0;
|
|||
unsigned short nextnatpmptoclean_eport = 0;
|
||||
unsigned short nextnatpmptoclean_proto = 0;
|
||||
#endif
|
||||
#ifdef PCP_SADSCP
|
||||
struct dscp_values* dscp_values_list = 0;
|
||||
unsigned int num_dscp_values = 0;
|
||||
#endif //PCP_SADSCP
|
||||
#endif
|
||||
|
||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||
|
@ -76,6 +83,7 @@ const char * tag = 0;
|
|||
/* chain name to use, both in the nat table
|
||||
* and the filter table */
|
||||
const char * miniupnpd_nat_chain = "MINIUPNPD";
|
||||
const char * miniupnpd_peer_chain = "MINIUPNPD-PCP-PEER";
|
||||
const char * miniupnpd_forward_chain = "MINIUPNPD";
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
const char * miniupnpd_v6_filter_chain = "MINIUPNPD";
|
||||
|
|
|
@ -32,6 +32,10 @@ extern unsigned long upstream_bitrate;
|
|||
/* statup time */
|
||||
extern time_t startup_time;
|
||||
|
||||
extern unsigned long int min_lifetime;
|
||||
extern unsigned long int max_lifetime;
|
||||
|
||||
|
||||
/* runtime boolean flags */
|
||||
extern int runtime_flags;
|
||||
#define LOGPACKETSMASK 0x0001
|
||||
|
@ -81,6 +85,10 @@ extern unsigned int nextnatpmptoclean_timestamp;
|
|||
extern unsigned short nextnatpmptoclean_eport;
|
||||
extern unsigned short nextnatpmptoclean_proto;
|
||||
#endif
|
||||
#ifdef PCP_SADSCP
|
||||
extern struct dscp_values* dscp_values_list;
|
||||
extern unsigned int num_dscp_values;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||
|
@ -95,6 +103,7 @@ extern const char * tag;
|
|||
|
||||
#ifdef USE_NETFILTER
|
||||
extern const char * miniupnpd_nat_chain;
|
||||
extern const char * miniupnpd_peer_chain;
|
||||
extern const char * miniupnpd_forward_chain;
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
extern const char * miniupnpd_v6_filter_chain;
|
||||
|
|
|
@ -505,6 +505,32 @@ get_upnp_rules_state_list(int max_rules_number_target)
|
|||
if(!tmp)
|
||||
break;
|
||||
}
|
||||
#ifdef PCP_PEER
|
||||
i=0;
|
||||
while(get_peer_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
|
||||
&iport, &proto, 0, 0, 0,0,0, ×tamp,
|
||||
&tmp->packets, &tmp->bytes) >= 0)
|
||||
{
|
||||
tmp->to_remove = 0;
|
||||
if(timestamp > 0) {
|
||||
/* need to remove this port mapping ? */
|
||||
if(timestamp <= (unsigned int)current_time)
|
||||
tmp->to_remove = 1;
|
||||
else if((nextruletoclean_timestamp <= (unsigned int)current_time)
|
||||
|| (timestamp < nextruletoclean_timestamp))
|
||||
nextruletoclean_timestamp = timestamp;
|
||||
}
|
||||
tmp->proto = (short)proto;
|
||||
/* add tmp to list */
|
||||
tmp->next = list;
|
||||
list = tmp;
|
||||
/* prepare next iteration */
|
||||
i++;
|
||||
tmp = malloc(sizeof(struct rule_state));
|
||||
if(!tmp)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
free(tmp);
|
||||
/* remove the redirections that need to be removed */
|
||||
for(p = &list, tmp = list; tmp; tmp = *p)
|
||||
|
|
Loading…
Reference in New Issue