|
version 1.1, 2012/02/21 23:16:02
|
version 1.1.1.3, 2013/07/22 00:32:35
|
|
Line 1
|
Line 1
|
| /* $Id$ */ |
/* $Id$ */ |
| /* MiniUPnP project |
/* MiniUPnP project |
| * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
| * (c) 2006-2010 Thomas Bernard | * (c) 2006-2012 Thomas Bernard |
| * This software is subject to the conditions detailed |
* This software is subject to the conditions detailed |
| * in the LICENCE file provided within the distribution */ |
* in the LICENCE file provided within the distribution */ |
| |
|
|
Line 55
|
Line 55
|
| #include <stdio.h> |
#include <stdio.h> |
| #include <stdlib.h> |
#include <stdlib.h> |
| |
|
| |
#include "../macros.h" |
| #include "../config.h" |
#include "../config.h" |
| #include "obsdrdr.h" |
#include "obsdrdr.h" |
| #include "../upnpglobalvars.h" |
#include "../upnpglobalvars.h" |
| |
|
| /* anchor name */ | /* list too keep timestamps for port mappings having a lease duration */ |
| static const char anchor_name[] = "miniupnpd"; | struct timestamp_entry { |
| | struct timestamp_entry * next; |
| | unsigned int timestamp; |
| | unsigned short eport; |
| | short protocol; |
| | }; |
| |
|
| |
static struct timestamp_entry * timestamp_list = NULL; |
| |
|
| |
static unsigned int |
| |
get_timestamp(unsigned short eport, int proto) |
| |
{ |
| |
struct timestamp_entry * e; |
| |
e = timestamp_list; |
| |
while(e) { |
| |
if(e->eport == eport && e->protocol == (short)proto) |
| |
return e->timestamp; |
| |
e = e->next; |
| |
} |
| |
return 0; |
| |
} |
| |
|
| |
static void |
| |
remove_timestamp_entry(unsigned short eport, int proto) |
| |
{ |
| |
struct timestamp_entry * e; |
| |
struct timestamp_entry * * p; |
| |
p = ×tamp_list; |
| |
e = *p; |
| |
while(e) { |
| |
if(e->eport == eport && e->protocol == (short)proto) { |
| |
/* remove the entry */ |
| |
*p = e->next; |
| |
free(e); |
| |
return; |
| |
} |
| |
p = &(e->next); |
| |
e = *p; |
| |
} |
| |
} |
| |
|
| /* /dev/pf when opened */ |
/* /dev/pf when opened */ |
| static int dev = -1; | int dev = -1; |
| |
|
| /* shutdown_redirect() : |
/* shutdown_redirect() : |
| * close the /dev/pf device */ |
* close the /dev/pf device */ |
|
Line 138 error:
|
Line 178 error:
|
| /* add_redirect_rule2() : |
/* add_redirect_rule2() : |
| * create a rdr rule */ |
* create a rdr rule */ |
| int |
int |
| add_redirect_rule2(const char * ifname, unsigned short eport, | add_redirect_rule2(const char * ifname, |
| | const char * rhost, unsigned short eport, |
| const char * iaddr, unsigned short iport, int proto, |
const char * iaddr, unsigned short iport, int proto, |
| const char * desc) | const char * desc, unsigned int timestamp) |
| { |
{ |
| int r; |
int r; |
| struct pfioc_rule pcr; |
struct pfioc_rule pcr; |
|
Line 171 add_redirect_rule2(const char * ifname, unsigned short
|
Line 212 add_redirect_rule2(const char * ifname, unsigned short
|
| if(1) |
if(1) |
| { |
{ |
| pcr.rule.direction = PF_IN; |
pcr.rule.direction = PF_IN; |
| //pcr.rule.src.addr.type = PF_ADDR_NONE; | /*pcr.rule.src.addr.type = PF_ADDR_NONE;*/ |
| pcr.rule.src.addr.type = PF_ADDR_ADDRMASK; |
pcr.rule.src.addr.type = PF_ADDR_ADDRMASK; |
| pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK; |
pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK; |
| pcr.rule.nat.addr.type = PF_ADDR_NONE; |
pcr.rule.nat.addr.type = PF_ADDR_NONE; |
| pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK; |
pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK; |
| #endif |
#endif |
| | |
| pcr.rule.dst.port_op = PF_OP_EQ; |
pcr.rule.dst.port_op = PF_OP_EQ; |
| pcr.rule.dst.port[0] = htons(eport); |
pcr.rule.dst.port[0] = htons(eport); |
| pcr.rule.dst.port[1] = htons(eport); |
pcr.rule.dst.port[1] = htons(eport); |
|
Line 205 add_redirect_rule2(const char * ifname, unsigned short
|
Line 246 add_redirect_rule2(const char * ifname, unsigned short
|
| #ifdef PFRULE_HAS_RTABLEID |
#ifdef PFRULE_HAS_RTABLEID |
| pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ |
pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ |
| #endif |
#endif |
| |
#ifdef PFRULE_HAS_ONRDOMAIN |
| |
pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */ |
| |
#endif |
| pcr.rule.quick = 1; |
pcr.rule.quick = 1; |
| pcr.rule.keep_state = PF_STATE_NORMAL; |
pcr.rule.keep_state = PF_STATE_NORMAL; |
| if(tag) |
if(tag) |
| strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE); |
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE); |
| strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); |
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); |
| |
if(rhost && rhost[0] != '\0' && rhost[0] != '*') |
| |
{ |
| |
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 |
#ifndef PF_NEWSTYLE |
| pcr.rule.rpool.proxy_port[0] = iport; |
pcr.rule.rpool.proxy_port[0] = iport; |
| pcr.rule.rpool.proxy_port[1] = iport; |
pcr.rule.rpool.proxy_port[1] = iport; |
|
Line 255 add_redirect_rule2(const char * ifname, unsigned short
|
Line 304 add_redirect_rule2(const char * ifname, unsigned short
|
| free(a); |
free(a); |
| #endif |
#endif |
| } |
} |
| |
if(r == 0 && timestamp > 0) |
| |
{ |
| |
struct timestamp_entry * tmp; |
| |
tmp = malloc(sizeof(struct timestamp_entry)); |
| |
if(tmp) |
| |
{ |
| |
tmp->next = timestamp_list; |
| |
tmp->timestamp = timestamp; |
| |
tmp->eport = eport; |
| |
tmp->protocol = (short)proto; |
| |
timestamp_list = tmp; |
| |
} |
| |
} |
| return r; |
return r; |
| } |
} |
| |
|
| /* thanks to Seth Mos for this function */ |
/* thanks to Seth Mos for this function */ |
| int |
int |
| add_filter_rule2(const char * ifname, const char * iaddr, | add_filter_rule2(const char * ifname, |
| | const char * rhost, const char * iaddr, |
| unsigned short eport, unsigned short iport, |
unsigned short eport, unsigned short iport, |
| int proto, const char * desc) |
int proto, const char * desc) |
| { |
{ |
| #ifndef PF_ENABLE_FILTER_RULES |
#ifndef PF_ENABLE_FILTER_RULES |
| |
UNUSED(ifname); |
| |
UNUSED(rhost); UNUSED(iaddr); |
| |
UNUSED(eport); UNUSED(iport); |
| |
UNUSED(proto); UNUSED(desc); |
| return 0; |
return 0; |
| #else |
#else |
| int r; |
int r; |
|
Line 296 add_filter_rule2(const char * ifname, const char * iad
|
Line 363 add_filter_rule2(const char * ifname, const char * iad
|
| if(1) |
if(1) |
| { |
{ |
| #endif |
#endif |
| | |
| pcr.rule.dst.port_op = PF_OP_EQ; |
pcr.rule.dst.port_op = PF_OP_EQ; |
| pcr.rule.dst.port[0] = htons(eport); |
pcr.rule.dst.port[0] = htons(eport); |
| pcr.rule.direction = PF_IN; |
pcr.rule.direction = PF_IN; |
|
Line 314 add_filter_rule2(const char * ifname, const char * iad
|
Line 381 add_filter_rule2(const char * ifname, const char * iad
|
| pcr.rule.flags = TH_SYN; |
pcr.rule.flags = TH_SYN; |
| pcr.rule.flagset = (TH_SYN|TH_ACK); |
pcr.rule.flagset = (TH_SYN|TH_ACK); |
| #ifdef PFRULE_HAS_RTABLEID |
#ifdef PFRULE_HAS_RTABLEID |
| pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ | pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ |
| #endif |
#endif |
| |
#ifdef PFRULE_HAS_ONRDOMAIN |
| |
pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */ |
| |
#endif |
| pcr.rule.keep_state = 1; |
pcr.rule.keep_state = 1; |
| strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); |
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); |
| if(queue) |
if(queue) |
|
Line 323 add_filter_rule2(const char * ifname, const char * iad
|
Line 393 add_filter_rule2(const char * ifname, const char * iad
|
| if(tag) |
if(tag) |
| strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE); |
strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE); |
| |
|
| |
if(rhost && rhost[0] != '\0' && rhost[0] != '*') |
| |
{ |
| |
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 |
#ifndef PF_NEWSTYLE |
| pcr.rule.rpool.proxy_port[0] = eport; |
pcr.rule.rpool.proxy_port[0] = eport; |
| a = calloc(1, sizeof(struct pf_pooladdr)); |
a = calloc(1, sizeof(struct pf_pooladdr)); |
|
Line 332 add_filter_rule2(const char * ifname, const char * iad
|
Line 407 add_filter_rule2(const char * ifname, const char * iad
|
| TAILQ_INIT(&pcr.rule.rpool.list); |
TAILQ_INIT(&pcr.rule.rpool.list); |
| inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); |
inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); |
| TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); |
TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); |
| | |
| /* we have any - any port = # keep state label */ |
/* we have any - any port = # keep state label */ |
| /* we want any - iaddr port = # keep state label */ |
/* we want any - iaddr port = # keep state label */ |
| /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */ |
/* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */ |
|
Line 381 int
|
Line 456 int
|
| get_redirect_rule(const char * ifname, unsigned short eport, int proto, |
get_redirect_rule(const char * ifname, unsigned short eport, int proto, |
| char * iaddr, int iaddrlen, unsigned short * iport, |
char * iaddr, int iaddrlen, unsigned short * iport, |
| char * desc, int desclen, |
char * desc, int desclen, |
| |
char * rhost, int rhostlen, |
| |
unsigned int * timestamp, |
| u_int64_t * packets, u_int64_t * bytes) |
u_int64_t * packets, u_int64_t * bytes) |
| { |
{ |
| int i, n; |
int i, n; |
|
Line 388 get_redirect_rule(const char * ifname, unsigned short
|
Line 465 get_redirect_rule(const char * ifname, unsigned short
|
| #ifndef PF_NEWSTYLE |
#ifndef PF_NEWSTYLE |
| struct pfioc_pooladdr pp; |
struct pfioc_pooladdr pp; |
| #endif |
#endif |
| |
UNUSED(ifname); |
| |
|
| if(dev<0) { |
if(dev<0) { |
| syslog(LOG_ERR, "pf device is not open"); |
syslog(LOG_ERR, "pf device is not open"); |
| return -1; |
return -1; |
|
Line 461 get_redirect_rule(const char * ifname, unsigned short
|
Line 540 get_redirect_rule(const char * ifname, unsigned short
|
| inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, |
inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, |
| iaddr, iaddrlen); |
iaddr, iaddrlen); |
| #endif |
#endif |
| |
if(rhost && rhostlen > 0) |
| |
{ |
| |
if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0) |
| |
{ |
| |
rhost[0] = '\0'; /* empty string */ |
| |
} |
| |
else |
| |
{ |
| |
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, |
| |
rhost, rhostlen); |
| |
} |
| |
} |
| |
if(timestamp) |
| |
*timestamp = get_timestamp(eport, proto); |
| return 0; |
return 0; |
| } |
} |
| } |
} |
|
Line 473 delete_redirect_rule(const char * ifname, unsigned sho
|
Line 566 delete_redirect_rule(const char * ifname, unsigned sho
|
| { |
{ |
| int i, n; |
int i, n; |
| struct pfioc_rule pr; |
struct pfioc_rule pr; |
| |
UNUSED(ifname); |
| |
|
| if(dev<0) { |
if(dev<0) { |
| syslog(LOG_ERR, "pf device is not open"); |
syslog(LOG_ERR, "pf device is not open"); |
| return -1; |
return -1; |
|
Line 513 delete_redirect_rule(const char * ifname, unsigned sho
|
Line 608 delete_redirect_rule(const char * ifname, unsigned sho
|
| syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); |
syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m"); |
| goto error; |
goto error; |
| } |
} |
| |
remove_timestamp_entry(eport, proto); |
| return 0; |
return 0; |
| } |
} |
| } |
} |
|
Line 524 int
|
Line 620 int
|
| delete_filter_rule(const char * ifname, unsigned short eport, int proto) |
delete_filter_rule(const char * ifname, unsigned short eport, int proto) |
| { |
{ |
| #ifndef PF_ENABLE_FILTER_RULES |
#ifndef PF_ENABLE_FILTER_RULES |
| |
UNUSED(ifname); UNUSED(eport); UNUSED(proto); |
| return 0; |
return 0; |
| #else |
#else |
| int i, n; |
int i, n; |
|
Line 578 get_redirect_rule_by_index(int index,
|
Line 675 get_redirect_rule_by_index(int index,
|
| char * ifname, unsigned short * eport, |
char * ifname, unsigned short * eport, |
| char * iaddr, int iaddrlen, unsigned short * iport, |
char * iaddr, int iaddrlen, unsigned short * iport, |
| int * proto, char * desc, int desclen, |
int * proto, char * desc, int desclen, |
| |
char * rhost, int rhostlen, |
| |
unsigned int * timestamp, |
| u_int64_t * packets, u_int64_t * bytes) |
u_int64_t * packets, u_int64_t * bytes) |
| { |
{ |
| int n; |
int n; |
|
Line 660 get_redirect_rule_by_index(int index,
|
Line 759 get_redirect_rule_by_index(int index,
|
| inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, |
inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, |
| iaddr, iaddrlen); |
iaddr, iaddrlen); |
| #endif |
#endif |
| |
if(rhost && rhostlen > 0) |
| |
{ |
| |
if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0) |
| |
{ |
| |
rhost[0] = '\0'; /* empty string */ |
| |
} |
| |
else |
| |
{ |
| |
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, |
| |
rhost, rhostlen); |
| |
} |
| |
} |
| |
if(timestamp) |
| |
*timestamp = get_timestamp(*eport, *proto); |
| return 0; |
return 0; |
| error: |
error: |
| return -1; |
return -1; |
| } |
} |
| |
|
| |
/* return an (malloc'ed) array of "external" port for which there is |
| |
* a port mapping. number is the size of the array */ |
| |
unsigned short * |
| |
get_portmappings_in_range(unsigned short startport, unsigned short endport, |
| |
int proto, unsigned int * number) |
| |
{ |
| |
unsigned short * array; |
| |
unsigned int capacity; |
| |
int i, n; |
| |
unsigned short eport; |
| |
struct pfioc_rule pr; |
| |
|
| |
*number = 0; |
| |
if(dev<0) { |
| |
syslog(LOG_ERR, "pf device is not open"); |
| |
return NULL; |
| |
} |
| |
capacity = 128; |
| |
array = calloc(capacity, sizeof(unsigned short)); |
| |
if(!array) |
| |
{ |
| |
syslog(LOG_ERR, "get_portmappings_in_range() : calloc error"); |
| |
return NULL; |
| |
} |
| |
memset(&pr, 0, sizeof(pr)); |
| |
strlcpy(pr.anchor, anchor_name, MAXPATHLEN); |
| |
#ifndef PF_NEWSTYLE |
| |
pr.rule.action = PF_RDR; |
| |
#endif |
| |
if(ioctl(dev, DIOCGETRULES, &pr) < 0) |
| |
{ |
| |
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m"); |
| |
free(array); |
| |
return NULL; |
| |
} |
| |
n = pr.nr; |
| |
for(i=0; i<n; i++) |
| |
{ |
| |
pr.nr = i; |
| |
if(ioctl(dev, DIOCGETRULE, &pr) < 0) |
| |
{ |
| |
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); |
| |
continue; |
| |
} |
| |
eport = ntohs(pr.rule.dst.port[0]); |
| |
if( (eport == ntohs(pr.rule.dst.port[1])) |
| |
&& (pr.rule.proto == proto) |
| |
&& (startport <= eport) && (eport <= endport) ) |
| |
{ |
| |
if(*number >= capacity) |
| |
{ |
| |
/* need to increase the capacity of the array */ |
| |
capacity += 128; |
| |
array = realloc(array, sizeof(unsigned short)*capacity); |
| |
if(!array) |
| |
{ |
| |
syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity); |
| |
*number = 0; |
| |
return NULL; |
| |
} |
| |
} |
| |
array[*number] = eport; |
| |
(*number)++; |
| |
} |
| |
} |
| |
return array; |
| |
} |
| |
|
| /* this function is only for testing */ |
/* this function is only for testing */ |
| #if TEST |
#if TEST |
| void |
void |
|
Line 695 list_rules(void)
|
Line 876 list_rules(void)
|
| pr.nr = i; |
pr.nr = i; |
| if(ioctl(dev, DIOCGETRULE, &pr) < 0) |
if(ioctl(dev, DIOCGETRULE, &pr) < 0) |
| perror("DIOCGETRULE"); |
perror("DIOCGETRULE"); |
| printf(" %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n", | printf(" %s %s %d:%d -> %d:%d proto %d keep_state=%d action=%d\n", |
| pr.rule.ifname, |
pr.rule.ifname, |
| |
inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, buf, 32), |
| (int)ntohs(pr.rule.dst.port[0]), |
(int)ntohs(pr.rule.dst.port[0]), |
| (int)ntohs(pr.rule.dst.port[1]), |
(int)ntohs(pr.rule.dst.port[1]), |
| #ifndef PF_NEWSTYLE |
#ifndef PF_NEWSTYLE |