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

Commit0ec3722

Browse files
committed
chore: add configMaps component to tailnet
1 parent21093c0 commit0ec3722

File tree

2 files changed

+425
-0
lines changed

2 files changed

+425
-0
lines changed

‎tailnet/configmaps.go‎

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp