Skip to content

Commit 95e5419

Browse files
authored
chore: fail server startup on invalid DERP map (#10536)
1 parent 5b9e26a commit 95e5419

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

cli/server_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,3 +1755,22 @@ func TestConnectToPostgres(t *testing.T) {
17551755
})
17561756
require.NoError(t, sqlDB.PingContext(ctx))
17571757
}
1758+
1759+
func TestServer_InvalidDERP(t *testing.T) {
1760+
t.Parallel()
1761+
1762+
// Try to start a server with the built-in DERP server disabled and no
1763+
// external DERP map.
1764+
inv, _ := clitest.New(t,
1765+
"server",
1766+
"--in-memory",
1767+
"--http-address", ":0",
1768+
"--access-url", "http://example.com",
1769+
"--derp-server-enable=false",
1770+
"--derp-server-stun-addresses", "disable",
1771+
"--block-direct-connections",
1772+
)
1773+
err := inv.Run()
1774+
require.Error(t, err)
1775+
require.ErrorContains(t, err, "A valid DERP map is required for networking to work")
1776+
}

tailnet/derpmap.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,25 @@ func NewDERPMap(ctx context.Context, region *tailcfg.DERPRegion, stunAddrs []str
130130
}
131131
}
132132

133+
// Fail if the DERP map has no regions or no DERP nodes.
134+
badDerpMapMsg := "A valid DERP map is required for networking to work. You must either supply your own DERP map or use the built-in DERP server"
135+
if len(derpMap.Regions) == 0 {
136+
return nil, xerrors.New("DERP map has no regions. " + badDerpMapMsg)
137+
}
138+
foundValidNode := false
139+
regionLoop:
140+
for _, region := range derpMap.Regions {
141+
for _, node := range region.Nodes {
142+
if !node.STUNOnly {
143+
foundValidNode = true
144+
break regionLoop
145+
}
146+
}
147+
}
148+
if !foundValidNode {
149+
return nil, xerrors.New("DERP map has no DERP nodes. " + badDerpMapMsg)
150+
}
151+
133152
return derpMap, nil
134153
}
135154

tailnet/derpmap_test.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ func TestNewDERPMap(t *testing.T) {
3333
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3434
data, _ := json.Marshal(&tailcfg.DERPMap{
3535
Regions: map[int]*tailcfg.DERPRegion{
36-
1: {},
36+
1: {
37+
RegionID: 1,
38+
Nodes: []*tailcfg.DERPNode{{}},
39+
},
3740
},
3841
})
3942
_, _ = w.Write(data)
@@ -66,7 +69,9 @@ func TestNewDERPMap(t *testing.T) {
6669
localPath := filepath.Join(t.TempDir(), "derp.json")
6770
content, err := json.Marshal(&tailcfg.DERPMap{
6871
Regions: map[int]*tailcfg.DERPRegion{
69-
1: {},
72+
1: {
73+
Nodes: []*tailcfg.DERPNode{{}},
74+
},
7075
},
7176
})
7277
require.NoError(t, err)
@@ -131,4 +136,29 @@ func TestNewDERPMap(t *testing.T) {
131136
// region.
132137
require.EqualValues(t, -1, derpMap.Regions[3].Nodes[0].STUNPort)
133138
})
139+
t.Run("RequireRegions", func(t *testing.T) {
140+
t.Parallel()
141+
_, err := tailnet.NewDERPMap(context.Background(), nil, nil, "", "", false)
142+
require.Error(t, err)
143+
require.ErrorContains(t, err, "DERP map has no regions")
144+
})
145+
t.Run("RequireDERPNodes", func(t *testing.T) {
146+
t.Parallel()
147+
148+
// No nodes.
149+
_, err := tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{}, nil, "", "", false)
150+
require.Error(t, err)
151+
require.ErrorContains(t, err, "DERP map has no DERP nodes")
152+
153+
// No DERP nodes.
154+
_, err = tailnet.NewDERPMap(context.Background(), &tailcfg.DERPRegion{
155+
Nodes: []*tailcfg.DERPNode{
156+
{
157+
STUNOnly: true,
158+
},
159+
},
160+
}, nil, "", "", false)
161+
require.Error(t, err)
162+
require.ErrorContains(t, err, "DERP map has no DERP nodes")
163+
})
134164
}

0 commit comments

Comments
 (0)