version 1.1, 2012/02/21 23:16:02
|
version 1.1.1.2, 2012/05/29 12:55:57
|
Line 59
|
Line 59
|
#include "obsdrdr.h" |
#include "obsdrdr.h" |
#include "../upnpglobalvars.h" |
#include "../upnpglobalvars.h" |
|
|
|
/* list too keep timestamps for port mappings having a lease duration */ |
|
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; |
|
} |
|
} |
|
|
/* anchor name */ |
/* anchor name */ |
static const char anchor_name[] = "miniupnpd"; |
static const char anchor_name[] = "miniupnpd"; |
|
|
Line 138 error:
|
Line 180 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 210 add_redirect_rule2(const char * ifname, unsigned short
|
Line 253 add_redirect_rule2(const char * ifname, unsigned short
|
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 303 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) |
{ |
{ |
Line 323 add_filter_rule2(const char * ifname, const char * iad
|
Line 385 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 381 int
|
Line 448 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 461 get_redirect_rule(const char * ifname, unsigned short
|
Line 530 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 513 delete_redirect_rule(const char * ifname, unsigned sho
|
Line 596 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 578 get_redirect_rule_by_index(int index,
|
Line 662 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 746 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 863 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 |