Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend PortMappingListener to support more routers and use-cases #262

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

fishface60
Copy link

@fishface60 fishface60 commented Dec 27, 2024

I have recently been working on porting an application's UPnP implementation to jupnp as it had been non-functional for a while.

Jupnp was the best maintained option, and the PortMappingListener was valuable for getting it working, but was not sufficient on its own.

The missing functionality was:

  1. Specifying the internal client address ahead of time wasn't a good fit, since the application binds to the wildcard address rather than having a configured address to serve on, thus the address that needs to be mapped isn't obvious until after the IGD device has been discovered, so if the internal client is null it should determine an appropriate address to use.
  2. The application provides user feedback on whether UPnP successfully mapped some ports, so some callbacks for when an IGD has been discovered and when a port has been mapped are needed.
  3. My router doesn't support InternetGatewayDevice:1, only InternetGatewayDevice:2. The relevant actions are compatible with InternetGatewayDevice:1 so it just needs to know to look for devices with the other version number.

Closes #263
Closes #264
Closes #265

Providing the address to bind isn't always possible, since it is not
known in advance which of the device's addresses are reachable by a IGD.

Since we can only map one port to the address we need to pick which port
to map carefully.

The dominant constraint is that routers may reject mapping requests
where the address to map doesn't match the sender's address,
and by using the address the device was discovered on we guarantee that
the address matches some address the Control Point sends requests from
so when the Router sends the PortMappingAdd action from every bound UDP
port it guarantees that the router will accept one of them if

The second constraint is that some addresses are faster than others
e.g. Ethernet is usually preferred over WiFi.
Linux handles this preference with metrics in the routing table
and could be consulted by connecting a socket to the gateway
and getting the local address of the socket.

However this address may not be one of the addresses the Control Point
is serving or the computer may be connected to multiple networks with
the same gateway address and the heuristic can't return both addresses
so the fastest responding request will have to suffice.

Signed-off-by: Richard Maw <[email protected]>
It is useful to be able to hook into the logic to provide user feedback
on whether any IGDs were successfully discovered or successfully mapped
ports e.g. via a CompletableFuture that you can get with a timeout.

Signed-off-by: Richard Maw <[email protected]>
InternetGatewayDevice:2 adds WANConnectionDevice:2 as a sub-device
that implements WANIPConnection:2 instead of WANIPConnection:1.

This provides the same methods as WANIPConnection:1 but has some
additional constraints such as the gateway must only serve it on the
LAN interface and should reject mappings to an address that wasn't the
origin of the request.

Signed-off-by: Richard Maw <[email protected]>
@fishface60
Copy link
Author

I discovered the guidance in CONTRIBUTING after submitting, I'll try to adapt it to the guidance post-hoc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant