add update_portmapping() / update_portmapping_desc_timestamp() functions
This commit is contained in:
parent
34f80a011f
commit
bdac007771
|
@ -3,6 +3,7 @@ $Id: Changelog.txt,v 1.421 2016/02/12 12:34:37 nanard Exp $
|
||||||
2016/02/12:
|
2016/02/12:
|
||||||
return error 729 - ConflictWithOtherMechanisms if IGD v2 is enabled.
|
return error 729 - ConflictWithOtherMechanisms if IGD v2 is enabled.
|
||||||
add iptc_init() check in iptcrdr.c/init_redirect()
|
add iptc_init() check in iptcrdr.c/init_redirect()
|
||||||
|
add update_portmapping() / update_portmapping_desc_timestamp() functions
|
||||||
|
|
||||||
2016/02/11:
|
2016/02/11:
|
||||||
use Linux libuuid uuid_generate() / BSD uuid_create() API
|
use Linux libuuid uuid_generate() / BSD uuid_create() API
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $Id: commonrdr.h,v 1.9 2014/02/11 09:36:15 nanard Exp $ */
|
/* $Id: commonrdr.h,v 1.10 2016/02/12 12:34:39 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* (c) 2006-2014 Thomas Bernard
|
* (c) 2006-2016 Thomas Bernard
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* 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 */
|
||||||
|
@ -52,5 +52,16 @@ unsigned short *
|
||||||
get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||||
int proto, unsigned int * number);
|
int proto, unsigned int * number);
|
||||||
|
|
||||||
#endif
|
/* update the port mapping internal port, decription and timestamp */
|
||||||
|
int
|
||||||
|
update_portmapping(const char * ifname, unsigned short eport, int proto,
|
||||||
|
unsigned short iport, const char * desc,
|
||||||
|
unsigned int timestamp);
|
||||||
|
|
||||||
|
/* update the port mapping decription and timestamp */
|
||||||
|
int
|
||||||
|
update_portmapping_desc_timestamp(const char * ifname,
|
||||||
|
unsigned short eport, int proto,
|
||||||
|
const char * desc, unsigned int timestamp);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* $Id: ipfwrdr.c,v 1.12 2012/02/11 13:10:57 nanard Exp $ */
|
/* $Id: ipfwrdr.c,v 1.16 2016/02/12 13:44:01 nanard Exp $ */
|
||||||
/*
|
/*
|
||||||
* MiniUPnP project
|
* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2009 Jardel Weyrich
|
* (c) 2009 Jardel Weyrich
|
||||||
* (c) 2011-2012 Thomas Bernard
|
* (c) 2011-2016 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
|
||||||
*/
|
*/
|
||||||
|
@ -478,3 +478,71 @@ error:
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
update_portmapping_desc_timestamp(const char * ifname,
|
||||||
|
unsigned short eport, int proto,
|
||||||
|
const char * desc, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
UNUSED(ifname);
|
||||||
|
del_desc_time(eport, proto);
|
||||||
|
add_desc_time(eport, proto, desc, timestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
update_portmapping(const char * ifname, unsigned short eport, int proto,
|
||||||
|
unsigned short iport, const char * desc,
|
||||||
|
unsigned int timestamp)
|
||||||
|
{
|
||||||
|
int i, count_rules, total_rules = 0;
|
||||||
|
struct ip_fw * rules = NULL;
|
||||||
|
int r = -1;
|
||||||
|
char iaddr[16];
|
||||||
|
char rhost[16];
|
||||||
|
int found;
|
||||||
|
|
||||||
|
if (ipfw_validate_protocol(proto) < 0)
|
||||||
|
return -1;
|
||||||
|
if (ipfw_validate_ifname(ifname) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
|
||||||
|
if (count_rules < 0)
|
||||||
|
goto error;
|
||||||
|
} while (count_rules == 10);
|
||||||
|
|
||||||
|
found = 0;
|
||||||
|
iaddr[0] = '\0';
|
||||||
|
rhost[0] = '\0';
|
||||||
|
|
||||||
|
for (i=0; i<total_rules-1; i++) {
|
||||||
|
const struct ip_fw const * ptr = &rules[i];
|
||||||
|
if (proto == ptr->fw_prot && eport == ptr->fw_uar.fw_pts[0]) {
|
||||||
|
if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, sizeof(iaddr)) == NULL) {
|
||||||
|
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ((ptr->fw_src.s_addr != 0) &&
|
||||||
|
(inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, sizeof(rhost)) == NULL)) {
|
||||||
|
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
|
if (ipfw_exec(IP_FW_DEL, (struct ip_fw *)ptr, sizeof(*ptr)) < 0)
|
||||||
|
goto error;
|
||||||
|
del_desc_time(eport, proto);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipfw_free_ruleset(&rules);
|
||||||
|
rules = NULL;
|
||||||
|
|
||||||
|
if(found)
|
||||||
|
r = add_redirect_rule2(ifname, rhost, eport, iaddr, iport, proto, desc, timestamp);
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (rules != NULL)
|
||||||
|
ipfw_free_ruleset(&rules);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -1552,6 +1552,249 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
update_portmapping_desc_timestamp(const char * ifname,
|
||||||
|
unsigned short eport, int proto,
|
||||||
|
const char * desc, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
UNUSED(ifname);
|
||||||
|
del_redirect_desc(eport, proto);
|
||||||
|
add_redirect_desc(eport, proto, desc, timestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
update_rule_and_commit(const char * table, const char * chain,
|
||||||
|
unsigned index, const struct ipt_entry * e)
|
||||||
|
{
|
||||||
|
IPTC_HANDLE h;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
h = iptc_init(table);
|
||||||
|
if(!h)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
|
||||||
|
"update_rule_and_commit", iptc_strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
if(!iptc_replace_entry(chain, e, index, h))
|
||||||
|
#else
|
||||||
|
if(!iptc_replace_entry(chain, e, index, &h))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "%s(): iptc_replace_entry: %s",
|
||||||
|
"update_rule_and_commit", 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",
|
||||||
|
"update_rule_and_commit", iptc_strerror(errno));
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
iptc_free(h);
|
||||||
|
#else
|
||||||
|
iptc_free(&h);
|
||||||
|
#endif
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
update_portmapping(const char * ifname, unsigned short eport, int proto,
|
||||||
|
unsigned short iport, const char * desc,
|
||||||
|
unsigned int timestamp)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
int found = 0;
|
||||||
|
unsigned index = 0;
|
||||||
|
unsigned i = 0;
|
||||||
|
IPTC_HANDLE h;
|
||||||
|
const struct ipt_entry * e;
|
||||||
|
struct ipt_entry * new_e = NULL;
|
||||||
|
size_t entry_len;
|
||||||
|
const struct ipt_entry_target * target;
|
||||||
|
struct ip_nat_multi_range * mr;
|
||||||
|
const struct ipt_entry_match *match;
|
||||||
|
uint32_t iaddr = 0;
|
||||||
|
unsigned short old_iport;
|
||||||
|
|
||||||
|
h = iptc_init("nat");
|
||||||
|
if(!h)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
|
||||||
|
"update_portmapping", iptc_strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* First step : find the right nat rule */
|
||||||
|
if(!iptc_is_chain(miniupnpd_nat_chain, h))
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
for(e = iptc_first_rule(miniupnpd_nat_chain, h);
|
||||||
|
e;
|
||||||
|
e = iptc_next_rule(e, h), i++)
|
||||||
|
#else
|
||||||
|
for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
|
||||||
|
e;
|
||||||
|
e = iptc_next_rule(e, &h), i++)
|
||||||
|
#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;
|
||||||
|
if(eport != info->dpts[0])
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const struct ipt_udp * info;
|
||||||
|
info = (const struct ipt_udp *)match->data;
|
||||||
|
if(eport != info->dpts[0])
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* we found the right rule */
|
||||||
|
found = 1;
|
||||||
|
index = i;
|
||||||
|
target = (void *)e + e->target_offset;
|
||||||
|
mr = (struct ip_nat_multi_range *)&target->data[0];
|
||||||
|
iaddr = mr->range[0].min_ip;
|
||||||
|
old_iport = ntohs(mr->range[0].min.all);
|
||||||
|
entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size;
|
||||||
|
new_e = malloc(entry_len);
|
||||||
|
if(new_e == NULL) {
|
||||||
|
syslog(LOG_ERR, "%s: malloc(%u) error",
|
||||||
|
"update_portmapping", (unsigned)entry_len);
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(new_e, e, entry_len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
iptc_free(h);
|
||||||
|
#else
|
||||||
|
iptc_free(&h);
|
||||||
|
#endif
|
||||||
|
if(!found || r < 0)
|
||||||
|
return -1;
|
||||||
|
syslog(LOG_INFO, "Trying to update nat rule at index %u", index);
|
||||||
|
target = (void *)new_e + new_e->target_offset;
|
||||||
|
mr = (struct ip_nat_multi_range *)&target->data[0];
|
||||||
|
mr->range[0].min.all = mr->range[0].max.all = htons(iport);
|
||||||
|
/* first update the nat rule */
|
||||||
|
r = update_rule_and_commit("nat", miniupnpd_nat_chain, index, new_e);
|
||||||
|
free(new_e); new_e = NULL;
|
||||||
|
if(r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* update filter rule */
|
||||||
|
h = iptc_init("filter");
|
||||||
|
if(!h)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "%s() : iptc_init() failed : %s",
|
||||||
|
"update_portmapping", iptc_strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
i = 0; found = 0;
|
||||||
|
if(!iptc_is_chain(miniupnpd_forward_chain, h))
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "chain %s not found", miniupnpd_forward_chain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* we must find the right index for the filter rule */
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
for(e = iptc_first_rule(miniupnpd_forward_chain, h);
|
||||||
|
e;
|
||||||
|
e = iptc_next_rule(e, h), i++)
|
||||||
|
#else
|
||||||
|
for(e = iptc_first_rule(miniupnpd_forward_chain, &h);
|
||||||
|
e;
|
||||||
|
e = iptc_next_rule(e, &h), i++)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(proto!=e->ip.proto)
|
||||||
|
continue;
|
||||||
|
target = (void *)e + e->target_offset;
|
||||||
|
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;
|
||||||
|
if(old_iport != info->dpts[0])
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const struct ipt_udp * info;
|
||||||
|
info = (const struct ipt_udp *)match->data;
|
||||||
|
if(old_iport != info->dpts[0])
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(iaddr != e->ip.dst.s_addr)
|
||||||
|
continue;
|
||||||
|
index = i;
|
||||||
|
found = 1;
|
||||||
|
entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size;
|
||||||
|
new_e = malloc(entry_len);
|
||||||
|
if(new_e == NULL) {
|
||||||
|
syslog(LOG_ERR, "%s: malloc(%u) error",
|
||||||
|
"update_portmapping", (unsigned)entry_len);
|
||||||
|
r = -1;
|
||||||
|
} else {
|
||||||
|
memcpy(new_e, e, entry_len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef IPTABLES_143
|
||||||
|
iptc_free(h);
|
||||||
|
#else
|
||||||
|
iptc_free(&h);
|
||||||
|
#endif
|
||||||
|
if(!found || r < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "Trying to update filter rule at index %u", index);
|
||||||
|
match = (struct ipt_entry_match *)&new_e->elems;
|
||||||
|
if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
|
||||||
|
{
|
||||||
|
struct ipt_tcp * info;
|
||||||
|
info = (struct ipt_tcp *)match->data;
|
||||||
|
info->dpts[0] = info->dpts[1] = iport;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct ipt_udp * info;
|
||||||
|
info = (struct ipt_udp *)match->data;
|
||||||
|
info->dpts[0] = info->dpts[1] = iport;
|
||||||
|
}
|
||||||
|
r = update_rule_and_commit("filter", miniupnpd_forward_chain, index, new_e);
|
||||||
|
free(new_e); new_e = NULL;
|
||||||
|
if(r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return update_portmapping_desc_timestamp(ifname, eport, proto, desc, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================ */
|
/* ================================ */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -53,6 +53,8 @@ main(int argc, char ** argv)
|
||||||
fprintf(stderr, "addpeenatrule failed\n");
|
fprintf(stderr, "addpeenatrule failed\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/*update_portmapping_desc_timestamp(NULL, eport, proto, "updated desc", time(NULL)+42);*/
|
||||||
|
update_portmapping(NULL, eport, proto, iport+1, "updated rule", time(NULL)+42);
|
||||||
/* test */
|
/* test */
|
||||||
{
|
{
|
||||||
unsigned short p1, p2;
|
unsigned short p1, p2;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: obsdrdr.c,v 1.84 2015/02/08 08:55:55 nanard Exp $ */
|
/* $Id: obsdrdr.c,v 1.86 2016/02/12 13:11:03 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2015 Thomas Bernard
|
* (c) 2006-2016 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 */
|
||||||
|
|
||||||
|
@ -607,7 +607,7 @@ error:
|
||||||
static int
|
static int
|
||||||
priv_delete_redirect_rule(const char * ifname, unsigned short eport,
|
priv_delete_redirect_rule(const char * ifname, unsigned short eport,
|
||||||
int proto, unsigned short * iport,
|
int proto, unsigned short * iport,
|
||||||
in_addr_t * iaddr)
|
in_addr_t * iaddr, char * rhost, int rhostlen)
|
||||||
{
|
{
|
||||||
int i, n;
|
int i, n;
|
||||||
struct pfioc_rule pr;
|
struct pfioc_rule pr;
|
||||||
|
@ -683,6 +683,14 @@ priv_delete_redirect_rule(const char * ifname, unsigned short eport,
|
||||||
*iaddr = pr.rule.rdr.addr.v.a.addr.v4.s_addr;
|
*iaddr = pr.rule.rdr.addr.v.a.addr.v4.s_addr;
|
||||||
}
|
}
|
||||||
#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);
|
||||||
|
}
|
||||||
pr.action = PF_CHANGE_GET_TICKET;
|
pr.action = PF_CHANGE_GET_TICKET;
|
||||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||||
{
|
{
|
||||||
|
@ -708,7 +716,7 @@ int
|
||||||
delete_redirect_rule(const char * ifname, unsigned short eport,
|
delete_redirect_rule(const char * ifname, unsigned short eport,
|
||||||
int proto)
|
int proto)
|
||||||
{
|
{
|
||||||
return priv_delete_redirect_rule(ifname, eport, proto, NULL, NULL);
|
return priv_delete_redirect_rule(ifname, eport, proto, NULL, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -782,7 +790,7 @@ delete_redirect_and_filter_rules(const char * ifname, unsigned short eport,
|
||||||
int r;
|
int r;
|
||||||
unsigned short iport;
|
unsigned short iport;
|
||||||
in_addr_t iaddr;
|
in_addr_t iaddr;
|
||||||
r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr);
|
r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr, NULL, 0);
|
||||||
if(r == 0)
|
if(r == 0)
|
||||||
{
|
{
|
||||||
r = priv_delete_filter_rule(ifname, iport, proto, iaddr);
|
r = priv_delete_filter_rule(ifname, iport, proto, iaddr);
|
||||||
|
@ -978,6 +986,61 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport,
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* update the port mapping internal port, decription and timestamp */
|
||||||
|
int
|
||||||
|
update_portmapping(const char * ifname, unsigned short eport, int proto,
|
||||||
|
unsigned short iport, const char * desc,
|
||||||
|
unsigned int timestamp)
|
||||||
|
{
|
||||||
|
unsigned short old_iport;
|
||||||
|
in_addr_t iaddr;
|
||||||
|
char iaddr_str[16];
|
||||||
|
char rhost[32];
|
||||||
|
|
||||||
|
if(priv_delete_redirect_rule(ifname, eport, proto, &old_iport, &iaddr, rhost, sizeof(rhost)) < 0)
|
||||||
|
return -1;
|
||||||
|
if (priv_delete_filter_rule(ifname, old_iport, proto, iaddr) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &iaddr, iaddr_str, sizeof(iaddr_str));
|
||||||
|
|
||||||
|
if(add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto,
|
||||||
|
desc, timestamp) < 0)
|
||||||
|
return -1;
|
||||||
|
if(add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update the port mapping decription and timestamp */
|
||||||
|
int
|
||||||
|
update_portmapping_desc_timestamp(const char * ifname,
|
||||||
|
unsigned short eport, int proto,
|
||||||
|
const char * desc, unsigned int timestamp)
|
||||||
|
{
|
||||||
|
unsigned short iport;
|
||||||
|
in_addr_t iaddr;
|
||||||
|
char iaddr_str[16];
|
||||||
|
char rhost[32];
|
||||||
|
|
||||||
|
if(priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr, rhost, sizeof(rhost)) < 0)
|
||||||
|
return -1;
|
||||||
|
if (priv_delete_filter_rule(ifname, iport, proto, iaddr) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &iaddr, iaddr_str, sizeof(iaddr_str));
|
||||||
|
|
||||||
|
if(add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto,
|
||||||
|
desc, timestamp) < 0)
|
||||||
|
return -1;
|
||||||
|
if(add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* this function is only for testing */
|
/* this function is only for testing */
|
||||||
#if TEST
|
#if TEST
|
||||||
void
|
void
|
||||||
|
|
|
@ -264,6 +264,7 @@ upnp_redirect(const char * rhost, unsigned short eport,
|
||||||
{
|
{
|
||||||
int proto, r;
|
int proto, r;
|
||||||
char iaddr_old[32];
|
char iaddr_old[32];
|
||||||
|
char rhost_old[32];
|
||||||
unsigned short iport_old;
|
unsigned short iport_old;
|
||||||
struct in_addr address;
|
struct in_addr address;
|
||||||
unsigned int timestamp;
|
unsigned int timestamp;
|
||||||
|
@ -280,20 +281,59 @@ upnp_redirect(const char * rhost, unsigned short eport,
|
||||||
"%hu->%s:%hu %s", eport, iaddr, iport, protocol);
|
"%hu->%s:%hu %s", eport, iaddr, iport, protocol);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
/* IGDv1 (WANIPConnection:1 Service Template Version 1.01 / Nov 12, 2001)
|
||||||
|
* - 2.2.20.PortMappingDescription :
|
||||||
|
* Overwriting Previous / Existing Port Mappings:
|
||||||
|
* If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient
|
||||||
|
* are exactly the same as an existing mapping, the existing mapping values
|
||||||
|
* for InternalPort, PortMappingDescription, PortMappingEnabled and
|
||||||
|
* PortMappingLeaseDuration are overwritten.
|
||||||
|
* Rejecting a New Port Mapping:
|
||||||
|
* In cases where the RemoteHost, ExternalPort and PortMappingProtocol
|
||||||
|
* are the same as an existing mapping, but the InternalClient is
|
||||||
|
* different, the action is rejected with an appropriate error.
|
||||||
|
* Add or Reject New Port Mapping behavior based on vendor implementation:
|
||||||
|
* In cases where the ExternalPort, PortMappingProtocol and InternalClient
|
||||||
|
* are the same, but RemoteHost is different, the vendor can choose to
|
||||||
|
* support both mappings simultaneously, or reject the second mapping
|
||||||
|
* with an appropriate error.
|
||||||
|
*
|
||||||
|
* - 2.4.16.AddPortMapping
|
||||||
|
* This action creates a new port mapping or overwrites an existing
|
||||||
|
* mapping with the same internal client. If the ExternalPort and
|
||||||
|
* PortMappingProtocol pair is already mapped to another internal client,
|
||||||
|
* an error is returned.
|
||||||
|
*
|
||||||
|
* IGDv2 (WANIPConnection:2 Service Standardized DCP (SDCP) Sep 10, 2010)
|
||||||
|
* Protocol ExternalPort RemoteHost InternalClient Result
|
||||||
|
* = = ≠ ≠ Failure
|
||||||
|
* = = ≠ = Failure or success
|
||||||
|
* (vendor specific)
|
||||||
|
* = = = ≠ Failure
|
||||||
|
* = = = = Success (overwrite)
|
||||||
|
*/
|
||||||
|
rhost_old[0] = '\0';
|
||||||
r = get_redirect_rule(ext_if_name, eport, proto,
|
r = get_redirect_rule(ext_if_name, eport, proto,
|
||||||
iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
|
iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
|
||||||
0, 0,
|
rhost_old, sizeof(rhost_old),
|
||||||
×tamp, 0, 0);
|
×tamp, 0, 0);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
/* if existing redirect rule matches redirect request return success
|
if(strcmp(iaddr, iaddr_old)==0 &&
|
||||||
* xbox 360 does not keep track of the port it redirects and will
|
((rhost == NULL && rhost_old[0]=='\0') ||
|
||||||
* redirect another port when receiving ConflictInMappingEntry */
|
(rhost && (strcmp(rhost, "*") == 0) && rhost_old[0]=='\0') ||
|
||||||
if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
|
(rhost && (strcmp(rhost, rhost_old) == 0)))) {
|
||||||
syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect");
|
syslog(LOG_INFO, "updating existing port mapping %hu %s (rhost '%s') => %s:%hu",
|
||||||
|
eport, protocol, rhost_old, iaddr_old, iport_old);
|
||||||
|
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
|
||||||
|
/* TODO : update lease file */
|
||||||
|
if(iport != iport_old) {
|
||||||
|
return update_portmapping(ext_if_name, eport, proto, iport, desc, timestamp);
|
||||||
|
} else {
|
||||||
|
return update_portmapping_desc_timestamp(ext_if_name, eport, proto, desc, timestamp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
syslog(LOG_INFO, "port %hu %s (rhost '%s') already redirected to %s:%hu",
|
||||||
syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
|
eport, protocol, rhost_old, iaddr_old, iport_old);
|
||||||
eport, protocol, iaddr_old, iport_old);
|
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
#ifdef CHECK_PORTINUSE
|
#ifdef CHECK_PORTINUSE
|
||||||
|
@ -309,8 +349,6 @@ upnp_redirect(const char * rhost, unsigned short eport,
|
||||||
return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
|
return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
|
||||||
desc, timestamp);
|
desc, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -445,14 +445,6 @@ AddPortMapping(struct upnphttp * h, const char * action, const char * ns)
|
||||||
action, eport, int_ip, iport, protocol, desc, leaseduration,
|
action, eport, int_ip, iport, protocol, desc, leaseduration,
|
||||||
r_host ? r_host : "NULL");
|
r_host ? r_host : "NULL");
|
||||||
|
|
||||||
/* TODO : be compliant with IGD spec for updating existing port mappings.
|
|
||||||
See "WANIPConnection:1 Service Template Version 1.01" 2.2.20.PortMappingDescription :
|
|
||||||
Overwriting Previous / Existing Port Mappings:
|
|
||||||
If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient are
|
|
||||||
exactly the same as an existing mapping, the existing mapping values for InternalPort,
|
|
||||||
PortMappingDescription, PortMappingEnabled and PortMappingLeaseDuration are
|
|
||||||
overwritten.
|
|
||||||
*/
|
|
||||||
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
|
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
|
||||||
|
|
||||||
ClearNameValueList(&data);
|
ClearNameValueList(&data);
|
||||||
|
|
Loading…
Reference in New Issue