noise: reject non-HEAD on PingResponseHandler

chi routes only HEAD to the handler, but assert explicitly so a
future router config change cannot silently accept GET/POST and leak
latency bytes or side-effects.

Updates #3157
This commit is contained in:
Kristoffer Dalby 2026-04-17 05:48:43 +00:00
parent f3eb9a7bba
commit 5a7cafdf85
2 changed files with 37 additions and 0 deletions

View File

@ -302,6 +302,11 @@ func (h *Headscale) PingResponseHandler(
writer http.ResponseWriter,
req *http.Request,
) {
if req.Method != http.MethodHead {
http.Error(writer, "method not allowed", http.StatusMethodNotAllowed)
return
}
pingID := req.URL.Query().Get("id")
if pingID == "" {
http.Error(writer, "missing ping ID", http.StatusBadRequest)

View File

@ -1,6 +1,8 @@
package servertest_test
import (
"context"
"net/http"
"testing"
"time"
@ -167,3 +169,33 @@ func TestPingResolveByHostname(t *testing.T) {
t.Fatal("ping response not received")
}
}
// TestPingResponseHandlerRejectsNonHEAD verifies the endpoint returns 405
// for method verbs other than HEAD, even when chi is configured to allow
// them.
func TestPingResponseHandlerRejectsNonHEAD(t *testing.T) {
t.Parallel()
h := servertest.NewHarness(t, 1)
for _, method := range []string{http.MethodGet, http.MethodPost, http.MethodPut} {
t.Run(method, func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, method, h.Server.URL+"/machine/ping-response?id=x", nil)
require.NoError(t, err)
resp, err := http.DefaultClient.Do(req)
if err != nil {
// chi may refuse the method entirely; that's equivalent to 405.
return
}
defer resp.Body.Close()
assert.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
})
}
}