@@ -54,6 +54,7 @@ var bar = core.NewKeyedBarrier[*x.NetStat, string](30 * time.Second)
5454var (
5555 errNoStatCache = errors .New ("netstat: stat in cache is nil" )
5656 errClosed = errors .New ("tunnel closed for business" )
57+ errMakeTunnel = errors .New ("could not make tunnel" )
5758)
5859
5960type Bridge interface {
@@ -92,6 +93,8 @@ type Tunnel interface {
9293 SetRoute (engine int ) error
9394 // SetLinkAndRoutes sets the tun fd as link with mtu & engine as routes for the tunnel.
9495 SetLinkAndRoutes (fd , mtu , engine int ) error
96+ // Restart restarts the tunnel with the given fd, mtu, and engine.
97+ Restart (fd , mtu , engine int ) error
9598
9699 // Sets pcap output to fpcap which is the absolute filepath
97100 // to which a PCAP file will be written to.
@@ -105,6 +108,7 @@ type rtunnel struct {
105108 tunmu sync.Mutex // serializes access to tunnel.Tunnel
106109 ctx context.Context
107110 done context.CancelFunc
111+ handlers netstack.GConnHandler
108112 proxies ipn.Proxies
109113 resolver dnsx.Resolver
110114 services rnet.Services
@@ -183,19 +187,21 @@ func NewTunnel(fd, mtu int, fakedns string, dtr DefaultDNS, bdg Bridge) (t Tunne
183187
184188 gt , revhdl , err := tunnel .NewGTunnel (ctx , fd , mtu , dualstack , hdl )
185189
186- if err != nil {
190+ if gt == nil || err != nil {
187191 log .W ("tun: <<< new >>>; err(%v)" , err )
188- return nil , err
192+ return nil , core . OneErr ( err , errMakeTunnel )
189193 }
190194
191195 log .D ("tun: <<< new >>>; netstack: ok" )
192196
197+ // TODO: err on reverser errors too?
193198 rerr := proxies .Reverser (revhdl )
194199
195200 t = & rtunnel {
196201 Tunnel : gt ,
197202 ctx : ctx ,
198203 done : cancel ,
204+ handlers : hdl ,
199205 proxies : proxies ,
200206 resolver : resolver ,
201207 services : services ,
@@ -244,6 +250,51 @@ func (t *rtunnel) SetLinkAndRoutes(fd, mtu, engine int) error {
244250 if l3diff {
245251 t .resolver .Add (newMDNSTransport (t .ctx , l3 , t .proxies ))
246252 }
253+ })
254+
255+ return err
256+ }
257+
258+ func (t * rtunnel ) Restart (fd , mtu , engine int ) error {
259+ if t .closed .Load () {
260+ log .W ("tun: <<< restart >>>; already closed" )
261+ return errClosed
262+ }
263+
264+ countdown := make (chan struct {})
265+ defer close (countdown )
266+
267+ ontimeout := func () {
268+ log .E ("tun: <<< restart >>>; timed out ..." )
269+ t .done ()
270+ }
271+
272+ go core .EitherOr (countdown , ontimeout , mktunTimeout )
273+
274+ l3 := settings .L3 (engine )
275+ l3diff := dialers .IPProtos (l3 )
276+
277+ gt , revhdl , err := tunnel .NewGTunnel (t .ctx , fd , mtu , l3 , t .handlers )
278+
279+ if gt == nil || err != nil {
280+ log .W ("tun: <<< restart >>>; err(%v)" , err )
281+ t .Tunnel .Disconnect ()
282+ return core .OneErr (err , errMakeTunnel )
283+ }
284+
285+ t .tunmu .Lock ()
286+ t .Tunnel .Disconnect ()
287+ t .Tunnel = gt
288+ t .tunmu .Unlock ()
289+
290+ // TODO: err on reverser errors too?
291+ rerr := t .proxies .Reverser (revhdl )
292+
293+ log .D ("tun: <<< restart >>>; netstack: ok; rev err? %v" , rerr )
294+
295+ core .Gx ("i.RestartRefresh" , func () {
296+ // Refresh proxies to update to the new reverser
297+ go t .proxies .RefreshProto (l3 , mtu , true /*force; reverser changed*/ ) // also updates reverser
247298 if l3diff {
248299 t .resolver .Add (newMDNSTransport (t .ctx , l3 , t .proxies ))
249300 }
0 commit comments