From efbb95aa10765326a2358b11e5d6b9657caf255f Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Tue, 11 Mar 2014 01:54:10 -0700 Subject: [PATCH] miniupnpd/pcpserver.c: port NAT-PMP updates to PCP This change ports the recent updates to the permissions checking and eport selection code for NAT-PMP to the PCP MAP handler. --- miniupnpd/pcpserver.c | 44 +++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 8a88c6a..5ba4a25 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -805,6 +805,8 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) char desc[64]; char iaddr_old[INET_ADDRSTRLEN]; uint16_t iport_old; + uint16_t eport_first = 0; + int any_eport_allowed = 0; unsigned int timestamp; int r=0; @@ -812,6 +814,32 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) pcp_msg_info->ext_port = pcp_msg_info->int_port; } do { + if (eport_first == 0) { /* first time in loop */ + eport_first = pcp_msg_info->ext_port; + } else if (pcp_msg_info->ext_port == eport_first) { /* no eport available */ + if (any_eport_allowed == 0) { /* all eports rejected by permissions */ + pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED; + } else { /* at least one eport allowed (but none available) */ + pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; + } + return; + } + if ((IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && + (!check_upnp_rule_against_permissions(upnppermlist, + num_upnpperm, pcp_msg_info->ext_port, + ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], + pcp_msg_info->int_port)))) { + if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; + } + pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } + continue; + } + any_eport_allowed = 1; r = get_redirect_rule(ext_if_name, pcp_msg_info->ext_port, pcp_msg_info->protocol, @@ -836,24 +864,20 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) if (_upnp_delete_redir(pcp_msg_info->ext_port, pcp_msg_info->protocol)==0) { break; + } else if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; } } pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } } } while (r==0); timestamp = time(NULL) + pcp_msg_info->lifetime; - if ((pcp_msg_info->ext_port == 0) || - (IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && - (!check_upnp_rule_against_permissions(upnppermlist, - num_upnpperm, pcp_msg_info->ext_port, - ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], - pcp_msg_info->int_port)))) { - pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; - return; - } - snprintf(desc, sizeof(desc), "PCP %hu %s", pcp_msg_info->ext_port, (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp");