Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitda115a4

Browse files
committed
chore: add configMaps component to tailnet
1 parent9704400 commitda115a4

File tree

2 files changed

+428
-0
lines changed

2 files changed

+428
-0
lines changed

‎tailnet/configmaps.go‎

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
package tailnet
2+
3+
import (
4+
"context"
5+
"errors"
6+
"net/netip"
7+
"sync"
8+
"time"
9+
10+
"github.com/google/uuid"
11+
"go4.org/netipx"
12+
"tailscale.com/net/dns"
13+
"tailscale.com/tailcfg"
14+
"tailscale.com/types/ipproto"
15+
"tailscale.com/types/key"
16+
"tailscale.com/types/netmap"
17+
"tailscale.com/wgengine"
18+
"tailscale.com/wgengine/filter"
19+
"tailscale.com/wgengine/router"
20+
"tailscale.com/wgengine/wgcfg"
21+
"tailscale.com/wgengine/wgcfg/nmcfg"
22+
23+
"cdr.dev/slog"
24+
"github.com/coder/coder/v2/tailnet/proto"
25+
)
26+
27+
// engineConfigurable is the subset of wgengine.Engine that we use for configuration.
28+
//
29+
// This allows us to test configuration code without faking the whole interface.
30+
typeengineConfigurableinterface {
31+
SetNetworkMap(*netmap.NetworkMap)
32+
Reconfig(*wgcfg.Config,*router.Config,*dns.Config,*tailcfg.Debug)error
33+
SetDERPMap(*tailcfg.DERPMap)
34+
SetFilter(*filter.Filter)
35+
}
36+
37+
typephaseint
38+
39+
const (
40+
idlephase=iota
41+
configuring
42+
closed
43+
)
44+
45+
typeconfigMapsstruct {
46+
sync.Cond
47+
netmapDirtybool
48+
derpMapDirtybool
49+
filterDirtybool
50+
closingbool
51+
phasephase
52+
53+
engineengineConfigurable
54+
static netmap.NetworkMap
55+
peersmap[uuid.UUID]*peerLifecycle
56+
addresses []netip.Prefix
57+
endpoints []tailcfg.Endpoint
58+
derpMap*proto.DERPMap
59+
logger slog.Logger
60+
}
61+
62+
funcnewConfigMaps(logger slog.Logger,engineengineConfigurable,nodeID tailcfg.NodeID,nodeKey key.NodePrivate,discoKey key.DiscoPublic,addresses []netip.Prefix)*configMaps {
63+
pubKey:=nodeKey.Public()
64+
c:=&configMaps{
65+
Cond:*(sync.NewCond(&sync.Mutex{})),
66+
logger:logger,
67+
engine:engine,
68+
static: netmap.NetworkMap{
69+
SelfNode:&tailcfg.Node{
70+
ID:nodeID,
71+
Key:pubKey,
72+
DiscoKey:discoKey,
73+
},
74+
NodeKey:pubKey,
75+
PrivateKey:nodeKey,
76+
PacketFilter: []filter.Match{{
77+
// Allow any protocol!
78+
IPProto: []ipproto.Proto{ipproto.TCP,ipproto.UDP,ipproto.ICMPv4,ipproto.ICMPv6,ipproto.SCTP},
79+
// Allow traffic sourced from anywhere.
80+
Srcs: []netip.Prefix{
81+
netip.PrefixFrom(netip.AddrFrom4([4]byte{}),0),
82+
netip.PrefixFrom(netip.AddrFrom16([16]byte{}),0),
83+
},
84+
// Allow traffic to route anywhere.
85+
Dsts: []filter.NetPortRange{
86+
{
87+
Net:netip.PrefixFrom(netip.AddrFrom4([4]byte{}),0),
88+
Ports: filter.PortRange{
89+
First:0,
90+
Last:65535,
91+
},
92+
},
93+
{
94+
Net:netip.PrefixFrom(netip.AddrFrom16([16]byte{}),0),
95+
Ports: filter.PortRange{
96+
First:0,
97+
Last:65535,
98+
},
99+
},
100+
},
101+
Caps: []filter.CapMatch{},
102+
}},
103+
},
104+
peers:make(map[uuid.UUID]*peerLifecycle),
105+
addresses:addresses,
106+
}
107+
goc.configLoop()
108+
returnc
109+
}
110+
111+
func (c*configMaps)configLoop() {
112+
c.L.Lock()
113+
deferc.L.Unlock()
114+
deferfunc() {
115+
c.phase=closed
116+
c.Broadcast()
117+
}()
118+
for {
119+
for!(c.closing||c.netmapDirty||c.filterDirty||c.derpMapDirty) {
120+
c.phase=idle
121+
c.Wait()
122+
}
123+
ifc.closing {
124+
return
125+
}
126+
// queue up the reconfiguration actions we will take while we have
127+
// the configMaps locked. We will execute them while unlocked to avoid
128+
// blocking during reconfig.
129+
actions:=make([]func(),0,3)
130+
ifc.derpMapDirty {
131+
derpMap:=c.derpMapLocked()
132+
actions=append(actions,func() {
133+
c.engine.SetDERPMap(derpMap)
134+
})
135+
}
136+
ifc.netmapDirty {
137+
nm:=c.netMapLocked()
138+
actions=append(actions,func() {
139+
c.engine.SetNetworkMap(nm)
140+
c.reconfig(nm)
141+
})
142+
}
143+
ifc.filterDirty {
144+
f:=c.filterLocked()
145+
actions=append(actions,func() {
146+
c.engine.SetFilter(f)
147+
})
148+
}
149+
150+
c.netmapDirty=false
151+
c.filterDirty=false
152+
c.derpMapDirty=false
153+
c.phase=configuring
154+
c.Broadcast()
155+
func() {
156+
// this may look a little odd, but here we want this code to run
157+
// without the lock, and then relock when done
158+
c.L.Unlock()
159+
deferc.L.Lock()
160+
for_,a:=rangeactions {
161+
a()
162+
}
163+
}()
164+
}
165+
}
166+
167+
func (c*configMaps)close() {
168+
c.L.Lock()
169+
deferc.L.Unlock()
170+
c.closing=true
171+
c.Broadcast()
172+
forc.phase!=closed {
173+
c.Wait()
174+
}
175+
}
176+
177+
func (c*configMaps)netMapLocked()*netmap.NetworkMap {
178+
nm:=new(netmap.NetworkMap)
179+
*nm=c.static
180+
181+
nm.Addresses=make([]netip.Prefix,len(c.addresses))
182+
copy(nm.Addresses,c.addresses)
183+
184+
nm.DERPMap=DERPMapFromProto(c.derpMap)
185+
nm.Peers=c.peerConfigLocked()
186+
nm.SelfNode.Addresses=nm.Addresses
187+
nm.SelfNode.AllowedIPs=nm.Addresses
188+
returnnm
189+
}
190+
191+
func (c*configMaps)peerConfigLocked() []*tailcfg.Node {
192+
out:=make([]*tailcfg.Node,0,len(c.peers))
193+
for_,p:=rangec.peers {
194+
out=append(out,p.node.Clone())
195+
}
196+
returnout
197+
}
198+
199+
func (c*configMaps)setAddresses(ips []netip.Prefix) {
200+
c.L.Lock()
201+
deferc.L.Unlock()
202+
ifd:=prefixesDifferent(c.addresses,ips);!d {
203+
return
204+
}
205+
c.addresses=make([]netip.Prefix,len(ips))
206+
copy(c.addresses,ips)
207+
c.netmapDirty=true
208+
c.filterDirty=true
209+
c.Broadcast()
210+
return
211+
}
212+
213+
func (c*configMaps)derpMapLocked()*tailcfg.DERPMap {
214+
m:=DERPMapFromProto(c.derpMap)
215+
returnm
216+
}
217+
218+
func (c*configMaps)reconfig(nm*netmap.NetworkMap) {
219+
cfg,err:=nmcfg.WGCfg(nm,Logger(c.logger.Named("net.wgconfig")),netmap.AllowSingleHosts,"")
220+
iferr!=nil {
221+
// WGCfg never returns an error at the time this code was written. If it starts, returning
222+
// errors if/when we upgrade tailscale, we'll need to deal.
223+
c.logger.Critical(context.Background(),"update wireguard config failed",slog.Error(err))
224+
return
225+
}
226+
227+
rc:=&router.Config{LocalAddrs:nm.Addresses}
228+
err=c.engine.Reconfig(cfg,rc,&dns.Config{},&tailcfg.Debug{})
229+
iferr!=nil {
230+
iferrors.Is(err,wgengine.ErrNoChanges) {
231+
return
232+
}
233+
c.logger.Error(context.Background(),"failed to reconfigure wireguard engine",slog.Error(err))
234+
}
235+
}
236+
237+
func (c*configMaps)filterLocked()*filter.Filter {
238+
localIPSet:= netipx.IPSetBuilder{}
239+
for_,addr:=rangec.addresses {
240+
localIPSet.AddPrefix(addr)
241+
}
242+
localIPs,_:=localIPSet.IPSet()
243+
logIPSet:= netipx.IPSetBuilder{}
244+
logIPs,_:=logIPSet.IPSet()
245+
returnfilter.New(
246+
c.static.PacketFilter,
247+
localIPs,
248+
logIPs,
249+
nil,
250+
Logger(c.logger.Named("net.packet-filter")),
251+
)
252+
}
253+
254+
typepeerLifecyclestruct {
255+
node*tailcfg.Node
256+
lastHandshake time.Time
257+
timer time.Timer
258+
}
259+
260+
// prefixesDifferent returns true if the two slices contain different prefixes
261+
// where order doesn't matter.
262+
funcprefixesDifferent(a,b []netip.Prefix)bool {
263+
iflen(a)!=len(b) {
264+
returntrue
265+
}
266+
as:=make(map[string]bool)
267+
for_,p:=rangea {
268+
as[p.String()]=true
269+
}
270+
for_,p:=rangeb {
271+
if!as[p.String()] {
272+
returntrue
273+
}
274+
}
275+
returnfalse
276+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp