version 1.1, 2012/02/21 23:16:02
|
version 1.1.1.2, 2012/05/29 12:55:57
|
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-2008 Thomas Bernard | * (c) 2006-2011 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 */ |
#include <stdio.h> |
#include <stdio.h> |
Line 20
|
Line 20
|
|
|
#if IPTABLES_143 |
#if IPTABLES_143 |
/* IPTABLES API version >= 1.4.3 */ |
/* IPTABLES API version >= 1.4.3 */ |
|
|
|
/* added in order to compile on gentoo : |
|
* http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183 */ |
|
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) |
|
#define __must_be_array(a) \ |
|
BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0]))) |
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) |
|
#define LIST_POISON2 ((void *) 0x00200200 ) |
|
|
#include <net/netfilter/nf_nat.h> |
#include <net/netfilter/nf_nat.h> |
#define ip_nat_multi_range nf_nat_multi_range |
#define ip_nat_multi_range nf_nat_multi_range |
#define ip_nat_range nf_nat_range |
#define ip_nat_range nf_nat_range |
Line 34
|
Line 43
|
#define IPTC_HANDLE iptc_handle_t |
#define IPTC_HANDLE iptc_handle_t |
#endif |
#endif |
|
|
|
/* IPT_ALIGN was renamed XT_ALIGN in iptables-1.4.11 */ |
|
#ifndef IPT_ALIGN |
|
#define IPT_ALIGN XT_ALIGN |
|
#endif |
|
|
#include "iptcrdr.h" |
#include "iptcrdr.h" |
#include "../upnpglobalvars.h" |
#include "../upnpglobalvars.h" |
|
|
|
/* local functions declarations */ |
|
static int |
|
addnatrule(int proto, unsigned short eport, |
|
const char * iaddr, unsigned short iport, |
|
const char * rhost); |
|
|
|
static int |
|
add_filter_rule(int proto, const char * rhost, |
|
const char * iaddr, unsigned short iport); |
|
|
/* dummy init and shutdown functions */ |
/* dummy init and shutdown functions */ |
int init_redirect(void) |
int init_redirect(void) |
{ |
{ |
Line 60 static int snprintip(char * dst, size_t size, uint32_t
|
Line 84 static int snprintip(char * dst, size_t size, uint32_t
|
* own structure to store them */ |
* own structure to store them */ |
struct rdr_desc { |
struct rdr_desc { |
struct rdr_desc * next; |
struct rdr_desc * next; |
|
unsigned int timestamp; |
unsigned short eport; |
unsigned short eport; |
short proto; |
short proto; |
char str[]; |
char str[]; |
Line 68 struct rdr_desc {
|
Line 93 struct rdr_desc {
|
/* pointer to the chained list where descriptions are stored */ |
/* pointer to the chained list where descriptions are stored */ |
static struct rdr_desc * rdr_desc_list = 0; |
static struct rdr_desc * rdr_desc_list = 0; |
|
|
|
/* add a description to the list of redirection descriptions */ |
static void |
static void |
add_redirect_desc(unsigned short eport, int proto, const char * desc) | add_redirect_desc(unsigned short eport, int proto, |
| const char * desc, unsigned int timestamp) |
{ |
{ |
struct rdr_desc * p; |
struct rdr_desc * p; |
size_t l; |
size_t l; |
/* if(desc) | /* set a default description if none given */ |
{*/ | if(!desc) |
if ((l = strlen(desc) + 1) == 1) l = 5; | desc = "miniupnpd"; |
p = malloc(sizeof(struct rdr_desc) + l); | l = strlen(desc) + 1; |
if(p) | p = malloc(sizeof(struct rdr_desc) + l); |
{ | if(p) |
p->next = rdr_desc_list; | { |
p->eport = eport; | p->next = rdr_desc_list; |
p->proto = (short)proto; | p->timestamp = timestamp; |
if(desc) memcpy(p->str, desc, l); else memcpy(p->str, "upnp", 4); | p->eport = eport; |
rdr_desc_list = p; | p->proto = (short)proto; |
} | memcpy(p->str, desc, l); |
/* }*/ | rdr_desc_list = p; |
| } |
} |
} |
|
|
|
/* delete a description from the list */ |
static void |
static void |
del_redirect_desc(unsigned short eport, int proto) |
del_redirect_desc(unsigned short eport, int proto) |
{ |
{ |
Line 110 del_redirect_desc(unsigned short eport, int proto)
|
Line 139 del_redirect_desc(unsigned short eport, int proto)
|
} |
} |
} |
} |
|
|
|
/* go through the list to find the description */ |
static void |
static void |
get_redirect_desc(unsigned short eport, int proto, |
get_redirect_desc(unsigned short eport, int proto, |
char * desc, int desclen) | char * desc, int desclen, |
| unsigned int * timestamp) |
{ |
{ |
struct rdr_desc * p; |
struct rdr_desc * p; |
if(!desc || (desclen == 0)) |
|
return; |
|
for(p = rdr_desc_list; p; p = p->next) |
for(p = rdr_desc_list; p; p = p->next) |
{ |
{ |
if(p->eport == eport && p->proto == (short)proto) |
if(p->eport == eport && p->proto == (short)proto) |
{ |
{ |
strncpy(desc, p->str, desclen); | if(desc) |
| strncpy(desc, p->str, desclen); |
| if(timestamp) |
| *timestamp = p->timestamp; |
return; |
return; |
} |
} |
} |
} |
/* if no description was found, return miniupnpd as default */ |
/* if no description was found, return miniupnpd as default */ |
strncpy(desc, "miniupnpd", desclen); | if(desc) |
| strncpy(desc, "miniupnpd", desclen); |
| if(timestamp) |
| *timestamp = 0; |
} |
} |
|
|
int | #if USE_INDEX_FROM_DESC_LIST |
| static int |
get_redirect_desc_by_index(int index, unsigned short * eport, int * proto, |
get_redirect_desc_by_index(int index, unsigned short * eport, int * proto, |
char * desc, int desclen) | char * desc, int desclen, unsigned int * timestamp) |
{ |
{ |
int i = 0; |
int i = 0; |
struct rdr_desc * p; |
struct rdr_desc * p; |
Line 144 get_redirect_desc_by_index(int index, unsigned short *
|
Line 180 get_redirect_desc_by_index(int index, unsigned short *
|
*eport = p->eport; |
*eport = p->eport; |
*proto = (int)p->proto; |
*proto = (int)p->proto; |
strncpy(desc, p->str, desclen); |
strncpy(desc, p->str, desclen); |
|
if(timestamp) |
|
*timestamp = p->timestamp; |
return 0; |
return 0; |
} |
} |
} |
} |
return -1; |
return -1; |
} |
} |
|
#endif |
|
|
/* add_redirect_rule2() */ |
/* add_redirect_rule2() */ |
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 = addnatrule(proto, eport, iaddr, iport); | int r = addnatrule(proto, eport, iaddr, iport, rhost); |
if(r >= 0) |
if(r >= 0) |
add_redirect_desc(eport, proto, desc); | add_redirect_desc(eport, proto, desc, timestamp); |
return r; |
return r; |
} |
} |
|
|
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) |
{ |
{ |
return add_filter_rule(proto, iaddr, iport); | return add_filter_rule(proto, rhost, iaddr, iport); |
} |
} |
|
|
/* get_redirect_rule() |
/* get_redirect_rule() |
Line 176 int
|
Line 217 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 r = -1; |
int r = -1; |
Line 231 get_redirect_rule(const char * ifname, unsigned short
|
Line 274 get_redirect_rule(const char * ifname, unsigned short
|
mr = (const struct ip_nat_multi_range *)&target->data[0]; |
mr = (const struct ip_nat_multi_range *)&target->data[0]; |
snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); |
snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); |
*iport = ntohs(mr->range[0].min.all); |
*iport = ntohs(mr->range[0].min.all); |
/*if(desc) | get_redirect_desc(eport, proto, desc, desclen, timestamp); |
strncpy(desc, "miniupnpd", desclen);*/ | |
get_redirect_desc(eport, proto, desc, desclen); | |
if(packets) |
if(packets) |
*packets = e->counters.pcnt; |
*packets = e->counters.pcnt; |
if(bytes) |
if(bytes) |
*bytes = e->counters.bcnt; |
*bytes = e->counters.bcnt; |
|
/* rhost */ |
|
if(e->ip.src.s_addr && rhost) { |
|
snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr)); |
|
} |
r = 0; |
r = 0; |
break; |
break; |
} |
} |
Line 259 get_redirect_rule_by_index(int index,
|
Line 304 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 r = -1; |
int r = -1; |
r = get_redirect_desc_by_index(index, eport, proto, desc, desclen); | #if USE_INDEX_FROM_DESC_LIST |
| r = get_redirect_desc_by_index(index, eport, proto, |
| desc, desclen, timestamp); |
if (r==0) |
if (r==0) |
|
{ |
r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport, |
r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport, |
0, 0, packets, bytes); |
0, 0, packets, bytes); |
#if 0 | } |
| #else |
int i = 0; |
int i = 0; |
IPTC_HANDLE h; |
IPTC_HANDLE h; |
const struct ipt_entry * e; |
const struct ipt_entry * e; |
Line 318 get_redirect_rule_by_index(int index,
|
Line 369 get_redirect_rule_by_index(int index,
|
mr = (const struct ip_nat_multi_range *)&target->data[0]; |
mr = (const struct ip_nat_multi_range *)&target->data[0]; |
snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); |
snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); |
*iport = ntohs(mr->range[0].min.all); |
*iport = ntohs(mr->range[0].min.all); |
/*if(desc) | get_redirect_desc(*eport, *proto, desc, desclen, timestamp); |
strncpy(desc, "miniupnpd", desclen);*/ | |
get_redirect_desc(*eport, *proto, desc, desclen); | |
if(packets) |
if(packets) |
*packets = e->counters.pcnt; |
*packets = e->counters.pcnt; |
if(bytes) |
if(bytes) |
*bytes = e->counters.bcnt; |
*bytes = e->counters.bcnt; |
|
/* rhost */ |
|
if(rhost && rhostlen > 0) { |
|
if(e->ip.src.s_addr) { |
|
snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr)); |
|
} else { |
|
rhost[0] = '\0'; |
|
} |
|
} |
r = 0; |
r = 0; |
break; |
break; |
} |
} |
Line 337 get_redirect_rule_by_index(int index,
|
Line 394 get_redirect_rule_by_index(int index,
|
#else |
#else |
iptc_free(&h); |
iptc_free(&h); |
#endif |
#endif |
#endif /*0*/ | #endif |
return r; |
return r; |
} |
} |
|
|
/* delete_rule_and_commit() : |
/* delete_rule_and_commit() : |
* subfunction used in delete_redirect_and_filter_rules() */ |
* subfunction used in delete_redirect_and_filter_rules() */ |
|
static int |
|
delete_rule_and_commit(unsigned int index, IPTC_HANDLE h, |
|
const char * miniupnpd_chain, |
|
const char * logcaller) |
|
{ |
|
int r = 0; |
|
#ifdef IPTABLES_143 |
|
if(!iptc_delete_num_entry(miniupnpd_chain, index, h)) |
|
#else |
|
if(!iptc_delete_num_entry(miniupnpd_chain, index, &h)) |
|
#endif |
|
{ |
|
syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n", |
|
logcaller, iptc_strerror(errno)); |
|
r = -1; |
|
} |
|
#ifdef IPTABLES_143 |
|
else if(!iptc_commit(h)) |
|
#else |
|
else if(!iptc_commit(&h)) |
|
#endif |
|
{ |
|
syslog(LOG_ERR, "%s() : iptc_commit(): %s\n", |
|
logcaller, iptc_strerror(errno)); |
|
r = -1; |
|
} |
|
if(h) |
|
#ifdef IPTABLES_143 |
|
iptc_free(h); |
|
#else |
|
iptc_free(&h); |
|
#endif |
|
return r; |
|
} |
|
|
|
/* delete_redirect_and_filter_rules() |
|
*/ |
int |
int |
delete_rule_and_commit(const char * table, | delete_redirect_and_filter_rules(unsigned short eport, int proto) |
const char * miniupnpd_chain, | |
unsigned short eport, int proto, | |
const char * logcaller) | |
{ |
{ |
int r = -1; |
int r = -1; |
unsigned index = 0; |
unsigned index = 0; |
unsigned i = 0; |
unsigned i = 0; |
IPTC_HANDLE h; |
IPTC_HANDLE h; |
const struct ipt_entry * e; |
const struct ipt_entry * e; |
|
const struct ipt_entry_target * target; |
|
const struct ip_nat_multi_range * mr; |
const struct ipt_entry_match *match; |
const struct ipt_entry_match *match; |
|
unsigned short iport = 0; |
|
uint32_t iaddr = 0; |
|
|
h = iptc_init(table); | h = iptc_init("nat"); |
if(!h) |
if(!h) |
{ |
{ |
syslog(LOG_ERR, "get_index_rules() : " | syslog(LOG_ERR, "delete_redirect_and_filter_rules() : " |
"iptc_init(%s) failed : %s", | "iptc_init() failed : %s", |
table, | |
iptc_strerror(errno)); |
iptc_strerror(errno)); |
return -1; |
return -1; |
} |
} |
if(!iptc_is_chain(miniupnpd_chain, h)) | /* First step : find the right nat rule */ |
| if(!iptc_is_chain(miniupnpd_nat_chain, h)) |
{ |
{ |
syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); | syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); |
} |
} |
else |
else |
{ |
{ |
#ifdef IPTABLES_143 |
#ifdef IPTABLES_143 |
for(e = iptc_first_rule(miniupnpd_chain, h); | for(e = iptc_first_rule(miniupnpd_nat_chain, h); |
e; |
e; |
e = iptc_next_rule(e, h), i++) |
e = iptc_next_rule(e, h), i++) |
#else |
#else |
for(e = iptc_first_rule(miniupnpd_chain, &h); | for(e = iptc_first_rule(miniupnpd_nat_chain, &h); |
e; |
e; |
e = iptc_next_rule(e, &h), i++) |
e = iptc_next_rule(e, &h), i++) |
#endif |
#endif |
Line 398 delete_rule_and_commit(const char * table,
|
Line 493 delete_rule_and_commit(const char * table,
|
if(eport != info->dpts[0]) |
if(eport != info->dpts[0]) |
continue; |
continue; |
} |
} |
r = 0; | /* get the index, the internal address and the internal port |
| * of the rule */ |
index = i; |
index = i; |
|
target = (void *)e + e->target_offset; |
|
mr = (const struct ip_nat_multi_range *)&target->data[0]; |
|
iaddr = mr->range[0].min_ip; |
|
iport = ntohs(mr->range[0].min.all); |
|
r = 0; |
break; |
break; |
} |
} |
} |
} |
Line 410 delete_rule_and_commit(const char * table,
|
Line 511 delete_rule_and_commit(const char * table,
|
#else |
#else |
iptc_free(&h); |
iptc_free(&h); |
#endif |
#endif |
if ((r == 0) && (h = iptc_init(table))) { | if(r == 0) |
syslog(LOG_INFO, "Trying to delete rules at index %u", index); | { |
| syslog(LOG_INFO, "Trying to delete nat rule at index %u", index); |
/* Now delete both rules */ |
/* Now delete both rules */ |
|
/* first delete the nat rule */ |
|
h = iptc_init("nat"); |
|
if(h) |
|
{ |
|
r = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_redirect_rule"); |
|
} |
|
if((r == 0) && (h = iptc_init("filter"))) |
|
{ |
|
i = 0; |
|
/* we must find the right index for the filter rule */ |
#ifdef IPTABLES_143 |
#ifdef IPTABLES_143 |
if(!iptc_delete_num_entry(miniupnpd_chain, index, h)) | for(e = iptc_first_rule(miniupnpd_forward_chain, h); |
| e; |
| e = iptc_next_rule(e, h), i++) |
#else |
#else |
if(!iptc_delete_num_entry(miniupnpd_chain, index, &h)) | for(e = iptc_first_rule(miniupnpd_forward_chain, &h); |
| e; |
| e = iptc_next_rule(e, &h), i++) |
#endif |
#endif |
{ | { |
syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n", | if(proto==e->ip.proto) |
logcaller, iptc_strerror(errno)); | { |
r = -1; | 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->dpts[0]) |
| continue; |
| } |
| else |
| { |
| const struct ipt_udp * info; |
| info = (const struct ipt_udp *)match->data; |
| if(iport != info->dpts[0]) |
| continue; |
| } |
| if(iaddr != e->ip.dst.s_addr) |
| continue; |
| index = i; |
| 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"); |
| } |
} |
} |
#ifdef IPTABLES_143 | del_redirect_desc(eport, proto); |
else if(!iptc_commit(h)) | |
#else | |
else if(!iptc_commit(&h)) | |
#endif | |
{ | |
syslog(LOG_ERR, "%s() : iptc_commit(): %s\n", | |
logcaller, iptc_strerror(errno)); | |
r = -1; | |
} | |
if(h) | |
#ifdef IPTABLES_143 | |
iptc_free(h); | |
#else | |
iptc_free(&h); | |
#endif | |
} | |
return r; |
return r; |
} |
} |
|
|
/* delete_redirect_and_filter_rules() |
|
*/ |
|
int |
|
delete_redirect_and_filter_rules(unsigned short eport, int proto) |
|
{ |
|
int r = -1; |
|
if ((r = delete_rule_and_commit("nat", miniupnpd_nat_chain, eport, proto, "delete_redirect_rule") && |
|
delete_rule_and_commit("filter", miniupnpd_forward_chain, eport, proto, "delete_filter_rule")) == 0) |
|
del_redirect_desc(eport, proto); |
|
return r; |
|
} |
|
|
|
/* ==================================== */ |
/* ==================================== */ |
/* TODO : add the -m state --state NEW,ESTABLISHED,RELATED |
/* TODO : add the -m state --state NEW,ESTABLISHED,RELATED |
* only for the filter rule */ |
* only for the filter rule */ |
Line 468 get_tcp_match(unsigned short dport)
|
Line 581 get_tcp_match(unsigned short dport)
|
+ IPT_ALIGN(sizeof(struct ipt_tcp)); |
+ IPT_ALIGN(sizeof(struct ipt_tcp)); |
match = calloc(1, size); |
match = calloc(1, size); |
match->u.match_size = size; |
match->u.match_size = size; |
strncpy(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN); | strncpy(match->u.user.name, "tcp", sizeof(match->u.user.name)); |
tcpinfo = (struct ipt_tcp *)match->data; |
tcpinfo = (struct ipt_tcp *)match->data; |
tcpinfo->spts[0] = 0; /* all source ports */ |
tcpinfo->spts[0] = 0; /* all source ports */ |
tcpinfo->spts[1] = 0xFFFF; |
tcpinfo->spts[1] = 0xFFFF; |
Line 487 get_udp_match(unsigned short dport)
|
Line 600 get_udp_match(unsigned short dport)
|
+ IPT_ALIGN(sizeof(struct ipt_udp)); |
+ IPT_ALIGN(sizeof(struct ipt_udp)); |
match = calloc(1, size); |
match = calloc(1, size); |
match->u.match_size = size; |
match->u.match_size = size; |
strncpy(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN); | strncpy(match->u.user.name, "udp", sizeof(match->u.user.name)); |
udpinfo = (struct ipt_udp *)match->data; |
udpinfo = (struct ipt_udp *)match->data; |
udpinfo->spts[0] = 0; /* all source ports */ |
udpinfo->spts[0] = 0; /* all source ports */ |
udpinfo->spts[1] = 0xFFFF; |
udpinfo->spts[1] = 0xFFFF; |
Line 508 get_dnat_target(const char * daddr, unsigned short dpo
|
Line 621 get_dnat_target(const char * daddr, unsigned short dpo
|
+ IPT_ALIGN(sizeof(struct ip_nat_multi_range)); |
+ IPT_ALIGN(sizeof(struct ip_nat_multi_range)); |
target = calloc(1, size); |
target = calloc(1, size); |
target->u.target_size = size; |
target->u.target_size = size; |
strncpy(target->u.user.name, "DNAT", IPT_FUNCTION_MAXNAMELEN); | strncpy(target->u.user.name, "DNAT", sizeof(target->u.user.name)); |
/* one ip_nat_range already included in ip_nat_multi_range */ |
/* one ip_nat_range already included in ip_nat_multi_range */ |
mr = (struct ip_nat_multi_range *)&target->data[0]; |
mr = (struct ip_nat_multi_range *)&target->data[0]; |
mr->rangesize = 1; |
mr->rangesize = 1; |
Line 523 get_dnat_target(const char * daddr, unsigned short dpo
|
Line 636 get_dnat_target(const char * daddr, unsigned short dpo
|
/* iptc_init_verify_and_append() |
/* iptc_init_verify_and_append() |
* return 0 on success, -1 on failure */ |
* return 0 on success, -1 on failure */ |
static int |
static int |
iptc_init_verify_and_append(const char * table, const char * miniupnpd_chain, struct ipt_entry * e, | iptc_init_verify_and_append(const char * table, |
| const char * miniupnpd_chain, |
| struct ipt_entry * e, |
const char * logcaller) |
const char * logcaller) |
{ |
{ |
IPTC_HANDLE h; |
IPTC_HANDLE h; |
Line 536 iptc_init_verify_and_append(const char * table, const
|
Line 651 iptc_init_verify_and_append(const char * table, const
|
} |
} |
if(!iptc_is_chain(miniupnpd_chain, h)) |
if(!iptc_is_chain(miniupnpd_chain, h)) |
{ |
{ |
syslog(LOG_ERR, "%s : iptc_is_chain() error : %s\n", | syslog(LOG_ERR, "%s : chain %s not found", |
logcaller, iptc_strerror(errno)); | logcaller, miniupnpd_chain); |
if(h) |
if(h) |
#ifdef IPTABLES_143 |
#ifdef IPTABLES_143 |
iptc_free(h); |
iptc_free(h); |
Line 591 iptc_init_verify_and_append(const char * table, const
|
Line 706 iptc_init_verify_and_append(const char * table, const
|
/* add nat rule |
/* add nat rule |
* iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport |
* iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport |
* */ |
* */ |
int | static int |
addnatrule(int proto, unsigned short eport, |
addnatrule(int proto, unsigned short eport, |
const char * iaddr, unsigned short iport) | const char * iaddr, unsigned short iport, |
| const char * rhost) |
{ |
{ |
int r = 0; |
int r = 0; |
struct ipt_entry * e; |
struct ipt_entry * e; |
Line 623 addnatrule(int proto, unsigned short eport,
|
Line 739 addnatrule(int proto, unsigned short eport,
|
e->next_offset = sizeof(struct ipt_entry) |
e->next_offset = sizeof(struct ipt_entry) |
+ match->u.match_size |
+ match->u.match_size |
+ target->u.target_size; |
+ target->u.target_size; |
|
/* remote host */ |
|
if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) |
|
{ |
|
e->ip.src.s_addr = inet_addr(rhost); |
|
e->ip.smsk.s_addr = INADDR_NONE; |
|
} |
|
|
r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()"); |
r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()"); |
free(target); |
free(target); |
Line 640 get_accept_target(void)
|
Line 762 get_accept_target(void)
|
+ IPT_ALIGN(sizeof(int)); |
+ IPT_ALIGN(sizeof(int)); |
target = calloc(1, size); |
target = calloc(1, size); |
target->u.user.target_size = size; |
target->u.user.target_size = size; |
strncpy(target->u.user.name, "ACCEPT", IPT_FUNCTION_MAXNAMELEN); | strncpy(target->u.user.name, "ACCEPT", sizeof(target->u.user.name)); |
return target; |
return target; |
} |
} |
|
|
/* add_filter_rule() |
/* add_filter_rule() |
* */ |
* */ |
int | static int |
add_filter_rule(int proto, const char * iaddr, unsigned short iport) | add_filter_rule(int proto, const char * rhost, |
| const char * iaddr, unsigned short iport) |
{ |
{ |
int r = 0; |
int r = 0; |
struct ipt_entry * e; |
struct ipt_entry * e; |
Line 679 add_filter_rule(int proto, const char * iaddr, unsigne
|
Line 802 add_filter_rule(int proto, const char * iaddr, unsigne
|
e->next_offset = sizeof(struct ipt_entry) |
e->next_offset = sizeof(struct ipt_entry) |
+ match->u.match_size |
+ match->u.match_size |
+ target->u.target_size; |
+ target->u.target_size; |
|
/* remote host */ |
|
if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) |
|
{ |
|
e->ip.src.s_addr = inet_addr(rhost); |
|
e->ip.smsk.s_addr = INADDR_NONE; |
|
} |
|
|
r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()"); |
r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()"); |
free(target); |
free(target); |
Line 687 add_filter_rule(int proto, const char * iaddr, unsigne
|
Line 816 add_filter_rule(int proto, const char * iaddr, unsigne
|
return r; |
return r; |
} |
} |
|
|
|
/* 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; |
|
unsigned short eport; |
|
IPTC_HANDLE h; |
|
const struct ipt_entry * e; |
|
const struct ipt_entry_match *match; |
|
|
|
*number = 0; |
|
capacity = 128; |
|
array = calloc(capacity, sizeof(unsigned short)); |
|
if(!array) |
|
{ |
|
syslog(LOG_ERR, "get_portmappings_in_range() : calloc error"); |
|
return NULL; |
|
} |
|
|
|
h = iptc_init("nat"); |
|
if(!h) |
|
{ |
|
syslog(LOG_ERR, "get_redirect_rule_by_index() : " |
|
"iptc_init() failed : %s", |
|
iptc_strerror(errno)); |
|
free(array); |
|
return NULL; |
|
} |
|
if(!iptc_is_chain(miniupnpd_nat_chain, h)) |
|
{ |
|
syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); |
|
free(array); |
|
array = NULL; |
|
} |
|
else |
|
{ |
|
#ifdef IPTABLES_143 |
|
for(e = iptc_first_rule(miniupnpd_nat_chain, h); |
|
e; |
|
e = iptc_next_rule(e, h)) |
|
#else |
|
for(e = iptc_first_rule(miniupnpd_nat_chain, &h); |
|
e; |
|
e = iptc_next_rule(e, &h)) |
|
#endif |
|
{ |
|
if(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; |
|
eport = info->dpts[0]; |
|
} |
|
else |
|
{ |
|
const struct ipt_udp * info; |
|
info = (const struct ipt_udp *)match->data; |
|
eport = info->dpts[0]; |
|
} |
|
if(startport <= eport && eport <= endport) |
|
{ |
|
if(*number >= capacity) |
|
{ |
|
/* need to increase the capacity of the array */ |
|
array = realloc(array, sizeof(unsigned short)*capacity); |
|
if(!array) |
|
{ |
|
syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error", |
|
(unsigned)sizeof(unsigned short)*capacity); |
|
*number = 0; |
|
break; |
|
} |
|
array[*number] = eport; |
|
(*number)++; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if(h) |
|
#ifdef IPTABLES_143 |
|
iptc_free(h); |
|
#else |
|
iptc_free(&h); |
|
#endif |
|
return array; |
|
} |
|
|
/* ================================ */ |
/* ================================ */ |
|
#ifdef DEBUG |
static int |
static int |
print_match(const struct ipt_entry_match *match) |
print_match(const struct ipt_entry_match *match) |
{ |
{ |
Line 752 list_redirect_rule(const char * ifname)
|
Line 975 list_redirect_rule(const char * ifname)
|
const struct ipt_entry_target * target; |
const struct ipt_entry_target * target; |
const struct ip_nat_multi_range * mr; |
const struct ip_nat_multi_range * mr; |
const char * target_str; |
const char * target_str; |
|
char addr[16], mask[16]; |
|
|
h = iptc_init("nat"); |
h = iptc_init("nat"); |
if(!h) |
if(!h) |
Line 783 list_redirect_rule(const char * ifname)
|
Line 1007 list_redirect_rule(const char * ifname)
|
target_str = iptc_get_target(e, &h); |
target_str = iptc_get_target(e, &h); |
#endif |
#endif |
printf("===\n"); |
printf("===\n"); |
|
inet_ntop(AF_INET, &e->ip.src, addr, sizeof(addr)); |
|
inet_ntop(AF_INET, &e->ip.smsk, mask, sizeof(mask)); |
printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"", |
printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"", |
inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk)); | /*inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk)*/ |
| addr, mask); |
| inet_ntop(AF_INET, &e->ip.dst, addr, sizeof(addr)); |
| inet_ntop(AF_INET, &e->ip.dmsk, mask, sizeof(mask)); |
printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"", |
printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"", |
inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk)); | /*inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk)*/ |
| addr, mask); |
/*printf("in_if = %s out_if = %s\n", e->ip.iniface, e->ip.outiface);*/ |
/*printf("in_if = %s out_if = %s\n", e->ip.iniface, e->ip.outiface);*/ |
printf("in_if = "); |
printf("in_if = "); |
print_iface(e->ip.iniface, e->ip.iniface_mask, |
print_iface(e->ip.iniface, e->ip.iniface_mask, |
Line 822 list_redirect_rule(const char * ifname)
|
Line 1052 list_redirect_rule(const char * ifname)
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
| #endif |