mirror of
https://github.com/juanfont/headscale.git
synced 2026-11-07 14:09:25 +09:00
derp: reject non-200 DERP map responses
A JSON error page decoded to an empty map; a refresh then dropped that URL's regions. Errors now name the URL. Updates #3142
This commit is contained in:
1 parent
8bc7e793a8
commit
a25aff2ccc
2 files changed
+25
-3
No files matched your search
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
var (
|
||||
errEmptyDERPMapFile = errors.New("DERP map file has no regions or homeparams")
|
||||
errDERPMapStatus = errors.New("unexpected HTTP status")
|
||||
|
||||
ErrRegionIDKey = errors.New("doesn't match its key")
|
||||
ErrRegionNoNodes = errors.New("must specify at least one node in DERP Region")
|
||||
@@ -130,21 +131,26 @@ func loadDERPMapFromURL(addr url.URL) (*tailcfg.DERPMap, error) {
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
// An error page can be JSON that decodes to an empty map.
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("DERP map %s: %w: %s", addr.Redacted(), errDERPMapStatus, resp.Status)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("DERP map %s: %w", addr.Redacted(), err)
|
||||
}
|
||||
|
||||
var derpMap tailcfg.DERPMap
|
||||
|
||||
err = json.Unmarshal(body, &derpMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("DERP map %s: %w", addr.Redacted(), err)
|
||||
}
|
||||
|
||||
err = validateRegions(&derpMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DERP map %s: %w", addr.String(), err)
|
||||
return nil, fmt.Errorf("DERP map %s: %w", addr.Redacted(), err)
|
||||
}
|
||||
|
||||
return &derpMap, nil
|
||||
|
||||
@@ -499,3 +499,19 @@ func TestLoadDERPMapFromURLValidates(t *testing.T) {
|
||||
_, err = loadDERPMapFromURL(*addr)
|
||||
require.ErrorIs(t, err, ErrRegionIDKey)
|
||||
}
|
||||
|
||||
// TestLoadDERPMapFromURLRejectsHTTPError: an error page that happens to be
|
||||
// JSON must not pass as an empty map, or a refresh drops that URL's regions.
|
||||
func TestLoadDERPMapFromURLRejectsHTTPError(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
_, _ = w.Write([]byte(`{"message": "down for maintenance"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
addr, err := url.Parse(srv.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = loadDERPMapFromURL(*addr)
|
||||
require.ErrorIs(t, err, errDERPMapStatus)
|
||||
}
|
||||
Reference in new issue
Block a user