mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-04 07:25:39 +00:00
net/portmapper: also send UPnP SSDP query to the SSDP multicast address.
Fixes #3197
Signed-off-by: David Anderson <danderson@tailscale.com>
(cherry picked from commit 4a65b07e34
)
This commit is contained in:
parent
647486dc46
commit
d117f77094
@ -677,6 +677,7 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
|
||||
|
||||
pxpAddr := netaddr.IPPortFrom(gw, c.pxpPort()).UDPAddr()
|
||||
upnpAddr := netaddr.IPPortFrom(gw, c.upnpPort()).UDPAddr()
|
||||
upnpMulticastAddr := netaddr.IPPortFrom(netaddr.IPv4(239, 255, 255, 250), c.upnpPort()).UDPAddr()
|
||||
|
||||
// Don't send probes to services that we recently learned (for
|
||||
// the same gw/myIP) are available. See
|
||||
@ -694,7 +695,47 @@ func (c *Client) Probe(ctx context.Context) (res ProbeResult, err error) {
|
||||
if c.sawUPnPRecently() {
|
||||
res.UPnP = true
|
||||
} else if !DisableUPnP {
|
||||
// Strictly speaking, you discover UPnP services by sending an
|
||||
// SSDP query (which uPnPPacket is) to udp/1900 on the SSDP
|
||||
// multicast address, and then get a flood of responses back
|
||||
// from everything on your network.
|
||||
//
|
||||
// Empirically, many home routers also respond to SSDP queries
|
||||
// directed at udp/1900 on their LAN unicast IP
|
||||
// (e.g. 192.168.1.1). This is handy because it means we can
|
||||
// probe the router directly and likely get a reply. However,
|
||||
// the specs do not _require_ UPnP devices to respond to
|
||||
// unicast SSDP queries, so some conformant UPnP
|
||||
// implementations only respond to multicast queries.
|
||||
//
|
||||
// In theory, we could send just the multicast query and get
|
||||
// all compliant devices to respond. However, we instead send
|
||||
// to both a unicast and a multicast addresses, for a couple
|
||||
// of reasons:
|
||||
//
|
||||
// First, some LANs and OSes have broken multicast in one way
|
||||
// or another, so it's possible for the multicast query to be
|
||||
// lost while the unicast query gets through. But we still
|
||||
// have to send the multicast query to also get a response
|
||||
// from strict-UPnP devices on multicast-working networks.
|
||||
//
|
||||
// Second, SSDP's packet dynamics are a bit weird: you send
|
||||
// the SSDP query from your unicast IP to the SSDP multicast
|
||||
// IP, but responses are from the UPnP devices's _unicast_ IP
|
||||
// to your unicast IP. This can confuse some less-intelligent
|
||||
// stateful host firewalls, who might block the responses. To
|
||||
// work around this, we send the unicast query first, to teach
|
||||
// the firewall to expect a unicast response from the router,
|
||||
// and then send our multicast query. That way, even if the
|
||||
// device doesn't respond to the unicast query, we've set the
|
||||
// stage for the host firewall to accept the response to the
|
||||
// multicast query.
|
||||
//
|
||||
// See https://github.com/tailscale/tailscale/issues/3197 for
|
||||
// an example of a device that strictly implements UPnP, and
|
||||
// only responds to multicast queries.
|
||||
uc.WriteTo(uPnPPacket, upnpAddr)
|
||||
uc.WriteTo(uPnPPacket, upnpMulticastAddr)
|
||||
}
|
||||
|
||||
buf := make([]byte, 1500)
|
||||
|
Loading…
Reference in New Issue
Block a user