2021-02-06 16:26:23 +00:00
|
|
|
// Package dns defines interfaces to interact with DNS and DNS over TLS.
|
2020-07-08 13:14:39 +00:00
|
|
|
package dns
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2021-01-02 18:31:39 +00:00
|
|
|
"net/http"
|
2020-07-08 13:14:39 +00:00
|
|
|
"time"
|
|
|
|
|
|
2021-05-14 14:06:30 +00:00
|
|
|
"github.com/qdm12/dns/pkg/blacklist"
|
2021-01-02 18:31:39 +00:00
|
|
|
"github.com/qdm12/dns/pkg/unbound"
|
2021-02-06 11:05:50 -05:00
|
|
|
"github.com/qdm12/gluetun/internal/configuration"
|
2020-07-26 12:07:06 +00:00
|
|
|
"github.com/qdm12/gluetun/internal/constants"
|
2020-12-19 20:10:34 -05:00
|
|
|
"github.com/qdm12/gluetun/internal/models"
|
2020-07-08 13:14:39 +00:00
|
|
|
"github.com/qdm12/golibs/logging"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Looper interface {
|
2021-05-11 22:24:32 +00:00
|
|
|
Run(ctx context.Context, done chan<- struct{})
|
|
|
|
|
RunRestartTicker(ctx context.Context, done chan<- struct{})
|
2020-12-19 20:10:34 -05:00
|
|
|
GetStatus() (status models.LoopStatus)
|
2021-07-16 19:00:56 +00:00
|
|
|
ApplyStatus(ctx context.Context, status models.LoopStatus) (
|
2021-07-15 22:42:58 +00:00
|
|
|
outcome string, err error)
|
2021-02-06 11:05:50 -05:00
|
|
|
GetSettings() (settings configuration.DNS)
|
2021-07-15 22:42:58 +00:00
|
|
|
SetSettings(ctx context.Context, settings configuration.DNS) (
|
|
|
|
|
outcome string)
|
2020-07-08 13:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type looper struct {
|
2021-07-16 19:00:56 +00:00
|
|
|
state *state
|
2021-01-02 18:31:39 +00:00
|
|
|
conf unbound.Configurator
|
2021-07-23 16:06:19 +00:00
|
|
|
resolvConf string
|
2021-05-14 14:06:30 +00:00
|
|
|
blockBuilder blacklist.Builder
|
2021-01-02 18:31:39 +00:00
|
|
|
client *http.Client
|
2020-12-19 20:10:34 -05:00
|
|
|
logger logging.Logger
|
2021-07-16 21:21:09 +00:00
|
|
|
userTrigger bool
|
2021-07-16 19:00:56 +00:00
|
|
|
start <-chan struct{}
|
|
|
|
|
running chan<- models.LoopStatus
|
|
|
|
|
stop <-chan struct{}
|
|
|
|
|
stopped chan<- struct{}
|
|
|
|
|
updateTicker <-chan struct{}
|
2020-12-30 17:22:54 +00:00
|
|
|
backoffTime time.Duration
|
2020-12-19 20:10:34 -05:00
|
|
|
timeNow func() time.Time
|
|
|
|
|
timeSince func(time.Time) time.Duration
|
2020-07-08 13:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-30 17:22:54 +00:00
|
|
|
const defaultBackoffTime = 10 * time.Second
|
|
|
|
|
|
2021-07-23 18:55:53 +00:00
|
|
|
func NewLoop(conf unbound.Configurator, settings configuration.DNS, client *http.Client,
|
2021-07-23 16:06:19 +00:00
|
|
|
logger logging.Logger) Looper {
|
2021-07-16 19:00:56 +00:00
|
|
|
start := make(chan struct{})
|
|
|
|
|
running := make(chan models.LoopStatus)
|
|
|
|
|
stop := make(chan struct{})
|
|
|
|
|
stopped := make(chan struct{})
|
|
|
|
|
updateTicker := make(chan struct{})
|
|
|
|
|
|
|
|
|
|
state := newState(constants.Stopped, settings, start, running, stop, stopped, updateTicker)
|
|
|
|
|
|
2020-07-08 13:14:39 +00:00
|
|
|
return &looper{
|
2021-07-16 19:00:56 +00:00
|
|
|
state: state,
|
2020-07-08 13:14:39 +00:00
|
|
|
conf: conf,
|
2021-07-23 16:06:19 +00:00
|
|
|
resolvConf: "/etc/resolv.conf",
|
2021-05-14 14:06:30 +00:00
|
|
|
blockBuilder: blacklist.NewBuilder(client),
|
2021-01-02 18:31:39 +00:00
|
|
|
client: client,
|
2021-05-12 22:57:15 +00:00
|
|
|
logger: logger,
|
2021-07-16 21:21:09 +00:00
|
|
|
userTrigger: true,
|
2021-07-16 19:00:56 +00:00
|
|
|
start: start,
|
|
|
|
|
running: running,
|
|
|
|
|
stop: stop,
|
|
|
|
|
stopped: stopped,
|
|
|
|
|
updateTicker: updateTicker,
|
2020-12-30 17:22:54 +00:00
|
|
|
backoffTime: defaultBackoffTime,
|
2020-10-15 23:20:36 +00:00
|
|
|
timeNow: time.Now,
|
|
|
|
|
timeSince: time.Since,
|
2020-07-08 13:14:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-11 20:59:30 +00:00
|
|
|
func (l *looper) logAndWait(ctx context.Context, err error) {
|
2021-01-30 18:07:12 +00:00
|
|
|
if err != nil {
|
2021-07-23 17:36:08 +00:00
|
|
|
l.logger.Warn(err.Error())
|
2021-01-30 18:07:12 +00:00
|
|
|
}
|
2021-07-16 19:00:56 +00:00
|
|
|
l.logger.Info("attempting restart in " + l.backoffTime.String())
|
2020-12-30 17:22:54 +00:00
|
|
|
timer := time.NewTimer(l.backoffTime)
|
|
|
|
|
l.backoffTime *= 2
|
2020-10-20 02:45:28 +00:00
|
|
|
select {
|
|
|
|
|
case <-timer.C:
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
if !timer.Stop() {
|
|
|
|
|
<-timer.C
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-08 13:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
2021-07-16 21:21:09 +00:00
|
|
|
func (l *looper) signalOrSetStatus(status models.LoopStatus) {
|
|
|
|
|
if l.userTrigger {
|
|
|
|
|
l.userTrigger = false
|
2021-07-16 20:11:57 +00:00
|
|
|
select {
|
|
|
|
|
case l.running <- status:
|
2021-07-23 18:55:53 +00:00
|
|
|
default: // receiver dropped out - avoid deadlock on events routing when shutting down
|
2021-07-16 20:11:57 +00:00
|
|
|
}
|
2021-07-16 19:00:56 +00:00
|
|
|
} else {
|
|
|
|
|
l.state.SetStatus(status)
|
|
|
|
|
}
|
|
|
|
|
}
|