Compare commits
3 Commits
master
...
ivp6-level
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be935e70e6 | ||
|
|
5ca13021e7 | ||
|
|
dae44051f6 |
@@ -159,6 +159,8 @@ ENV VPN_SERVICE_PROVIDER=pia \
|
|||||||
FIREWALL_INPUT_PORTS= \
|
FIREWALL_INPUT_PORTS= \
|
||||||
FIREWALL_OUTBOUND_SUBNETS= \
|
FIREWALL_OUTBOUND_SUBNETS= \
|
||||||
FIREWALL_DEBUG=off \
|
FIREWALL_DEBUG=off \
|
||||||
|
# IPv6
|
||||||
|
IPV6_CHECK_ADDRESS=[2606:4700::6810:84e5]:443 \
|
||||||
# Logging
|
# Logging
|
||||||
LOG_LEVEL=info \
|
LOG_LEVEL=info \
|
||||||
# Health
|
# Health
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -242,10 +243,13 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ipv6Supported, err := netLinker.IsIPv6Supported()
|
ipv6SupportLevel, err := netLinker.FindIPv6SupportLevel(ctx,
|
||||||
|
allSettings.IPv6.CheckAddress, firewallConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("checking for IPv6 support: %w", err)
|
return fmt.Errorf("checking for IPv6 support: %w", err)
|
||||||
}
|
}
|
||||||
|
ipv6Supported := ipv6SupportLevel == netlink.IPv6Supported ||
|
||||||
|
ipv6SupportLevel == netlink.IPv6Internet
|
||||||
|
|
||||||
err = allSettings.Validate(storage, ipv6Supported, logger)
|
err = allSettings.Validate(storage, ipv6Supported, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -430,7 +434,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
httpClient, unzipper, parallelResolver, publicIPLooper.Fetcher(), openvpnFileExtractor)
|
httpClient, unzipper, parallelResolver, publicIPLooper.Fetcher(), openvpnFileExtractor)
|
||||||
|
|
||||||
vpnLogger := logger.New(log.SetComponent("vpn"))
|
vpnLogger := logger.New(log.SetComponent("vpn"))
|
||||||
vpnLooper := vpn.NewLoop(allSettings.VPN, ipv6Supported, allSettings.Firewall.VPNInputPorts,
|
vpnLooper := vpn.NewLoop(allSettings.VPN, ipv6SupportLevel, allSettings.Firewall.VPNInputPorts,
|
||||||
providers, storage, allSettings.Health, healthChecker, healthcheckServer, ovpnConf, netLinker, firewallConf,
|
providers, storage, allSettings.Health, healthChecker, healthcheckServer, ovpnConf, netLinker, firewallConf,
|
||||||
routingConf, portForwardLooper, cmder, publicIPLooper, dnsLooper, vpnLogger, httpClient,
|
routingConf, portForwardLooper, cmder, publicIPLooper, dnsLooper, vpnLogger, httpClient,
|
||||||
buildInfo, *allSettings.Version.Enabled)
|
buildInfo, *allSettings.Version.Enabled)
|
||||||
@@ -474,7 +478,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
logger.New(log.SetComponent("http server")),
|
logger.New(log.SetComponent("http server")),
|
||||||
allSettings.ControlServer.AuthFilePath,
|
allSettings.ControlServer.AuthFilePath,
|
||||||
buildInfo, vpnLooper, portForwardLooper, dnsLooper, updaterLooper, publicIPLooper,
|
buildInfo, vpnLooper, portForwardLooper, dnsLooper, updaterLooper, publicIPLooper,
|
||||||
storage, ipv6Supported)
|
storage, ipv6SupportLevel.IsSupported())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("setting up control server: %w", err)
|
return fmt.Errorf("setting up control server: %w", err)
|
||||||
}
|
}
|
||||||
@@ -550,7 +554,9 @@ type netLinker interface {
|
|||||||
Ruler
|
Ruler
|
||||||
Linker
|
Linker
|
||||||
IsWireguardSupported() (ok bool, err error)
|
IsWireguardSupported() (ok bool, err error)
|
||||||
IsIPv6Supported() (ok bool, err error)
|
FindIPv6SupportLevel(ctx context.Context,
|
||||||
|
checkAddress netip.AddrPort, firewall netlink.Firewall,
|
||||||
|
) (level netlink.IPv6SupportLevel, err error)
|
||||||
PatchLoggerLevel(level log.Level)
|
PatchLoggerLevel(level log.Level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
internal/cli/noopfirewall.go
Normal file
14
internal/cli/noopfirewall.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
type noopFirewall struct{}
|
||||||
|
|
||||||
|
func (f *noopFirewall) AcceptOutput(_ context.Context, _, _ string, _ netip.Addr,
|
||||||
|
_ uint16, _ bool,
|
||||||
|
) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||||
"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/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn/extract"
|
"github.com/qdm12/gluetun/internal/openvpn/extract"
|
||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
@@ -40,7 +41,9 @@ type IPFetcher interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type IPv6Checker interface {
|
type IPv6Checker interface {
|
||||||
IsIPv6Supported() (supported bool, err error)
|
FindIPv6SupportLevel(ctx context.Context,
|
||||||
|
checkAddress netip.AddrPort, firewall netlink.Firewall,
|
||||||
|
) (level netlink.IPv6SupportLevel, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, reader *reader.Reader,
|
func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, reader *reader.Reader,
|
||||||
@@ -58,12 +61,14 @@ func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, reader *reader.Reader,
|
|||||||
}
|
}
|
||||||
allSettings.SetDefaults()
|
allSettings.SetDefaults()
|
||||||
|
|
||||||
ipv6Supported, err := ipv6Checker.IsIPv6Supported()
|
ipv6SupportLevel, err := ipv6Checker.FindIPv6SupportLevel(context.Background(),
|
||||||
|
allSettings.IPv6.CheckAddress, &noopFirewall{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("checking for IPv6 support: %w", err)
|
return fmt.Errorf("checking for IPv6 support: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = allSettings.Validate(storage, ipv6Supported, logger); err != nil {
|
err = allSettings.Validate(storage, ipv6SupportLevel.IsSupported(), logger)
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("validating settings: %w", err)
|
return fmt.Errorf("validating settings: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,13 +84,13 @@ func (c *CLI) OpenvpnConfig(logger OpenvpnConfigLogger, reader *reader.Reader,
|
|||||||
unzipper, parallelResolver, ipFetcher, openvpnFileExtractor)
|
unzipper, parallelResolver, ipFetcher, openvpnFileExtractor)
|
||||||
providerConf := providers.Get(allSettings.VPN.Provider.Name)
|
providerConf := providers.Get(allSettings.VPN.Provider.Name)
|
||||||
connection, err := providerConf.GetConnection(
|
connection, err := providerConf.GetConnection(
|
||||||
allSettings.VPN.Provider.ServerSelection, ipv6Supported)
|
allSettings.VPN.Provider.ServerSelection, ipv6SupportLevel == netlink.IPv6Internet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := providerConf.OpenVPNConfig(connection,
|
lines := providerConf.OpenVPNConfig(connection,
|
||||||
allSettings.VPN.OpenVPN, ipv6Supported)
|
allSettings.VPN.OpenVPN, ipv6SupportLevel.IsSupported())
|
||||||
|
|
||||||
fmt.Println(strings.Join(lines, "\n"))
|
fmt.Println(strings.Join(lines, "\n"))
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
51
internal/configuration/settings/ipv6.go
Normal file
51
internal/configuration/settings/ipv6.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/qdm12/gosettings"
|
||||||
|
"github.com/qdm12/gosettings/reader"
|
||||||
|
"github.com/qdm12/gotree"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPv6 contains settings regarding IPv6 configuration.
|
||||||
|
type IPv6 struct {
|
||||||
|
// CheckAddress is the TCP ip:port address to dial to check
|
||||||
|
// IPv6 is supported, in case a default IPv6 route is found.
|
||||||
|
// It defaults to cloudflare.com address [2606:4700::6810:84e5]:443
|
||||||
|
CheckAddress netip.AddrPort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IPv6) validate() (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPv6) copy() (copied IPv6) {
|
||||||
|
return IPv6{
|
||||||
|
CheckAddress: i.CheckAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPv6) overrideWith(other IPv6) {
|
||||||
|
i.CheckAddress = gosettings.OverrideWithValidator(i.CheckAddress, other.CheckAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPv6) setDefaults() {
|
||||||
|
defaultCheckAddress := netip.MustParseAddrPort("[2606:4700::6810:84e5]:443")
|
||||||
|
i.CheckAddress = gosettings.DefaultComparable(i.CheckAddress, defaultCheckAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IPv6) String() string {
|
||||||
|
return i.toLinesNode().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i IPv6) toLinesNode() (node *gotree.Node) {
|
||||||
|
node = gotree.New("IPv6 settings:")
|
||||||
|
node.Appendf("Check address: %s", i.CheckAddress)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPv6) read(r *reader.Reader) (err error) {
|
||||||
|
i.CheckAddress, err = r.NetipAddrPort("IPV6_CHECK_ADDRESS")
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ type Settings struct {
|
|||||||
Updater Updater
|
Updater Updater
|
||||||
Version Version
|
Version Version
|
||||||
VPN VPN
|
VPN VPN
|
||||||
|
IPv6 IPv6
|
||||||
Pprof pprof.Settings
|
Pprof pprof.Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ func (s *Settings) Validate(filterChoicesGetter FilterChoicesGetter, ipv6Support
|
|||||||
"system": s.System.validate,
|
"system": s.System.validate,
|
||||||
"updater": s.Updater.Validate,
|
"updater": s.Updater.Validate,
|
||||||
"version": s.Version.validate,
|
"version": s.Version.validate,
|
||||||
|
"ipv6": s.IPv6.validate,
|
||||||
// Pprof validation done in pprof constructor
|
// Pprof validation done in pprof constructor
|
||||||
"VPN": func() error {
|
"VPN": func() error {
|
||||||
return s.VPN.Validate(filterChoicesGetter, ipv6Supported, warner)
|
return s.VPN.Validate(filterChoicesGetter, ipv6Supported, warner)
|
||||||
@@ -85,6 +87,7 @@ func (s *Settings) copy() (copied Settings) {
|
|||||||
Version: s.Version.copy(),
|
Version: s.Version.copy(),
|
||||||
VPN: s.VPN.Copy(),
|
VPN: s.VPN.Copy(),
|
||||||
Pprof: s.Pprof.Copy(),
|
Pprof: s.Pprof.Copy(),
|
||||||
|
IPv6: s.IPv6.copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +109,7 @@ func (s *Settings) OverrideWith(other Settings,
|
|||||||
patchedSettings.Version.overrideWith(other.Version)
|
patchedSettings.Version.overrideWith(other.Version)
|
||||||
patchedSettings.VPN.OverrideWith(other.VPN)
|
patchedSettings.VPN.OverrideWith(other.VPN)
|
||||||
patchedSettings.Pprof.OverrideWith(other.Pprof)
|
patchedSettings.Pprof.OverrideWith(other.Pprof)
|
||||||
|
patchedSettings.IPv6.overrideWith(other.IPv6)
|
||||||
err = patchedSettings.Validate(filterChoicesGetter, ipv6Supported, warner)
|
err = patchedSettings.Validate(filterChoicesGetter, ipv6Supported, warner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -121,6 +125,7 @@ func (s *Settings) SetDefaults() {
|
|||||||
s.Health.SetDefaults()
|
s.Health.SetDefaults()
|
||||||
s.HTTPProxy.setDefaults()
|
s.HTTPProxy.setDefaults()
|
||||||
s.Log.setDefaults()
|
s.Log.setDefaults()
|
||||||
|
s.IPv6.setDefaults()
|
||||||
s.PublicIP.setDefaults()
|
s.PublicIP.setDefaults()
|
||||||
s.Shadowsocks.setDefaults()
|
s.Shadowsocks.setDefaults()
|
||||||
s.Storage.setDefaults()
|
s.Storage.setDefaults()
|
||||||
@@ -142,6 +147,7 @@ func (s Settings) toLinesNode() (node *gotree.Node) {
|
|||||||
node.AppendNode(s.DNS.toLinesNode())
|
node.AppendNode(s.DNS.toLinesNode())
|
||||||
node.AppendNode(s.Firewall.toLinesNode())
|
node.AppendNode(s.Firewall.toLinesNode())
|
||||||
node.AppendNode(s.Log.toLinesNode())
|
node.AppendNode(s.Log.toLinesNode())
|
||||||
|
node.AppendNode(s.IPv6.toLinesNode())
|
||||||
node.AppendNode(s.Health.toLinesNode())
|
node.AppendNode(s.Health.toLinesNode())
|
||||||
node.AppendNode(s.Shadowsocks.toLinesNode())
|
node.AppendNode(s.Shadowsocks.toLinesNode())
|
||||||
node.AppendNode(s.HTTPProxy.toLinesNode())
|
node.AppendNode(s.HTTPProxy.toLinesNode())
|
||||||
@@ -208,6 +214,7 @@ func (s *Settings) Read(r *reader.Reader, warner Warner) (err error) {
|
|||||||
"updater": s.Updater.read,
|
"updater": s.Updater.read,
|
||||||
"version": s.Version.read,
|
"version": s.Version.read,
|
||||||
"VPN": s.VPN.read,
|
"VPN": s.VPN.read,
|
||||||
|
"IPv6": s.IPv6.read,
|
||||||
"profiling": s.Pprof.Read,
|
"profiling": s.Pprof.Read,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ func Test_Settings_String(t *testing.T) {
|
|||||||
| └── Enabled: yes
|
| └── Enabled: yes
|
||||||
├── Log settings:
|
├── Log settings:
|
||||||
| └── Log level: INFO
|
| └── Log level: INFO
|
||||||
|
├── IPv6 settings:
|
||||||
|
| └── Check address: [2606:4700::6810:84e5]:443
|
||||||
├── Health settings:
|
├── Health settings:
|
||||||
| ├── Server listening address: 127.0.0.1:9999
|
| ├── Server listening address: 127.0.0.1:9999
|
||||||
| ├── Target address: cloudflare.com:443
|
| ├── Target address: cloudflare.com:443
|
||||||
|
|||||||
@@ -162,6 +162,24 @@ func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
|
|||||||
return c.runIP6tablesInstruction(ctx, instruction)
|
return c.runIP6tablesInstruction(ctx, instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) AcceptOutput(ctx context.Context,
|
||||||
|
protocol, intf string, ip netip.Addr, port uint16, remove bool,
|
||||||
|
) error {
|
||||||
|
interfaceFlag := "-o " + intf
|
||||||
|
if intf == "*" { // all interfaces
|
||||||
|
interfaceFlag = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction := fmt.Sprintf("%s OUTPUT -d %s %s -p %s -m %s --dport %d -j ACCEPT",
|
||||||
|
appendOrDelete(remove), ip, interfaceFlag, protocol, protocol, port)
|
||||||
|
if ip.Is4() {
|
||||||
|
return c.runIptablesInstruction(ctx, instruction)
|
||||||
|
} else if c.ip6Tables == "" {
|
||||||
|
return fmt.Errorf("accept output to VPN server: %w", ErrNeedIP6Tables)
|
||||||
|
}
|
||||||
|
return c.runIP6tablesInstruction(ctx, instruction)
|
||||||
|
}
|
||||||
|
|
||||||
// Thanks to @npawelek.
|
// Thanks to @npawelek.
|
||||||
func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context,
|
func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context,
|
||||||
intf string, sourceIP netip.Addr, destinationSubnet netip.Prefix, remove bool,
|
intf string, sourceIP netip.Addr, destinationSubnet netip.Prefix, remove bool,
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import "github.com/qdm12/log"
|
import (
|
||||||
|
"context"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/qdm12/log"
|
||||||
|
)
|
||||||
|
|
||||||
type DebugLogger interface {
|
type DebugLogger interface {
|
||||||
Debug(message string)
|
Debug(message string)
|
||||||
Debugf(format string, args ...any)
|
Debugf(format string, args ...any)
|
||||||
Patch(options ...log.Option)
|
Patch(options ...log.Option)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Firewall interface {
|
||||||
|
AcceptOutput(ctx context.Context, protocol, intf string, ip netip.Addr,
|
||||||
|
port uint16, remove bool) (err error)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,37 +1,106 @@
|
|||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *NetLink) IsIPv6Supported() (supported bool, err error) {
|
type IPv6SupportLevel uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
IPv6Unsupported = iota
|
||||||
|
// IPv6Supported indicates the host supports IPv6 but has no access to the
|
||||||
|
// Internet via IPv6. It is true if one IPv6 route is found and no default
|
||||||
|
// IPv6 route is found.
|
||||||
|
IPv6Supported
|
||||||
|
// IPv6Internet indicates the host has access to the Internet via IPv6,
|
||||||
|
// which is detected when a default IPv6 route is found.
|
||||||
|
IPv6Internet
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i IPv6SupportLevel) IsSupported() bool {
|
||||||
|
return i == IPv6Supported || i == IPv6Internet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) FindIPv6SupportLevel(ctx context.Context,
|
||||||
|
checkAddress netip.AddrPort, firewall Firewall,
|
||||||
|
) (level IPv6SupportLevel, err error) {
|
||||||
routes, err := n.RouteList(FamilyV6)
|
routes, err := n.RouteList(FamilyV6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("listing IPv6 routes: %w", err)
|
return IPv6Unsupported, fmt.Errorf("listing IPv6 routes: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each route for IPv6 due to Podman bug listing IPv4 routes
|
// Check each route for IPv6 due to Podman bug listing IPv4 routes
|
||||||
// as IPv6 routes at container start, see:
|
// as IPv6 routes at container start, see:
|
||||||
// https://github.com/qdm12/gluetun/issues/1241#issuecomment-1333405949
|
// https://github.com/qdm12/gluetun/issues/1241#issuecomment-1333405949
|
||||||
|
level = IPv6Unsupported
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
link, err := n.LinkByIndex(route.LinkIndex)
|
link, err := n.LinkByIndex(route.LinkIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("finding link corresponding to route: %w", err)
|
return IPv6Unsupported, fmt.Errorf("finding link corresponding to route: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceIsIPv6 := route.Src.IsValid() && route.Src.Is6()
|
sourceIsIPv4 := route.Src.IsValid() && route.Src.Is4()
|
||||||
|
destinationIsIPv4 := route.Dst.IsValid() && route.Dst.Addr().Is4()
|
||||||
destinationIsIPv6 := route.Dst.IsValid() && route.Dst.Addr().Is6()
|
destinationIsIPv6 := route.Dst.IsValid() && route.Dst.Addr().Is6()
|
||||||
switch {
|
switch {
|
||||||
case !sourceIsIPv6 && !destinationIsIPv6,
|
case sourceIsIPv4 && destinationIsIPv4,
|
||||||
destinationIsIPv6 && route.Dst.Addr().IsLoopback():
|
destinationIsIPv6 && route.Dst.Addr().IsLoopback():
|
||||||
continue
|
case route.Dst.Addr().IsUnspecified(): // default ipv6 route
|
||||||
|
n.debugLogger.Debugf("IPv6 default route found on link %s", link.Name)
|
||||||
|
err = dialAddrThroughFirewall(ctx, link.Name, checkAddress, firewall)
|
||||||
|
if err != nil {
|
||||||
|
n.debugLogger.Debugf("IPv6 query failed on %s: %w", link.Name, err)
|
||||||
|
level = IPv6Supported
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n.debugLogger.Debugf("IPv6 internet is accessible through link %s", link.Name)
|
||||||
|
return IPv6Internet, nil
|
||||||
|
default: // non-default ipv6 route found
|
||||||
|
n.debugLogger.Debugf("IPv6 is supported by link %s", link.Name)
|
||||||
|
level = IPv6Supported
|
||||||
}
|
}
|
||||||
|
|
||||||
n.debugLogger.Debugf("IPv6 is supported by link %s", link.Name)
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n.debugLogger.Debugf("IPv6 is not supported after searching %d routes",
|
if level == IPv6Unsupported {
|
||||||
len(routes))
|
n.debugLogger.Debugf("no IPv6 route found in %d routes", len(routes))
|
||||||
return false, nil
|
}
|
||||||
|
return level, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialAddrThroughFirewall(ctx context.Context, intf string,
|
||||||
|
checkAddress netip.AddrPort, firewall Firewall,
|
||||||
|
) (err error) {
|
||||||
|
const protocol = "tcp"
|
||||||
|
remove := false
|
||||||
|
err = firewall.AcceptOutput(ctx, protocol, intf,
|
||||||
|
checkAddress.Addr(), checkAddress.Port(), remove)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("accepting output traffic: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
remove = true
|
||||||
|
firewallErr := firewall.AcceptOutput(ctx, protocol, intf,
|
||||||
|
checkAddress.Addr(), checkAddress.Port(), remove)
|
||||||
|
if err == nil && firewallErr != nil {
|
||||||
|
err = fmt.Errorf("removing output traffic rule: %w", firewallErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
dialer := &net.Dialer{
|
||||||
|
Timeout: time.Second,
|
||||||
|
}
|
||||||
|
conn, err := dialer.DialContext(ctx, protocol, checkAddress.String())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("dialing: %w", err)
|
||||||
|
}
|
||||||
|
err = conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("closing connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
167
internal/netlink/ipv6_test.go
Normal file
167
internal/netlink/ipv6_test.go
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isIPv6LocallySupported() bool {
|
||||||
|
dialer := net.Dialer{Timeout: time.Millisecond}
|
||||||
|
_, err := dialer.Dial("tcp6", "[::1]:9999")
|
||||||
|
return !strings.HasSuffix(err.Error(), "connect: cannot assign requested address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Susceptible to TOCTOU but it should be fine for the use case.
|
||||||
|
func findAvailableTCPPort(t *testing.T) (port uint16) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
config := &net.ListenConfig{}
|
||||||
|
listener, err := config.Listen(context.Background(), "tcp", "localhost:0")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
addr := listener.Addr().String()
|
||||||
|
err = listener.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
addrPort, err := netip.ParseAddrPort(addr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return addrPort.Port()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_dialAddrThroughFirewall(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
errTest := errors.New("test error")
|
||||||
|
|
||||||
|
const ipv6InternetWorks = false
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
getIPv6CheckAddr func(t *testing.T) netip.AddrPort
|
||||||
|
firewallAddErr error
|
||||||
|
firewallRemoveErr error
|
||||||
|
errMessageRegex func() string
|
||||||
|
}{
|
||||||
|
"cloudflare.com": {
|
||||||
|
getIPv6CheckAddr: func(_ *testing.T) netip.AddrPort {
|
||||||
|
return netip.MustParseAddrPort("[2606:4700::6810:84e5]:443")
|
||||||
|
},
|
||||||
|
errMessageRegex: func() string {
|
||||||
|
if ipv6InternetWorks {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "dialing: dial tcp \\[2606:4700::6810:84e5\\]:443: " +
|
||||||
|
"connect: (cannot assign requested address|network is unreachable)"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"local_server": {
|
||||||
|
getIPv6CheckAddr: func(t *testing.T) netip.AddrPort {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
network := "tcp6"
|
||||||
|
loopback := netip.MustParseAddr("::1")
|
||||||
|
if !isIPv6LocallySupported() {
|
||||||
|
network = "tcp4"
|
||||||
|
loopback = netip.MustParseAddr("127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := net.ListenTCP(network, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := listener.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
addrPort := netip.MustParseAddrPort(listener.Addr().String())
|
||||||
|
return netip.AddrPortFrom(loopback, addrPort.Port())
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"no_local_server": {
|
||||||
|
getIPv6CheckAddr: func(t *testing.T) netip.AddrPort {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
loopback := netip.MustParseAddr("::1")
|
||||||
|
if !ipv6InternetWorks {
|
||||||
|
loopback = netip.MustParseAddr("127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
availablePort := findAvailableTCPPort(t)
|
||||||
|
return netip.AddrPortFrom(loopback, availablePort)
|
||||||
|
},
|
||||||
|
errMessageRegex: func() string {
|
||||||
|
return "dialing: dial tcp (\\[::1\\]|127\\.0\\.0\\.1):[1-9][0-9]{1,4}: " +
|
||||||
|
"connect: connection refused"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"firewall_add_error": {
|
||||||
|
firewallAddErr: errTest,
|
||||||
|
errMessageRegex: func() string {
|
||||||
|
return "accepting output traffic: test error"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"firewall_remove_error": {
|
||||||
|
getIPv6CheckAddr: func(t *testing.T) netip.AddrPort {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
network := "tcp4"
|
||||||
|
loopback := netip.MustParseAddr("127.0.0.1")
|
||||||
|
listener, err := net.ListenTCP(network, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := listener.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
addrPort := netip.MustParseAddrPort(listener.Addr().String())
|
||||||
|
return netip.AddrPortFrom(loopback, addrPort.Port())
|
||||||
|
},
|
||||||
|
firewallRemoveErr: errTest,
|
||||||
|
errMessageRegex: func() string {
|
||||||
|
return "removing output traffic rule: test error"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
|
var checkAddr netip.AddrPort
|
||||||
|
if testCase.getIPv6CheckAddr != nil {
|
||||||
|
checkAddr = testCase.getIPv6CheckAddr(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
const intf = "eth0"
|
||||||
|
firewall := NewMockFirewall(ctrl)
|
||||||
|
call := firewall.EXPECT().AcceptOutput(ctx, "tcp", intf,
|
||||||
|
checkAddr.Addr(), checkAddr.Port(), false).
|
||||||
|
Return(testCase.firewallAddErr)
|
||||||
|
if testCase.firewallAddErr == nil {
|
||||||
|
firewall.EXPECT().AcceptOutput(ctx, "tcp", intf,
|
||||||
|
checkAddr.Addr(), checkAddr.Port(), true).
|
||||||
|
Return(testCase.firewallRemoveErr).After(call)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dialAddrThroughFirewall(ctx, intf, checkAddr, firewall)
|
||||||
|
var errMessageRegex string
|
||||||
|
if testCase.errMessageRegex != nil {
|
||||||
|
errMessageRegex = testCase.errMessageRegex()
|
||||||
|
}
|
||||||
|
if errMessageRegex == "" {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Regexp(t, errMessageRegex, err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
3
internal/netlink/mocks_generate_test.go
Normal file
3
internal/netlink/mocks_generate_test.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=mocks_test.go -package=$GOPACKAGE . Firewall
|
||||||
50
internal/netlink/mocks_test.go
Normal file
50
internal/netlink/mocks_test.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: github.com/qdm12/gluetun/internal/netlink (interfaces: Firewall)
|
||||||
|
|
||||||
|
// Package netlink is a generated GoMock package.
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
netip "net/netip"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockFirewall is a mock of Firewall interface.
|
||||||
|
type MockFirewall struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockFirewallMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockFirewallMockRecorder is the mock recorder for MockFirewall.
|
||||||
|
type MockFirewallMockRecorder struct {
|
||||||
|
mock *MockFirewall
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockFirewall creates a new mock instance.
|
||||||
|
func NewMockFirewall(ctrl *gomock.Controller) *MockFirewall {
|
||||||
|
mock := &MockFirewall{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockFirewallMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockFirewall) EXPECT() *MockFirewallMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptOutput mocks base method.
|
||||||
|
func (m *MockFirewall) AcceptOutput(arg0 context.Context, arg1, arg2 string, arg3 netip.Addr, arg4 uint16, arg5 bool) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AcceptOutput", arg0, arg1, arg2, arg3, arg4, arg5)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptOutput indicates an expected call of AcceptOutput.
|
||||||
|
func (mr *MockFirewallMockRecorder) AcceptOutput(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptOutput", reflect.TypeOf((*MockFirewall)(nil).AcceptOutput), arg0, arg1, arg2, arg3, arg4, arg5)
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/loopstate"
|
"github.com/qdm12/gluetun/internal/loopstate"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/vpn/state"
|
"github.com/qdm12/gluetun/internal/vpn/state"
|
||||||
"github.com/qdm12/log"
|
"github.com/qdm12/log"
|
||||||
)
|
)
|
||||||
@@ -21,10 +22,10 @@ type Loop struct {
|
|||||||
healthChecker HealthChecker
|
healthChecker HealthChecker
|
||||||
healthServer HealthServer
|
healthServer HealthServer
|
||||||
// Fixed parameters
|
// Fixed parameters
|
||||||
buildInfo models.BuildInformation
|
buildInfo models.BuildInformation
|
||||||
versionInfo bool
|
versionInfo bool
|
||||||
ipv6Supported bool
|
ipv6SupportLevel netlink.IPv6SupportLevel
|
||||||
vpnInputPorts []uint16 // TODO make changeable through stateful firewall
|
vpnInputPorts []uint16 // TODO make changeable through stateful firewall
|
||||||
// Configurators
|
// Configurators
|
||||||
openvpnConf OpenVPN
|
openvpnConf OpenVPN
|
||||||
netLinker NetLinker
|
netLinker NetLinker
|
||||||
@@ -51,7 +52,7 @@ const (
|
|||||||
defaultBackoffTime = 15 * time.Second
|
defaultBackoffTime = 15 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLoop(vpnSettings settings.VPN, ipv6Supported bool, vpnInputPorts []uint16,
|
func NewLoop(vpnSettings settings.VPN, ipv6SupportLevel netlink.IPv6SupportLevel, vpnInputPorts []uint16,
|
||||||
providers Providers, storage Storage, healthSettings settings.Health,
|
providers Providers, storage Storage, healthSettings settings.Health,
|
||||||
healthChecker HealthChecker, healthServer HealthServer, openvpnConf OpenVPN,
|
healthChecker HealthChecker, healthServer HealthServer, openvpnConf OpenVPN,
|
||||||
netLinker NetLinker, fw Firewall, routing Routing,
|
netLinker NetLinker, fw Firewall, routing Routing,
|
||||||
@@ -69,32 +70,32 @@ func NewLoop(vpnSettings settings.VPN, ipv6Supported bool, vpnInputPorts []uint1
|
|||||||
state := state.New(statusManager, vpnSettings)
|
state := state.New(statusManager, vpnSettings)
|
||||||
|
|
||||||
return &Loop{
|
return &Loop{
|
||||||
statusManager: statusManager,
|
statusManager: statusManager,
|
||||||
state: state,
|
state: state,
|
||||||
providers: providers,
|
providers: providers,
|
||||||
storage: storage,
|
storage: storage,
|
||||||
healthSettings: healthSettings,
|
healthSettings: healthSettings,
|
||||||
healthChecker: healthChecker,
|
healthChecker: healthChecker,
|
||||||
healthServer: healthServer,
|
healthServer: healthServer,
|
||||||
buildInfo: buildInfo,
|
buildInfo: buildInfo,
|
||||||
versionInfo: versionInfo,
|
versionInfo: versionInfo,
|
||||||
ipv6Supported: ipv6Supported,
|
ipv6SupportLevel: ipv6SupportLevel,
|
||||||
vpnInputPorts: vpnInputPorts,
|
vpnInputPorts: vpnInputPorts,
|
||||||
openvpnConf: openvpnConf,
|
openvpnConf: openvpnConf,
|
||||||
netLinker: netLinker,
|
netLinker: netLinker,
|
||||||
fw: fw,
|
fw: fw,
|
||||||
routing: routing,
|
routing: routing,
|
||||||
portForward: portForward,
|
portForward: portForward,
|
||||||
publicip: publicip,
|
publicip: publicip,
|
||||||
dnsLooper: dnsLooper,
|
dnsLooper: dnsLooper,
|
||||||
starter: starter,
|
starter: starter,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
client: client,
|
client: client,
|
||||||
start: start,
|
start: start,
|
||||||
running: running,
|
running: running,
|
||||||
stop: stop,
|
stop: stop,
|
||||||
stopped: stopped,
|
stopped: stopped,
|
||||||
userTrigger: true,
|
userTrigger: true,
|
||||||
backoffTime: defaultBackoffTime,
|
backoffTime: defaultBackoffTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/openvpn"
|
||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
)
|
)
|
||||||
@@ -14,15 +15,16 @@ import (
|
|||||||
// It returns a serverName for port forwarding (PIA) and an error if it fails.
|
// It returns a serverName for port forwarding (PIA) and an error if it fails.
|
||||||
func setupOpenVPN(ctx context.Context, fw Firewall,
|
func setupOpenVPN(ctx context.Context, fw Firewall,
|
||||||
openvpnConf OpenVPN, providerConf provider.Provider,
|
openvpnConf OpenVPN, providerConf provider.Provider,
|
||||||
settings settings.VPN, ipv6Supported bool, starter CmdStarter,
|
settings settings.VPN, ipv6SupportLevel netlink.IPv6SupportLevel, starter CmdStarter,
|
||||||
logger openvpn.Logger) (runner *openvpn.Runner, connection models.Connection, err error,
|
logger openvpn.Logger) (runner *openvpn.Runner, connection models.Connection, err error,
|
||||||
) {
|
) {
|
||||||
connection, err = providerConf.GetConnection(settings.Provider.ServerSelection, ipv6Supported)
|
ipv6Internet := ipv6SupportLevel == netlink.IPv6Internet
|
||||||
|
connection, err = providerConf.GetConnection(settings.Provider.ServerSelection, ipv6Internet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, models.Connection{}, fmt.Errorf("finding a valid server connection: %w", err)
|
return nil, models.Connection{}, fmt.Errorf("finding a valid server connection: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := providerConf.OpenVPNConfig(connection, settings.OpenVPN, ipv6Supported)
|
lines := providerConf.OpenVPNConfig(connection, settings.OpenVPN, ipv6SupportLevel.IsSupported())
|
||||||
|
|
||||||
if err := openvpnConf.WriteConfig(lines); err != nil {
|
if err := openvpnConf.WriteConfig(lines); err != nil {
|
||||||
return nil, models.Connection{}, fmt.Errorf("writing configuration to file: %w", err)
|
return nil, models.Connection{}, fmt.Errorf("writing configuration to file: %w", err)
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
|
|||||||
if settings.Type == vpn.OpenVPN {
|
if settings.Type == vpn.OpenVPN {
|
||||||
vpnInterface = settings.OpenVPN.Interface
|
vpnInterface = settings.OpenVPN.Interface
|
||||||
vpnRunner, connection, err = setupOpenVPN(ctx, l.fw,
|
vpnRunner, connection, err = setupOpenVPN(ctx, l.fw,
|
||||||
l.openvpnConf, providerConf, settings, l.ipv6Supported, l.starter, subLogger)
|
l.openvpnConf, providerConf, settings, l.ipv6SupportLevel, l.starter, subLogger)
|
||||||
} else { // Wireguard
|
} else { // Wireguard
|
||||||
vpnInterface = settings.Wireguard.Interface
|
vpnInterface = settings.Wireguard.Interface
|
||||||
vpnRunner, connection, err = setupWireguard(ctx, l.netLinker, l.fw,
|
vpnRunner, connection, err = setupWireguard(ctx, l.netLinker, l.fw,
|
||||||
providerConf, settings, l.ipv6Supported, subLogger)
|
providerConf, settings, l.ipv6SupportLevel, subLogger)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.crashed(ctx, err)
|
l.crashed(ctx, err)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration/settings"
|
"github.com/qdm12/gluetun/internal/configuration/settings"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/provider"
|
"github.com/qdm12/gluetun/internal/provider"
|
||||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||||
"github.com/qdm12/gluetun/internal/wireguard"
|
"github.com/qdm12/gluetun/internal/wireguard"
|
||||||
@@ -16,15 +17,16 @@ import (
|
|||||||
// It returns a serverName for port forwarding (PIA) and an error if it fails.
|
// It returns a serverName for port forwarding (PIA) and an error if it fails.
|
||||||
func setupWireguard(ctx context.Context, netlinker NetLinker,
|
func setupWireguard(ctx context.Context, netlinker NetLinker,
|
||||||
fw Firewall, providerConf provider.Provider,
|
fw Firewall, providerConf provider.Provider,
|
||||||
settings settings.VPN, ipv6Supported bool, logger wireguard.Logger) (
|
settings settings.VPN, ipv6SupportLevel netlink.IPv6SupportLevel, logger wireguard.Logger) (
|
||||||
wireguarder *wireguard.Wireguard, connection models.Connection, err error,
|
wireguarder *wireguard.Wireguard, connection models.Connection, err error,
|
||||||
) {
|
) {
|
||||||
connection, err = providerConf.GetConnection(settings.Provider.ServerSelection, ipv6Supported)
|
ipv6Internet := ipv6SupportLevel == netlink.IPv6Internet
|
||||||
|
connection, err = providerConf.GetConnection(settings.Provider.ServerSelection, ipv6Internet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, models.Connection{}, fmt.Errorf("finding a VPN server: %w", err)
|
return nil, models.Connection{}, fmt.Errorf("finding a VPN server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wireguardSettings := utils.BuildWireguardSettings(connection, settings.Wireguard, ipv6Supported)
|
wireguardSettings := utils.BuildWireguardSettings(connection, settings.Wireguard, ipv6SupportLevel.IsSupported())
|
||||||
|
|
||||||
logger.Debug("Wireguard server public key: " + wireguardSettings.PublicKey)
|
logger.Debug("Wireguard server public key: " + wireguardSettings.PublicKey)
|
||||||
logger.Debug("Wireguard client private key: " + gosettings.ObfuscateKey(wireguardSettings.PrivateKey))
|
logger.Debug("Wireguard client private key: " + gosettings.ObfuscateKey(wireguardSettings.PrivateKey))
|
||||||
|
|||||||
Reference in New Issue
Block a user