Skip to content

Commit

Permalink
listen for generate_204 on 80
Browse files Browse the repository at this point in the history
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
  • Loading branch information
kradalby committed Feb 16, 2024
1 parent afa064f commit 61fe21d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 7 deletions.
31 changes: 30 additions & 1 deletion hscontrol/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,11 @@ func (h *Headscale) createRouter(grpcMux *grpcRuntime.ServeMux) *mux.Router {
router.HandleFunc("/derp", h.DERPServer.DERPHandler)
router.HandleFunc("/derp/probe", derpServer.DERPProbeHandler)
router.HandleFunc("/bootstrap-dns", derpServer.DERPBootstrapDNSHandler(h.DERPMap))
router.HandleFunc("/generate_204", derpServer.DERPNoContextHandler)

// Only add to main muxer if running on port 80
if strings.HasSuffix(h.cfg.Addr, ":80") {
router.HandleFunc("/generate_204", derpServer.DERPNoContextHandler)
}
}

apiRouter := router.PathPrefix("/api").Subrouter()
Expand Down Expand Up @@ -697,6 +701,31 @@ func (h *Headscale) Serve() error {
log.Info().
Msgf("listening and serving HTTP on: %s", h.cfg.Addr)

// If headscale is not listening on port 80 and embedded DERP server
// is enabled, run a small http endpoint for generate204.
// This is not configurable as captive portal busting requires http/80.
if h.cfg.DERP.ServerEnabled || !strings.HasSuffix(h.cfg.Addr, ":80") {
httpDerpMux := http.NewServeMux()
httpDerpMux.HandleFunc("/generate_204", derpServer.DERPNoContextHandler)

addr := "0.0.0.0:80"
httpDerpServer := &http.Server{
Addr: addr,
Handler: httpDerpMux,
ReadTimeout: types.HTTPReadTimeout,
}

httpDerpListener, err := net.Listen("tcp", addr)
if err != nil {
return fmt.Errorf("binding port 80 for DERP HTTP endpoint: %w", err)
}

errorGroup.Go(func() error { return httpDerpServer.Serve(httpDerpListener) })

log.Info().
Msgf("listening and serving HTTP DERP generate_204 on: %s", addr)
}

promMux := http.NewServeMux()
promMux.Handle("/metrics", promhttp.Handler())

Expand Down
15 changes: 10 additions & 5 deletions integration/embedded_derp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestDERPServerScenario(t *testing.T) {
spec,
hsic.WithConfigEnv(headscaleConfig),
hsic.WithTestName("derpserver"),
hsic.WithExtraPorts([]string{"3478/udp"}),
hsic.WithExtraPorts("3478/udp"),
hsic.WithTLS(),
hsic.WithHostnameAsServerURL(),
)
Expand Down Expand Up @@ -88,7 +88,7 @@ func TestDERPValidateEmbedded(t *testing.T) {

scenario, err := NewScenario()
assertNoErr(t, err)
defer scenario.Shutdown()
// defer scenario.Shutdown()

spec := map[string]int{
"user1": 1,
Expand All @@ -103,6 +103,10 @@ func TestDERPValidateEmbedded(t *testing.T) {
"HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR": "0.0.0.0:3478",
"HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH": "/tmp/derp.key",

// Magic DNS breaks the docker DNS system which means
// DERP cannot look up the DERP server for some things.
"HEADSCALE_DNS_CONFIG_MAGIC_DNS": "0",

// Envknob for enabling DERP debug logs
"DERP_DEBUG_LOGS": "true",
"DERP_PROBER_DEBUG_LOGS": "true",
Expand All @@ -113,10 +117,9 @@ func TestDERPValidateEmbedded(t *testing.T) {
[]tsic.Option{},
hsic.WithConfigEnv(headscaleConfig),
hsic.WithTestName("derpvalidate"),
hsic.WithExtraPorts([]string{"3478/udp"}),
hsic.WithExtraPorts("3478/udp", "80/tcp"),
hsic.WithTLS(),
hsic.WithHostnameAsServerURL(),
hsic.WithPort(80),
)
assertNoErrHeadscaleEnv(t, err)

Expand Down Expand Up @@ -149,7 +152,9 @@ func TestDERPValidateEmbedded(t *testing.T) {

for _, warn := range derpReport.Warnings {
if strings.Contains(warn, "captive portal check") {
t.Errorf("derp report contains warning about portal check, generate_204 endpoint not working")
t.Errorf(
"derp report contains warning about portal check, generate_204 endpoint not working",
)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion integration/hsic/hsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func WithPort(port int) Option {
}

// WithExtraPorts exposes additional ports on the container (e.g. 3478/udp for STUN).
func WithExtraPorts(ports []string) Option {
func WithExtraPorts(ports ...string) Option {
return func(hsic *HeadscaleInContainer) {
hsic.extraPorts = ports
}
Expand Down

0 comments on commit 61fe21d

Please sign in to comment.