Some reports that a certain app is abusing UPnP for exploiting upload
bandwidth. This commit adds support to restrict UPnP rules to a regex.
By matching requester's description string against rule's regex, this
will make some obstacles for that app.
This ensures that all requests for getting public IP address (either via UPnP IGD or PCP/PMP) would contain correct public IP address or an error (instead of some invalid private/reserved IP address).
The eport_first variable now gets initialized in the first
iteration of the while loop; the assignment right before the
loop should have been removed in the previous commit.
The find_available_eport function that was intended to check if
at least one eport is allowed for a given iaddr/iport does not
work as intended; for example, it does not properly handle rule
precedence (i.e., it considers allow rules even if they are
effectively masked by earlier deny rules), and it also does not
handle the case where no rules are specified at all (which
should default to accept in order to be consistent with
check_upnp_rule_against_permissions). The present change removes
this function and instead integrates the check into the existing
while loop that iterates over all eports.
When skipping ports that are in use or not allowed, the existing
NAT-PMP code will consider port zero as a candidate eport after
wraparound occurs. Since this is not a legal port, we skip over it.
port zero as an eport value.
These two break statements are redundant: The subsequent continue
statement will cause the loop condition to be re-evaluated, at which
point the loop will terminate if resp[3] != 0.
Instead of returning code 3 ("Network Failure"), we should the
more appropriate code 4 ("Out of resources") when no external
port is available for a mapping.
The NAT-PMP code attempts to find a different eport if the
requested one is already in use. If all eports are in use, that
would previously cause the code to iterate through the range of
eports forever. To avoid this case, we keep track of the first
eport we attempted to use and abort the loop once we've cycled
through all possible values exactly once (which takes us back
to the initial eport).