miniupnpd/pf: add_nat_rule()

This commit is contained in:
Thomas Bernard 2020-05-21 02:24:39 +02:00
parent abefb6c6d0
commit 2cf50c57fa
No known key found for this signature in database
GPG Key ID: 0FF11B67A5C0863C
1 changed files with 172 additions and 1 deletions

View File

@ -1,4 +1,4 @@
/* $Id: obsdrdr.c,v 1.95 2020/05/17 20:22:01 nanard Exp $ */
/* $Id: obsdrdr.c,v 1.96 2020/05/21 00:18:04 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
@ -67,6 +67,7 @@
#include "config.h"
#include "obsdrdr.h"
#include "../upnpglobalvars.h"
#include "../getifaddr.h"
#ifndef USE_PF
#error "USE_PF macro is undefined, check consistency between config.h and Makefile"
@ -246,6 +247,168 @@ error:
}
#endif
#ifdef ENABLE_PORT_TRIGGERING
/* add_nat_rule()
* nat on re0 inet proto udp from 192.168.1.49 port 3074 to any -> (re0) port 3148
* <re0> is ext_if, (re0) is ext_ip
* should be created when a port mapping (3148 => 192.168.1.49:3074 UDP) is created.
* for symetric NAT / UPnP IGD NAT Port Triggering */
int add_nat_rule(const char * ifname,
const char * rhost, unsigned short eport,
const char * iaddr, unsigned short iport, int proto,
const char * desc)
{
int r;
struct pfioc_rule pcr;
#ifndef PF_NEWSTYLE
struct pfioc_pooladdr pp;
struct pf_pooladdr *a;
#endif
const char * extaddr;
char extaddr_buf[INET_ADDRSTRLEN];
if(dev<0) {
syslog(LOG_ERR, "pf device is not open");
return -1;
}
if(use_ext_ip_addr && use_ext_ip_addr[0] != '\0') {
extaddr = use_ext_ip_addr;
} else {
if(getifaddr(ifname, extaddr_buf, INET_ADDRSTRLEN, NULL, NULL) < 0) {
syslog(LOG_WARNING, "failed to get address for interface %s", ifname);
return -1;
}
extaddr = extaddr_buf;
}
syslog(LOG_DEBUG, "use external ip %s", extaddr);
r = 0;
memset(&pcr, 0, sizeof(pcr));
strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
#ifndef PF_NEWSTYLE
memset(&pp, 0, sizeof(pp));
strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
r = -1;
}
else
{
pcr.pool_ticket = pp.ticket;
#else
{
pcr.rule.nat.addr.type = PF_ADDR_ADDRMASK;
pcr.rule.rdr.addr.type = PF_ADDR_NONE;
#endif
/*pcr.rule.src.addr.type = PF_ADDR_NONE;*/
pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
pcr.rule.action = PF_NAT;
pcr.rule.af = AF_INET;
#ifdef USE_IFNAME_IN_RULES
if(ifname)
strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
#endif
pcr.rule.proto = proto;
pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/
#ifdef PFRULE_HAS_RTABLEID
pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
#endif
#ifdef PFRULE_HAS_ONRDOMAIN
pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */
#endif
pcr.rule.quick = 1;
pcr.rule.keep_state = PF_STATE_NORMAL;
if(tag)
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
#ifdef PFVAR_NEW_STYLE
inet_pton(AF_INET, iaddr, &pcr.rule.src.addr.v.a.addr.v4addr.s_addr);
pcr.rule.src.addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE);
#else
inet_pton(AF_INET, iaddr, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
#endif
#ifdef __APPLE__
pcr.rule.src.xport.range.op = PF_OP_EQ;
pcr.rule.src.xport.range.port[0] = htons(iport);
pcr.rule.src.xport.range.port[1] = htons(iport);
#else
pcr.rule.src.port_op = PF_OP_EQ;
pcr.rule.src.port[0] = htons(iport);
pcr.rule.src.port[1] = htons(iport);
#endif
if(rhost && rhost[0] != '\0' && rhost[0] != '*')
{
#ifdef PFVAR_NEW_STYLE
inet_pton(AF_INET, rhost, &pcr.rule.dst.addr.v.a.addr.v4addr.s_addr);
pcr.rule.dst.addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE);
#else
inet_pton(AF_INET, rhost, &pcr.rule.dst.addr.v.a.addr.v4.s_addr);
pcr.rule.dst.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
#endif
}
#ifdef __APPLE__
pcr.rule.dst.xport.range.op = PF_OP_NONE;
#else
pcr.rule.dst.port_op = PF_OP_NONE;
#endif
/* -> xxx.xxx.xxx.xxx port 1234 */
#ifndef PF_NEWSTYLE
pcr.rule.rpool.proxy_port[0] = eport;
pcr.rule.rpool.proxy_port[1] = eport;
TAILQ_INIT(&pcr.rule.rpool.list);
a = calloc(1, sizeof(struct pf_pooladdr));
#ifdef PFVAR_NEW_STYLE
inet_pton(AF_INET, extaddr, &a->addr.v.a.addr.v4addr.s_addr);
a->addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE);
#else
inet_pton(AF_INET, extaddr, &a->addr.v.a.addr.v4.s_addr);
a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
#endif
TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
if(ioctl(dev, DIOCADDADDR, &pp) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
r = -1;
}
else
{
#else
pcr.rule.nat.proxy_port[0] = eport;
pcr.rule.nat.proxy_port[1] = eport;
inet_pton(AF_INET, extaddr, &pcr.rule.nat.addr.v.a.addr.v4.s_addr);
pcr.rule.nat.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
{
#endif /* PF_NEWSTYLE */
pcr.action = PF_CHANGE_GET_TICKET;
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
r = -1;
}
else
{
pcr.action = PF_CHANGE_ADD_TAIL;
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
{
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
r = -1;
}
}
}
#ifndef PF_NEWSTYLE
free(a);
#endif
}
return r;
}
#endif
/* add_redirect_rule2() :
* create a rdr rule */
int
@ -260,6 +423,7 @@ add_redirect_rule2(const char * ifname,
struct pfioc_pooladdr pp;
struct pf_pooladdr *a;
#endif
if(dev<0) {
syslog(LOG_ERR, "pf device is not open");
return -1;
@ -407,6 +571,13 @@ add_redirect_rule2(const char * ifname,
}
if(r == 0 && timestamp > 0)
add_timestamp_entry(eport, proto, timestamp);
#ifdef ENABLE_PORT_TRIGGERING
if(r == 0 && proto == IPPROTO_UDP)
{
add_nat_rule(ifname, rhost, eport, iaddr, iport, proto, desc);
/* TODO check error */
}
#endif
return r;
}