diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index 2f909ee8e..aa9ad2fb4 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -55,6 +55,12 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ github.com/google/gnostic-models/openapiv3 from k8s.io/kube-openapi/pkg/handler3+ github.com/google/uuid from github.com/prometheus-community/pro-bing+ github.com/hdevalence/ed25519consensus from tailscale.com/tka + github.com/huin/goupnp from github.com/huin/goupnp/dcps/internetgateway2+ + github.com/huin/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper + github.com/huin/goupnp/httpu from github.com/huin/goupnp+ + github.com/huin/goupnp/scpd from github.com/huin/goupnp + github.com/huin/goupnp/soap from github.com/huin/goupnp+ + github.com/huin/goupnp/ssdp from github.com/huin/goupnp github.com/josharian/intern from github.com/mailru/easyjson/jlexer L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/netmon L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink @@ -103,12 +109,6 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ W 💣 github.com/tailscale/go-winio/internal/socket from github.com/tailscale/go-winio W github.com/tailscale/go-winio/internal/stringbuffer from github.com/tailscale/go-winio/internal/fs W github.com/tailscale/go-winio/pkg/guid from github.com/tailscale/go-winio+ - github.com/tailscale/goupnp from github.com/tailscale/goupnp/dcps/internetgateway2+ - github.com/tailscale/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper - github.com/tailscale/goupnp/httpu from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/scpd from github.com/tailscale/goupnp - github.com/tailscale/goupnp/soap from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp github.com/tailscale/hujson from tailscale.com/ipn/conffile+ LD github.com/tailscale/peercred from tailscale.com/ipn/ipnauth github.com/tailscale/web-client-prebuilt from tailscale.com/client/web diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index 695c8a85e..1a6a1a52c 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -35,6 +35,12 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep github.com/golang/groupcache/lru from tailscale.com/net/dnscache DW github.com/google/uuid from tailscale.com/clientupdate+ github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+ + github.com/huin/goupnp from github.com/huin/goupnp/dcps/internetgateway2+ + github.com/huin/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper + github.com/huin/goupnp/httpu from github.com/huin/goupnp+ + github.com/huin/goupnp/scpd from github.com/huin/goupnp + github.com/huin/goupnp/soap from github.com/huin/goupnp+ + github.com/huin/goupnp/ssdp from github.com/huin/goupnp L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/netmon L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink github.com/kballard/go-shellquote from tailscale.com/cmd/tailscale/cli @@ -55,12 +61,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep W 💣 github.com/tailscale/go-winio/internal/socket from github.com/tailscale/go-winio W github.com/tailscale/go-winio/internal/stringbuffer from github.com/tailscale/go-winio/internal/fs W github.com/tailscale/go-winio/pkg/guid from github.com/tailscale/go-winio+ - github.com/tailscale/goupnp from github.com/tailscale/goupnp/dcps/internetgateway2+ - github.com/tailscale/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper - github.com/tailscale/goupnp/httpu from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/scpd from github.com/tailscale/goupnp - github.com/tailscale/goupnp/soap from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp github.com/tailscale/hujson from tailscale.com/ipn/conffile github.com/tailscale/web-client-prebuilt from tailscale.com/client/web github.com/toqueteos/webbrowser from tailscale.com/cmd/tailscale/cli+ @@ -463,7 +463,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep path from archive/tar+ path/filepath from archive/tar+ reflect from archive/tar+ - regexp from github.com/tailscale/goupnp/httpu+ + regexp from github.com/huin/goupnp/httpu+ regexp/syntax from regexp runtime from archive/tar+ runtime/debug from tailscale.com+ diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 13c1f5daf..ed8f6a512 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -125,6 +125,12 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de L github.com/google/nftables/xt from github.com/google/nftables/expr+ DW github.com/google/uuid from tailscale.com/clientupdate+ github.com/hdevalence/ed25519consensus from tailscale.com/clientupdate/distsign+ + github.com/huin/goupnp from github.com/huin/goupnp/dcps/internetgateway2+ + github.com/huin/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper + github.com/huin/goupnp/httpu from github.com/huin/goupnp+ + github.com/huin/goupnp/scpd from github.com/huin/goupnp + github.com/huin/goupnp/soap from github.com/huin/goupnp+ + github.com/huin/goupnp/ssdp from github.com/huin/goupnp L 💣 github.com/illarion/gonotify/v3 from tailscale.com/feature/linuxdnsfight L github.com/illarion/gonotify/v3/syscallf from github.com/illarion/gonotify/v3 L github.com/insomniacslk/dhcp/dhcpv4 from tailscale.com/feature/tap @@ -168,12 +174,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de W 💣 github.com/tailscale/go-winio/internal/socket from github.com/tailscale/go-winio W github.com/tailscale/go-winio/internal/stringbuffer from github.com/tailscale/go-winio/internal/fs W github.com/tailscale/go-winio/pkg/guid from github.com/tailscale/go-winio+ - github.com/tailscale/goupnp from github.com/tailscale/goupnp/dcps/internetgateway2+ - github.com/tailscale/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper - github.com/tailscale/goupnp/httpu from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/scpd from github.com/tailscale/goupnp - github.com/tailscale/goupnp/soap from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp github.com/tailscale/hujson from tailscale.com/ipn/conffile L 💣 github.com/tailscale/netlink from tailscale.com/net/routetable+ L 💣 github.com/tailscale/netlink/nl from github.com/tailscale/netlink diff --git a/cmd/tsidp/depaware.txt b/cmd/tsidp/depaware.txt index aa5d63346..24069551e 100644 --- a/cmd/tsidp/depaware.txt +++ b/cmd/tsidp/depaware.txt @@ -30,6 +30,12 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar github.com/google/btree from gvisor.dev/gvisor/pkg/tcpip/header+ D github.com/google/uuid from github.com/prometheus-community/pro-bing github.com/hdevalence/ed25519consensus from tailscale.com/tka + github.com/huin/goupnp from github.com/huin/goupnp/dcps/internetgateway2+ + github.com/huin/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper + github.com/huin/goupnp/httpu from github.com/huin/goupnp+ + github.com/huin/goupnp/scpd from github.com/huin/goupnp + github.com/huin/goupnp/soap from github.com/huin/goupnp+ + github.com/huin/goupnp/ssdp from github.com/huin/goupnp L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/netmon L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink github.com/klauspost/compress from github.com/klauspost/compress/zstd @@ -53,12 +59,6 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar W 💣 github.com/tailscale/go-winio/internal/socket from github.com/tailscale/go-winio W github.com/tailscale/go-winio/internal/stringbuffer from github.com/tailscale/go-winio/internal/fs W github.com/tailscale/go-winio/pkg/guid from github.com/tailscale/go-winio+ - github.com/tailscale/goupnp from github.com/tailscale/goupnp/dcps/internetgateway2+ - github.com/tailscale/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper - github.com/tailscale/goupnp/httpu from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/scpd from github.com/tailscale/goupnp - github.com/tailscale/goupnp/soap from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp github.com/tailscale/hujson from tailscale.com/ipn/conffile LD github.com/tailscale/peercred from tailscale.com/ipn/ipnauth github.com/tailscale/web-client-prebuilt from tailscale.com/client/web @@ -471,7 +471,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar encoding/hex from crypto/x509+ encoding/json from expvar+ encoding/pem from crypto/tls+ - encoding/xml from github.com/tailscale/goupnp+ + encoding/xml from github.com/huin/goupnp+ errors from bufio+ expvar from tailscale.com/health+ flag from tailscale.com/cmd/tsidp+ @@ -562,7 +562,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar path from debug/dwarf+ path/filepath from crypto/x509+ reflect from crypto/x509+ - regexp from github.com/tailscale/goupnp/httpu+ + regexp from github.com/huin/goupnp/httpu+ regexp/syntax from regexp runtime from crypto/internal/fips140+ runtime/debug from github.com/coder/websocket/internal/xsync+ diff --git a/flake.nix b/flake.nix index 9ee1b8f4f..dd8016b4e 100644 --- a/flake.nix +++ b/flake.nix @@ -151,4 +151,4 @@ }); }; } -# nix-direnv cache busting line: sha256-PVE4oEwcoTbXbPJnBcVgBeXITWlnkhBf+UT5nqSeANM= +# nix-direnv cache busting line: sha256-knSIes9pFVkVfK5hcBG9BSR1ueH+yPpx4hv/UsyaW2M= diff --git a/go.mod b/go.mod index 68f8de188..c8be839c3 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,7 @@ require ( github.com/hashicorp/raft v1.7.2 github.com/hashicorp/raft-boltdb/v2 v2.3.1 github.com/hdevalence/ed25519consensus v0.2.0 + github.com/huin/goupnp v1.3.0 github.com/illarion/gonotify/v3 v3.0.2 github.com/inetaf/tcpproxy v0.0.0-20250203165043-ded522cbd03f github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 @@ -86,7 +87,6 @@ require ( github.com/tailscale/depaware v0.0.0-20251001183927-9c2ad255ef3f github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41 github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 - github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a github.com/tailscale/mkctr v0.0.0-20260107121656-ea857e3e500b github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 diff --git a/go.mod.sri b/go.mod.sri index a38597267..fd2ab9d7a 100644 --- a/go.mod.sri +++ b/go.mod.sri @@ -1 +1 @@ -sha256-PVE4oEwcoTbXbPJnBcVgBeXITWlnkhBf+UT5nqSeANM= +sha256-knSIes9pFVkVfK5hcBG9BSR1ueH+yPpx4hv/UsyaW2M= diff --git a/go.sum b/go.sum index e7fc54e9f..19703e072 100644 --- a/go.sum +++ b/go.sum @@ -670,6 +670,8 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hugelgupf/vmtest v0.0.0-20240216064925-0561770280a1 h1:jWoR2Yqg8tzM0v6LAiP7i1bikZJu3gxpgvu3g1Lw+a0= github.com/hugelgupf/vmtest v0.0.0-20240216064925-0561770280a1/go.mod h1:B63hDJMhTupLWCHwopAyEo7wRFowx9kOc8m8j1sfOqE= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk= github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= @@ -1090,8 +1092,6 @@ github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41 h1:/V2rCMMWcsjY github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41/go.mod h1:/roCdA6gg6lQyw/Oz6gIIGu3ggJKYhF+WC/AQReE5XQ= github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 h1:SRL6irQkKGQKKLzvQP/ke/2ZuB7Py5+XuqtOgSj+iMM= github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= -github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= -github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= github.com/tailscale/mkctr v0.0.0-20260107121656-ea857e3e500b h1:QKqCnmp0qHWUHySySKjpuhZANzRn7XrTVZWUuUgJ3lQ= diff --git a/licenses/android.md b/licenses/android.md index d4d8c9d7b..4dc8e6c6d 100644 --- a/licenses/android.md +++ b/licenses/android.md @@ -27,7 +27,7 @@ Client][]. See also the dependencies in the [Tailscale CLI][]. - [github.com/mdlayher/socket](https://pkg.go.dev/github.com/mdlayher/socket) ([MIT](https://github.com/mdlayher/socket/blob/v0.5.0/LICENSE.md)) - [github.com/pierrec/lz4/v4](https://pkg.go.dev/github.com/pierrec/lz4/v4) ([BSD-3-Clause](https://github.com/pierrec/lz4/blob/v4.1.21/LICENSE)) - [github.com/pires/go-proxyproto](https://pkg.go.dev/github.com/pires/go-proxyproto) ([Apache-2.0](https://github.com/pires/go-proxyproto/blob/v0.8.1/LICENSE)) - - [github.com/tailscale/goupnp](https://pkg.go.dev/github.com/tailscale/goupnp) ([BSD-2-Clause](https://github.com/tailscale/goupnp/blob/c64d0f06ea05/LICENSE)) + - [github.com/huin/goupnp](https://pkg.go.dev/github.com/huin/goupnp) ([BSD-2-Clause](https://github.com/huin/goupnp/blob/v1.3.0/LICENSE)) - [github.com/tailscale/peercred](https://pkg.go.dev/github.com/tailscale/peercred) ([BSD-3-Clause](https://github.com/tailscale/peercred/blob/35a0c7bd7edc/LICENSE)) - [github.com/tailscale/tailscale-android/libtailscale](https://pkg.go.dev/github.com/tailscale/tailscale-android/libtailscale) ([BSD-3-Clause](https://github.com/tailscale/tailscale-android/blob/HEAD/LICENSE)) - [github.com/tailscale/wireguard-go](https://pkg.go.dev/github.com/tailscale/wireguard-go) ([MIT](https://github.com/tailscale/wireguard-go/blob/1d0488a3d7da/LICENSE)) diff --git a/licenses/apple.md b/licenses/apple.md index 6bb109f77..c3f2d3bb7 100644 --- a/licenses/apple.md +++ b/licenses/apple.md @@ -59,7 +59,7 @@ See also the dependencies in the [Tailscale CLI][]. - [github.com/pires/go-proxyproto](https://pkg.go.dev/github.com/pires/go-proxyproto) ([Apache-2.0](https://github.com/pires/go-proxyproto/blob/v0.8.1/LICENSE)) - [github.com/prometheus-community/pro-bing](https://pkg.go.dev/github.com/prometheus-community/pro-bing) ([MIT](https://github.com/prometheus-community/pro-bing/blob/v0.4.0/LICENSE)) - [github.com/safchain/ethtool](https://pkg.go.dev/github.com/safchain/ethtool) ([Apache-2.0](https://github.com/safchain/ethtool/blob/v0.3.0/LICENSE)) - - [github.com/tailscale/goupnp](https://pkg.go.dev/github.com/tailscale/goupnp) ([BSD-2-Clause](https://github.com/tailscale/goupnp/blob/c64d0f06ea05/LICENSE)) + - [github.com/huin/goupnp](https://pkg.go.dev/github.com/huin/goupnp) ([BSD-2-Clause](https://github.com/huin/goupnp/blob/v1.3.0/LICENSE)) - [github.com/tailscale/netlink](https://pkg.go.dev/github.com/tailscale/netlink) ([Apache-2.0](https://github.com/tailscale/netlink/blob/4d49adab4de7/LICENSE)) - [github.com/tailscale/peercred](https://pkg.go.dev/github.com/tailscale/peercred) ([BSD-3-Clause](https://github.com/tailscale/peercred/blob/35a0c7bd7edc/LICENSE)) - [github.com/tailscale/wireguard-go](https://pkg.go.dev/github.com/tailscale/wireguard-go) ([MIT](https://github.com/tailscale/wireguard-go/blob/1d0488a3d7da/LICENSE)) diff --git a/net/portmapper/legacy_upnp.go b/net/portmapper/legacy_upnp.go index 042ced16c..2ce92dc65 100644 --- a/net/portmapper/legacy_upnp.go +++ b/net/portmapper/legacy_upnp.go @@ -10,8 +10,8 @@ package portmapper import ( "context" - "github.com/tailscale/goupnp" - "github.com/tailscale/goupnp/soap" + "github.com/huin/goupnp" + "github.com/huin/goupnp/soap" ) const ( @@ -32,8 +32,8 @@ type legacyWANPPPConnection1 struct { goupnp.ServiceClient } -// AddPortMapping implements upnpClient -func (client *legacyWANPPPConnection1) AddPortMapping( +// AddPortMappingCtx implements upnpClient +func (client *legacyWANPPPConnection1) AddPortMappingCtx( ctx context.Context, NewRemoteHost string, NewExternalPort uint16, @@ -85,11 +85,11 @@ func (client *legacyWANPPPConnection1) AddPortMapping( response := any(nil) // Perform the SOAP call. - return client.SOAPClient.PerformAction(ctx, urn_LegacyWANPPPConnection_1, "AddPortMapping", request, response) + return client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANPPPConnection_1, "AddPortMapping", request, response) } -// DeletePortMapping implements upnpClient -func (client *legacyWANPPPConnection1) DeletePortMapping(ctx context.Context, NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { +// DeletePortMappingCtx implements upnpClient +func (client *legacyWANPPPConnection1) DeletePortMappingCtx(ctx context.Context, NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { // Request structure. request := &struct { NewRemoteHost string @@ -110,11 +110,11 @@ func (client *legacyWANPPPConnection1) DeletePortMapping(ctx context.Context, Ne response := any(nil) // Perform the SOAP call. - return client.SOAPClient.PerformAction(ctx, urn_LegacyWANPPPConnection_1, "DeletePortMapping", request, response) + return client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANPPPConnection_1, "DeletePortMapping", request, response) } -// GetExternalIPAddress implements upnpClient -func (client *legacyWANPPPConnection1) GetExternalIPAddress(ctx context.Context) (NewExternalIPAddress string, err error) { +// GetExternalIPAddressCtx implements upnpClient +func (client *legacyWANPPPConnection1) GetExternalIPAddressCtx(ctx context.Context) (NewExternalIPAddress string, err error) { // Request structure. request := any(nil) @@ -124,7 +124,7 @@ func (client *legacyWANPPPConnection1) GetExternalIPAddress(ctx context.Context) }{} // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(ctx, urn_LegacyWANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { + if err = client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANPPPConnection_1, "GetExternalIPAddress", request, response); err != nil { return } @@ -134,8 +134,8 @@ func (client *legacyWANPPPConnection1) GetExternalIPAddress(ctx context.Context) return } -// GetStatusInfo implements upnpClient -func (client *legacyWANPPPConnection1) GetStatusInfo(ctx context.Context) (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { +// GetStatusInfoCtx implements upnpClient +func (client *legacyWANPPPConnection1) GetStatusInfoCtx(ctx context.Context) (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { // Request structure. request := any(nil) @@ -147,7 +147,7 @@ func (client *legacyWANPPPConnection1) GetStatusInfo(ctx context.Context) (NewCo }{} // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(ctx, urn_LegacyWANPPPConnection_1, "GetStatusInfo", request, response); err != nil { + if err = client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANPPPConnection_1, "GetStatusInfo", request, response); err != nil { return } @@ -171,8 +171,8 @@ type legacyWANIPConnection1 struct { goupnp.ServiceClient } -// AddPortMapping implements upnpClient -func (client *legacyWANIPConnection1) AddPortMapping( +// AddPortMappingCtx implements upnpClient +func (client *legacyWANIPConnection1) AddPortMappingCtx( ctx context.Context, NewRemoteHost string, NewExternalPort uint16, @@ -224,11 +224,11 @@ func (client *legacyWANIPConnection1) AddPortMapping( response := any(nil) // Perform the SOAP call. - return client.SOAPClient.PerformAction(ctx, urn_LegacyWANIPConnection_1, "AddPortMapping", request, response) + return client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANIPConnection_1, "AddPortMapping", request, response) } -// DeletePortMapping implements upnpClient -func (client *legacyWANIPConnection1) DeletePortMapping(ctx context.Context, NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { +// DeletePortMappingCtx implements upnpClient +func (client *legacyWANIPConnection1) DeletePortMappingCtx(ctx context.Context, NewRemoteHost string, NewExternalPort uint16, NewProtocol string) (err error) { // Request structure. request := &struct { NewRemoteHost string @@ -249,11 +249,11 @@ func (client *legacyWANIPConnection1) DeletePortMapping(ctx context.Context, New response := any(nil) // Perform the SOAP call. - return client.SOAPClient.PerformAction(ctx, urn_LegacyWANIPConnection_1, "DeletePortMapping", request, response) + return client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANIPConnection_1, "DeletePortMapping", request, response) } -// GetExternalIPAddress implements upnpClient -func (client *legacyWANIPConnection1) GetExternalIPAddress(ctx context.Context) (NewExternalIPAddress string, err error) { +// GetExternalIPAddressCtx implements upnpClient +func (client *legacyWANIPConnection1) GetExternalIPAddressCtx(ctx context.Context) (NewExternalIPAddress string, err error) { // Request structure. request := any(nil) @@ -263,7 +263,7 @@ func (client *legacyWANIPConnection1) GetExternalIPAddress(ctx context.Context) }{} // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(ctx, urn_LegacyWANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { + if err = client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANIPConnection_1, "GetExternalIPAddress", request, response); err != nil { return } @@ -273,8 +273,8 @@ func (client *legacyWANIPConnection1) GetExternalIPAddress(ctx context.Context) return } -// GetStatusInfo implements upnpClient -func (client *legacyWANIPConnection1) GetStatusInfo(ctx context.Context) (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { +// GetStatusInfoCtx implements upnpClient +func (client *legacyWANIPConnection1) GetStatusInfoCtx(ctx context.Context) (NewConnectionStatus string, NewLastConnectionError string, NewUptime uint32, err error) { // Request structure. request := any(nil) @@ -286,7 +286,7 @@ func (client *legacyWANIPConnection1) GetStatusInfo(ctx context.Context) (NewCon }{} // Perform the SOAP call. - if err = client.SOAPClient.PerformAction(ctx, urn_LegacyWANIPConnection_1, "GetStatusInfo", request, response); err != nil { + if err = client.SOAPClient.PerformActionCtx(ctx, urn_LegacyWANIPConnection_1, "GetStatusInfo", request, response); err != nil { return } diff --git a/net/portmapper/select_test.go b/net/portmapper/select_test.go index af2e35cbf..cc685bc25 100644 --- a/net/portmapper/select_test.go +++ b/net/portmapper/select_test.go @@ -11,8 +11,8 @@ import ( "strings" "testing" - "github.com/tailscale/goupnp" - "github.com/tailscale/goupnp/dcps/internetgateway2" + "github.com/huin/goupnp" + "github.com/huin/goupnp/dcps/internetgateway2" ) // NOTE: this is in a distinct file because the various string constants are @@ -168,7 +168,7 @@ func TestSelectBestService(t *testing.T) { // Ensure that we're using the HTTP client that talks to our test IGD server ctx := context.Background() - ctx = goupnp.WithHTTPClient(ctx, c.upnpHTTPClientLocked()) + ctx = upnpHTTPClientKey.WithValue(ctx, c.upnpHTTPClientLocked()) loc := mustParseURL(igd.ts.URL) rootDev := mustParseRootDev(t, rootDesc, loc) diff --git a/net/portmapper/upnp.go b/net/portmapper/upnp.go index d65d6e94d..34140e947 100644 --- a/net/portmapper/upnp.go +++ b/net/portmapper/upnp.go @@ -25,15 +25,47 @@ import ( "sync/atomic" "time" - "github.com/tailscale/goupnp" - "github.com/tailscale/goupnp/dcps/internetgateway2" - "github.com/tailscale/goupnp/soap" + "github.com/huin/goupnp" + "github.com/huin/goupnp/dcps/internetgateway2" + "github.com/huin/goupnp/soap" "tailscale.com/envknob" "tailscale.com/net/netns" "tailscale.com/types/logger" + "tailscale.com/util/ctxkey" "tailscale.com/util/mak" ) +// upnpHTTPClientKey is a context key for storing an HTTP client to use +// for UPnP requests. This allows us to use a custom HTTP client (with custom +// dialer, timeouts, etc.) while using the upstream goupnp library which only +// supports a global HTTPClientDefault. +var upnpHTTPClientKey = ctxkey.New[*http.Client]("portmapper.upnpHTTPClient", nil) + +// delegatingRoundTripper implements http.RoundTripper by delegating to +// the HTTP client stored in the request's context. This allows us to use +// per-request HTTP client configuration with the upstream goupnp library. +type delegatingRoundTripper struct { + inner *http.Client +} + +func (d delegatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if c := upnpHTTPClientKey.Value(req.Context()); c != nil { + return c.Transport.RoundTrip(req) + } + return d.inner.Do(req) +} + +func init() { + // The upstream goupnp library uses a global HTTP client for all + // requests, while we want to be able to use a per-Client + // [http.Client]. We replace its global HTTP client with one that + // delegates to the HTTP client stored in the request's context. + old := goupnp.HTTPClientDefault + goupnp.HTTPClientDefault = &http.Client{ + Transport: delegatingRoundTripper{old}, + } +} + // References: // // WANIP Connection v2: http://upnp.org/specs/gw/UPnP-gw-WANIPConnection-v2-Service.pdf @@ -79,14 +111,17 @@ func (u *upnpMapping) MappingDebug() string { u.loc) } func (u *upnpMapping) Release(ctx context.Context) { - u.client.DeletePortMapping(ctx, "", u.external.Port(), upnpProtocolUDP) + u.client.DeletePortMappingCtx(ctx, "", u.external.Port(), upnpProtocolUDP) } // upnpClient is an interface over the multiple different clients exported by goupnp, // exposing the functions we need for portmapping. Those clients are auto-generated from XML-specs, // which is why they're not very idiomatic. +// +// The method names use the *Ctx suffix to match the upstream goupnp library's convention +// for context-aware methods. type upnpClient interface { - AddPortMapping( + AddPortMappingCtx( ctx context.Context, // remoteHost is the remote device sending packets to this device, in the format of x.x.x.x. @@ -119,9 +154,9 @@ type upnpClient interface { leaseDurationSec uint32, ) error - DeletePortMapping(ctx context.Context, remoteHost string, externalPort uint16, protocol string) error - GetExternalIPAddress(ctx context.Context) (externalIPAddress string, err error) - GetStatusInfo(ctx context.Context) (status string, lastConnError string, uptime uint32, err error) + DeletePortMappingCtx(ctx context.Context, remoteHost string, externalPort uint16, protocol string) error + GetExternalIPAddressCtx(ctx context.Context) (externalIPAddress string, err error) + GetStatusInfoCtx(ctx context.Context) (status string, lastConnError string, uptime uint32, err error) } // tsPortMappingDesc gets sent to UPnP clients as a human-readable label for the portmapping. @@ -171,7 +206,7 @@ func addAnyPortMapping( // First off, try using AddAnyPortMapping; if there's a conflict, the // router will pick another port and return it. if upnp, ok := upnp.(*internetgateway2.WANIPConnection2); ok { - return upnp.AddAnyPortMapping( + return upnp.AddAnyPortMappingCtx( ctx, "", externalPort, @@ -186,7 +221,7 @@ func addAnyPortMapping( // Fall back to using AddPortMapping, which requests a mapping to/from // a specific external port. - err = upnp.AddPortMapping( + err = upnp.AddPortMappingCtx( ctx, "", externalPort, @@ -244,7 +279,7 @@ func getUPnPRootDevice(ctx context.Context, logf logger.Logf, debug DebugKnobs, defer cancel() // This part does a network fetch. - root, err := goupnp.DeviceByURL(ctx, u) + root, err := goupnp.DeviceByURLCtx(ctx, u) if err != nil { return nil, nil, err } @@ -257,8 +292,7 @@ func getUPnPRootDevice(ctx context.Context, logf logger.Logf, debug DebugKnobs, // // loc is the parsed location that was used to fetch the given RootDevice. // -// The provided ctx is not retained in the returned upnpClient, but -// its associated HTTP client is (if set via goupnp.WithHTTPClient). +// The provided ctx is not retained in the returned upnpClient. func selectBestService(ctx context.Context, logf logger.Logf, root *goupnp.RootDevice, loc *url.URL) (client upnpClient, err error) { method := "none" defer func() { @@ -274,9 +308,9 @@ func selectBestService(ctx context.Context, logf logger.Logf, root *goupnp.RootD // First, get all available clients from the device, and append to our // list of possible clients. Order matters here; we want to prefer // WANIPConnection2 over WANIPConnection1 or WANPPPConnection. - wanIP2, _ := internetgateway2.NewWANIPConnection2ClientsFromRootDevice(ctx, root, loc) - wanIP1, _ := internetgateway2.NewWANIPConnection1ClientsFromRootDevice(ctx, root, loc) - wanPPP, _ := internetgateway2.NewWANPPPConnection1ClientsFromRootDevice(ctx, root, loc) + wanIP2, _ := internetgateway2.NewWANIPConnection2ClientsFromRootDevice(root, loc) + wanIP1, _ := internetgateway2.NewWANIPConnection1ClientsFromRootDevice(root, loc) + wanPPP, _ := internetgateway2.NewWANPPPConnection1ClientsFromRootDevice(root, loc) var clients []upnpClient for _, v := range wanIP2 { @@ -291,12 +325,12 @@ func selectBestService(ctx context.Context, logf logger.Logf, root *goupnp.RootD // These are legacy services that were deprecated in 2015, but are // still in use by older devices; try them just in case. - legacyClients, _ := goupnp.NewServiceClientsFromRootDevice(ctx, root, loc, urn_LegacyWANPPPConnection_1) + legacyClients, _ := goupnp.NewServiceClientsFromRootDevice(root, loc, urn_LegacyWANPPPConnection_1) metricUPnPSelectLegacy.Add(int64(len(legacyClients))) for _, client := range legacyClients { clients = append(clients, &legacyWANPPPConnection1{client}) } - legacyClients, _ = goupnp.NewServiceClientsFromRootDevice(ctx, root, loc, urn_LegacyWANIPConnection_1) + legacyClients, _ = goupnp.NewServiceClientsFromRootDevice(root, loc, urn_LegacyWANIPConnection_1) metricUPnPSelectLegacy.Add(int64(len(legacyClients))) for _, client := range legacyClients { clients = append(clients, &legacyWANIPConnection1{client}) @@ -346,7 +380,7 @@ func selectBestService(ctx context.Context, logf logger.Logf, root *goupnp.RootD } // Check if the device has an external IP address. - extIP, err := svc.GetExternalIPAddress(ctx) + extIP, err := svc.GetExternalIPAddressCtx(ctx) if err != nil { continue } @@ -399,7 +433,7 @@ func selectBestService(ctx context.Context, logf logger.Logf, root *goupnp.RootD // serviceIsConnected returns whether a given UPnP service is connected, based // on the NewConnectionStatus field returned from GetStatusInfo. func serviceIsConnected(ctx context.Context, logf logger.Logf, svc upnpClient) bool { - status, _ /* NewLastConnectionError */, _ /* NewUptime */, err := svc.GetStatusInfo(ctx) + status, _ /* NewLastConnectionError */, _ /* NewUptime */, err := svc.GetStatusInfoCtx(ctx) if err != nil { return false } @@ -454,7 +488,7 @@ func (c *Client) getUPnPPortMapping( c.mu.Lock() oldMapping, ok := c.mapping.(*upnpMapping) metas := c.uPnPMetas - ctx = goupnp.WithHTTPClient(ctx, c.upnpHTTPClientLocked()) + ctx = upnpHTTPClientKey.WithValue(ctx, c.upnpHTTPClientLocked()) c.mu.Unlock() // Wrapper for a uPnPDiscoResponse with an optional existing root @@ -629,7 +663,7 @@ func (c *Client) tryUPnPPortmapWithDevice( } // TODO cache this ip somewhere? - extIP, err := client.GetExternalIPAddress(ctx) + extIP, err := client.GetExternalIPAddressCtx(ctx) c.vlogf("client.GetExternalIPAddress: %v, %v", extIP, err) if err != nil { return netip.AddrPort{}, nil, err diff --git a/shell.nix b/shell.nix index 4f4714fea..c494ce47c 100644 --- a/shell.nix +++ b/shell.nix @@ -16,4 +16,4 @@ ) { src = ./.; }).shellNix -# nix-direnv cache busting line: sha256-PVE4oEwcoTbXbPJnBcVgBeXITWlnkhBf+UT5nqSeANM= +# nix-direnv cache busting line: sha256-knSIes9pFVkVfK5hcBG9BSR1ueH+yPpx4hv/UsyaW2M= diff --git a/tsnet/depaware.txt b/tsnet/depaware.txt index 7702de69d..f2b80f2bd 100644 --- a/tsnet/depaware.txt +++ b/tsnet/depaware.txt @@ -30,6 +30,12 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) github.com/google/btree from gvisor.dev/gvisor/pkg/tcpip/header+ DI github.com/google/uuid from github.com/prometheus-community/pro-bing github.com/hdevalence/ed25519consensus from tailscale.com/tka + github.com/huin/goupnp from github.com/huin/goupnp/dcps/internetgateway2+ + github.com/huin/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper + github.com/huin/goupnp/httpu from github.com/huin/goupnp+ + github.com/huin/goupnp/scpd from github.com/huin/goupnp + github.com/huin/goupnp/soap from github.com/huin/goupnp+ + github.com/huin/goupnp/ssdp from github.com/huin/goupnp L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/netmon L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink github.com/klauspost/compress from github.com/klauspost/compress/zstd @@ -53,12 +59,6 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) W 💣 github.com/tailscale/go-winio/internal/socket from github.com/tailscale/go-winio W github.com/tailscale/go-winio/internal/stringbuffer from github.com/tailscale/go-winio/internal/fs W github.com/tailscale/go-winio/pkg/guid from github.com/tailscale/go-winio+ - github.com/tailscale/goupnp from github.com/tailscale/goupnp/dcps/internetgateway2+ - github.com/tailscale/goupnp/dcps/internetgateway2 from tailscale.com/net/portmapper - github.com/tailscale/goupnp/httpu from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/scpd from github.com/tailscale/goupnp - github.com/tailscale/goupnp/soap from github.com/tailscale/goupnp+ - github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp LDW github.com/tailscale/hujson from tailscale.com/ipn/conffile LDAI github.com/tailscale/peercred from tailscale.com/ipn/ipnauth LDW github.com/tailscale/web-client-prebuilt from tailscale.com/client/web @@ -464,7 +464,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) encoding/hex from crypto/x509+ encoding/json from expvar+ encoding/pem from crypto/tls+ - encoding/xml from github.com/tailscale/goupnp+ + encoding/xml from github.com/huin/goupnp+ errors from bufio+ expvar from tailscale.com/health+ flag from tailscale.com/util/testenv @@ -554,7 +554,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware) path from debug/dwarf+ path/filepath from crypto/x509+ reflect from crypto/x509+ - regexp from github.com/tailscale/goupnp/httpu+ + regexp from github.com/huin/goupnp/httpu+ regexp/syntax from regexp runtime from crypto/internal/fips140+ runtime/debug from github.com/coder/websocket/internal/xsync+ diff --git a/tstest/jsdeps/jsdeps_test.go b/tstest/jsdeps/jsdeps_test.go index eb44df62e..27570fc26 100644 --- a/tstest/jsdeps/jsdeps_test.go +++ b/tstest/jsdeps/jsdeps_test.go @@ -14,12 +14,12 @@ func TestDeps(t *testing.T) { GOOS: "js", GOARCH: "wasm", BadDeps: map[string]string{ - "testing": "do not use testing package in production code", - "runtime/pprof": "bloat", - "golang.org/x/net/http2/h2c": "bloat", - "net/http/pprof": "bloat", - "golang.org/x/net/proxy": "bloat", - "github.com/tailscale/goupnp": "bloat, which can't work anyway in wasm", + "testing": "do not use testing package in production code", + "runtime/pprof": "bloat", + "golang.org/x/net/http2/h2c": "bloat", + "net/http/pprof": "bloat", + "golang.org/x/net/proxy": "bloat", + "github.com/huin/goupnp": "bloat, which can't work anyway in wasm", }, }.Check(t) }