mirror of
https://github.com/juanfont/headscale.git
synced 2026-10-09 00:00:10 +09:00
derp: clone regions when merging DERP maps
In-place node shuffling aliased regions shared with the served map.
This commit is contained in:
committed by
Kristoffer Dalby
parent
0921972f96
commit
e413919810
@@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"hash/crc64"
|
"hash/crc64"
|
||||||
"io"
|
"io"
|
||||||
"maps"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -85,7 +84,12 @@ func mergeDERPMaps(derpMaps []*tailcfg.DERPMap) *tailcfg.DERPMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, derpMap := range derpMaps {
|
for _, derpMap := range derpMaps {
|
||||||
maps.Copy(result.Regions, derpMap.Regions)
|
// Clone each region: copying the pointer would let a later in-place
|
||||||
|
// shuffle (shuffleRegionNoClone) alias regions shared with the source
|
||||||
|
// map or a previously served map, racing concurrent readers.
|
||||||
|
for id, region := range derpMap.Regions {
|
||||||
|
result.Regions[id] = region.Clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, region := range result.Regions {
|
for id, region := range result.Regions {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package derp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestMergeDERPMapsClonesRegions ensures merged DERP maps own their regions
|
||||||
|
// rather than aliasing the source pointers, so a later in-place node shuffle
|
||||||
|
// cannot mutate a shared or previously served map.
|
||||||
|
func TestMergeDERPMapsClonesRegions(t *testing.T) {
|
||||||
|
src := &tailcfg.DERPMap{
|
||||||
|
Regions: map[int]*tailcfg.DERPRegion{
|
||||||
|
1: {RegionID: 1, Nodes: []*tailcfg.DERPNode{{Name: "a"}, {Name: "b"}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
merged := mergeDERPMaps([]*tailcfg.DERPMap{src})
|
||||||
|
|
||||||
|
assert.NotSame(t, src.Regions[1], merged.Regions[1],
|
||||||
|
"merged region must not alias the source region pointer")
|
||||||
|
|
||||||
|
merged.Regions[1].Nodes[0] = &tailcfg.DERPNode{Name: "mutated"}
|
||||||
|
assert.Equal(t, "a", src.Regions[1].Nodes[0].Name,
|
||||||
|
"source region was mutated through a shared pointer")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user