Skip to content

Commit

Permalink
chore(lint): upgrade golangci-lint to v1.47.2
Browse files Browse the repository at this point in the history
- Fix Slowloris attacks on HTTP servers
- Force set default of 5 minutes for pprof read timeout
- Change `ShutdownTimeout` to time.Duration since it cannot be set to 0
  • Loading branch information
qdm12 committed Jul 29, 2022
1 parent 877617c commit 87db081
Show file tree
Hide file tree
Showing 23 changed files with 346 additions and 158 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Expand Up @@ -2,7 +2,7 @@ ARG ALPINE_VERSION=3.16
ARG GO_ALPINE_VERSION=3.16
ARG GO_VERSION=1.17
ARG XCPUTRANSLATE_VERSION=v0.6.0
ARG GOLANGCI_LINT_VERSION=v1.46.2
ARG GOLANGCI_LINT_VERSION=v1.47.2
ARG MOCKGEN_VERSION=v1.6.0
ARG BUILDPLATFORM=linux/amd64

Expand Down
6 changes: 3 additions & 3 deletions internal/configuration/settings/dot.go
Expand Up @@ -65,7 +65,7 @@ func (d *DoT) copy() (copied DoT) {
// unset field of the receiver settings object.
func (d *DoT) mergeWith(other DoT) {
d.Enabled = helpers.MergeWithBool(d.Enabled, other.Enabled)
d.UpdatePeriod = helpers.MergeWithDuration(d.UpdatePeriod, other.UpdatePeriod)
d.UpdatePeriod = helpers.MergeWithDurationPtr(d.UpdatePeriod, other.UpdatePeriod)
d.Unbound.mergeWith(other.Unbound)
d.Blacklist.mergeWith(other.Blacklist)
}
Expand All @@ -75,15 +75,15 @@ func (d *DoT) mergeWith(other DoT) {
// settings.
func (d *DoT) overrideWith(other DoT) {
d.Enabled = helpers.OverrideWithBool(d.Enabled, other.Enabled)
d.UpdatePeriod = helpers.OverrideWithDuration(d.UpdatePeriod, other.UpdatePeriod)
d.UpdatePeriod = helpers.OverrideWithDurationPtr(d.UpdatePeriod, other.UpdatePeriod)
d.Unbound.overrideWith(other.Unbound)
d.Blacklist.overrideWith(other.Blacklist)
}

func (d *DoT) setDefaults() {
d.Enabled = helpers.DefaultBool(d.Enabled, true)
const defaultUpdatePeriod = 24 * time.Hour
d.UpdatePeriod = helpers.DefaultDuration(d.UpdatePeriod, defaultUpdatePeriod)
d.UpdatePeriod = helpers.DefaultDurationPtr(d.UpdatePeriod, defaultUpdatePeriod)
d.Unbound.setDefaults()
d.Blacklist.setDefaults()
}
Expand Down
25 changes: 22 additions & 3 deletions internal/configuration/settings/health.go
Expand Up @@ -3,6 +3,7 @@ package settings
import (
"fmt"
"os"
"time"

"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
"github.com/qdm12/gotree"
Expand All @@ -15,6 +16,12 @@ type Health struct {
// for the health check server.
// It cannot be the empty string in the internal state.
ServerAddress string
// ReadHeaderTimeout is the HTTP server header read timeout
// duration of the HTTP server. It defaults to 100 milliseconds.
ReadHeaderTimeout time.Duration
// ReadTimeout is the HTTP read timeout duration of the
// HTTP server. It defaults to 500 milliseconds.
ReadTimeout time.Duration
// TargetAddress is the address (host or host:port)
// to TCP dial to periodically for the health check.
// It cannot be the empty string in the internal state.
Expand All @@ -40,16 +47,20 @@ func (h Health) Validate() (err error) {

func (h *Health) copy() (copied Health) {
return Health{
ServerAddress: h.ServerAddress,
TargetAddress: h.TargetAddress,
VPN: h.VPN.copy(),
ServerAddress: h.ServerAddress,
ReadHeaderTimeout: h.ReadHeaderTimeout,
ReadTimeout: h.ReadTimeout,
TargetAddress: h.TargetAddress,
VPN: h.VPN.copy(),
}
}

// MergeWith merges the other settings into any
// unset field of the receiver settings object.
func (h *Health) MergeWith(other Health) {
h.ServerAddress = helpers.MergeWithString(h.ServerAddress, other.ServerAddress)
h.ReadHeaderTimeout = helpers.MergeWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
h.ReadTimeout = helpers.MergeWithDuration(h.ReadTimeout, other.ReadTimeout)
h.TargetAddress = helpers.MergeWithString(h.TargetAddress, other.TargetAddress)
h.VPN.mergeWith(other.VPN)
}
Expand All @@ -59,12 +70,18 @@ func (h *Health) MergeWith(other Health) {
// settings.
func (h *Health) OverrideWith(other Health) {
h.ServerAddress = helpers.OverrideWithString(h.ServerAddress, other.ServerAddress)
h.ReadHeaderTimeout = helpers.OverrideWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
h.ReadTimeout = helpers.OverrideWithDuration(h.ReadTimeout, other.ReadTimeout)
h.TargetAddress = helpers.OverrideWithString(h.TargetAddress, other.TargetAddress)
h.VPN.overrideWith(other.VPN)
}

func (h *Health) SetDefaults() {
h.ServerAddress = helpers.DefaultString(h.ServerAddress, "127.0.0.1:9999")
const defaultReadHeaderTimeout = 100 * time.Millisecond
h.ReadHeaderTimeout = helpers.DefaultDuration(h.ReadHeaderTimeout, defaultReadHeaderTimeout)
const defaultReadTimeout = 500 * time.Millisecond
h.ReadTimeout = helpers.DefaultDuration(h.ReadTimeout, defaultReadTimeout)
h.TargetAddress = helpers.DefaultString(h.TargetAddress, "cloudflare.com:443")
h.VPN.setDefaults()
}
Expand All @@ -77,6 +94,8 @@ func (h Health) toLinesNode() (node *gotree.Node) {
node = gotree.New("Health settings:")
node.Appendf("Server listening address: %s", h.ServerAddress)
node.Appendf("Target address: %s", h.TargetAddress)
node.Appendf("Read header timeout: %s", h.ReadHeaderTimeout)
node.Appendf("Read timeout: %s", h.ReadTimeout)
node.AppendNode(h.VPN.toLinesNode("VPN"))
return node
}
12 changes: 6 additions & 6 deletions internal/configuration/settings/healthywait.go
Expand Up @@ -35,23 +35,23 @@ func (h *HealthyWait) copy() (copied HealthyWait) {
// mergeWith merges the other settings into any
// unset field of the receiver settings object.
func (h *HealthyWait) mergeWith(other HealthyWait) {
h.Initial = helpers.MergeWithDuration(h.Initial, other.Initial)
h.Addition = helpers.MergeWithDuration(h.Addition, other.Addition)
h.Initial = helpers.MergeWithDurationPtr(h.Initial, other.Initial)
h.Addition = helpers.MergeWithDurationPtr(h.Addition, other.Addition)
}

// overrideWith overrides fields of the receiver
// settings object with any field set in the other
// settings.
func (h *HealthyWait) overrideWith(other HealthyWait) {
h.Initial = helpers.OverrideWithDuration(h.Initial, other.Initial)
h.Addition = helpers.OverrideWithDuration(h.Addition, other.Addition)
h.Initial = helpers.OverrideWithDurationPtr(h.Initial, other.Initial)
h.Addition = helpers.OverrideWithDurationPtr(h.Addition, other.Addition)
}

func (h *HealthyWait) setDefaults() {
const initialDurationDefault = 6 * time.Second
const additionDurationDefault = 5 * time.Second
h.Initial = helpers.DefaultDuration(h.Initial, initialDurationDefault)
h.Addition = helpers.DefaultDuration(h.Addition, additionDurationDefault)
h.Initial = helpers.DefaultDurationPtr(h.Initial, initialDurationDefault)
h.Addition = helpers.DefaultDurationPtr(h.Addition, additionDurationDefault)
}

func (h HealthyWait) String() string {
Expand Down
10 changes: 9 additions & 1 deletion internal/configuration/settings/helpers/default.go
Expand Up @@ -73,7 +73,15 @@ func DefaultStringPtr(existing *string, defaultValue string) (result *string) {
return result
}

func DefaultDuration(existing *time.Duration,
func DefaultDuration(existing time.Duration,
defaultValue time.Duration) (result time.Duration) {
if existing != 0 {
return existing
}
return defaultValue
}

func DefaultDurationPtr(existing *time.Duration,
defaultValue time.Duration) (result *time.Duration) {
if existing != nil {
return existing
Expand Down
9 changes: 8 additions & 1 deletion internal/configuration/settings/helpers/merge.go
Expand Up @@ -107,7 +107,14 @@ func MergeWithIP(existing, other net.IP) (result net.IP) {
return result
}

func MergeWithDuration(existing, other *time.Duration) (result *time.Duration) {
func MergeWithDuration(existing, other time.Duration) (result time.Duration) {
if existing != 0 {
return existing
}
return other
}

func MergeWithDurationPtr(existing, other *time.Duration) (result *time.Duration) {
if existing != nil {
return existing
}
Expand Down
11 changes: 10 additions & 1 deletion internal/configuration/settings/helpers/override.go
Expand Up @@ -93,7 +93,16 @@ func OverrideWithIP(existing, other net.IP) (result net.IP) {
return result
}

func OverrideWithDuration(existing, other *time.Duration) (result *time.Duration) {
func OverrideWithDuration(existing, other time.Duration) (
result time.Duration) {
if other == 0 {
return existing
}
return other
}

func OverrideWithDurationPtr(existing, other *time.Duration) (
result *time.Duration) {
if other == nil {
return existing
}
Expand Down
31 changes: 25 additions & 6 deletions internal/configuration/settings/httpproxy.go
Expand Up @@ -3,6 +3,7 @@ package settings
import (
"fmt"
"os"
"time"

"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
"github.com/qdm12/gotree"
Expand Down Expand Up @@ -33,6 +34,12 @@ type HTTPProxy struct {
// each request/response. It cannot be nil in the
// internal state.
Log *bool
// ReadHeaderTimeout is the HTTP header read timeout duration
// of the HTTP server. It defaults to 1 second if left unset.
ReadHeaderTimeout time.Duration
// ReadTimeout is the HTTP read timeout duration
// of the HTTP server. It defaults to 3 seconds if left unset.
ReadTimeout time.Duration
}

func (h HTTPProxy) validate() (err error) {
Expand All @@ -49,12 +56,14 @@ func (h HTTPProxy) validate() (err error) {

func (h *HTTPProxy) copy() (copied HTTPProxy) {
return HTTPProxy{
User: helpers.CopyStringPtr(h.User),
Password: helpers.CopyStringPtr(h.Password),
ListeningAddress: h.ListeningAddress,
Enabled: helpers.CopyBoolPtr(h.Enabled),
Stealth: helpers.CopyBoolPtr(h.Stealth),
Log: helpers.CopyBoolPtr(h.Log),
User: helpers.CopyStringPtr(h.User),
Password: helpers.CopyStringPtr(h.Password),
ListeningAddress: h.ListeningAddress,
Enabled: helpers.CopyBoolPtr(h.Enabled),
Stealth: helpers.CopyBoolPtr(h.Stealth),
Log: helpers.CopyBoolPtr(h.Log),
ReadHeaderTimeout: h.ReadHeaderTimeout,
ReadTimeout: h.ReadTimeout,
}
}

Expand All @@ -67,6 +76,8 @@ func (h *HTTPProxy) mergeWith(other HTTPProxy) {
h.Enabled = helpers.MergeWithBool(h.Enabled, other.Enabled)
h.Stealth = helpers.MergeWithBool(h.Stealth, other.Stealth)
h.Log = helpers.MergeWithBool(h.Log, other.Log)
h.ReadHeaderTimeout = helpers.MergeWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
h.ReadTimeout = helpers.MergeWithDuration(h.ReadTimeout, other.ReadTimeout)
}

// overrideWith overrides fields of the receiver
Expand All @@ -79,6 +90,8 @@ func (h *HTTPProxy) overrideWith(other HTTPProxy) {
h.Enabled = helpers.OverrideWithBool(h.Enabled, other.Enabled)
h.Stealth = helpers.OverrideWithBool(h.Stealth, other.Stealth)
h.Log = helpers.OverrideWithBool(h.Log, other.Log)
h.ReadHeaderTimeout = helpers.OverrideWithDuration(h.ReadHeaderTimeout, other.ReadHeaderTimeout)
h.ReadTimeout = helpers.OverrideWithDuration(h.ReadTimeout, other.ReadTimeout)
}

func (h *HTTPProxy) setDefaults() {
Expand All @@ -88,6 +101,10 @@ func (h *HTTPProxy) setDefaults() {
h.Enabled = helpers.DefaultBool(h.Enabled, false)
h.Stealth = helpers.DefaultBool(h.Stealth, false)
h.Log = helpers.DefaultBool(h.Log, false)
const defaultReadHeaderTimeout = time.Second
h.ReadHeaderTimeout = helpers.DefaultDuration(h.ReadHeaderTimeout, defaultReadHeaderTimeout)
const defaultReadTimeout = 3 * time.Second
h.ReadTimeout = helpers.DefaultDuration(h.ReadTimeout, defaultReadTimeout)
}

func (h HTTPProxy) String() string {
Expand All @@ -106,6 +123,8 @@ func (h HTTPProxy) toLinesNode() (node *gotree.Node) {
node.Appendf("Password: %s", helpers.ObfuscatePassword(*h.Password))
node.Appendf("Stealth mode: %s", helpers.BoolPtrToYesNo(h.Stealth))
node.Appendf("Log: %s", helpers.BoolPtrToYesNo(h.Log))
node.Appendf("Read header timeout: %s", h.ReadHeaderTimeout)
node.Appendf("Read timeout: %s", h.ReadTimeout)

return node
}
6 changes: 3 additions & 3 deletions internal/configuration/settings/publicip.go
Expand Up @@ -48,18 +48,18 @@ func (p *PublicIP) copy() (copied PublicIP) {
}

func (p *PublicIP) mergeWith(other PublicIP) {
p.Period = helpers.MergeWithDuration(p.Period, other.Period)
p.Period = helpers.MergeWithDurationPtr(p.Period, other.Period)
p.IPFilepath = helpers.MergeWithStringPtr(p.IPFilepath, other.IPFilepath)
}

func (p *PublicIP) overrideWith(other PublicIP) {
p.Period = helpers.OverrideWithDuration(p.Period, other.Period)
p.Period = helpers.OverrideWithDurationPtr(p.Period, other.Period)
p.IPFilepath = helpers.OverrideWithStringPtr(p.IPFilepath, other.IPFilepath)
}

func (p *PublicIP) setDefaults() {
const defaultPeriod = 12 * time.Hour
p.Period = helpers.DefaultDuration(p.Period, defaultPeriod)
p.Period = helpers.DefaultDurationPtr(p.Period, defaultPeriod)
p.IPFilepath = helpers.DefaultStringPtr(p.IPFilepath, "/tmp/gluetun/ip")
}

Expand Down
6 changes: 3 additions & 3 deletions internal/configuration/settings/updater.go
Expand Up @@ -73,7 +73,7 @@ func (u *Updater) copy() (copied Updater) {
// mergeWith merges the other settings into any
// unset field of the receiver settings object.
func (u *Updater) mergeWith(other Updater) {
u.Period = helpers.MergeWithDuration(u.Period, other.Period)
u.Period = helpers.MergeWithDurationPtr(u.Period, other.Period)
u.DNSAddress = helpers.MergeWithString(u.DNSAddress, other.DNSAddress)
u.MinRatio = helpers.MergeWithFloat64(u.MinRatio, other.MinRatio)
u.Providers = helpers.MergeStringSlices(u.Providers, other.Providers)
Expand All @@ -83,14 +83,14 @@ func (u *Updater) mergeWith(other Updater) {
// settings object with any field set in the other
// settings.
func (u *Updater) overrideWith(other Updater) {
u.Period = helpers.OverrideWithDuration(u.Period, other.Period)
u.Period = helpers.OverrideWithDurationPtr(u.Period, other.Period)
u.DNSAddress = helpers.OverrideWithString(u.DNSAddress, other.DNSAddress)
u.MinRatio = helpers.OverrideWithFloat64(u.MinRatio, other.MinRatio)
u.Providers = helpers.OverrideWithStringSlice(u.Providers, other.Providers)
}

func (u *Updater) SetDefaults(vpnProvider string) {
u.Period = helpers.DefaultDuration(u.Period, 0)
u.Period = helpers.DefaultDurationPtr(u.Period, 0)
u.DNSAddress = helpers.DefaultString(u.DNSAddress, "1.1.1.1:53")

if u.MinRatio == 0 {
Expand Down
6 changes: 4 additions & 2 deletions internal/healthcheck/run.go
Expand Up @@ -14,8 +14,10 @@ func (s *Server) Run(ctx context.Context, done chan<- struct{}) {
go s.runHealthcheckLoop(ctx, loopDone)

server := http.Server{
Addr: s.config.ServerAddress,
Handler: s.handler,
Addr: s.config.ServerAddress,
Handler: s.handler,
ReadHeaderTimeout: s.config.ReadHeaderTimeout,
ReadTimeout: s.config.ReadTimeout,
}
serverDone := make(chan struct{})
go func() {
Expand Down
2 changes: 1 addition & 1 deletion internal/httpproxy/run.go
Expand Up @@ -23,7 +23,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
settings := l.state.GetSettings()
server := New(runCtx, settings.ListeningAddress, l.logger,
*settings.Stealth, *settings.Log, *settings.User,
*settings.Password)
*settings.Password, settings.ReadHeaderTimeout, settings.ReadTimeout)

errorCh := make(chan error)
go server.Run(runCtx, errorCh)
Expand Down
30 changes: 20 additions & 10 deletions internal/httpproxy/server.go
Expand Up @@ -8,25 +8,35 @@ import (
)

type Server struct {
address string
handler http.Handler
logger infoErrorer
internalWG *sync.WaitGroup
address string
handler http.Handler
logger infoErrorer
internalWG *sync.WaitGroup
readHeaderTimeout time.Duration
readTimeout time.Duration
}

func New(ctx context.Context, address string, logger Logger,
stealth, verbose bool, username, password string) *Server {
stealth, verbose bool, username, password string,
readHeaderTimeout, readTimeout time.Duration) *Server {
wg := &sync.WaitGroup{}
return &Server{
address: address,
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
logger: logger,
internalWG: wg,
address: address,
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
logger: logger,
internalWG: wg,
readHeaderTimeout: readHeaderTimeout,
readTimeout: readTimeout,
}
}

func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
server := http.Server{Addr: s.address, Handler: s.handler}
server := http.Server{
Addr: s.address,
Handler: s.handler,
ReadHeaderTimeout: s.readHeaderTimeout,
ReadTimeout: s.readTimeout,
}
go func() {
<-ctx.Done()
const shutdownGraceDuration = 2 * time.Second
Expand Down
3 changes: 0 additions & 3 deletions internal/httpserver/helpers_test.go
Expand Up @@ -2,13 +2,10 @@ package httpserver

import (
"regexp"
"time"

gomock "github.com/golang/mock/gomock"
)

func durationPtr(d time.Duration) *time.Duration { return &d }

var _ Logger = (*testLogger)(nil)

type testLogger struct{}
Expand Down

0 comments on commit 87db081

Please sign in to comment.