diff --git a/config-example.yaml b/config-example.yaml index 8a7d1609..9c86ed20 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -87,11 +87,8 @@ derp: region_code: "headscale" region_name: "Headscale Embedded DERP" - # If non-empty, an admission controller URL for permitting client connections - verify_client_url: "http://127.0.0.1:8080/verify" - - # Whether derp fail open if verify_client_url is unreachable - verify_client_url_fail_open: false + # Verify clients to this DERP server using the Headscale node list + verify_clients: true # Listens over UDP at the configured address for STUN connections - to help with NAT traversal. # When the embedded DERP server is enabled stun_listen_addr MUST be defined. diff --git a/hscontrol/app.go b/hscontrol/app.go index 3349392b..6eb5cffb 100644 --- a/hscontrol/app.go +++ b/hscontrol/app.go @@ -221,6 +221,7 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) { embeddedDERPServer, err := derpServer.NewDERPServer( cfg.ServerURL, + app.VerifyHandler, key.NodePrivate(*derpServerKey), &cfg.DERP, ) diff --git a/hscontrol/derp/server/derp_server.go b/hscontrol/derp/server/derp_server.go index 479d5ffa..d0cec7eb 100644 --- a/hscontrol/derp/server/derp_server.go +++ b/hscontrol/derp/server/derp_server.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "net/http" + "net/http/httptest" "net/netip" "net/url" "strconv" @@ -39,14 +40,20 @@ type DERPServer struct { func NewDERPServer( serverURL string, + verifyHandler func(writer http.ResponseWriter, req *http.Request), derpKey key.NodePrivate, cfg *types.DERPConfig, ) (*DERPServer, error) { log.Trace().Caller().Msg("Creating new embedded DERP server") server := derp.NewServer(derpKey, util.TSLogfWrapper()) // nolint // zerolinter complains - if cfg.ServerVerifyClientURL != "" { - server.SetVerifyClientURL(cfg.ServerVerifyClientURL) - server.SetVerifyClientURLFailOpen(cfg.ServerVerifyFailOpen) + + if cfg.ServerVerifyClients { + t := http.DefaultTransport.(*http.Transport) + t.RegisterProtocol("headscale", &HeadscaleTransport{ + verifyHandler: verifyHandler, + }) + server.SetVerifyClientURL("headscale://verify") + server.SetVerifyClientURLFailOpen(false) } return &DERPServer{ @@ -364,3 +371,14 @@ func serverSTUNListener(ctx context.Context, packetConn *net.UDPConn) { } } } + +type HeadscaleTransport struct { + verifyHandler func(writer http.ResponseWriter, req *http.Request) +} + +func (t *HeadscaleTransport) RoundTrip(req *http.Request) (*http.Response, error) { + recorder := httptest.NewRecorder() + t.verifyHandler(recorder, req) + resp := recorder.Result() + return resp, nil +} diff --git a/hscontrol/types/config.go b/hscontrol/types/config.go index 72d7c07a..306f09a4 100644 --- a/hscontrol/types/config.go +++ b/hscontrol/types/config.go @@ -185,8 +185,7 @@ type DERPConfig struct { ServerRegionCode string ServerRegionName string ServerPrivateKeyPath string - ServerVerifyClientURL string - ServerVerifyFailOpen bool + ServerVerifyClients bool STUNAddr string URLs []url.URL Paths []string @@ -433,8 +432,7 @@ func derpConfig() DERPConfig { serverRegionID := viper.GetInt("derp.server.region_id") serverRegionCode := viper.GetString("derp.server.region_code") serverRegionName := viper.GetString("derp.server.region_name") - serverVerifyClientURL := viper.GetString("derp.server.verify_client_url") - serverVerifyFailOpen := viper.GetBool("derp.server.verify_client_url_fail_open") + serverVerifyClients := viper.GetBool("derp.server.verify_clients") stunAddr := viper.GetString("derp.server.stun_listen_addr") privateKeyPath := util.AbsolutePathFromConfigPath( viper.GetString("derp.server.private_key_path"), @@ -479,8 +477,7 @@ func derpConfig() DERPConfig { ServerRegionID: serverRegionID, ServerRegionCode: serverRegionCode, ServerRegionName: serverRegionName, - ServerVerifyClientURL: serverVerifyClientURL, - ServerVerifyFailOpen: serverVerifyFailOpen, + ServerVerifyClients: serverVerifyClients, ServerPrivateKeyPath: privateKeyPath, STUNAddr: stunAddr, URLs: urls,