diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index 2e335e8a..23dfe871 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -31,7 +31,6 @@ import ( "github.com/qdm12/gluetun/internal/storage" "github.com/qdm12/gluetun/internal/unix" "github.com/qdm12/gluetun/internal/updater" - versionpkg "github.com/qdm12/gluetun/internal/version" "github.com/qdm12/golibs/command" "github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/params" @@ -279,9 +278,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, } } - tunnelReadyCh := make(chan struct{}) - defer close(tunnelReadyCh) - if allSettings.Firewall.Enabled { err := firewallConf.SetEnabled(ctx, true) // disabled by default if err != nil { @@ -328,9 +324,37 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, "port forwarding", goshutdown.GoRoutineSettings{Timeout: time.Second}) go portForwardLooper.Run(portForwardCtx, portForwardDone) + unboundLogger := logger.NewChild(logging.Settings{Prefix: "dns over tls: "}) + unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient, + unboundLogger) + dnsHandler, dnsCtx, dnsDone := goshutdown.NewGoRoutineHandler( + "unbound", defaultGoRoutineSettings) + // wait for unboundLooper.Restart or its ticker launched with RunRestartTicker + go unboundLooper.Run(dnsCtx, dnsDone) + otherGroupHandler.Add(dnsHandler) + + dnsTickerHandler, dnsTickerCtx, dnsTickerDone := goshutdown.NewGoRoutineHandler( + "dns ticker", defaultGoRoutineSettings) + go unboundLooper.RunRestartTicker(dnsTickerCtx, dnsTickerDone) + controlGroupHandler.Add(dnsTickerHandler) + + publicIPLooper := publicip.NewLoop(httpClient, + logger.NewChild(logging.Settings{Prefix: "ip getter: "}), + allSettings.PublicIP, puid, pgid) + pubIPHandler, pubIPCtx, pubIPDone := goshutdown.NewGoRoutineHandler( + "public IP", defaultGoRoutineSettings) + go publicIPLooper.Run(pubIPCtx, pubIPDone) + otherGroupHandler.Add(pubIPHandler) + + pubIPTickerHandler, pubIPTickerCtx, pubIPTickerDone := goshutdown.NewGoRoutineHandler( + "public IP", defaultGoRoutineSettings) + go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone) + tickersGroupHandler.Add(pubIPTickerHandler) + openvpnLogger := logger.NewChild(logging.Settings{Prefix: "openvpn: "}) openvpnLooper := openvpn.NewLoop(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers, - ovpnConf, firewallConf, routingConf, portForwardLooper, openvpnLogger, httpClient, tunnelReadyCh) + ovpnConf, firewallConf, routingConf, portForwardLooper, publicIPLooper, unboundLooper, + openvpnLogger, httpClient, buildInfo, allSettings.VersionInformation) openvpnHandler, openvpnCtx, openvpnDone := goshutdown.NewGoRoutineHandler( "openvpn", goshutdown.GoRoutineSettings{Timeout: time.Second}) // wait for restartOpenvpn @@ -345,27 +369,10 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, go updaterLooper.Run(updaterCtx, updaterDone) tickersGroupHandler.Add(updaterHandler) - unboundLogger := logger.NewChild(logging.Settings{Prefix: "dns over tls: "}) - unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient, - unboundLogger) - dnsHandler, dnsCtx, dnsDone := goshutdown.NewGoRoutineHandler( - "unbound", defaultGoRoutineSettings) - // wait for unboundLooper.Restart or its ticker launched with RunRestartTicker - go unboundLooper.Run(dnsCtx, dnsDone) - otherGroupHandler.Add(dnsHandler) - - publicIPLooper := publicip.NewLoop(httpClient, - logger.NewChild(logging.Settings{Prefix: "ip getter: "}), - allSettings.PublicIP, puid, pgid) - pubIPHandler, pubIPCtx, pubIPDone := goshutdown.NewGoRoutineHandler( - "public IP", defaultGoRoutineSettings) - go publicIPLooper.Run(pubIPCtx, pubIPDone) - otherGroupHandler.Add(pubIPHandler) - - pubIPTickerHandler, pubIPTickerCtx, pubIPTickerDone := goshutdown.NewGoRoutineHandler( - "public IP", defaultGoRoutineSettings) - go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone) - tickersGroupHandler.Add(pubIPTickerHandler) + updaterTickerHandler, updaterTickerCtx, updaterTickerDone := goshutdown.NewGoRoutineHandler( + "updater ticker", defaultGoRoutineSettings) + go updaterLooper.RunRestartTicker(updaterTickerCtx, updaterTickerDone) + controlGroupHandler.Add(updaterTickerHandler) httpProxyLooper := httpproxy.NewLoop( logger.NewChild(logging.Settings{Prefix: "http proxy: "}), @@ -382,13 +389,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation, go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone) otherGroupHandler.Add(shadowsocksHandler) - eventsRoutingHandler, eventsRoutingCtx, eventsRoutingDone := goshutdown.NewGoRoutineHandler( - "events routing", defaultGoRoutineSettings) - go routeReadyEvents(eventsRoutingCtx, eventsRoutingDone, buildInfo, tunnelReadyCh, - unboundLooper, updaterLooper, publicIPLooper, routingConf, logger, httpClient, - allSettings.VersionInformation) - controlGroupHandler.Add(eventsRoutingHandler) - controlServerAddress := ":" + strconv.Itoa(int(allSettings.ControlServer.Port)) controlServerLogging := allSettings.ControlServer.Log httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler( @@ -445,64 +445,3 @@ func printVersions(ctx context.Context, logger logging.Logger, return nil } - -func routeReadyEvents(ctx context.Context, done chan<- struct{}, buildInfo models.BuildInformation, - tunnelReadyCh <-chan struct{}, - unboundLooper dns.Looper, updaterLooper updater.Looper, publicIPLooper publicip.Looper, - routing routing.VPNGetter, logger logging.Logger, httpClient *http.Client, - versionInformation bool) { - defer close(done) - - // for linters only - var restartTickerContext context.Context - var restartTickerCancel context.CancelFunc = func() {} - - unboundTickerDone := make(chan struct{}) - close(unboundTickerDone) - updaterTickerDone := make(chan struct{}) - close(updaterTickerDone) - - first := true - for { - select { - case <-ctx.Done(): - restartTickerCancel() // for linters only - <-unboundTickerDone - <-updaterTickerDone - return - case <-tunnelReadyCh: // blocks until openvpn is connected - vpnDestination, err := routing.VPNDestinationIP() - if err != nil { - logger.Warn(err.Error()) - } else { - logger.Info("VPN routing IP address: " + vpnDestination.String()) - } - - if unboundLooper.GetSettings().Enabled { - _, _ = unboundLooper.ApplyStatus(ctx, constants.Running) - } - - restartTickerCancel() // stop previous restart tickers - <-unboundTickerDone - <-updaterTickerDone - restartTickerContext, restartTickerCancel = context.WithCancel(ctx) - - // Runs the Public IP getter job once - _, _ = publicIPLooper.ApplyStatus(ctx, constants.Running) - if versionInformation && first { - first = false - message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient) - if err != nil { - logger.Error("cannot get version information: " + err.Error()) - } else { - logger.Info(message) - } - } - - unboundTickerDone = make(chan struct{}) - updaterTickerDone = make(chan struct{}) - go unboundLooper.RunRestartTicker(restartTickerContext, unboundTickerDone) - go updaterLooper.RunRestartTicker(restartTickerContext, updaterTickerDone) - } - } -} diff --git a/internal/openvpn/logs.go b/internal/openvpn/logs.go index 7db76477..4ad2c912 100644 --- a/internal/openvpn/logs.go +++ b/internal/openvpn/logs.go @@ -46,7 +46,7 @@ func (l *Loop) collectLines(ctx context.Context, done chan<- struct{}, l.logger.Error(line) } if strings.Contains(line, "Initialization Sequence Completed") { - l.tunnelReady <- struct{}{} + l.onTunnelUp(ctx) l.startPFCh <- struct{}{} } } diff --git a/internal/openvpn/loop.go b/internal/openvpn/loop.go index 68107e9f..da8effba 100644 --- a/internal/openvpn/loop.go +++ b/internal/openvpn/loop.go @@ -6,11 +6,13 @@ import ( "github.com/qdm12/gluetun/internal/configuration" "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/dns" "github.com/qdm12/gluetun/internal/firewall" "github.com/qdm12/gluetun/internal/loopstate" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/openvpn/state" "github.com/qdm12/gluetun/internal/portforward" + "github.com/qdm12/gluetun/internal/publicip" "github.com/qdm12/gluetun/internal/routing" "github.com/qdm12/golibs/logging" ) @@ -33,15 +35,18 @@ type Loop struct { puid int pgid int targetConfPath string + buildInfo models.BuildInformation + versionInfo bool // Configurators conf StarterAuthWriter fw firewallConfigurer - routing routing.VPNLocalGatewayIPGetter + routing routing.VPNGetter portForward portforward.StartStopper + publicip publicip.Looper + dnsLooper dns.Looper // Other objects - logger logging.Logger - client *http.Client - tunnelReady chan<- struct{} + logger logging.Logger + client *http.Client // Internal channels and values stop <-chan struct{} stopped chan<- struct{} @@ -64,9 +69,11 @@ const ( func NewLoop(settings configuration.OpenVPN, username string, puid, pgid int, allServers models.AllServers, conf Configurator, - fw firewallConfigurer, routing routing.VPNLocalGatewayIPGetter, - portForward portforward.StartStopper, logger logging.Logger, - client *http.Client, tunnelReady chan<- struct{}) *Loop { + fw firewallConfigurer, routing routing.VPNGetter, + portForward portforward.StartStopper, + publicip publicip.Looper, dnsLooper dns.Looper, + logger logging.Logger, client *http.Client, + buildInfo models.BuildInformation, versionInfo bool) *Loop { start := make(chan struct{}) running := make(chan models.LoopStatus) stop := make(chan struct{}) @@ -82,13 +89,16 @@ func NewLoop(settings configuration.OpenVPN, username string, puid: puid, pgid: pgid, targetConfPath: constants.OpenVPNConf, + buildInfo: buildInfo, + versionInfo: versionInfo, conf: conf, fw: fw, routing: routing, portForward: portForward, + publicip: publicip, + dnsLooper: dnsLooper, logger: logger, client: client, - tunnelReady: tunnelReady, start: start, running: running, stop: stop, diff --git a/internal/openvpn/tunnelup.go b/internal/openvpn/tunnelup.go new file mode 100644 index 00000000..7515e712 --- /dev/null +++ b/internal/openvpn/tunnelup.go @@ -0,0 +1,33 @@ +package openvpn + +import ( + "context" + + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/version" +) + +func (l *Loop) onTunnelUp(ctx context.Context) { + vpnDestination, err := l.routing.VPNDestinationIP() + if err != nil { + l.logger.Warn(err.Error()) + } else { + l.logger.Info("VPN routing IP address: " + vpnDestination.String()) + } + + if l.dnsLooper.GetSettings().Enabled { + _, _ = l.dnsLooper.ApplyStatus(ctx, constants.Running) + } + + // Runs the Public IP getter job once + _, _ = l.publicip.ApplyStatus(ctx, constants.Running) + if l.versionInfo { + l.versionInfo = false // only get the version information once + message, err := version.GetMessage(ctx, l.buildInfo, l.client) + if err != nil { + l.logger.Error("cannot get version information: " + err.Error()) + } else { + l.logger.Info(message) + } + } +}