Merge branch 'fix_pf_redirect'

Conflicts:
	miniupnpd/pf/testobsdrdr.c
This commit is contained in:
Thomas Bernard 2014-03-10 00:03:06 +01:00
commit a27979afde
4 changed files with 178 additions and 64 deletions

View File

@ -1,7 +1,7 @@
/* $Id: obsdrdr.c,v 1.74 2012/05/01 09:20:43 nanard Exp $ */
/* $Id: obsdrdr.c,v 1.80 2014/03/06 13:02:46 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard
* (c) 2006-2014 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -9,15 +9,19 @@
* pf rules created (with ext_if = xl1)
* - OpenBSD up to version 4.6 :
* rdr pass on xl1 inet proto udp from any to any port = 54321 \
* label "test label" -> 192.168.0.141 port 12345
* or a rdr rule + a pass rule
* keep state label "test label" -> 192.168.0.42 port 12345
* or a rdr rule + a pass rule :
* rdr quick on xl1 inet proto udp from any to any port = 54321 \
* keep state label "test label" -> 192.168.0.42 port 12345
* pass in quick on xl1 inet proto udp from any to 192.168.0.42 port = 12345 \
* flags S/SA keep state label "test label"
*
* - OpenBSD starting from version 4.7
* match in on xl1 inet proto udp from any to any port 54321 \
* label "test label" rdr-to 192.168.0.141 port 12345
* label "test label" rdr-to 192.168.0.42 port 12345
* or
* pass in quick on xl1 inet proto udp from any to any port 54321 \
* label "test label" rdr-to 192.168.0.141 port 12345
* label "test label" rdr-to 192.168.0.42 port 12345
*
*
*
@ -176,6 +180,45 @@ clear_redirect_rules(void)
error:
return -1;
}
int
clear_filter_rules(void)
{
#ifndef PF_ENABLE_FILTER_RULES
return 0;
#else
struct pfioc_trans io;
struct pfioc_trans_e ioe;
if(dev<0) {
syslog(LOG_ERR, "pf device is not open");
return -1;
}
memset(&ioe, 0, sizeof(ioe));
io.size = 1;
io.esize = sizeof(ioe);
io.array = &ioe;
#ifndef PF_NEWSTYLE
ioe.rs_num = PF_RULESET_FILTER;
#else
/* ? */
ioe.type = PF_TRANS_RULESET;
#endif
strlcpy(ioe.anchor, anchor_name, MAXPATHLEN);
if(ioctl(dev, DIOCXBEGIN, &io) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
goto error;
}
if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
goto error;
}
return 0;
error:
return -1;
#endif
}
#endif
/* add_redirect_rule2() :
@ -347,8 +390,11 @@ add_filter_rule2(const char * ifname,
struct pfioc_rule pcr;
#ifndef PF_NEWSTYLE
struct pfioc_pooladdr pp;
struct pf_pooladdr *a;
#endif
#ifndef USE_IFNAME_IN_RULES
UNUSED(ifname);
#endif
UNUSED(eport);
if(dev<0) {
syslog(LOG_ERR, "pf device is not open");
return -1;
@ -372,9 +418,8 @@ add_filter_rule2(const char * ifname,
if(1)
{
#endif
pcr.rule.dst.port_op = PF_OP_EQ;
pcr.rule.dst.port[0] = htons(eport);
pcr.rule.dst.port[0] = htons(iport);
pcr.rule.direction = PF_IN;
pcr.rule.action = PF_PASS;
pcr.rule.af = AF_INET;
@ -407,33 +452,16 @@ add_filter_rule2(const char * ifname,
inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
}
#ifndef PF_NEWSTYLE
pcr.rule.rpool.proxy_port[0] = eport;
a = calloc(1, sizeof(struct pf_pooladdr));
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
TAILQ_INIT(&pcr.rule.rpool.list);
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
/* we have any - any port = # keep state label */
/* we want any - iaddr port = # keep state label */
/* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
if(ioctl(dev, DIOCADDADDR, &pp) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
r = -1;
}
else
{
#else
inet_pton(AF_INET, iaddr, &pcr.rule.dst.addr.v.a.addr.v4.s_addr);
pcr.rule.dst.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
#ifndef PF_NEWSTYLE
pcr.rule.rpool.proxy_port[0] = iport;
pcr.rule.rpool.proxy_port[1] = iport;
TAILQ_INIT(&pcr.rule.rpool.list);
#endif
if(1)
{
#endif
pcr.action = PF_CHANGE_GET_TICKET;
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
{
@ -450,9 +478,6 @@ add_filter_rule2(const char * ifname,
}
}
}
#ifndef PF_NEWSTYLE
free(a);
#endif
}
return r;
#endif
@ -575,8 +600,10 @@ error:
return -1;
}
int
delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
static int
priv_delete_redirect_rule(const char * ifname, unsigned short eport,
int proto, unsigned short * iport,
in_addr_t * iaddr)
{
int i, n;
struct pfioc_rule pr;
@ -614,6 +641,44 @@ delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
#endif
&& (pr.rule.proto == proto) )
{
/* retrieve iport in order to remove filter rule */
#ifndef PF_NEWSTYLE
if(iport) *iport = pr.rule.rpool.proxy_port[0];
if(iaddr)
{
/* retrieve internal address */
struct pfioc_pooladdr pp;
memset(&pp, 0, sizeof(pp));
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
pp.r_action = PF_RDR;
pp.r_num = i;
pp.ticket = pr.ticket;
if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
goto error;
}
if(pp.nr != 1)
{
syslog(LOG_NOTICE, "No address associated with pf rule");
goto error;
}
pp.nr = 0; /* first */
if(ioctl(dev, DIOCGETADDR, &pp) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
goto error;
}
*iaddr = pp.addr.addr.v.a.addr.v4.s_addr;
}
#else
if(iport) *iport = pr.rule.rdr.proxy_port[0];
if(iaddr)
{
/* retrieve internal address */
*iaddr = pr.rule.rdr.addr.v.a.addr.v4.s_addr;
}
#endif
pr.action = PF_CHANGE_GET_TICKET;
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
{
@ -636,14 +701,23 @@ error:
}
int
delete_filter_rule(const char * ifname, unsigned short eport, int proto)
delete_redirect_rule(const char * ifname, unsigned short eport,
int proto)
{
return priv_delete_redirect_rule(ifname, eport, proto, NULL, NULL);
}
static int
priv_delete_filter_rule(const char * ifname, unsigned short iport,
int proto, in_addr_t iaddr)
{
#ifndef PF_ENABLE_FILTER_RULES
UNUSED(ifname); UNUSED(eport); UNUSED(proto);
UNUSED(ifname); UNUSED(iport); UNUSED(proto);
return 0;
#else
int i, n;
struct pfioc_rule pr;
UNUSED(ifname);
if(dev<0) {
syslog(LOG_ERR, "pf device is not open");
return -1;
@ -665,8 +739,16 @@ delete_filter_rule(const char * ifname, unsigned short eport, int proto)
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
goto error;
}
if( (eport == ntohs(pr.rule.dst.port[0]))
&& (pr.rule.proto == proto) )
#ifdef TEST
syslog(LOG_DEBUG, "%2d port=%hu proto=%d addr=%8x",
i, ntohs(pr.rule.dst.port[0]), pr.rule.proto,
pr.rule.dst.addr.v.a.addr.v4.s_addr);
/*pr.rule.dst.addr.v.a.mask.v4.s_addr*/
#endif
if( (iport == ntohs(pr.rule.dst.port[0]))
&& (pr.rule.proto == proto) &&
(iaddr == pr.rule.dst.addr.v.a.addr.v4.s_addr)
)
{
pr.action = PF_CHANGE_GET_TICKET;
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
@ -689,6 +771,21 @@ error:
#endif
}
int
delete_redirect_and_filter_rules(const char * ifname, unsigned short eport,
int proto)
{
int r;
unsigned short iport;
in_addr_t iaddr;
r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr);
if(r == 0)
{
r = priv_delete_filter_rule(ifname, iport, proto, iaddr);
}
return r;
}
int
get_redirect_rule_by_index(int index,
char * ifname, unsigned short * eport,

View File

@ -1,7 +1,7 @@
/* $Id: obsdrdr.h,v 1.20 2012/03/05 20:36:20 nanard Exp $ */
/* $Id: obsdrdr.h,v 1.23 2014/03/06 12:24:33 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006 Thomas Bernard
* (c) 2006-2014 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -52,13 +52,18 @@ get_redirect_rule_by_index(int index,
int
delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
/* delete_filter_rule()
/* delete_redirect_and_filter_rules()
*/
int
delete_filter_rule(const char * ifname, unsigned short eport, int proto);
delete_redirect_and_filter_rules(const char * ifname, unsigned short eport,
int proto);
#ifdef TEST
int
clear_redirect_rules(void);
int
clear_filter_rules(void);
#endif
#endif

View File

@ -1,10 +1,11 @@
/* $Id: testobsdrdr.c,v 1.26 2014/02/28 18:03:31 nanard Exp $ */
/* $Id: testobsdrdr.c,v 1.28 2014/03/06 13:02:47 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@ -68,7 +69,7 @@ test_index(void)
}
int
main(int arc, char * * argv)
main(int argc, char * * argv)
{
char buf[32];
char desc[64];
@ -78,6 +79,12 @@ main(int arc, char * * argv)
unsigned int timestamp;
u_int64_t packets = 0;
u_int64_t bytes = 0;
int clear = 0;
if(argc > 1) {
if(0 == strcmp(argv[1], "--clear") || 0 == strcmp(argv[1], "-c"))
clear = 1;
}
openlog("testobsdrdr", LOG_PERROR, LOG_USER);
if(init_redirect() < 0)
@ -89,12 +96,15 @@ main(int arc, char * * argv)
add_redirect_rule("ep0", 12123, "192.168.1.23", 1234);
add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP);
#endif
add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234,
IPPROTO_UDP, "test description", 0);
add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234,
IPPROTO_TCP, "test description tcp", 0);
add_filter_rule2("em0", NULL, "127.1.2.3", 12123, 1234, IPPROTO_TCP,
"test description tcp");
if(add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234,
IPPROTO_UDP, "test description", 0) < 0)
printf("add_redirect_rule2() #3 failed\n");
if(add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234,
IPPROTO_TCP, "test description tcp", 0) < 0)
printf("add_redirect_rule2() #4 failed\n");
if(add_filter_rule2("em0", NULL, "127.1.2.3", 12123, 1234, IPPROTO_TCP,
"test description tcp") < 0)
printf("add_filter_rule2() #1 failed\n");
list_rules();
list_eports_tcp();
@ -114,20 +124,20 @@ main(int arc, char * * argv)
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
printf("delete_redirect_rule() failed\n");
else
printf("delete_redirect_rule() succeded\n");
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
printf("delete_redirect_rule() failed\n");
else
printf("delete_redirect_rule() succeded\n");
#if 0
if(delete_redirect_and_filter_rules("em0", 12123, IPPROTO_TCP) < 0)
printf("delete_redirect_and_filter_rules() failed\n");
test_index();
clear_redirect_rules();
list_rules();
#endif
if(clear) {
clear_redirect_rules();
clear_filter_rules();
}
/*list_rules();*/
return 0;
}

View File

@ -1,7 +1,7 @@
/* $Id: upnpredirect.c,v 1.80 2012/05/01 20:08:22 nanard Exp $ */
/* $Id: upnpredirect.c,v 1.82 2014/02/28 20:18:35 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard
* (c) 2006-2014 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -419,6 +419,8 @@ _upnp_delete_redir(unsigned short eport, int proto)
int r;
#if defined(__linux__)
r = delete_redirect_and_filter_rules(eport, proto);
#elif defined(USE_PF)
r = delete_redirect_and_filter_rules(ext_if_name, eport, proto);
#else
r = delete_redirect_rule(ext_if_name, eport, proto);
delete_filter_rule(ext_if_name, eport, proto);