ipn/ipnlocal: drop h2c package, use net/http's support

In Dec 2021 in d3d503d997 I had grand plans to make exit node DNS
cheaper by using HTTP/2 over PeerAPI, at least on some platforms. I
only did server-side support though and never made it to the client.

In the ~4 years since, some things have happened:

* Go 1.24 got support for http.Protocols (https://pkg.go.dev/net/http#Protocols)
  and doing UnencryptedHTTP2 ("HTTP2 with prior knowledge")
* The old h2c upgrade mechanism was deprecated; see https://github.com/golang/go/issues/63565
  and https://github.com/golang/go/issues/67816
* Go plans to deprecate x/net/http2 and move everything to the standard library.

So this drops our use of the x/net/http2/h2c package and instead
enables h2c (on all platforms now) using the standard library.

This does mean we lose the deprecated h2c Upgrade support, but that's
fine.

If/when we do the h2c client support for ExitDNS, we'll have to probe
the peer to see whether it supports it. Or have it reply with a header
saying that future requests can us h2c. (It's tempting to use capver,
but maybe people will disable that support anyway, so we should
discover it at runtime instead.)

Also do the same in the sessionrecording package.

Updates #17305

Change-Id: If323f5ef32486effb18ed836888aa05c0efb701e
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-09-29 17:42:38 -07:00
committed by Brad Fitzpatrick
parent bcd79b161a
commit 3f5c560fd4
9 changed files with 15 additions and 46 deletions

View File

@@ -910,8 +910,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from k8s.io/apimachinery/pkg/util/net+
golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+ golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+

View File

@@ -220,8 +220,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from tailscale.com/control/controlclient+
golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from tailscale.com/net/ping golang.org/x/net/icmp from tailscale.com/net/ping
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+

View File

@@ -247,8 +247,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from tailscale.com/cmd/tailscale/cli+
golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from tailscale.com/net/ping golang.org/x/net/icmp from tailscale.com/net/ping
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+

View File

@@ -500,8 +500,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from tailscale.com/control/controlclient+
golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from tailscale.com/net/ping+ golang.org/x/net/icmp from tailscale.com/net/ping+
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+

View File

@@ -338,8 +338,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from tailscale.com/control/controlclient+
golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+ golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+

View File

@@ -42,10 +42,6 @@ import (
var initListenConfig func(*net.ListenConfig, netip.Addr, *netmon.State, string) error var initListenConfig func(*net.ListenConfig, netip.Addr, *netmon.State, string) error
// addH2C is non-nil on platforms where we want to add H2C
// ("cleartext" HTTP/2) support to the peerAPI.
var addH2C func(*http.Server)
// peerDNSQueryHandler is implemented by tsdns.Resolver. // peerDNSQueryHandler is implemented by tsdns.Resolver.
type peerDNSQueryHandler interface { type peerDNSQueryHandler interface {
HandlePeerDNSQuery(context.Context, []byte, netip.AddrPort, func(name string) bool) (res []byte, err error) HandlePeerDNSQuery(context.Context, []byte, netip.AddrPort, func(name string) bool) (res []byte, err error)
@@ -195,11 +191,11 @@ func (pln *peerAPIListener) ServeConn(src netip.AddrPort, c net.Conn) {
peerUser: peerUser, peerUser: peerUser,
} }
httpServer := &http.Server{ httpServer := &http.Server{
Handler: h, Handler: h,
} Protocols: new(http.Protocols),
if addH2C != nil {
addH2C(httpServer)
} }
httpServer.Protocols.SetHTTP1(true)
httpServer.Protocols.SetUnencryptedHTTP2(true) // over WireGuard; "unencrypted" means no TLS
go httpServer.Serve(netutil.NewOneConnListener(c, nil)) go httpServer.Serve(netutil.NewOneConnListener(c, nil))
} }

View File

@@ -1,20 +0,0 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ios && !android && !js
package ipnlocal
import (
"net/http"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
func init() {
addH2C = func(s *http.Server) {
h2s := &http2.Server{}
s.Handler = h2c.NewHandler(s.Handler, h2s)
}
}

View File

@@ -7,7 +7,6 @@ package sessionrecording
import ( import (
"context" "context"
"crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -19,7 +18,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/net/http2"
"tailscale.com/net/netx" "tailscale.com/net/netx"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/util/httpm" "tailscale.com/util/httpm"
@@ -312,14 +310,15 @@ func clientHTTP1(dialCtx context.Context, dial netx.DialFunc) *http.Client {
// requests (HTTP/2 over plaintext). Unfortunately the same client does not // requests (HTTP/2 over plaintext). Unfortunately the same client does not
// work for HTTP/1 so we need to split these up. // work for HTTP/1 so we need to split these up.
func clientHTTP2(dialCtx context.Context, dial netx.DialFunc) *http.Client { func clientHTTP2(dialCtx context.Context, dial netx.DialFunc) *http.Client {
var p http.Protocols
p.SetUnencryptedHTTP2(true)
return &http.Client{ return &http.Client{
Transport: &http2.Transport{ Transport: &http.Transport{
// Allow "http://" scheme in URLs. Protocols: &p,
AllowHTTP: true,
// Pretend like we're using TLS, but actually use the provided // Pretend like we're using TLS, but actually use the provided
// DialFunc underneath. This is necessary to convince the transport // DialFunc underneath. This is necessary to convince the transport
// to actually dial. // to actually dial.
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
perAttemptCtx, cancel := context.WithTimeout(ctx, perDialAttemptTimeout) perAttemptCtx, cancel := context.WithTimeout(ctx, perDialAttemptTimeout)
defer cancel() defer cancel()
go func() { go func() {

View File

@@ -331,8 +331,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
golang.org/x/net/dns/dnsmessage from net+ golang.org/x/net/dns/dnsmessage from net+
golang.org/x/net/http/httpguts from golang.org/x/net/http2+ golang.org/x/net/http/httpguts from golang.org/x/net/http2+
golang.org/x/net/http/httpproxy from net/http+ golang.org/x/net/http/httpproxy from net/http+
golang.org/x/net/http2 from golang.org/x/net/http2/h2c+ golang.org/x/net/http2 from tailscale.com/control/controlclient+
LDW golang.org/x/net/http2/h2c from tailscale.com/ipn/ipnlocal
golang.org/x/net/http2/hpack from golang.org/x/net/http2+ golang.org/x/net/http2/hpack from golang.org/x/net/http2+
golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+ golang.org/x/net/icmp from github.com/prometheus-community/pro-bing+
golang.org/x/net/idna from golang.org/x/net/http/httpguts+ golang.org/x/net/idna from golang.org/x/net/http/httpguts+