Maintenance: improve stream merging
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
nativeos "os"
|
nativeos "os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -33,7 +32,6 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/unix"
|
"github.com/qdm12/gluetun/internal/unix"
|
||||||
"github.com/qdm12/gluetun/internal/updater"
|
"github.com/qdm12/gluetun/internal/updater"
|
||||||
versionpkg "github.com/qdm12/gluetun/internal/version"
|
versionpkg "github.com/qdm12/gluetun/internal/version"
|
||||||
"github.com/qdm12/golibs/command"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
"github.com/qdm12/golibs/os/user"
|
"github.com/qdm12/golibs/os/user"
|
||||||
@@ -141,7 +139,6 @@ func _main(background context.Context, buildInfo models.BuildInformation,
|
|||||||
"/etc/unbound", "/usr/sbin/unbound", cacertsPath)
|
"/etc/unbound", "/usr/sbin/unbound", cacertsPath)
|
||||||
routingConf := routing.NewRouting(logger)
|
routingConf := routing.NewRouting(logger)
|
||||||
firewallConf := firewall.NewConfigurator(logger, routingConf, os.OpenFile)
|
firewallConf := firewall.NewConfigurator(logger, routingConf, os.OpenFile)
|
||||||
streamMerger := command.NewStreamMerger()
|
|
||||||
|
|
||||||
paramsReader := params.NewReader(logger, os)
|
paramsReader := params.NewReader(logger, os)
|
||||||
fmt.Println(gluetunLogging.Splash(buildInfo))
|
fmt.Println(gluetunLogging.Splash(buildInfo))
|
||||||
@@ -266,11 +263,8 @@ func _main(background context.Context, buildInfo models.BuildInformation,
|
|||||||
|
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
wg.Add(1)
|
|
||||||
go collectStreamLines(ctx, wg, streamMerger, logger, tunnelReadyCh)
|
|
||||||
|
|
||||||
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers,
|
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers,
|
||||||
ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, streamMerger, cancel)
|
ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, tunnelReadyCh, cancel)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
// wait for restartOpenvpn
|
// wait for restartOpenvpn
|
||||||
go openvpnLooper.Run(ctx, wg)
|
go openvpnLooper.Run(ctx, wg)
|
||||||
@@ -282,7 +276,7 @@ func _main(background context.Context, buildInfo models.BuildInformation,
|
|||||||
go updaterLooper.Run(ctx, wg)
|
go updaterLooper.Run(ctx, wg)
|
||||||
|
|
||||||
unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, httpClient,
|
unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, httpClient,
|
||||||
logger, streamMerger, nonRootUsername, puid, pgid)
|
logger, nonRootUsername, puid, pgid)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
|
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
|
||||||
go unboundLooper.Run(ctx, wg, dnsReadyCh)
|
go unboundLooper.Run(ctx, wg, dnsReadyCh)
|
||||||
@@ -352,42 +346,6 @@ func printVersions(ctx context.Context, logger logging.Logger,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectStreamLines(ctx context.Context, wg *sync.WaitGroup,
|
|
||||||
streamMerger command.StreamMerger,
|
|
||||||
logger logging.Logger, tunnelReadyCh chan<- struct{}) {
|
|
||||||
defer wg.Done()
|
|
||||||
// Blocking line merging paramsReader for openvpn and unbound
|
|
||||||
logger.Info("Launching standard output merger")
|
|
||||||
streamMerger.CollectLines(ctx, func(line string) {
|
|
||||||
line, level := gluetunLogging.PostProcessLine(line)
|
|
||||||
if line == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch level {
|
|
||||||
case logging.DebugLevel:
|
|
||||||
logger.Debug(line)
|
|
||||||
case logging.InfoLevel:
|
|
||||||
logger.Info(line)
|
|
||||||
case logging.WarnLevel:
|
|
||||||
logger.Warn(line)
|
|
||||||
case logging.ErrorLevel:
|
|
||||||
logger.Error(line)
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case strings.Contains(line, "Initialization Sequence Completed"):
|
|
||||||
tunnelReadyCh <- struct{}{}
|
|
||||||
case strings.Contains(line, "TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)"): //nolint:lll
|
|
||||||
logger.Warn("This means that either...")
|
|
||||||
logger.Warn("1. The VPN server IP address you are trying to connect to is no longer valid, see https://github.com/qdm12/gluetun/wiki/Update-servers-information") //nolint:lll
|
|
||||||
logger.Warn("2. The VPN server crashed, try changing region")
|
|
||||||
logger.Warn("3. Your Internet connection is not working, ensure it works")
|
|
||||||
logger.Warn("Feel free to create an issue at https://github.com/qdm12/gluetun/issues/new/choose")
|
|
||||||
}
|
|
||||||
}, func(err error) {
|
|
||||||
logger.Warn(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, buildInfo models.BuildInformation,
|
func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, buildInfo models.BuildInformation,
|
||||||
tunnelReadyCh, dnsReadyCh <-chan struct{},
|
tunnelReadyCh, dnsReadyCh <-chan struct{},
|
||||||
unboundLooper dns.Looper, updaterLooper updater.Looper, publicIPLooper publicip.Looper,
|
unboundLooper dns.Looper, updaterLooper updater.Looper, publicIPLooper publicip.Looper,
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -6,8 +6,8 @@ require (
|
|||||||
github.com/fatih/color v1.10.0
|
github.com/fatih/color v1.10.0
|
||||||
github.com/golang/mock v1.4.4
|
github.com/golang/mock v1.4.4
|
||||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||||
github.com/qdm12/dns v1.4.0-rc4
|
github.com/qdm12/dns v1.4.0-rc5
|
||||||
github.com/qdm12/golibs v0.0.0-20210110211000-0a3a4541ae09
|
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217
|
||||||
github.com/qdm12/ss-server v0.1.0
|
github.com/qdm12/ss-server v0.1.0
|
||||||
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a
|
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
|||||||
10
go.sum
10
go.sum
@@ -92,13 +92,11 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/qdm12/dns v1.4.0-rc4 h1:pCcFMqismbktPQX7yrtdmJZq30Y05JBfWRTXY1ZLVFw=
|
github.com/qdm12/dns v1.4.0-rc5 h1:XXjYaFI3pDY1U4YFH5t5AI5IEKlIALmnE34VFhgkdQE=
|
||||||
github.com/qdm12/dns v1.4.0-rc4/go.mod h1:JhUKBhuDRYBUQ2XwW/jbeWx/qS0sSJjIFjGTCFGP5I8=
|
github.com/qdm12/dns v1.4.0-rc5/go.mod h1:WUY4/U8Z2O8888DPrahrIBv8GdYeoIcEy4aUDecZ+UM=
|
||||||
github.com/qdm12/golibs v0.0.0-20201227203847-2fd99ffdfdba/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
github.com/qdm12/golibs v0.0.0-20201227203847-2fd99ffdfdba/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||||
github.com/qdm12/golibs v0.0.0-20210102020307-17bc97def973 h1:5YeJALmDjvg2wSi6XB8MpQQekbT/eBnwGahJrh01HHQ=
|
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217 h1:/eMBq0vbc/KmVPXbwLfssp547pp6APRS1x/JNmPvm0s=
|
||||||
github.com/qdm12/golibs v0.0.0-20210102020307-17bc97def973/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
github.com/qdm12/golibs v0.0.0-20210124192933-79a950eaf217/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||||
github.com/qdm12/golibs v0.0.0-20210110211000-0a3a4541ae09 h1:zP+ZRwV3GldgTWFgKNBQ2zoFA8mIczb+fvTvrX8LZRo=
|
|
||||||
github.com/qdm12/golibs v0.0.0-20210110211000-0a3a4541ae09/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
|
||||||
github.com/qdm12/ss-server v0.1.0 h1:WV9MkHCDEWRwe4WpnYFeR/zcZAxYoTbfntLDnw9AQ50=
|
github.com/qdm12/ss-server v0.1.0 h1:WV9MkHCDEWRwe4WpnYFeR/zcZAxYoTbfntLDnw9AQ50=
|
||||||
github.com/qdm12/ss-server v0.1.0/go.mod h1:ABVUkxubboL3vqBkOwDV9glX1/x7SnYrckBe5d+M/zw=
|
github.com/qdm12/ss-server v0.1.0/go.mod h1:ABVUkxubboL3vqBkOwDV9glX1/x7SnYrckBe5d+M/zw=
|
||||||
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a h1:gkyP+gMEeBgMgyRYGrVNcoy6cL1065IvXsyfB6xboIc=
|
github.com/qdm12/updated v0.0.0-20210102005021-dd457d77f94a h1:gkyP+gMEeBgMgyRYGrVNcoy6cL1065IvXsyfB6xboIc=
|
||||||
|
|||||||
61
internal/dns/logs.go
Normal file
61
internal/dns/logs.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (l *looper) collectLines(wg *sync.WaitGroup, stdout, stderr <-chan string) {
|
||||||
|
defer wg.Done()
|
||||||
|
var line string
|
||||||
|
var ok bool
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case line, ok = <-stderr:
|
||||||
|
case line, ok = <-stdout:
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
line, level := processLogLine(line)
|
||||||
|
switch level {
|
||||||
|
case logging.DebugLevel:
|
||||||
|
l.logger.Debug(line)
|
||||||
|
case logging.InfoLevel:
|
||||||
|
l.logger.Info(line)
|
||||||
|
case logging.WarnLevel:
|
||||||
|
l.logger.Warn(line)
|
||||||
|
case logging.ErrorLevel:
|
||||||
|
l.logger.Error(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unboundPrefix = regexp.MustCompile(`\[[0-9]{10}\] unbound\[[0-9]+:[0|1]\] `)
|
||||||
|
|
||||||
|
func processLogLine(s string) (filtered string, level logging.Level) {
|
||||||
|
prefix := unboundPrefix.FindString(s)
|
||||||
|
filtered = s[len(prefix):]
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(filtered, "notice: "):
|
||||||
|
filtered = strings.TrimPrefix(filtered, "notice: ")
|
||||||
|
level = logging.InfoLevel
|
||||||
|
case strings.HasPrefix(filtered, "info: "):
|
||||||
|
filtered = strings.TrimPrefix(filtered, "info: ")
|
||||||
|
level = logging.InfoLevel
|
||||||
|
case strings.HasPrefix(filtered, "warn: "):
|
||||||
|
filtered = strings.TrimPrefix(filtered, "warn: ")
|
||||||
|
level = logging.WarnLevel
|
||||||
|
case strings.HasPrefix(filtered, "error: "):
|
||||||
|
filtered = strings.TrimPrefix(filtered, "error: ")
|
||||||
|
level = logging.ErrorLevel
|
||||||
|
default:
|
||||||
|
level = logging.InfoLevel
|
||||||
|
}
|
||||||
|
filtered = constants.ColorUnbound().Sprintf(filtered)
|
||||||
|
return filtered, level
|
||||||
|
}
|
||||||
49
internal/dns/logs_test.go
Normal file
49
internal/dns/logs_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_processLogLine(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tests := map[string]struct {
|
||||||
|
s string
|
||||||
|
filtered string
|
||||||
|
level logging.Level
|
||||||
|
}{
|
||||||
|
"empty string": {"", "", logging.InfoLevel},
|
||||||
|
"random string": {"asdasqdb", "asdasqdb", logging.InfoLevel},
|
||||||
|
"unbound notice": {
|
||||||
|
"[1594595249] unbound[75:0] notice: init module 0: validator",
|
||||||
|
"init module 0: validator",
|
||||||
|
logging.InfoLevel},
|
||||||
|
"unbound info": {
|
||||||
|
"[1594595249] unbound[75:0] info: init module 0: validator",
|
||||||
|
"init module 0: validator",
|
||||||
|
logging.InfoLevel},
|
||||||
|
"unbound warn": {
|
||||||
|
"[1594595249] unbound[75:0] warn: init module 0: validator",
|
||||||
|
"init module 0: validator",
|
||||||
|
logging.WarnLevel},
|
||||||
|
"unbound error": {
|
||||||
|
"[1594595249] unbound[75:0] error: init module 0: validator",
|
||||||
|
"init module 0: validator",
|
||||||
|
logging.ErrorLevel},
|
||||||
|
"unbound unknown": {
|
||||||
|
"[1594595249] unbound[75:0] BLA: init module 0: validator",
|
||||||
|
"BLA: init module 0: validator",
|
||||||
|
logging.InfoLevel},
|
||||||
|
}
|
||||||
|
for name, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
filtered, level := processLogLine(tc.s)
|
||||||
|
assert.Equal(t, tc.filtered, filtered)
|
||||||
|
assert.Equal(t, tc.level, level)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
"github.com/qdm12/gluetun/internal/settings"
|
||||||
"github.com/qdm12/golibs/command"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +29,6 @@ type looper struct {
|
|||||||
conf unbound.Configurator
|
conf unbound.Configurator
|
||||||
client *http.Client
|
client *http.Client
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
streamMerger command.StreamMerger
|
|
||||||
username string
|
username string
|
||||||
puid int
|
puid int
|
||||||
pgid int
|
pgid int
|
||||||
@@ -48,8 +46,7 @@ type looper struct {
|
|||||||
const defaultBackoffTime = 10 * time.Second
|
const defaultBackoffTime = 10 * time.Second
|
||||||
|
|
||||||
func NewLooper(conf unbound.Configurator, settings settings.DNS, client *http.Client,
|
func NewLooper(conf unbound.Configurator, settings settings.DNS, client *http.Client,
|
||||||
logger logging.Logger, streamMerger command.StreamMerger,
|
logger logging.Logger, username string, puid, pgid int) Looper {
|
||||||
username string, puid, pgid int) Looper {
|
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
status: constants.Stopped,
|
status: constants.Stopped,
|
||||||
@@ -61,7 +58,6 @@ func NewLooper(conf unbound.Configurator, settings settings.DNS, client *http.Cl
|
|||||||
username: username,
|
username: username,
|
||||||
puid: puid,
|
puid: puid,
|
||||||
pgid: pgid,
|
pgid: pgid,
|
||||||
streamMerger: streamMerger,
|
|
||||||
start: make(chan struct{}),
|
start: make(chan struct{}),
|
||||||
running: make(chan models.LoopStatus),
|
running: make(chan models.LoopStatus),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
@@ -107,8 +103,10 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup, dnsReadyCh chan<-
|
|||||||
|
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
// Upper scope variables for Unbound only
|
// Upper scope variables for Unbound only
|
||||||
var unboundCancel context.CancelFunc = func() {}
|
// Their values are to be used if DOT=off
|
||||||
waitError := make(chan error)
|
var waitError chan error
|
||||||
|
var unboundCancel context.CancelFunc
|
||||||
|
var closeStreams func()
|
||||||
|
|
||||||
for l.GetSettings().Enabled {
|
for l.GetSettings().Enabled {
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
@@ -116,7 +114,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup, dnsReadyCh chan<-
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
unboundCancel, err = l.setupUnbound(ctx, crashed, waitError)
|
unboundCancel, waitError, closeStreams, err = l.setupUnbound(ctx, wg, crashed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, errUpdateFiles) {
|
if !errors.Is(err, errUpdateFiles) {
|
||||||
const fallback = true
|
const fallback = true
|
||||||
@@ -130,6 +128,9 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup, dnsReadyCh chan<-
|
|||||||
if !l.GetSettings().Enabled {
|
if !l.GetSettings().Enabled {
|
||||||
const fallback = false
|
const fallback = false
|
||||||
l.useUnencryptedDNS(fallback)
|
l.useUnencryptedDNS(fallback)
|
||||||
|
waitError := make(chan error)
|
||||||
|
unboundCancel = func() { waitError <- nil }
|
||||||
|
closeStreams = func() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsReadyCh <- struct{}{}
|
dnsReadyCh <- struct{}{}
|
||||||
@@ -142,6 +143,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup, dnsReadyCh chan<-
|
|||||||
unboundCancel()
|
unboundCancel()
|
||||||
<-waitError
|
<-waitError
|
||||||
close(waitError)
|
close(waitError)
|
||||||
|
closeStreams()
|
||||||
return
|
return
|
||||||
case <-l.stop:
|
case <-l.stop:
|
||||||
l.logger.Info("stopping")
|
l.logger.Info("stopping")
|
||||||
@@ -163,7 +165,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup, dnsReadyCh chan<-
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(waitError)
|
close(waitError)
|
||||||
unboundCancel()
|
closeStreams()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,28 +174,29 @@ var errUpdateFiles = errors.New("cannot update files")
|
|||||||
// Returning cancel == nil signals we want to re-run setupUnbound
|
// Returning cancel == nil signals we want to re-run setupUnbound
|
||||||
// Returning err == errUpdateFiles signals we should not fall back
|
// Returning err == errUpdateFiles signals we should not fall back
|
||||||
// on the plaintext DNS as DOT is still up and running.
|
// on the plaintext DNS as DOT is still up and running.
|
||||||
func (l *looper) setupUnbound(ctx context.Context,
|
func (l *looper) setupUnbound(ctx context.Context, wg *sync.WaitGroup,
|
||||||
previousCrashed bool, waitError chan<- error) (cancel context.CancelFunc, err error) {
|
previousCrashed bool) (cancel context.CancelFunc, waitError chan error,
|
||||||
|
closeStreams func(), err error) {
|
||||||
err = l.updateFiles(ctx)
|
err = l.updateFiles(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.state.setStatusWithLock(constants.Crashed)
|
l.state.setStatusWithLock(constants.Crashed)
|
||||||
return nil, errUpdateFiles
|
return nil, nil, nil, errUpdateFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := l.GetSettings()
|
settings := l.GetSettings()
|
||||||
|
|
||||||
unboundCtx, cancel := context.WithCancel(context.Background())
|
unboundCtx, cancel := context.WithCancel(context.Background())
|
||||||
stream, waitFn, err := l.conf.Start(unboundCtx, settings.Unbound.VerbosityDetailsLevel)
|
stdoutLines, stderrLines, waitError, err := l.conf.Start(unboundCtx, settings.Unbound.VerbosityDetailsLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
if !previousCrashed {
|
if !previousCrashed {
|
||||||
l.running <- constants.Crashed
|
l.running <- constants.Crashed
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Started successfully
|
wg.Add(1)
|
||||||
go l.streamMerger.Merge(unboundCtx, stream, command.MergeName("unbound"))
|
go l.collectLines(wg, stdoutLines, stderrLines)
|
||||||
|
|
||||||
l.conf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound
|
l.conf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound
|
||||||
if err := l.conf.UseDNSSystemWide(net.IP{127, 0, 0, 1}, settings.KeepNameserver); err != nil { // use Unbound
|
if err := l.conf.UseDNSSystemWide(net.IP{127, 0, 0, 1}, settings.KeepNameserver); err != nil { // use Unbound
|
||||||
@@ -205,14 +208,13 @@ func (l *looper) setupUnbound(ctx context.Context,
|
|||||||
l.running <- constants.Crashed
|
l.running <- constants.Crashed
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
return nil, err
|
<-waitError
|
||||||
|
close(waitError)
|
||||||
|
close(stdoutLines)
|
||||||
|
close(stderrLines)
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
|
||||||
err := waitFn() // blocking
|
|
||||||
waitError <- err
|
|
||||||
}()
|
|
||||||
|
|
||||||
l.logger.Info("ready")
|
l.logger.Info("ready")
|
||||||
if !previousCrashed {
|
if !previousCrashed {
|
||||||
l.running <- constants.Running
|
l.running <- constants.Running
|
||||||
@@ -220,7 +222,13 @@ func (l *looper) setupUnbound(ctx context.Context,
|
|||||||
l.backoffTime = defaultBackoffTime
|
l.backoffTime = defaultBackoffTime
|
||||||
l.state.setStatusWithLock(constants.Running)
|
l.state.setStatusWithLock(constants.Running)
|
||||||
}
|
}
|
||||||
return cancel, nil
|
|
||||||
|
closeStreams = func() {
|
||||||
|
close(stdoutLines)
|
||||||
|
close(stderrLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cancel, waitError, closeStreams, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *looper) useUnencryptedDNS(fallback bool) {
|
func (l *looper) useUnencryptedDNS(fallback bool) {
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package logging
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
var regularExpressions = struct { //nolint:gochecknoglobals
|
|
||||||
unboundPrefix *regexp.Regexp
|
|
||||||
}{
|
|
||||||
unboundPrefix: regexp.MustCompile(`unbound: \[[0-9]{10}\] unbound\[[0-9]+:[0|1]\] `),
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostProcessLine(s string) (filtered string, level logging.Level) {
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(s, "openvpn: "):
|
|
||||||
for _, ignored := range []string{
|
|
||||||
"openvpn: WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail",
|
|
||||||
"openvpn: NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay",
|
|
||||||
} {
|
|
||||||
if s == ignored {
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(s, "openvpn: NOTE: "):
|
|
||||||
filtered = strings.TrimPrefix(s, "openvpn: NOTE: ")
|
|
||||||
filtered = "openvpn: " + filtered
|
|
||||||
level = logging.InfoLevel
|
|
||||||
case strings.HasPrefix(s, "openvpn: WARNING: "):
|
|
||||||
filtered = strings.TrimPrefix(s, "openvpn: WARNING: ")
|
|
||||||
filtered = "openvpn: " + filtered
|
|
||||||
level = logging.WarnLevel
|
|
||||||
case strings.HasPrefix(s, "openvpn: Options error: "):
|
|
||||||
filtered = strings.TrimPrefix(s, "openvpn: Options error: ")
|
|
||||||
filtered = "openvpn: " + filtered
|
|
||||||
level = logging.ErrorLevel
|
|
||||||
case s == "openvpn: Initialization Sequence Completed":
|
|
||||||
return color.HiGreenString(s), logging.InfoLevel
|
|
||||||
case s == "openvpn: AUTH: Received control message: AUTH_FAILED":
|
|
||||||
filtered = s + "\n\n (IF YOU ARE USING PIA servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n" //nolint:lll
|
|
||||||
level = logging.ErrorLevel
|
|
||||||
default:
|
|
||||||
filtered = s
|
|
||||||
level = logging.InfoLevel
|
|
||||||
}
|
|
||||||
filtered = constants.ColorOpenvpn().Sprintf(filtered)
|
|
||||||
return filtered, level
|
|
||||||
case strings.HasPrefix(s, "unbound: "):
|
|
||||||
prefix := regularExpressions.unboundPrefix.FindString(s)
|
|
||||||
filtered = s[len(prefix):]
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(filtered, "notice: "):
|
|
||||||
filtered = strings.TrimPrefix(filtered, "notice: ")
|
|
||||||
level = logging.InfoLevel
|
|
||||||
case strings.HasPrefix(filtered, "info: "):
|
|
||||||
filtered = strings.TrimPrefix(filtered, "info: ")
|
|
||||||
level = logging.InfoLevel
|
|
||||||
case strings.HasPrefix(filtered, "warn: "):
|
|
||||||
filtered = strings.TrimPrefix(filtered, "warn: ")
|
|
||||||
level = logging.WarnLevel
|
|
||||||
case strings.HasPrefix(filtered, "error: "):
|
|
||||||
filtered = strings.TrimPrefix(filtered, "error: ")
|
|
||||||
level = logging.ErrorLevel
|
|
||||||
default:
|
|
||||||
level = logging.ErrorLevel
|
|
||||||
}
|
|
||||||
filtered = fmt.Sprintf("unbound: %s", filtered)
|
|
||||||
filtered = constants.ColorUnbound().Sprintf(filtered)
|
|
||||||
return filtered, level
|
|
||||||
}
|
|
||||||
return s, logging.InfoLevel
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package logging
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/qdm12/golibs/logging"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_PostProcessLine(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
tests := map[string]struct {
|
|
||||||
s string
|
|
||||||
filtered string
|
|
||||||
level logging.Level
|
|
||||||
}{
|
|
||||||
"empty string": {"", "", logging.InfoLevel},
|
|
||||||
"random string": {"asdasqdb", "asdasqdb", logging.InfoLevel},
|
|
||||||
"unbound notice": {
|
|
||||||
"unbound: [1594595249] unbound[75:0] notice: init module 0: validator",
|
|
||||||
"unbound: init module 0: validator",
|
|
||||||
logging.InfoLevel},
|
|
||||||
"unbound info": {
|
|
||||||
"unbound: [1594595249] unbound[75:0] info: init module 0: validator",
|
|
||||||
"unbound: init module 0: validator",
|
|
||||||
logging.InfoLevel},
|
|
||||||
"unbound warn": {
|
|
||||||
"unbound: [1594595249] unbound[75:0] warn: init module 0: validator",
|
|
||||||
"unbound: init module 0: validator",
|
|
||||||
logging.WarnLevel},
|
|
||||||
"unbound error": {
|
|
||||||
"unbound: [1594595249] unbound[75:0] error: init module 0: validator",
|
|
||||||
"unbound: init module 0: validator",
|
|
||||||
logging.ErrorLevel},
|
|
||||||
"unbound unknown": {
|
|
||||||
"unbound: [1594595249] unbound[75:0] BLA: init module 0: validator",
|
|
||||||
"unbound: BLA: init module 0: validator",
|
|
||||||
logging.ErrorLevel},
|
|
||||||
"openvpn unknown": {
|
|
||||||
"openvpn: message",
|
|
||||||
"openvpn: message",
|
|
||||||
logging.InfoLevel},
|
|
||||||
"openvpn note": {
|
|
||||||
"openvpn: NOTE: message",
|
|
||||||
"openvpn: message",
|
|
||||||
logging.InfoLevel},
|
|
||||||
"openvpn warning": {
|
|
||||||
"openvpn: WARNING: message",
|
|
||||||
"openvpn: message",
|
|
||||||
logging.WarnLevel},
|
|
||||||
"openvpn options error": {
|
|
||||||
"openvpn: Options error: message",
|
|
||||||
"openvpn: message",
|
|
||||||
logging.ErrorLevel},
|
|
||||||
"openvpn ignored message": {
|
|
||||||
"openvpn: NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay",
|
|
||||||
"",
|
|
||||||
""},
|
|
||||||
"openvpn success": {
|
|
||||||
"openvpn: Initialization Sequence Completed",
|
|
||||||
"openvpn: Initialization Sequence Completed",
|
|
||||||
logging.InfoLevel},
|
|
||||||
"openvpn auth failed": {
|
|
||||||
"openvpn: AUTH: Received control message: AUTH_FAILED",
|
|
||||||
"openvpn: AUTH: Received control message: AUTH_FAILED\n\n (IF YOU ARE USING PIA servers, MAYBE CHECK OUT https://github.com/qdm12/gluetun/issues/265)\n", //nolint:lll
|
|
||||||
logging.ErrorLevel},
|
|
||||||
}
|
|
||||||
for name, tc := range tests {
|
|
||||||
tc := tc
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
filtered, level := PostProcessLine(tc.s)
|
|
||||||
assert.Equal(t, tc.filtered, filtered)
|
|
||||||
assert.Equal(t, tc.level, level)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,16 +3,14 @@ package openvpn
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *configurator) Start(ctx context.Context) (stdout io.ReadCloser, waitFn func() error, err error) {
|
func (c *configurator) Start(ctx context.Context) (stdoutLines, stderrLines chan string, waitError chan error, err error) {
|
||||||
c.logger.Info("starting openvpn")
|
c.logger.Info("starting openvpn")
|
||||||
stdout, _, waitFn, err = c.commander.Start(ctx, "openvpn", "--config", string(constants.OpenVPNConf))
|
return c.commander.Start(ctx, "openvpn", "--config", string(constants.OpenVPNConf))
|
||||||
return stdout, waitFn, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||||
|
|||||||
100
internal/openvpn/logs.go
Normal file
100
internal/openvpn/logs.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package openvpn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (l *looper) collectLines(wg *sync.WaitGroup, stdout, stderr <-chan string) {
|
||||||
|
defer wg.Done()
|
||||||
|
var line string
|
||||||
|
var ok, errLine bool
|
||||||
|
|
||||||
|
for {
|
||||||
|
errLine = false
|
||||||
|
select {
|
||||||
|
case line, ok = <-stdout:
|
||||||
|
case line, ok = <-stderr:
|
||||||
|
errLine = true
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
line, level := processLogLine(line)
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue // filtered out
|
||||||
|
}
|
||||||
|
if errLine {
|
||||||
|
level = logging.ErrorLevel
|
||||||
|
}
|
||||||
|
switch level {
|
||||||
|
case logging.DebugLevel:
|
||||||
|
l.logger.Debug(line)
|
||||||
|
case logging.InfoLevel:
|
||||||
|
l.logger.Info(line)
|
||||||
|
case logging.WarnLevel:
|
||||||
|
l.logger.Warn(line)
|
||||||
|
case logging.ErrorLevel:
|
||||||
|
l.logger.Error(line)
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "Initialization Sequence Completed") {
|
||||||
|
l.tunnelReady <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processLogLine(s string) (filtered string, level logging.Level) {
|
||||||
|
for _, ignored := range []string{
|
||||||
|
"WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail",
|
||||||
|
"NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay",
|
||||||
|
} {
|
||||||
|
if s == ignored {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(s, "NOTE: "):
|
||||||
|
filtered = strings.TrimPrefix(s, "NOTE: ")
|
||||||
|
level = logging.InfoLevel
|
||||||
|
case strings.HasPrefix(s, "WARNING: "):
|
||||||
|
filtered = strings.TrimPrefix(s, "WARNING: ")
|
||||||
|
level = logging.WarnLevel
|
||||||
|
case strings.HasPrefix(s, "Options error: "):
|
||||||
|
filtered = strings.TrimPrefix(s, "Options error: ")
|
||||||
|
level = logging.ErrorLevel
|
||||||
|
case s == "Initialization Sequence Completed":
|
||||||
|
return color.HiGreenString(s), logging.InfoLevel
|
||||||
|
case s == "AUTH: Received control message: AUTH_FAILED":
|
||||||
|
filtered = s + `
|
||||||
|
|
||||||
|
Your credentials might be wrong 🤨
|
||||||
|
|
||||||
|
💡 If you use Private Internet Access, check https://github.com/qdm12/gluetun/issues/265
|
||||||
|
|
||||||
|
`
|
||||||
|
level = logging.ErrorLevel
|
||||||
|
case strings.Contains(s, "TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)"):
|
||||||
|
s += `
|
||||||
|
🚒🚒🚒🚒🚒🚨🚨🚨🚨🚨🚨🚒🚒🚒🚒🚒
|
||||||
|
That error usually happens because either:
|
||||||
|
|
||||||
|
1. The VPN server IP address you are trying to connect to is no longer valid 🔌
|
||||||
|
Update your server information using https://github.com/qdm12/gluetun/wiki/Updating-Servers
|
||||||
|
|
||||||
|
2. The VPN server crashed 💥, try changing your VPN servers filtering options such as REGION
|
||||||
|
|
||||||
|
3. Your Internet connection is not working 🤯, ensure it works
|
||||||
|
|
||||||
|
4. Something else ➡️ https://github.com/qdm12/gluetun/issues/new/choose
|
||||||
|
`
|
||||||
|
default:
|
||||||
|
filtered = s
|
||||||
|
level = logging.InfoLevel
|
||||||
|
}
|
||||||
|
filtered = constants.ColorOpenvpn().Sprintf(filtered)
|
||||||
|
return filtered, level
|
||||||
|
}
|
||||||
57
internal/openvpn/logs_test.go
Normal file
57
internal/openvpn/logs_test.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package openvpn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_processLogLine(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tests := map[string]struct {
|
||||||
|
s string
|
||||||
|
filtered string
|
||||||
|
level logging.Level
|
||||||
|
}{
|
||||||
|
"empty string": {"", "", logging.InfoLevel},
|
||||||
|
"random string": {"asdasqdb", "asdasqdb", logging.InfoLevel},
|
||||||
|
"openvpn unknown": {
|
||||||
|
"message",
|
||||||
|
"message",
|
||||||
|
logging.InfoLevel},
|
||||||
|
"openvpn note": {
|
||||||
|
"NOTE: message",
|
||||||
|
"message",
|
||||||
|
logging.InfoLevel},
|
||||||
|
"openvpn warning": {
|
||||||
|
"WARNING: message",
|
||||||
|
"message",
|
||||||
|
logging.WarnLevel},
|
||||||
|
"openvpn options error": {
|
||||||
|
"Options error: message",
|
||||||
|
"message",
|
||||||
|
logging.ErrorLevel},
|
||||||
|
"openvpn ignored message": {
|
||||||
|
"NOTE: UID/GID downgrade will be delayed because of --client, --pull, or --up-delay",
|
||||||
|
"",
|
||||||
|
""},
|
||||||
|
"openvpn success": {
|
||||||
|
"Initialization Sequence Completed",
|
||||||
|
"Initialization Sequence Completed",
|
||||||
|
logging.InfoLevel},
|
||||||
|
"openvpn auth failed": {
|
||||||
|
"AUTH: Received control message: AUTH_FAILED",
|
||||||
|
"AUTH: Received control message: AUTH_FAILED\n\nYour credentials might be wrong 🤨\n\n💡 If you use Private Internet Access, check https://github.com/qdm12/gluetun/issues/265\n\n", //nolint:lll
|
||||||
|
logging.ErrorLevel},
|
||||||
|
}
|
||||||
|
for name, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
filtered, level := processLogLine(tc.s)
|
||||||
|
assert.Equal(t, tc.filtered, filtered)
|
||||||
|
assert.Equal(t, tc.level, level)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
"github.com/qdm12/gluetun/internal/routing"
|
"github.com/qdm12/gluetun/internal/routing"
|
||||||
"github.com/qdm12/gluetun/internal/settings"
|
"github.com/qdm12/gluetun/internal/settings"
|
||||||
"github.com/qdm12/golibs/command"
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/os"
|
"github.com/qdm12/golibs/os"
|
||||||
)
|
)
|
||||||
@@ -45,7 +44,7 @@ type looper struct {
|
|||||||
logger, pfLogger logging.Logger
|
logger, pfLogger logging.Logger
|
||||||
client *http.Client
|
client *http.Client
|
||||||
openFile os.OpenFileFunc
|
openFile os.OpenFileFunc
|
||||||
streamMerger command.StreamMerger
|
tunnelReady chan<- struct{}
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
// Internal channels and locks
|
// Internal channels and locks
|
||||||
loopLock sync.Mutex
|
loopLock sync.Mutex
|
||||||
@@ -63,7 +62,7 @@ func NewLooper(settings settings.OpenVPN,
|
|||||||
username string, puid, pgid int, allServers models.AllServers,
|
username string, puid, pgid int, allServers models.AllServers,
|
||||||
conf Configurator, fw firewall.Configurator, routing routing.Routing,
|
conf Configurator, fw firewall.Configurator, routing routing.Routing,
|
||||||
logger logging.Logger, client *http.Client, openFile os.OpenFileFunc,
|
logger logging.Logger, client *http.Client, openFile os.OpenFileFunc,
|
||||||
streamMerger command.StreamMerger, cancel context.CancelFunc) Looper {
|
tunnelReady chan<- struct{}, cancel context.CancelFunc) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
state: state{
|
state: state{
|
||||||
status: constants.Stopped,
|
status: constants.Stopped,
|
||||||
@@ -80,7 +79,7 @@ func NewLooper(settings settings.OpenVPN,
|
|||||||
pfLogger: logger.WithPrefix("port forwarding: "),
|
pfLogger: logger.WithPrefix("port forwarding: "),
|
||||||
client: client,
|
client: client,
|
||||||
openFile: openFile,
|
openFile: openFile,
|
||||||
streamMerger: streamMerger,
|
tunnelReady: tunnelReady,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
start: make(chan struct{}),
|
start: make(chan struct{}),
|
||||||
running: make(chan models.LoopStatus),
|
running: make(chan models.LoopStatus),
|
||||||
@@ -144,7 +143,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
|
|
||||||
openvpnCtx, openvpnCancel := context.WithCancel(context.Background())
|
openvpnCtx, openvpnCancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
stream, waitFn, err := l.conf.Start(openvpnCtx)
|
stdoutLines, stderrLines, waitError, err := l.conf.Start(openvpnCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
openvpnCancel()
|
openvpnCancel()
|
||||||
l.signalCrashedStatus()
|
l.signalCrashedStatus()
|
||||||
@@ -152,6 +151,9 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go l.collectLines(wg, stdoutLines, stderrLines)
|
||||||
|
|
||||||
// Needs the stream line from main.go to know when the tunnel is up
|
// Needs the stream line from main.go to know when the tunnel is up
|
||||||
go func(ctx context.Context) {
|
go func(ctx context.Context) {
|
||||||
for {
|
for {
|
||||||
@@ -166,13 +168,6 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
}(openvpnCtx)
|
}(openvpnCtx)
|
||||||
|
|
||||||
go l.streamMerger.Merge(openvpnCtx, stream, command.MergeName("openvpn"))
|
|
||||||
waitError := make(chan error)
|
|
||||||
go func() {
|
|
||||||
err := waitFn() // blocking
|
|
||||||
waitError <- err
|
|
||||||
}()
|
|
||||||
|
|
||||||
if l.crashed {
|
if l.crashed {
|
||||||
l.crashed = false
|
l.crashed = false
|
||||||
l.backoffTime = defaultBackoffTime
|
l.backoffTime = defaultBackoffTime
|
||||||
@@ -189,6 +184,8 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
openvpnCancel()
|
openvpnCancel()
|
||||||
<-waitError
|
<-waitError
|
||||||
close(waitError)
|
close(waitError)
|
||||||
|
close(stdoutLines)
|
||||||
|
close(stderrLines)
|
||||||
return
|
return
|
||||||
case <-l.stop:
|
case <-l.stop:
|
||||||
l.logger.Info("stopping")
|
l.logger.Info("stopping")
|
||||||
@@ -207,6 +204,8 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(waitError)
|
close(waitError)
|
||||||
|
close(stdoutLines)
|
||||||
|
close(stderrLines)
|
||||||
openvpnCancel() // just for the linter
|
openvpnCancel() // just for the linter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package openvpn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/unix"
|
"github.com/qdm12/gluetun/internal/unix"
|
||||||
"github.com/qdm12/golibs/command"
|
"github.com/qdm12/golibs/command"
|
||||||
@@ -15,7 +14,8 @@ type Configurator interface {
|
|||||||
WriteAuthFile(user, password string, puid, pgid int) error
|
WriteAuthFile(user, password string, puid, pgid int) error
|
||||||
CheckTUN() error
|
CheckTUN() error
|
||||||
CreateTUN() error
|
CreateTUN() error
|
||||||
Start(ctx context.Context) (stdout io.ReadCloser, waitFn func() error, err error)
|
Start(ctx context.Context) (stdoutLines, stderrLines chan string,
|
||||||
|
waitError chan error, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type configurator struct {
|
type configurator struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user