chore(all): replace net.IP with netip.Addr

This commit is contained in:
Quentin McGaw
2023-05-20 19:58:18 +00:00
parent 00ee6ff9a7
commit 0a29337c3b
91 changed files with 525 additions and 590 deletions

View File

@@ -3,8 +3,8 @@ package cli
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
"strings" "strings"
"time" "time"
@@ -28,11 +28,11 @@ type Unzipper interface {
type ParallelResolver interface { type ParallelResolver interface {
Resolve(ctx context.Context, settings resolver.ParallelSettings) ( Resolve(ctx context.Context, settings resolver.ParallelSettings) (
hostToIPs map[string][]net.IP, warnings []string, err error) hostToIPs map[string][]netip.Addr, warnings []string, err error)
} }
type IPFetcher interface { type IPFetcher interface {
FetchMultiInfo(ctx context.Context, ips []net.IP) (data []ipinfo.Response, err error) FetchMultiInfo(ctx context.Context, ips []netip.Addr) (data []ipinfo.Response, err error)
} }
type IPv6Checker interface { type IPv6Checker interface {

View File

@@ -2,7 +2,7 @@ package settings
import ( import (
"fmt" "fmt"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings/helpers" "github.com/qdm12/gluetun/internal/configuration/settings/helpers"
"github.com/qdm12/gotree" "github.com/qdm12/gotree"
@@ -13,9 +13,9 @@ type DNS struct {
// ServerAddress is the DNS server to use inside // ServerAddress is the DNS server to use inside
// the Go program and for the system. // the Go program and for the system.
// It defaults to '127.0.0.1' to be used with the // It defaults to '127.0.0.1' to be used with the
// DoT server. It cannot be nil in the internal // DoT server. It cannot be the zero value in the internal
// state. // state.
ServerAddress net.IP ServerAddress netip.Addr
// KeepNameserver is true if the Docker DNS server // KeepNameserver is true if the Docker DNS server
// found in /etc/resolv.conf should be kept. // found in /etc/resolv.conf should be kept.
// Note settings this to true will go around the // Note settings this to true will go around the
@@ -39,7 +39,7 @@ func (d DNS) validate() (err error) {
func (d *DNS) Copy() (copied DNS) { func (d *DNS) Copy() (copied DNS) {
return DNS{ return DNS{
ServerAddress: helpers.CopyIP(d.ServerAddress), ServerAddress: d.ServerAddress,
KeepNameserver: helpers.CopyBoolPtr(d.KeepNameserver), KeepNameserver: helpers.CopyBoolPtr(d.KeepNameserver),
DoT: d.DoT.copy(), DoT: d.DoT.copy(),
} }
@@ -63,7 +63,7 @@ func (d *DNS) overrideWith(other DNS) {
} }
func (d *DNS) setDefaults() { func (d *DNS) setDefaults() {
localhost := net.IPv4(127, 0, 0, 1) //nolint:gomnd localhost := netip.AddrFrom4([4]byte{127, 0, 0, 1})
d.ServerAddress = helpers.DefaultIP(d.ServerAddress, localhost) d.ServerAddress = helpers.DefaultIP(d.ServerAddress, localhost)
d.KeepNameserver = helpers.DefaultBool(d.KeepNameserver, false) d.KeepNameserver = helpers.DefaultBool(d.KeepNameserver, false)
d.DoT.setDefaults() d.DoT.setDefaults()

View File

@@ -1,8 +1,6 @@
package helpers package helpers
import ( import (
"fmt"
"net"
"net/netip" "net/netip"
"time" "time"
@@ -81,25 +79,6 @@ func CopyLogLevelPtr(original *log.Level) (copied *log.Level) {
return copied return copied
} }
func CopyIP(original net.IP) (copied net.IP) {
if original == nil {
return nil
}
copied = make(net.IP, len(original))
copy(copied, original)
return copied
}
func CopyNetipAddress(original netip.Addr) (copied netip.Addr) {
// AsSlice creates a new byte slice so no need to copy the bytes.
bytes := original.AsSlice()
copied, ok := netip.AddrFromSlice(bytes)
if !ok {
panic(fmt.Sprintf("cannot deep copy address with bytes %#v", bytes))
}
return copied
}
func CopyStringSlice(original []string) (copied []string) { func CopyStringSlice(original []string) (copied []string) {
if original == nil { if original == nil {
return nil return nil
@@ -136,9 +115,6 @@ func CopyNetipAddressesSlice(original []netip.Addr) (copied []netip.Addr) {
} }
copied = make([]netip.Addr, len(original)) copied = make([]netip.Addr, len(original))
for i := range original { copy(copied, original)
copied[i] = CopyNetipAddress(original[i])
}
return copied return copied
} }

View File

@@ -1,7 +1,7 @@
package helpers package helpers
import ( import (
"net" "net/netip"
"time" "time"
"github.com/qdm12/log" "github.com/qdm12/log"
@@ -101,9 +101,9 @@ func DefaultLogLevel(existing *log.Level,
return result return result
} }
func DefaultIP(existing net.IP, defaultValue net.IP) ( func DefaultIP(existing netip.Addr, defaultValue netip.Addr) (
result net.IP) { result netip.Addr) {
if existing != nil { if existing.IsValid() {
return existing return existing
} }
return defaultValue return defaultValue

View File

@@ -1,7 +1,7 @@
package helpers package helpers
import ( import (
"net" "fmt"
"net/http" "net/http"
"net/netip" "net/netip"
"time" "time"
@@ -96,14 +96,17 @@ func MergeWithUint32(existing, other *uint32) (result *uint32) {
return result return result
} }
func MergeWithIP(existing, other net.IP) (result net.IP) { func MergeWithIP(existing, other netip.Addr) (result netip.Addr) {
if existing != nil { if existing.IsValid() {
return existing
} else if !other.IsValid() {
return existing return existing
} else if other == nil {
return nil
} }
result = make(net.IP, len(other))
copy(result, other) result, ok := netip.AddrFromSlice(other.AsSlice())
if !ok {
panic(fmt.Sprintf("failed copying other address: %s", other))
}
return result return result
} }

View File

@@ -1,7 +1,7 @@
package helpers package helpers
import ( import (
"net" "fmt"
"net/http" "net/http"
"net/netip" "net/netip"
"time" "time"
@@ -84,12 +84,14 @@ func OverrideWithUint32(existing, other *uint32) (result *uint32) {
return result return result
} }
func OverrideWithIP(existing, other net.IP) (result net.IP) { func OverrideWithIP(existing, other netip.Addr) (result netip.Addr) {
if other == nil { if !other.IsValid() {
return existing return existing
} }
result = make(net.IP, len(other)) result, ok := netip.AddrFromSlice(other.AsSlice())
copy(result, other) if !ok {
panic(fmt.Sprintf("failed copying other address: %s", other))
}
return result return result
} }

View File

@@ -3,7 +3,7 @@ package settings
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"strings" "strings"
"github.com/qdm12/gluetun/internal/configuration/settings/helpers" "github.com/qdm12/gluetun/internal/configuration/settings/helpers"
@@ -21,10 +21,10 @@ type ServerSelection struct { //nolint:maligned
VPN string VPN string
// TargetIP is the server endpoint IP address to use. // TargetIP is the server endpoint IP address to use.
// It will override any IP address from the picked // It will override any IP address from the picked
// built-in server. It cannot be nil in the internal // built-in server. It cannot be the empty value in the internal
// state, and can be set to an empty net.IP{} to indicate // state, and can be set to the unspecified address to indicate
// there is not target IP address to use. // there is not target IP address to use.
TargetIP net.IP TargetIP netip.Addr
// Counties is the list of countries to filter VPN servers with. // Counties is the list of countries to filter VPN servers with.
Countries []string Countries []string
// Regions is the list of regions to filter VPN servers with. // Regions is the list of regions to filter VPN servers with.
@@ -202,7 +202,7 @@ func validateServerFilters(settings ServerSelection, filterChoices models.Filter
func (ss *ServerSelection) copy() (copied ServerSelection) { func (ss *ServerSelection) copy() (copied ServerSelection) {
return ServerSelection{ return ServerSelection{
VPN: ss.VPN, VPN: ss.VPN,
TargetIP: helpers.CopyIP(ss.TargetIP), TargetIP: ss.TargetIP,
Countries: helpers.CopyStringSlice(ss.Countries), Countries: helpers.CopyStringSlice(ss.Countries),
Regions: helpers.CopyStringSlice(ss.Regions), Regions: helpers.CopyStringSlice(ss.Regions),
Cities: helpers.CopyStringSlice(ss.Cities), Cities: helpers.CopyStringSlice(ss.Cities),
@@ -261,7 +261,7 @@ func (ss *ServerSelection) overrideWith(other ServerSelection) {
func (ss *ServerSelection) setDefaults(vpnProvider string) { func (ss *ServerSelection) setDefaults(vpnProvider string) {
ss.VPN = helpers.DefaultString(ss.VPN, vpn.OpenVPN) ss.VPN = helpers.DefaultString(ss.VPN, vpn.OpenVPN)
ss.TargetIP = helpers.DefaultIP(ss.TargetIP, net.IP{}) ss.TargetIP = helpers.DefaultIP(ss.TargetIP, netip.IPv4Unspecified())
ss.OwnedOnly = helpers.DefaultBool(ss.OwnedOnly, false) ss.OwnedOnly = helpers.DefaultBool(ss.OwnedOnly, false)
ss.FreeOnly = helpers.DefaultBool(ss.FreeOnly, false) ss.FreeOnly = helpers.DefaultBool(ss.FreeOnly, false)
ss.PremiumOnly = helpers.DefaultBool(ss.PremiumOnly, false) ss.PremiumOnly = helpers.DefaultBool(ss.PremiumOnly, false)
@@ -278,7 +278,7 @@ func (ss ServerSelection) String() string {
func (ss ServerSelection) toLinesNode() (node *gotree.Node) { func (ss ServerSelection) toLinesNode() (node *gotree.Node) {
node = gotree.New("Server selection settings:") node = gotree.New("Server selection settings:")
node.Appendf("VPN type: %s", ss.VPN) node.Appendf("VPN type: %s", ss.VPN)
if len(ss.TargetIP) > 0 { if !ss.TargetIP.IsUnspecified() {
node.Appendf("Target IP address: %s", ss.TargetIP) node.Appendf("Target IP address: %s", ss.TargetIP)
} }

View File

@@ -3,7 +3,6 @@ package settings
import ( import (
"errors" "errors"
"fmt" "fmt"
"net"
"net/netip" "net/netip"
"github.com/qdm12/dns/pkg/provider" "github.com/qdm12/dns/pkg/provider"
@@ -155,14 +154,24 @@ func (u Unbound) ToUnboundFormat() (settings unbound.Settings, err error) {
}, nil }, nil
} }
func (u Unbound) GetFirstPlaintextIPv4() (ipv4 net.IP, err error) { var (
ErrConvertingNetip = errors.New("converting net.IP to netip.Addr failed")
)
func (u Unbound) GetFirstPlaintextIPv4() (ipv4 netip.Addr, err error) {
s := u.Providers[0] s := u.Providers[0]
provider, err := provider.Parse(s) provider, err := provider.Parse(s)
if err != nil { if err != nil {
return nil, err return ipv4, err
} }
return provider.DNS().IPv4[0], nil ip := provider.DNS().IPv4[0]
ipv4, ok := netip.AddrFromSlice(ip)
if !ok {
return ipv4, fmt.Errorf("%w: for ip %s (%#v)",
ErrConvertingNetip, ip, ip)
}
return ipv4.Unmap(), nil
} }
func (u Unbound) String() string { func (u Unbound) String() string {

View File

@@ -2,7 +2,7 @@ package settings
import ( import (
"fmt" "fmt"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings/helpers" "github.com/qdm12/gluetun/internal/configuration/settings/helpers"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -15,9 +15,9 @@ type WireguardSelection struct {
// It is only used with VPN providers generating Wireguard // It is only used with VPN providers generating Wireguard
// configurations specific to each server and user. // configurations specific to each server and user.
// To indicate it should not be used, it should be set // To indicate it should not be used, it should be set
// to the empty net.IP{} slice. It can never be nil // to netaddr.IPv4Unspecified(). It can never be the zero value
// in the internal state. // in the internal state.
EndpointIP net.IP EndpointIP netip.Addr
// EndpointPort is a the server port to use for the VPN server. // EndpointPort is a the server port to use for the VPN server.
// It is optional for VPN providers IVPN, Mullvad, Surfshark // It is optional for VPN providers IVPN, Mullvad, Surfshark
// and Windscribe, and compulsory for the others. // and Windscribe, and compulsory for the others.
@@ -40,7 +40,7 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
providers.Surfshark, providers.Windscribe: providers.Surfshark, providers.Windscribe:
// endpoint IP addresses are baked in // endpoint IP addresses are baked in
case providers.Custom: case providers.Custom:
if len(w.EndpointIP) == 0 { if !w.EndpointIP.IsValid() || w.EndpointIP.IsUnspecified() {
return fmt.Errorf("%w", ErrWireguardEndpointIPNotSet) return fmt.Errorf("%w", ErrWireguardEndpointIPNotSet)
} }
default: // Providers not supporting Wireguard default: // Providers not supporting Wireguard
@@ -109,7 +109,7 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
func (w *WireguardSelection) copy() (copied WireguardSelection) { func (w *WireguardSelection) copy() (copied WireguardSelection) {
return WireguardSelection{ return WireguardSelection{
EndpointIP: helpers.CopyIP(w.EndpointIP), EndpointIP: w.EndpointIP,
EndpointPort: helpers.CopyUint16Ptr(w.EndpointPort), EndpointPort: helpers.CopyUint16Ptr(w.EndpointPort),
PublicKey: w.PublicKey, PublicKey: w.PublicKey,
} }
@@ -128,7 +128,7 @@ func (w *WireguardSelection) overrideWith(other WireguardSelection) {
} }
func (w *WireguardSelection) setDefaults() { func (w *WireguardSelection) setDefaults() {
w.EndpointIP = helpers.DefaultIP(w.EndpointIP, net.IP{}) w.EndpointIP = helpers.DefaultIP(w.EndpointIP, netip.IPv4Unspecified())
w.EndpointPort = helpers.DefaultUint16(w.EndpointPort, 0) w.EndpointPort = helpers.DefaultUint16(w.EndpointPort, 0)
} }
@@ -139,7 +139,7 @@ func (w WireguardSelection) String() string {
func (w WireguardSelection) toLinesNode() (node *gotree.Node) { func (w WireguardSelection) toLinesNode() (node *gotree.Node) {
node = gotree.New("Wireguard selection settings:") node = gotree.New("Wireguard selection settings:")
if len(w.EndpointIP) > 0 { if !w.EndpointIP.IsUnspecified() {
node.Appendf("Endpoint IP address: %s", w.EndpointIP) node.Appendf("Endpoint IP address: %s", w.EndpointIP)
} }

View File

@@ -2,7 +2,7 @@ package env
import ( import (
"fmt" "fmt"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
) )
@@ -26,19 +26,19 @@ func (s *Source) readDNS() (dns settings.DNS, err error) {
return dns, nil return dns, nil
} }
func (s *Source) readDNSServerAddress() (address net.IP, err error) { func (s *Source) readDNSServerAddress() (address netip.Addr, err error) {
key, value := s.getEnvWithRetro("DNS_ADDRESS", "DNS_PLAINTEXT_ADDRESS") key, value := s.getEnvWithRetro("DNS_ADDRESS", "DNS_PLAINTEXT_ADDRESS")
if value == "" { if value == "" {
return nil, nil return address, nil
} }
address = net.ParseIP(value) address, err = netip.ParseAddr(value)
if address == nil { if err != nil {
return nil, fmt.Errorf("environment variable %s: %w: %s", key, ErrIPAddressParse, value) return address, fmt.Errorf("environment variable %s: %w", key, err)
} }
// TODO remove in v4 // TODO remove in v4
if !address.Equal(net.IPv4(127, 0, 0, 1)) { //nolint:gomnd if address.Unmap().Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) != 0 {
s.warner.Warn(key + " is set to " + value + s.warner.Warn(key + " is set to " + value +
" so the DNS over TLS (DoT) server will not be used." + " so the DNS over TLS (DoT) server will not be used." +
" The default value changed to 127.0.0.1 so it uses the internal DoT serves." + " The default value changed to 127.0.0.1 so it uses the internal DoT serves." +

View File

@@ -3,7 +3,7 @@ package env
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"strconv" "strconv"
"strings" "strings"
@@ -113,16 +113,15 @@ var (
ErrInvalidIP = errors.New("invalid IP address") ErrInvalidIP = errors.New("invalid IP address")
) )
func (s *Source) readOpenVPNTargetIP() (ip net.IP, err error) { func (s *Source) readOpenVPNTargetIP() (ip netip.Addr, err error) {
envKey, value := s.getEnvWithRetro("VPN_ENDPOINT_IP", "OPENVPN_TARGET_IP") envKey, value := s.getEnvWithRetro("VPN_ENDPOINT_IP", "OPENVPN_TARGET_IP")
if value == "" { if value == "" {
return nil, nil return ip, nil
} }
ip = net.ParseIP(value) ip, err = netip.ParseAddr(value)
if ip == nil { if err != nil {
return nil, fmt.Errorf("environment variable %s: %w: %s", return ip, fmt.Errorf("environment variable %s: %w", envKey, err)
envKey, ErrInvalidIP, value)
} }
return ip, nil return ip, nil

View File

@@ -1,9 +1,8 @@
package env package env
import ( import (
"errors"
"fmt" "fmt"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/govalid/port" "github.com/qdm12/govalid/port"
@@ -26,18 +25,15 @@ func (s *Source) readWireguardSelection() (
return selection, nil return selection, nil
} }
var ErrIPAddressParse = errors.New("cannot parse IP address") func (s *Source) readWireguardEndpointIP() (endpointIP netip.Addr, err error) {
func (s *Source) readWireguardEndpointIP() (endpointIP net.IP, err error) {
key, value := s.getEnvWithRetro("VPN_ENDPOINT_IP", "WIREGUARD_ENDPOINT_IP") key, value := s.getEnvWithRetro("VPN_ENDPOINT_IP", "WIREGUARD_ENDPOINT_IP")
if value == "" { if value == "" {
return nil, nil return endpointIP, nil
} }
endpointIP = net.ParseIP(value) endpointIP, err = netip.ParseAddr(value)
if endpointIP == nil { if err != nil {
return nil, fmt.Errorf("environment variable %s: %w: %s", return endpointIP, fmt.Errorf("environment variable %s: %w", key, err)
key, ErrIPAddressParse, value)
} }
return endpointIP, nil return endpointIP, nil

View File

@@ -1,7 +1,7 @@
package dns package dns
import ( import (
"net" "net/netip"
"github.com/qdm12/dns/pkg/nameserver" "github.com/qdm12/dns/pkg/nameserver"
) )
@@ -12,14 +12,14 @@ func (l *Loop) useUnencryptedDNS(fallback bool) {
// Try with user provided plaintext ip address // Try with user provided plaintext ip address
// if it's not 127.0.0.1 (default for DoT) // if it's not 127.0.0.1 (default for DoT)
targetIP := settings.ServerAddress targetIP := settings.ServerAddress
if targetIP != nil && !targetIP.Equal(net.IPv4(127, 0, 0, 1)) { //nolint:gomnd if targetIP.Compare(netip.AddrFrom4([4]byte{127, 0, 0, 1})) != 0 {
if fallback { if fallback {
l.logger.Info("falling back on plaintext DNS at address " + targetIP.String()) l.logger.Info("falling back on plaintext DNS at address " + targetIP.String())
} else { } else {
l.logger.Info("using plaintext DNS at address " + targetIP.String()) l.logger.Info("using plaintext DNS at address " + targetIP.String())
} }
nameserver.UseDNSInternally(targetIP) nameserver.UseDNSInternally(targetIP.AsSlice())
err := nameserver.UseDNSSystemWide(l.resolvConf, targetIP, *settings.KeepNameserver) err := nameserver.UseDNSSystemWide(l.resolvConf, targetIP.AsSlice(), *settings.KeepNameserver)
if err != nil { if err != nil {
l.logger.Error(err.Error()) l.logger.Error(err.Error())
} }
@@ -38,8 +38,8 @@ func (l *Loop) useUnencryptedDNS(fallback bool) {
} else { } else {
l.logger.Info("using plaintext DNS at address " + targetIP.String()) l.logger.Info("using plaintext DNS at address " + targetIP.String())
} }
nameserver.UseDNSInternally(targetIP) nameserver.UseDNSInternally(targetIP.AsSlice())
err = nameserver.UseDNSSystemWide(l.resolvConf, targetIP, *settings.KeepNameserver) err = nameserver.UseDNSSystemWide(l.resolvConf, targetIP.AsSlice(), *settings.KeepNameserver)
if err != nil { if err != nil {
l.logger.Error(err.Error()) l.logger.Error(err.Error())
} }

View File

@@ -43,8 +43,8 @@ func (l *Loop) setupUnbound(ctx context.Context) (
} }
// use Unbound // use Unbound
nameserver.UseDNSInternally(settings.ServerAddress) nameserver.UseDNSInternally(settings.ServerAddress.AsSlice())
err = nameserver.UseDNSSystemWide(l.resolvConf, settings.ServerAddress, err = nameserver.UseDNSSystemWide(l.resolvConf, settings.ServerAddress.AsSlice(),
*settings.KeepNameserver) *settings.KeepNameserver)
if err != nil { if err != nil {
l.logger.Error(err.Error()) l.logger.Error(err.Error())

View File

@@ -130,7 +130,7 @@ func (c *Config) enable(ctx context.Context) (err error) {
} }
func (c *Config) allowVPNIP(ctx context.Context) (err error) { func (c *Config) allowVPNIP(ctx context.Context) (err error) {
if c.vpnConnection.IP == nil { if !c.vpnConnection.IP.IsValid() {
return nil return nil
} }

View File

@@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net"
"net/netip" "net/netip"
"os" "os"
"os/exec" "os/exec"
@@ -146,8 +145,7 @@ func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT", instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol, appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol,
connection.Protocol, connection.Port) connection.Protocol, connection.Port)
isIPv4 := connection.IP.To4() != nil if connection.IP.Is4() {
if isIPv4 {
return c.runIptablesInstruction(ctx, instruction) return c.runIptablesInstruction(ctx, instruction)
} else if c.ip6Tables == "" { } else if c.ip6Tables == "" {
return fmt.Errorf("accept output to VPN server: %w", ErrNeedIP6Tables) return fmt.Errorf("accept output to VPN server: %w", ErrNeedIP6Tables)
@@ -157,8 +155,8 @@ func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
// Thanks to @npawelek. // Thanks to @npawelek.
func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context, func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context,
intf string, sourceIP net.IP, destinationSubnet netip.Prefix, remove bool) error { intf string, sourceIP netip.Addr, destinationSubnet netip.Prefix, remove bool) error {
doIPv4 := sourceIP.To4() != nil && destinationSubnet.Addr().Is4() doIPv4 := sourceIP.Is4() && destinationSubnet.Addr().Is4()
interfaceFlag := "-o " + intf interfaceFlag := "-o " + intf
if intf == "*" { // all interfaces if intf == "*" { // all interfaces

View File

@@ -25,7 +25,7 @@ func (c *Config) SetVPNConnection(ctx context.Context,
} }
remove := true remove := true
if c.vpnConnection.IP != nil { if c.vpnConnection.IP.IsValid() {
for _, defaultRoute := range c.defaultRoutes { for _, defaultRoute := range c.defaultRoutes {
if err := c.acceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove); err != nil { if err := c.acceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove); err != nil {
c.logger.Error("cannot remove outdated VPN connection rule: " + err.Error()) c.logger.Error("cannot remove outdated VPN connection rule: " + err.Error())

View File

@@ -1,14 +1,14 @@
package models package models
import ( import (
"net" "net/netip"
) )
type Connection struct { type Connection struct {
// Type is the connection type and can be "openvpn" or "wireguard" // Type is the connection type and can be "openvpn" or "wireguard"
Type string `json:"type"` Type string `json:"type"`
// IP is the VPN server IP address. // IP is the VPN server IP address.
IP net.IP `json:"ip"` IP netip.Addr `json:"ip"`
// Port is the VPN server port. // Port is the VPN server port.
Port uint16 `json:"port"` Port uint16 `json:"port"`
// Protocol can be "tcp" or "udp". // Protocol can be "tcp" or "udp".
@@ -24,15 +24,15 @@ type Connection struct {
} }
func (c *Connection) Equal(other Connection) bool { func (c *Connection) Equal(other Connection) bool {
return c.IP.Equal(other.IP) && c.Port == other.Port && return c.IP.Compare(other.IP) == 0 && c.Port == other.Port &&
c.Protocol == other.Protocol && c.Hostname == other.Hostname && c.Protocol == other.Protocol && c.Hostname == other.Hostname &&
c.ServerName == other.ServerName && c.PubKey == other.PubKey c.ServerName == other.ServerName && c.PubKey == other.PubKey
} }
// UpdateEmptyWith updates each field of the connection where the // UpdateEmptyWith updates each field of the connection where the
// value is not set using the value given as arguments. // value is not set using the value given as arguments.
func (c *Connection) UpdateEmptyWith(ip net.IP, port uint16, protocol string) { func (c *Connection) UpdateEmptyWith(ip netip.Addr, port uint16, protocol string) {
if c.IP == nil { if !c.IP.IsValid() {
c.IP = ip c.IP = ip
} }
if c.Port == 0 { if c.Port == 0 {

View File

@@ -1,22 +1,24 @@
package models package models
import "net" import (
"net/netip"
)
type PublicIP struct { type PublicIP struct {
IP net.IP `json:"public_ip,omitempty"` IP netip.Addr `json:"public_ip,omitempty"`
Region string `json:"region,omitempty"` Region string `json:"region,omitempty"`
Country string `json:"country,omitempty"` Country string `json:"country,omitempty"`
City string `json:"city,omitempty"` City string `json:"city,omitempty"`
Hostname string `json:"hostname,omitempty"` Hostname string `json:"hostname,omitempty"`
Location string `json:"location,omitempty"` Location string `json:"location,omitempty"`
Organization string `json:"organization,omitempty"` Organization string `json:"organization,omitempty"`
PostalCode string `json:"postal_code,omitempty"` PostalCode string `json:"postal_code,omitempty"`
Timezone string `json:"timezone,omitempty"` Timezone string `json:"timezone,omitempty"`
} }
func (p *PublicIP) Copy() (publicIPCopy PublicIP) { func (p *PublicIP) Copy() (publicIPCopy PublicIP) {
publicIPCopy = PublicIP{ publicIPCopy = PublicIP{
IP: make(net.IP, len(p.IP)), IP: p.IP,
Region: p.Region, Region: p.Region,
Country: p.Country, Country: p.Country,
City: p.City, City: p.City,
@@ -26,6 +28,5 @@ func (p *PublicIP) Copy() (publicIPCopy PublicIP) {
PostalCode: p.PostalCode, PostalCode: p.PostalCode,
Timezone: p.Timezone, Timezone: p.Timezone,
} }
copy(publicIPCopy.IP, p.IP)
return publicIPCopy return publicIPCopy
} }

View File

@@ -3,7 +3,7 @@ package models
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"reflect" "reflect"
"strings" "strings"
@@ -13,26 +13,26 @@ import (
type Server struct { type Server struct {
VPN string `json:"vpn,omitempty"` VPN string `json:"vpn,omitempty"`
// Surfshark: country is also used for multi-hop // Surfshark: country is also used for multi-hop
Country string `json:"country,omitempty"` Country string `json:"country,omitempty"`
Region string `json:"region,omitempty"` Region string `json:"region,omitempty"`
City string `json:"city,omitempty"` City string `json:"city,omitempty"`
ISP string `json:"isp,omitempty"` ISP string `json:"isp,omitempty"`
Owned bool `json:"owned,omitempty"` Owned bool `json:"owned,omitempty"`
Number uint16 `json:"number,omitempty"` Number uint16 `json:"number,omitempty"`
ServerName string `json:"server_name,omitempty"` ServerName string `json:"server_name,omitempty"`
Hostname string `json:"hostname,omitempty"` Hostname string `json:"hostname,omitempty"`
TCP bool `json:"tcp,omitempty"` TCP bool `json:"tcp,omitempty"`
UDP bool `json:"udp,omitempty"` UDP bool `json:"udp,omitempty"`
OvpnX509 string `json:"x509,omitempty"` OvpnX509 string `json:"x509,omitempty"`
RetroLoc string `json:"retroloc,omitempty"` // TODO remove in v4 RetroLoc string `json:"retroloc,omitempty"` // TODO remove in v4
MultiHop bool `json:"multihop,omitempty"` MultiHop bool `json:"multihop,omitempty"`
WgPubKey string `json:"wgpubkey,omitempty"` WgPubKey string `json:"wgpubkey,omitempty"`
Free bool `json:"free,omitempty"` Free bool `json:"free,omitempty"`
Stream bool `json:"stream,omitempty"` Stream bool `json:"stream,omitempty"`
Premium bool `json:"premium,omitempty"` Premium bool `json:"premium,omitempty"`
PortForward bool `json:"port_forward,omitempty"` PortForward bool `json:"port_forward,omitempty"`
Keep bool `json:"keep,omitempty"` Keep bool `json:"keep,omitempty"`
IPs []net.IP `json:"ips,omitempty"` IPs []netip.Addr `json:"ips,omitempty"`
} }
var ( var (
@@ -72,13 +72,13 @@ func (s *Server) Equal(other Server) (equal bool) {
return reflect.DeepEqual(serverCopy, other) return reflect.DeepEqual(serverCopy, other)
} }
func ipsAreEqual(a, b []net.IP) (equal bool) { func ipsAreEqual(a, b []netip.Addr) (equal bool) {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }
for i := range a { for i := range a {
if !a[i].Equal(b[i]) { if a[i].Compare(b[i]) != 0 {
return false return false
} }
} }

View File

@@ -1,7 +1,7 @@
package models package models
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -17,28 +17,28 @@ func Test_Server_Equal(t *testing.T) {
}{ }{
"same IPs": { "same IPs": {
a: &Server{ a: &Server{
IPs: []net.IP{net.IPv4(1, 2, 3, 4)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
b: Server{ b: Server{
IPs: []net.IP{net.IPv4(1, 2, 3, 4)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
equal: true, equal: true,
}, },
"same IP strings": { "same IP strings": {
a: &Server{ a: &Server{
IPs: []net.IP{net.IPv4(1, 2, 3, 4)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
b: Server{ b: Server{
IPs: []net.IP{{1, 2, 3, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
equal: true, equal: true,
}, },
"different IPs": { "different IPs": {
a: &Server{ a: &Server{
IPs: []net.IP{{1, 2, 3, 4}, {2, 3, 4, 5}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4}), netip.AddrFrom4([4]byte{2, 3, 4, 5})},
}, },
b: Server{ b: Server{
IPs: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4}), netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
}, },
"all fields equal": { "all fields equal": {
@@ -61,7 +61,7 @@ func Test_Server_Equal(t *testing.T) {
Free: true, Free: true,
Stream: true, Stream: true,
PortForward: true, PortForward: true,
IPs: []net.IP{net.IPv4(1, 2, 3, 4)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
Keep: true, Keep: true,
}, },
b: Server{ b: Server{
@@ -83,7 +83,7 @@ func Test_Server_Equal(t *testing.T) {
Free: true, Free: true,
Stream: true, Stream: true,
PortForward: true, PortForward: true,
IPs: []net.IP{net.IPv4(1, 2, 3, 4)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
Keep: true, Keep: true,
}, },
equal: true, equal: true,

View File

@@ -3,7 +3,7 @@ package extract
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"strconv" "strconv"
"strings" "strings"
@@ -25,12 +25,12 @@ func extractDataFromLines(lines []string) (
connection.UpdateEmptyWith(ip, port, protocol) connection.UpdateEmptyWith(ip, port, protocol)
if connection.Protocol != "" && connection.IP != nil { if connection.Protocol != "" && connection.IP.IsValid() {
break break
} }
} }
if connection.IP == nil { if !connection.IP.IsValid() {
return connection, errRemoteLineNotFound return connection, errRemoteLineNotFound
} }
@@ -49,24 +49,24 @@ func extractDataFromLines(lines []string) (
} }
func extractDataFromLine(line string) ( func extractDataFromLine(line string) (
ip net.IP, port uint16, protocol string, err error) { ip netip.Addr, port uint16, protocol string, err error) {
switch { switch {
case strings.HasPrefix(line, "proto "): case strings.HasPrefix(line, "proto "):
protocol, err = extractProto(line) protocol, err = extractProto(line)
if err != nil { if err != nil {
return nil, 0, "", fmt.Errorf("extracting protocol from proto line: %w", err) return ip, 0, "", fmt.Errorf("extracting protocol from proto line: %w", err)
} }
return nil, 0, protocol, nil return ip, 0, protocol, nil
case strings.HasPrefix(line, "remote "): case strings.HasPrefix(line, "remote "):
ip, port, protocol, err = extractRemote(line) ip, port, protocol, err = extractRemote(line)
if err != nil { if err != nil {
return nil, 0, "", fmt.Errorf("extracting from remote line: %w", err) return ip, 0, "", fmt.Errorf("extracting from remote line: %w", err)
} }
return ip, port, protocol, nil return ip, port, protocol, nil
} }
return nil, 0, "", nil return ip, 0, "", nil
} }
var ( var (
@@ -95,19 +95,19 @@ var (
errPortNotValid = errors.New("port is not valid") errPortNotValid = errors.New("port is not valid")
) )
func extractRemote(line string) (ip net.IP, port uint16, func extractRemote(line string) (ip netip.Addr, port uint16,
protocol string, err error) { protocol string, err error) {
fields := strings.Fields(line) fields := strings.Fields(line)
n := len(fields) n := len(fields)
if n < 2 || n > 4 { if n < 2 || n > 4 {
return nil, 0, "", fmt.Errorf("%w: %s", errRemoteLineFieldsCount, line) return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errRemoteLineFieldsCount, line)
} }
host := fields[1] host := fields[1]
ip = net.ParseIP(host) ip, err = netip.ParseAddr(host)
if ip == nil { if err != nil {
return nil, 0, "", fmt.Errorf("%w: %s", errHostNotIP, host) return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errHostNotIP, host)
// TODO resolve hostname once there is an option to allow it through // TODO resolve hostname once there is an option to allow it through
// the firewall before the VPN is up. // the firewall before the VPN is up.
} }
@@ -115,9 +115,9 @@ func extractRemote(line string) (ip net.IP, port uint16,
if n > 2 { //nolint:gomnd if n > 2 { //nolint:gomnd
portInt, err := strconv.Atoi(fields[2]) portInt, err := strconv.Atoi(fields[2])
if err != nil { if err != nil {
return nil, 0, "", fmt.Errorf("%w: %s", errPortNotValid, line) return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errPortNotValid, line)
} else if portInt < 1 || portInt > 65535 { } else if portInt < 1 || portInt > 65535 {
return nil, 0, "", fmt.Errorf("%w: %d must be between 1 and 65535", errPortNotValid, portInt) return netip.Addr{}, 0, "", fmt.Errorf("%w: %d must be between 1 and 65535", errPortNotValid, portInt)
} }
port = uint16(portInt) port = uint16(portInt)
} }
@@ -127,7 +127,7 @@ func extractRemote(line string) (ip net.IP, port uint16,
case "tcp", "udp": case "tcp", "udp":
protocol = fields[3] protocol = fields[3]
default: default:
return nil, 0, "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[3]) return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[3])
} }
} }

View File

@@ -2,7 +2,7 @@ package extract
import ( import (
"errors" "errors"
"net" "net/netip"
"testing" "testing"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
@@ -22,7 +22,7 @@ func Test_extractDataFromLines(t *testing.T) {
"success": { "success": {
lines: []string{"bla bla", "proto tcp", "remote 1.2.3.4 1194 tcp", "dev tun6"}, lines: []string{"bla bla", "proto tcp", "remote 1.2.3.4 1194 tcp", "dev tun6"},
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 1194, Port: 1194,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
@@ -34,7 +34,7 @@ func Test_extractDataFromLines(t *testing.T) {
"only use first values found": { "only use first values found": {
lines: []string{"proto udp", "proto tcp", "remote 1.2.3.4 443 tcp", "remote 5.2.3.4 1194 udp"}, lines: []string{"proto udp", "proto tcp", "remote 1.2.3.4 443 tcp", "remote 5.2.3.4 1194 udp"},
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 443, Port: 443,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
@@ -49,7 +49,7 @@ func Test_extractDataFromLines(t *testing.T) {
"default TCP port": { "default TCP port": {
lines: []string{"remote 1.2.3.4", "proto tcp"}, lines: []string{"remote 1.2.3.4", "proto tcp"},
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 443, Port: 443,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
@@ -57,7 +57,7 @@ func Test_extractDataFromLines(t *testing.T) {
"default UDP port": { "default UDP port": {
lines: []string{"remote 1.2.3.4", "proto udp"}, lines: []string{"remote 1.2.3.4", "proto udp"},
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
@@ -88,7 +88,7 @@ func Test_extractDataFromLine(t *testing.T) {
testCases := map[string]struct { testCases := map[string]struct {
line string line string
ip net.IP ip netip.Addr
port uint16 port uint16
protocol string protocol string
isErr error isErr error
@@ -110,7 +110,7 @@ func Test_extractDataFromLine(t *testing.T) {
}, },
"extract remote success": { "extract remote success": {
line: "remote 1.2.3.4 1194 udp", line: "remote 1.2.3.4 1194 udp",
ip: net.IPv4(1, 2, 3, 4), ip: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
port: 1194, port: 1194,
protocol: constants.UDP, protocol: constants.UDP,
}, },
@@ -186,7 +186,7 @@ func Test_extractRemote(t *testing.T) {
testCases := map[string]struct { testCases := map[string]struct {
line string line string
ip net.IP ip netip.Addr
port uint16 port uint16
protocol string protocol string
err error err error
@@ -205,7 +205,7 @@ func Test_extractRemote(t *testing.T) {
}, },
"only IP host": { "only IP host": {
line: "remote 1.2.3.4", line: "remote 1.2.3.4",
ip: net.IPv4(1, 2, 3, 4), ip: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
}, },
"port not an integer": { "port not an integer": {
line: "remote 1.2.3.4 bad", line: "remote 1.2.3.4 bad",
@@ -225,7 +225,7 @@ func Test_extractRemote(t *testing.T) {
}, },
"IP host and port": { "IP host and port": {
line: "remote 1.2.3.4 8000", line: "remote 1.2.3.4 8000",
ip: net.IPv4(1, 2, 3, 4), ip: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
port: 8000, port: 8000,
}, },
"invalid protocol": { "invalid protocol": {
@@ -234,7 +234,7 @@ func Test_extractRemote(t *testing.T) {
}, },
"IP host and port and protocol": { "IP host and port and protocol": {
line: "remote 1.2.3.4 8000 udp", line: "remote 1.2.3.4 8000 udp",
ip: net.IPv4(1, 2, 3, 4), ip: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
port: 8000, port: 8000,
protocol: constants.UDP, protocol: constants.UDP,
}, },

View File

@@ -1,16 +1,16 @@
package state package state
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/provider" "github.com/qdm12/gluetun/internal/provider"
) )
type StartData struct { type StartData struct {
PortForwarder provider.PortForwarder PortForwarder provider.PortForwarder
Gateway net.IP // needed for PIA Gateway netip.Addr // needed for PIA
ServerName string // needed for PIA ServerName string // needed for PIA
Interface string // tun0 for example Interface string // tun0 for example
} }
func (s *State) GetStartData() (startData StartData) { func (s *State) GetStartData() (startData StartData) {

View File

@@ -4,8 +4,8 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
) )
@@ -15,20 +15,20 @@ type apiData struct {
} }
type apiServer struct { type apiServer struct {
PublicName string `json:"public_name"` PublicName string `json:"public_name"`
CountryName string `json:"country_name"` CountryName string `json:"country_name"`
CountryCode string `json:"country_code"` CountryCode string `json:"country_code"`
Location string `json:"location"` Location string `json:"location"`
Continent string `json:"continent"` Continent string `json:"continent"`
IPv4In1 net.IP `json:"ip_v4_in1"` IPv4In1 netip.Addr `json:"ip_v4_in1"`
IPv4In2 net.IP `json:"ip_v4_in2"` IPv4In2 netip.Addr `json:"ip_v4_in2"`
IPv4In3 net.IP `json:"ip_v4_in3"` IPv4In3 netip.Addr `json:"ip_v4_in3"`
IPv4In4 net.IP `json:"ip_v4_in4"` IPv4In4 netip.Addr `json:"ip_v4_in4"`
IPv6In1 net.IP `json:"ip_v6_in1"` IPv6In1 netip.Addr `json:"ip_v6_in1"`
IPv6In2 net.IP `json:"ip_v6_in2"` IPv6In2 netip.Addr `json:"ip_v6_in2"`
IPv6In3 net.IP `json:"ip_v6_in3"` IPv6In3 netip.Addr `json:"ip_v6_in3"`
IPv6In4 net.IP `json:"ip_v6_in4"` IPv6In4 netip.Addr `json:"ip_v6_in4"`
Health string `json:"health"` Health string `json:"health"`
} }
func fetchAPI(ctx context.Context, client *http.Client) ( func fetchAPI(ctx context.Context, client *http.Client) (

View File

@@ -3,7 +3,7 @@ package updater
import ( import (
"context" "context"
"fmt" "fmt"
"net" "net/netip"
"sort" "sort"
"strings" "strings"
@@ -57,12 +57,12 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
baseWireguardServer.WgPubKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=" baseWireguardServer.WgPubKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk="
ipv4WireguadServer := baseWireguardServer ipv4WireguadServer := baseWireguardServer
ipv4WireguadServer.IPs = []net.IP{apiServer.IPv4In1} ipv4WireguadServer.IPs = []netip.Addr{apiServer.IPv4In1}
ipv4WireguadServer.Hostname = apiServer.CountryCode + ".vpn.airdns.org" ipv4WireguadServer.Hostname = apiServer.CountryCode + ".vpn.airdns.org"
servers = append(servers, ipv4WireguadServer) servers = append(servers, ipv4WireguadServer)
ipv6WireguadServer := baseWireguardServer ipv6WireguadServer := baseWireguardServer
ipv6WireguadServer.IPs = []net.IP{apiServer.IPv6In1} ipv6WireguadServer.IPs = []netip.Addr{apiServer.IPv6In1}
ipv6WireguadServer.Hostname = apiServer.CountryCode + ".ipv6.vpn.airdns.org" ipv6WireguadServer.Hostname = apiServer.CountryCode + ".ipv6.vpn.airdns.org"
servers = append(servers, ipv6WireguadServer) servers = append(servers, ipv6WireguadServer)
@@ -74,22 +74,22 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
// Ignore IPs 1 and 2 since tls-crypt is superior to tls-auth really. // Ignore IPs 1 and 2 since tls-crypt is superior to tls-auth really.
ipv4In3OpenVPNServer := baseOpenVPNServer ipv4In3OpenVPNServer := baseOpenVPNServer
ipv4In3OpenVPNServer.IPs = []net.IP{apiServer.IPv4In3} ipv4In3OpenVPNServer.IPs = []netip.Addr{apiServer.IPv4In3}
ipv4In3OpenVPNServer.Hostname = apiServer.CountryCode + "3.vpn.airdns.org" ipv4In3OpenVPNServer.Hostname = apiServer.CountryCode + "3.vpn.airdns.org"
servers = append(servers, ipv4In3OpenVPNServer) servers = append(servers, ipv4In3OpenVPNServer)
ipv6In3OpenVPNServer := baseOpenVPNServer ipv6In3OpenVPNServer := baseOpenVPNServer
ipv6In3OpenVPNServer.IPs = []net.IP{apiServer.IPv6In3} ipv6In3OpenVPNServer.IPs = []netip.Addr{apiServer.IPv6In3}
ipv6In3OpenVPNServer.Hostname = apiServer.CountryCode + "3.ipv6.vpn.airdns.org" ipv6In3OpenVPNServer.Hostname = apiServer.CountryCode + "3.ipv6.vpn.airdns.org"
servers = append(servers, ipv6In3OpenVPNServer) servers = append(servers, ipv6In3OpenVPNServer)
ipv4In4OpenVPNServer := baseOpenVPNServer ipv4In4OpenVPNServer := baseOpenVPNServer
ipv4In4OpenVPNServer.IPs = []net.IP{apiServer.IPv4In4} ipv4In4OpenVPNServer.IPs = []netip.Addr{apiServer.IPv4In4}
ipv4In4OpenVPNServer.Hostname = apiServer.CountryCode + "4.vpn.airdns.org" ipv4In4OpenVPNServer.Hostname = apiServer.CountryCode + "4.vpn.airdns.org"
servers = append(servers, ipv4In4OpenVPNServer) servers = append(servers, ipv4In4OpenVPNServer)
ipv6In4OpenVPNServer := baseOpenVPNServer ipv6In4OpenVPNServer := baseOpenVPNServer
ipv6In4OpenVPNServer.IPs = []net.IP{apiServer.IPv6In4} ipv6In4OpenVPNServer.IPs = []netip.Addr{apiServer.IPv6In4}
ipv6In4OpenVPNServer.Hostname = apiServer.CountryCode + "4.ipv6.vpn.airdns.org" ipv6In4OpenVPNServer.Hostname = apiServer.CountryCode + "4.ipv6.vpn.airdns.org"
servers = append(servers, ipv6In4OpenVPNServer) servers = append(servers, ipv6In4OpenVPNServer)
} }

View File

@@ -6,7 +6,7 @@ package common
import ( import (
context "context" context "context"
net "net" netip "net/netip"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
@@ -39,10 +39,10 @@ func (m *MockParallelResolver) EXPECT() *MockParallelResolverMockRecorder {
} }
// Resolve mocks base method. // Resolve mocks base method.
func (m *MockParallelResolver) Resolve(arg0 context.Context, arg1 resolver.ParallelSettings) (map[string][]net.IP, []string, error) { func (m *MockParallelResolver) Resolve(arg0 context.Context, arg1 resolver.ParallelSettings) (map[string][]netip.Addr, []string, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Resolve", arg0, arg1) ret := m.ctrl.Call(m, "Resolve", arg0, arg1)
ret0, _ := ret[0].(map[string][]net.IP) ret0, _ := ret[0].(map[string][]netip.Addr)
ret1, _ := ret[1].([]string) ret1, _ := ret[1].([]string)
ret2, _ := ret[2].(error) ret2, _ := ret[2].(error)
return ret0, ret1, ret2 return ret0, ret1, ret2

View File

@@ -2,4 +2,5 @@ package common
// Exceptionally, these mocks are exported since they are used by all // Exceptionally, these mocks are exported since they are used by all
// provider subpackages tests, and it reduces test code duplication a lot. // provider subpackages tests, and it reduces test code duplication a lot.
// Note mocks.go might need to be removed before re-generating it.
//go:generate mockgen -destination=mocks.go -package $GOPACKAGE . ParallelResolver,Storage,Unzipper,Warner //go:generate mockgen -destination=mocks.go -package $GOPACKAGE . ParallelResolver,Storage,Unzipper,Warner

View File

@@ -3,7 +3,7 @@ package common
import ( import (
"context" "context"
"errors" "errors"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/publicip/ipinfo" "github.com/qdm12/gluetun/internal/publicip/ipinfo"
@@ -21,7 +21,7 @@ type Fetcher interface {
type ParallelResolver interface { type ParallelResolver interface {
Resolve(ctx context.Context, settings resolver.ParallelSettings) ( Resolve(ctx context.Context, settings resolver.ParallelSettings) (
hostToIPs map[string][]net.IP, warnings []string, err error) hostToIPs map[string][]netip.Addr, warnings []string, err error)
} }
type Unzipper interface { type Unzipper interface {
@@ -34,5 +34,5 @@ type Warner interface {
} }
type IPFetcher interface { type IPFetcher interface {
FetchMultiInfo(ctx context.Context, ips []net.IP) (data []ipinfo.Response, err error) FetchMultiInfo(ctx context.Context, ips []netip.Addr) (data []ipinfo.Response, err error)
} }

View File

@@ -1,7 +1,7 @@
package custom package custom
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
@@ -46,7 +46,7 @@ func Test_modifyConfig(t *testing.T) {
Verbosity: intPtr(0), Verbosity: intPtr(0),
}.WithDefaults(providers.Custom), }.WithDefaults(providers.Custom),
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -47,7 +47,7 @@ func (hts hostToServer) hostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -3,7 +3,7 @@ package expressvpn
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -41,7 +41,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN TCP port": { "default OpenVPN TCP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -52,7 +52,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN UDP port": { "default OpenVPN UDP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -61,14 +61,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1195, Port: 1195,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
}, },
"default Wireguard port": { "default Wireguard port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -33,7 +33,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"sort" "sort"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -38,7 +38,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -134,17 +134,17 @@ func Test_hostToServer_adaptWithIPs(t *testing.T) {
t.Parallel() t.Parallel()
testCases := map[string]struct { testCases := map[string]struct {
initialHTS hostToServer initialHTS hostToServer
hostToIPs map[string][]net.IP hostToIPs map[string][]netip.Addr
expectedHTS hostToServer expectedHTS hostToServer
}{ }{
"create server": { "create server": {
initialHTS: hostToServer{}, initialHTS: hostToServer{},
hostToIPs: map[string][]net.IP{ hostToIPs: map[string][]netip.Addr{
"A": {{1, 2, 3, 4}}, "A": {netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
expectedHTS: hostToServer{ expectedHTS: hostToServer{
"A": models.Server{ "A": models.Server{
IPs: []net.IP{{1, 2, 3, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
}, },
}, },
@@ -154,13 +154,13 @@ func Test_hostToServer_adaptWithIPs(t *testing.T) {
Country: "country", Country: "country",
}, },
}, },
hostToIPs: map[string][]net.IP{ hostToIPs: map[string][]netip.Addr{
"A": {{1, 2, 3, 4}}, "A": {netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
expectedHTS: hostToServer{ expectedHTS: hostToServer{
"A": models.Server{ "A": models.Server{
Country: "country", Country: "country",
IPs: []net.IP{{1, 2, 3, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
}, },
}, },
}, },
@@ -170,7 +170,7 @@ func Test_hostToServer_adaptWithIPs(t *testing.T) {
Country: "country", Country: "country",
}, },
}, },
hostToIPs: map[string][]net.IP{}, hostToIPs: map[string][]netip.Addr{},
expectedHTS: hostToServer{}, expectedHTS: hostToServer{},
}, },
} }

View File

@@ -3,7 +3,7 @@ package updater
import ( import (
"context" "context"
"errors" "errors"
"net" "net/netip"
"testing" "testing"
"time" "time"
@@ -32,7 +32,7 @@ func Test_Updater_GetServers(t *testing.T) {
// Resolution // Resolution
expectResolve bool expectResolve bool
resolverSettings resolver.ParallelSettings resolverSettings resolver.ParallelSettings
hostToIPs map[string][]net.IP hostToIPs map[string][]netip.Addr
resolveWarnings []string resolveWarnings []string
resolveErr error resolveErr error
@@ -161,9 +161,9 @@ func Test_Updater_GetServers(t *testing.T) {
SortIPs: true, SortIPs: true,
}, },
}, },
hostToIPs: map[string][]net.IP{ hostToIPs: map[string][]netip.Addr{
"hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}}, "hosta": {netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
"hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}}, "hostb": {netip.AddrFrom4([4]byte{3, 3, 3, 3}), netip.AddrFrom4([4]byte{4, 4, 4, 4})},
}, },
resolveWarnings: []string{"resolve warning"}, resolveWarnings: []string{"resolve warning"},
servers: []models.Server{ servers: []models.Server{
@@ -173,7 +173,7 @@ func Test_Updater_GetServers(t *testing.T) {
City: "City A", City: "City A",
Hostname: "hosta", Hostname: "hosta",
UDP: true, UDP: true,
IPs: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
}, },
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
@@ -181,7 +181,7 @@ func Test_Updater_GetServers(t *testing.T) {
City: "City B", City: "City B",
Hostname: "hostb", Hostname: "hostb",
UDP: true, UDP: true,
IPs: []net.IP{{3, 3, 3, 3}, {4, 4, 4, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{3, 3, 3, 3}), netip.AddrFrom4([4]byte{4, 4, 4, 4})},
}, },
}, },
}, },

View File

@@ -3,8 +3,8 @@ package ivpn
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net"
"net/http" "net/http"
"net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -41,7 +41,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN TCP port": { "default OpenVPN TCP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -50,14 +50,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 443, Port: 443,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
}, },
"default OpenVPN UDP port": { "default OpenVPN UDP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -66,21 +66,21 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
}, },
"default Wireguard port": { "default Wireguard port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, WgPubKey: "x"}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x"},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.Wireguard, Type: vpn.Wireguard,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 58237, Port: 58237,
Protocol: constants.UDP, Protocol: constants.UDP,
PubKey: "x", PubKey: "x",

View File

@@ -4,8 +4,8 @@ import (
"context" "context"
"errors" "errors"
"io" "io"
"net"
"net/http" "net/http"
"net/netip"
"strings" "strings"
"testing" "testing"
"time" "time"
@@ -36,7 +36,7 @@ func Test_Updater_GetServers(t *testing.T) {
// Resolution // Resolution
expectResolve bool expectResolve bool
resolveSettings resolver.ParallelSettings resolveSettings resolver.ParallelSettings
hostToIPs map[string][]net.IP hostToIPs map[string][]netip.Addr
resolveWarnings []string resolveWarnings []string
resolveErr error resolveErr error
@@ -109,24 +109,24 @@ func Test_Updater_GetServers(t *testing.T) {
SortIPs: true, SortIPs: true,
}, },
}, },
hostToIPs: map[string][]net.IP{ hostToIPs: map[string][]netip.Addr{
"hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}}, "hosta": {netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
"hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}}, "hostb": {netip.AddrFrom4([4]byte{3, 3, 3, 3}), netip.AddrFrom4([4]byte{4, 4, 4, 4})},
"hostc": {{5, 5, 5, 5}, {6, 6, 6, 6}}, "hostc": {netip.AddrFrom4([4]byte{5, 5, 5, 5}), netip.AddrFrom4([4]byte{6, 6, 6, 6})},
}, },
resolveWarnings: []string{"resolve warning"}, resolveWarnings: []string{"resolve warning"},
servers: []models.Server{ servers: []models.Server{
{VPN: vpn.OpenVPN, Country: "Country1", {VPN: vpn.OpenVPN, Country: "Country1",
City: "City A", Hostname: "hosta", TCP: true, UDP: true, City: "City A", Hostname: "hosta", TCP: true, UDP: true,
IPs: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})}},
{VPN: vpn.OpenVPN, Country: "Country2", {VPN: vpn.OpenVPN, Country: "Country2",
City: "City B", Hostname: "hostb", TCP: true, UDP: true, City: "City B", Hostname: "hostb", TCP: true, UDP: true,
IPs: []net.IP{{3, 3, 3, 3}, {4, 4, 4, 4}}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{3, 3, 3, 3}), netip.AddrFrom4([4]byte{4, 4, 4, 4})}},
{VPN: vpn.Wireguard, {VPN: vpn.Wireguard,
Country: "Country3", City: "City C", Country: "Country3", City: "City C",
Hostname: "hostc", Hostname: "hostc",
WgPubKey: "xyz", WgPubKey: "xyz",
IPs: []net.IP{{5, 5, 5, 5}, {6, 6, 6, 6}}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{5, 5, 5, 5}), netip.AddrFrom4([4]byte{6, 6, 6, 6})}},
}, },
}, },
} }

View File

@@ -3,8 +3,8 @@ package mullvad
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net"
"net/http" "net/http"
"net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -41,7 +41,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN TCP port": { "default OpenVPN TCP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -50,14 +50,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 443, Port: 443,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
}, },
"default OpenVPN UDP port": { "default OpenVPN UDP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -66,21 +66,21 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
}, },
"default Wireguard port": { "default Wireguard port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, WgPubKey: "x"}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x"},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.Wireguard, Type: vpn.Wireguard,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 51820, Port: 51820,
Protocol: constants.UDP, Protocol: constants.UDP,
PubKey: "x", PubKey: "x",

View File

@@ -3,7 +3,7 @@ package updater
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"strings" "strings"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -14,8 +14,8 @@ type hostToServer map[string]models.Server
var ( var (
ErrNoIP = errors.New("no IP address for VPN server") ErrNoIP = errors.New("no IP address for VPN server")
ErrParseIPv4 = errors.New("cannot parse IPv4 address") ErrIPIsNotV4 = errors.New("IP address is not IPv4")
ErrParseIPv6 = errors.New("cannot parse IPv6 address") ErrIPIsNotV6 = errors.New("IP address is not IPv6")
ErrVPNTypeNotSupported = errors.New("VPN type not supported") ErrVPNTypeNotSupported = errors.New("VPN type not supported")
) )
@@ -48,17 +48,21 @@ func (hts hostToServer) add(data serverData) (err error) {
} }
if data.IPv4 != "" { if data.IPv4 != "" {
ipv4 := net.ParseIP(data.IPv4) ipv4, err := netip.ParseAddr(data.IPv4)
if ipv4 == nil || ipv4.To4() == nil { if err != nil {
return fmt.Errorf("%w: %s", ErrParseIPv4, data.IPv4) return fmt.Errorf("parsing IPv4 address: %w", err)
} else if !ipv4.Is4() {
return fmt.Errorf("%w: %s", ErrIPIsNotV4, data.IPv4)
} }
server.IPs = append(server.IPs, ipv4) server.IPs = append(server.IPs, ipv4)
} }
if data.IPv6 != "" { if data.IPv6 != "" {
ipv6 := net.ParseIP(data.IPv6) ipv6, err := netip.ParseAddr(data.IPv6)
if ipv6 == nil || ipv6.To4() != nil { if err != nil {
return fmt.Errorf("%w: %s", ErrParseIPv6, data.IPv6) return fmt.Errorf("parsing IPv6 address: %w", err)
} else if !ipv6.Is6() {
return fmt.Errorf("%w: %s", ErrIPIsNotV6, data.IPv6)
} }
server.IPs = append(server.IPs, ipv6) server.IPs = append(server.IPs, ipv6)
} }

View File

@@ -1,29 +1,31 @@
package updater package updater
import ( import (
"bytes" "net/netip"
"net"
"sort" "sort"
) )
func uniqueSortedIPs(ips []net.IP) []net.IP { func uniqueSortedIPs(ips []netip.Addr) []netip.Addr {
uniqueIPs := make(map[string]struct{}, len(ips)) uniqueIPs := make(map[string]struct{}, len(ips))
for _, ip := range ips { for _, ip := range ips {
key := ip.String() key := ip.String()
uniqueIPs[key] = struct{}{} uniqueIPs[key] = struct{}{}
} }
ips = make([]net.IP, 0, len(uniqueIPs)) ips = make([]netip.Addr, 0, len(uniqueIPs))
for key := range uniqueIPs { for key := range uniqueIPs {
ip := net.ParseIP(key) ip, err := netip.ParseAddr(key)
if ipv4 := ip.To4(); ipv4 != nil { if err != nil {
ip = ipv4 panic(err)
}
if ip.Is4In6() {
ip = netip.AddrFrom4(ip.As4())
} }
ips = append(ips, ip) ips = append(ips, ip)
} }
sort.Slice(ips, func(i, j int) bool { sort.Slice(ips, func(i, j int) bool {
return bytes.Compare(ips[i], ips[j]) < 0 return ips[i].Compare(ips[j]) < 0
}) })
return ips return ips

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -10,24 +10,24 @@ import (
func Test_uniqueSortedIPs(t *testing.T) { func Test_uniqueSortedIPs(t *testing.T) {
t.Parallel() t.Parallel()
testCases := map[string]struct { testCases := map[string]struct {
inputIPs []net.IP inputIPs []netip.Addr
outputIPs []net.IP outputIPs []netip.Addr
}{ }{
"nil": { "nil": {
inputIPs: nil, inputIPs: nil,
outputIPs: []net.IP{}, outputIPs: []netip.Addr{},
}, },
"empty": { "empty": {
inputIPs: []net.IP{}, inputIPs: []netip.Addr{},
outputIPs: []net.IP{}, outputIPs: []netip.Addr{},
}, },
"single IPv4": { "single IPv4": {
inputIPs: []net.IP{{1, 1, 1, 1}}, inputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
outputIPs: []net.IP{{1, 1, 1, 1}}, outputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
}, },
"two IPv4s": { "two IPv4s": {
inputIPs: []net.IP{{1, 1, 2, 1}, {1, 1, 1, 1}}, inputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 2, 1}), netip.AddrFrom4([4]byte{1, 1, 1, 1})},
outputIPs: []net.IP{{1, 1, 1, 1}, {1, 1, 2, 1}}, outputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{1, 1, 2, 1})},
}, },
} }
for name, testCase := range testCases { for name, testCase := range testCases {

View File

@@ -2,15 +2,16 @@ package updater
import ( import (
"fmt" "fmt"
"net" "net/netip"
) )
func parseIPv4(s string) (ipv4 net.IP, err error) { func parseIPv4(s string) (ipv4 netip.Addr, err error) {
ip := net.ParseIP(s) ipv4, err = netip.ParseAddr(s)
if ip == nil { if err != nil {
return nil, fmt.Errorf("%w: %q", ErrParseIP, s) return ipv4, err
} else if ip.To4() == nil {
return nil, fmt.Errorf("%w: %s", ErrNotIPv4, ip)
} }
return ip, nil if !ipv4.Is4() {
return ipv4, fmt.Errorf("%w: %s", ErrNotIPv4, ipv4)
}
return ipv4, nil
} }

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"sort" "sort"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -13,7 +13,6 @@ import (
) )
var ( var (
ErrParseIP = errors.New("cannot parse IP address")
ErrNotIPv4 = errors.New("IP address is not IPv4") ErrNotIPv4 = errors.New("IP address is not IPv4")
) )
@@ -47,7 +46,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
Region: jsonServer.Country, Region: jsonServer.Country,
Hostname: jsonServer.Domain, Hostname: jsonServer.Domain,
Number: number, Number: number,
IPs: []net.IP{ip}, IPs: []netip.Addr{ip},
TCP: jsonServer.Features.TCP, TCP: jsonServer.Features.TCP,
UDP: jsonServer.Features.UDP, UDP: jsonServer.Features.UDP,
} }

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -9,7 +9,7 @@ import (
type cityToServer map[string]models.Server type cityToServer map[string]models.Server
func (cts cityToServer) add(city string, ips []net.IP) { func (cts cityToServer) add(city string, ips []netip.Addr) {
server, ok := cts[city] server, ok := cts[city]
if !ok { if !ok {
server.VPN = vpn.OpenVPN server.VPN = vpn.OpenVPN

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -28,7 +28,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -2,7 +2,7 @@ package updater
import ( import (
"context" "context"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
@@ -10,7 +10,7 @@ import (
func setLocationInfo(ctx context.Context, fetcher common.IPFetcher, servers []models.Server) (err error) { func setLocationInfo(ctx context.Context, fetcher common.IPFetcher, servers []models.Server) (err error) {
// Get public IP address information // Get public IP address information
ipsToGetInfo := make([]net.IP, 0, len(servers)) ipsToGetInfo := make([]netip.Addr, 0, len(servers))
for _, server := range servers { for _, server := range servers {
ipsToGetInfo = append(ipsToGetInfo, server.IPs...) ipsToGetInfo = append(ipsToGetInfo, server.IPs...)
} }

View File

@@ -9,6 +9,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/netip"
"net/url" "net/url"
"os" "os"
"strconv" "strconv"
@@ -21,14 +22,14 @@ import (
) )
var ( var (
ErrServerNameNotFound = errors.New("server name not found in servers") ErrServerNameNotFound = errors.New("server name not found in servers")
ErrGatewayIPIsNil = errors.New("gateway IP address is nil") ErrGatewayIPIsNotValid = errors.New("gateway IP address is not valid")
ErrServerNameEmpty = errors.New("server name is empty") ErrServerNameEmpty = errors.New("server name is empty")
) )
// PortForward obtains a VPN server side port forwarded from PIA. // PortForward obtains a VPN server side port forwarded from PIA.
func (p *Provider) PortForward(ctx context.Context, client *http.Client, func (p *Provider) PortForward(ctx context.Context, client *http.Client,
logger utils.Logger, gateway net.IP, serverName string) ( logger utils.Logger, gateway netip.Addr, serverName string) (
port uint16, err error) { port uint16, err error) {
server, ok := p.storage.GetServerByName(providers.PrivateInternetAccess, serverName) server, ok := p.storage.GetServerByName(providers.PrivateInternetAccess, serverName)
if !ok { if !ok {
@@ -40,8 +41,8 @@ func (p *Provider) PortForward(ctx context.Context, client *http.Client,
" (region " + server.Region + ") does not support port forwarding") " (region " + server.Region + ") does not support port forwarding")
return 0, nil return 0, nil
} }
if gateway == nil { if !gateway.IsValid() {
return 0, ErrGatewayIPIsNil return 0, fmt.Errorf("%w: %s", ErrGatewayIPIsNotValid, gateway)
} else if serverName == "" { } else if serverName == "" {
return 0, ErrServerNameEmpty return 0, ErrServerNameEmpty
} }
@@ -91,7 +92,7 @@ var (
) )
func (p *Provider) KeepPortForward(ctx context.Context, func (p *Provider) KeepPortForward(ctx context.Context,
gateway net.IP, serverName string) (err error) { gateway netip.Addr, serverName string) (err error) {
privateIPClient, err := newHTTPClient(serverName) privateIPClient, err := newHTTPClient(serverName)
if err != nil { if err != nil {
return fmt.Errorf("creating custom HTTP client: %w", err) return fmt.Errorf("creating custom HTTP client: %w", err)
@@ -132,7 +133,7 @@ func (p *Provider) KeepPortForward(ctx context.Context,
} }
func refreshPIAPortForwardData(ctx context.Context, client, privateIPClient *http.Client, func refreshPIAPortForwardData(ctx context.Context, client, privateIPClient *http.Client,
gateway net.IP, portForwardPath, authFilePath string) (data piaPortForwardData, err error) { gateway netip.Addr, portForwardPath, authFilePath string) (data piaPortForwardData, err error) {
data.Token, err = fetchToken(ctx, client, authFilePath) data.Token, err = fetchToken(ctx, client, authFilePath)
if err != nil { if err != nil {
return data, fmt.Errorf("fetching token: %w", err) return data, fmt.Errorf("fetching token: %w", err)
@@ -314,7 +315,7 @@ func getOpenvpnCredentials(authFilePath string) (
return username, password, nil return username, password, nil
} }
func fetchPortForwardData(ctx context.Context, client *http.Client, gateway net.IP, token string) ( func fetchPortForwardData(ctx context.Context, client *http.Client, gateway netip.Addr, token string) (
port uint16, signature string, expiration time.Time, err error) { port uint16, signature string, expiration time.Time, err error) {
errSubstitutions := map[string]string{url.QueryEscape(token): "<token>"} errSubstitutions := map[string]string{url.QueryEscape(token): "<token>"}
@@ -368,7 +369,7 @@ var (
ErrBadResponse = errors.New("bad response received") ErrBadResponse = errors.New("bad response received")
) )
func bindPort(ctx context.Context, client *http.Client, gateway net.IP, data piaPortForwardData) (err error) { func bindPort(ctx context.Context, client *http.Client, gateway netip.Addr, data piaPortForwardData) (err error) {
payload, err := packPayload(data.Port, data.Token, data.Expiration) payload, err := packPayload(data.Port, data.Token, data.Expiration)
if err != nil { if err != nil {
return fmt.Errorf("serializing payload: %w", err) return fmt.Errorf("serializing payload: %w", err)

View File

@@ -7,8 +7,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"net"
"net/http" "net/http"
"net/netip"
) )
var ( var (
@@ -31,8 +31,8 @@ type regionData struct {
} }
type serverData struct { type serverData struct {
IP net.IP `json:"ip"` IP netip.Addr `json:"ip"`
CN string `json:"cn"` CN string `json:"cn"`
} }
func fetchAPI(ctx context.Context, client *http.Client) ( func fetchAPI(ctx context.Context, client *http.Client) (

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -10,7 +10,7 @@ import (
type nameToServer map[string]models.Server type nameToServer map[string]models.Server
func (nts nameToServer) add(name, hostname, region string, func (nts nameToServer) add(name, hostname, region string,
tcp, udp, portForward bool, ip net.IP) (change bool) { tcp, udp, portForward bool, ip netip.Addr) (change bool) {
server, ok := nts[name] server, ok := nts[name]
if !ok { if !ok {
change = true change = true
@@ -32,7 +32,7 @@ func (nts nameToServer) add(name, hostname, region string,
ipFound := false ipFound := false
for _, existingIP := range server.IPs { for _, existingIP := range server.IPs {
if ip.Equal(existingIP) { if ip == existingIP {
ipFound = true ipFound = true
break break
} }

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -32,7 +32,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -5,8 +5,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
) )
var ( var (
@@ -26,8 +26,8 @@ type logicalServer struct {
} }
type physicalServer struct { type physicalServer struct {
EntryIP net.IP EntryIP netip.Addr
ExitIP net.IP ExitIP netip.Addr
Domain string Domain string
Status uint8 Status uint8
} }

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -10,7 +10,7 @@ import (
type ipToServer map[string]models.Server type ipToServer map[string]models.Server
func (its ipToServer) add(country, region, city, name, hostname string, func (its ipToServer) add(country, region, city, name, hostname string,
free bool, entryIP net.IP) { free bool, entryIP netip.Addr) {
key := entryIP.String() key := entryIP.String()
server, ok := its[key] server, ok := its[key]
@@ -27,7 +27,7 @@ func (its ipToServer) add(country, region, city, name, hostname string,
server.Free = free server.Free = free
server.UDP = true server.UDP = true
server.TCP = true server.TCP = true
server.IPs = []net.IP{entryIP} server.IPs = []netip.Addr{entryIP}
its[key] = server its[key] = server
} }

View File

@@ -2,8 +2,8 @@ package provider
import ( import (
"context" "context"
"net"
"net/http" "net/http"
"net/netip"
"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"
@@ -22,8 +22,8 @@ type Provider interface {
type PortForwarder interface { type PortForwarder interface {
PortForward(ctx context.Context, client *http.Client, PortForward(ctx context.Context, client *http.Client,
logger utils.Logger, gateway net.IP, serverName string) ( logger utils.Logger, gateway netip.Addr, serverName string) (
port uint16, err error) port uint16, err error)
KeepPortForward(ctx context.Context, gateway net.IP, KeepPortForward(ctx context.Context, gateway netip.Addr,
serverName string) (err error) serverName string) (err error)
} }

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -32,7 +32,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -3,7 +3,7 @@ package updater
import ( import (
"context" "context"
"fmt" "fmt"
"net" "net/netip"
"sort" "sort"
"strings" "strings"
@@ -76,7 +76,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
servers = hts.toServersSlice() servers = hts.toServersSlice()
// Get public IP address information // Get public IP address information
ipsToGetInfo := make([]net.IP, len(servers)) ipsToGetInfo := make([]netip.Addr, len(servers))
for i := range servers { for i := range servers {
ipsToGetInfo[i] = servers[i].IPs[0] ipsToGetInfo[i] = servers[i].IPs[0]
} }

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -75,7 +75,7 @@ func (hts hostToServers) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServers) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServers) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
servers := hts[host] servers := hts[host]
for i := range servers { for i := range servers {

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -10,7 +10,7 @@ import (
type hostToServer map[string]models.Server type hostToServer map[string]models.Server
func (hts hostToServer) add(host, country, city string, func (hts hostToServer) add(host, country, city string,
tcp, udp bool, ips []net.IP) { tcp, udp bool, ips []netip.Addr) {
server, ok := hts[host] server, ok := hts[host]
if !ok { if !ok {
server.VPN = vpn.OpenVPN server.VPN = vpn.OpenVPN
@@ -39,7 +39,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -48,7 +48,7 @@ func GetConnection(provider string,
connections := make([]models.Connection, 0, len(servers)) connections := make([]models.Connection, 0, len(servers))
for _, server := range servers { for _, server := range servers {
for _, ip := range server.IPs { for _, ip := range server.IPs {
if !ipv6Supported && ip.To4() == nil { if !ipv6Supported && ip.Is6() {
continue continue
} }

View File

@@ -3,7 +3,7 @@ package utils
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -58,7 +58,7 @@ func Test_GetConnection(t *testing.T) {
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
Hostname: "name", Hostname: "name",
}, },
}, },
@@ -68,7 +68,7 @@ func Test_GetConnection(t *testing.T) {
randSource: rand.NewSource(0), randSource: rand.NewSource(0),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Protocol: constants.UDP, Protocol: constants.UDP,
Port: 1194, Port: 1194,
Hostname: "name", Hostname: "name",
@@ -79,7 +79,7 @@ func Test_GetConnection(t *testing.T) {
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
Hostname: "hostname", Hostname: "hostname",
OvpnX509: "x509", OvpnX509: "x509",
}, },
@@ -90,7 +90,7 @@ func Test_GetConnection(t *testing.T) {
randSource: rand.NewSource(0), randSource: rand.NewSource(0),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Protocol: constants.UDP, Protocol: constants.UDP,
Port: 1194, Port: 1194,
Hostname: "x509", Hostname: "x509",
@@ -101,14 +101,14 @@ func Test_GetConnection(t *testing.T) {
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{ IPs: []netip.Addr{
net.IPv4(1, 1, 1, 1), netip.AddrFrom4([4]byte{1, 1, 1, 1}),
// All IPv6 is ignored // All IPv6 is ignored
net.IPv6zero, netip.IPv6Unspecified(),
net.IPv6zero, netip.IPv6Unspecified(),
net.IPv6zero, netip.IPv6Unspecified(),
net.IPv6zero, netip.IPv6Unspecified(),
net.IPv6zero, netip.IPv6Unspecified(),
}, },
}, },
}, },
@@ -118,7 +118,7 @@ func Test_GetConnection(t *testing.T) {
randSource: rand.NewSource(0), randSource: rand.NewSource(0),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Protocol: constants.UDP, Protocol: constants.UDP,
Port: 1194, Port: 1194,
}, },
@@ -128,9 +128,9 @@ func Test_GetConnection(t *testing.T) {
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{ IPs: []netip.Addr{
net.IPv6zero, netip.IPv6Unspecified(),
net.IPv4(1, 1, 1, 1), netip.AddrFrom4([4]byte{1, 1, 1, 1}),
}, },
}, },
}, },
@@ -141,7 +141,7 @@ func Test_GetConnection(t *testing.T) {
randSource: rand.NewSource(0), randSource: rand.NewSource(0),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv6zero, IP: netip.IPv6Unspecified(),
Protocol: constants.UDP, Protocol: constants.UDP,
Port: 1194, Port: 1194,
}, },
@@ -151,21 +151,21 @@ func Test_GetConnection(t *testing.T) {
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
OvpnX509: "ovpnx509", OvpnX509: "ovpnx509",
}, },
{ {
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
UDP: true, UDP: true,
IPs: []net.IP{net.IPv4(2, 2, 2, 2)}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{2, 2, 2, 2})},
OvpnX509: "ovpnx509", OvpnX509: "ovpnx509",
}, },
{ {
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
UDP: true, UDP: true,
IPs: []net.IP{ IPs: []netip.Addr{
net.IPv4(3, 3, 3, 3), netip.AddrFrom4([4]byte{3, 3, 3, 3}),
{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, // ipv6 ignored netip.AddrFrom16([16]byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), // ipv6 ignored
}, },
Hostname: "hostname", Hostname: "hostname",
}, },
@@ -176,7 +176,7 @@ func Test_GetConnection(t *testing.T) {
randSource: rand.NewSource(0), randSource: rand.NewSource(0),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Protocol: constants.UDP, Protocol: constants.UDP,
Port: 1194, Port: 1194,
Hostname: "ovpnx509", Hostname: "ovpnx509",

View File

@@ -4,15 +4,15 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
) )
type NoPortForwarder interface { type NoPortForwarder interface {
PortForward(ctx context.Context, client *http.Client, PortForward(ctx context.Context, client *http.Client,
logger Logger, gateway net.IP, serverName string) ( logger Logger, gateway netip.Addr, serverName string) (
port uint16, err error) port uint16, err error)
KeepPortForward(ctx context.Context, gateway net.IP, KeepPortForward(ctx context.Context, gateway netip.Addr,
serverName string) (err error) serverName string) (err error)
} }
@@ -29,10 +29,10 @@ func NewNoPortForwarding(providerName string) *NoPortForwarding {
var ErrPortForwardingNotSupported = errors.New("custom port forwarding obtention is not supported") var ErrPortForwardingNotSupported = errors.New("custom port forwarding obtention is not supported")
func (n *NoPortForwarding) PortForward(context.Context, *http.Client, func (n *NoPortForwarding) PortForward(context.Context, *http.Client,
Logger, net.IP, string) (port uint16, err error) { Logger, netip.Addr, string) (port uint16, err error) {
return 0, fmt.Errorf("%w: for %s", ErrPortForwardingNotSupported, n.providerName) return 0, fmt.Errorf("%w: for %s", ErrPortForwardingNotSupported, n.providerName)
} }
func (n *NoPortForwarding) KeepPortForward(context.Context, net.IP, string) (err error) { func (n *NoPortForwarding) KeepPortForward(context.Context, netip.Addr, string) (err error) {
return fmt.Errorf("%w: for %s", ErrPortForwardingNotSupported, n.providerName) return fmt.Errorf("%w: for %s", ErrPortForwardingNotSupported, n.providerName)
} }

View File

@@ -4,7 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -25,13 +25,15 @@ func pickConnection(connections []models.Connection,
return connection, ErrNoConnectionToPickFrom return connection, ErrNoConnectionToPickFrom
} }
if len(selection.TargetIP) > 0 && selection.VPN == vpn.Wireguard { targetIPSet := selection.TargetIP.IsValid() && !selection.TargetIP.IsUnspecified()
if targetIPSet && selection.VPN == vpn.Wireguard {
// we need the right public key // we need the right public key
return getTargetIPConnection(connections, selection.TargetIP) return getTargetIPConnection(connections, selection.TargetIP)
} }
connection = pickRandomConnection(connections, randSource) connection = pickRandomConnection(connections, randSource)
if len(selection.TargetIP) > 0 { if targetIPSet {
connection.IP = selection.TargetIP connection.IP = selection.TargetIP
} }
@@ -46,9 +48,9 @@ func pickRandomConnection(connections []models.Connection,
var errTargetIPNotFound = errors.New("target IP address not found") var errTargetIPNotFound = errors.New("target IP address not found")
func getTargetIPConnection(connections []models.Connection, func getTargetIPConnection(connections []models.Connection,
targetIP net.IP) (connection models.Connection, err error) { targetIP netip.Addr) (connection models.Connection, err error) {
for _, connection := range connections { for _, connection := range connections {
if targetIP.Equal(connection.IP) { if targetIP == connection.IP {
return connection, nil return connection, nil
} }
} }

View File

@@ -22,8 +22,7 @@ func BuildWireguardSettings(connection models.Connection,
settings.RulePriority = rulePriority settings.RulePriority = rulePriority
settings.Endpoint = new(net.UDPAddr) settings.Endpoint = new(net.UDPAddr)
settings.Endpoint.IP = make(net.IP, len(connection.IP)) settings.Endpoint.IP = connection.IP.AsSlice()
copy(settings.Endpoint.IP, connection.IP)
settings.Endpoint.Port = int(connection.Port) settings.Endpoint.Port = int(connection.Port)
settings.Addresses = make([]netip.Prefix, 0, len(userSettings.Addresses)) settings.Addresses = make([]netip.Prefix, 0, len(userSettings.Addresses))

View File

@@ -24,7 +24,7 @@ func Test_BuildWireguardSettings(t *testing.T) {
}{ }{
"some settings": { "some settings": {
connection: models.Connection{ connection: models.Connection{
IP: net.IPv4(1, 2, 3, 4), IP: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
Port: 51821, Port: 51821,
PubKey: "public", PubKey: "public",
}, },
@@ -44,7 +44,7 @@ func Test_BuildWireguardSettings(t *testing.T) {
PublicKey: "public", PublicKey: "public",
PreSharedKey: "pre-shared", PreSharedKey: "pre-shared",
Endpoint: &net.UDPAddr{ Endpoint: &net.UDPAddr{
IP: net.IPv4(1, 2, 3, 4), IP: net.IP{1, 2, 3, 4},
Port: 51821, Port: 51821,
}, },
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
@@ -16,7 +16,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
@@ -16,7 +16,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -1,7 +1,7 @@
package updater package updater
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
@@ -33,7 +33,7 @@ func (hts hostToServer) toHostsSlice() (hosts []string) {
return hosts return hosts
} }
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) { func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
for host, IPs := range hostToIPs { for host, IPs := range hostToIPs {
server := hts[host] server := hts[host]
server.IPs = IPs server.IPs = IPs

View File

@@ -3,7 +3,7 @@ package wevpn
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -41,7 +41,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN TCP port": { "default OpenVPN TCP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -50,14 +50,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1195, Port: 1195,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
}, },
"default OpenVPN UDP port": { "default OpenVPN UDP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -66,14 +66,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
}, },
"default Wireguard port": { "default Wireguard port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, WgPubKey: "x"}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x"},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,

View File

@@ -3,8 +3,8 @@ package windscribe
import ( import (
"errors" "errors"
"math/rand" "math/rand"
"net"
"net/http" "net/http"
"net/netip"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@@ -42,7 +42,7 @@ func Test_Provider_GetConnection(t *testing.T) {
}, },
"default OpenVPN TCP port": { "default OpenVPN TCP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -51,14 +51,14 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 443, Port: 443,
Protocol: constants.TCP, Protocol: constants.TCP,
}, },
}, },
"default OpenVPN UDP port": { "default OpenVPN UDP port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{ OpenVPN: settings.OpenVPNSelection{
@@ -67,21 +67,21 @@ func Test_Provider_GetConnection(t *testing.T) {
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.OpenVPN, Type: vpn.OpenVPN,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
}, },
}, },
"default Wireguard port": { "default Wireguard port": {
filteredServers: []models.Server{ filteredServers: []models.Server{
{IPs: []net.IP{net.IPv4(1, 1, 1, 1)}, WgPubKey: "x"}, {IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x"},
}, },
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
}.WithDefaults(provider), }.WithDefaults(provider),
connection: models.Connection{ connection: models.Connection{
Type: vpn.Wireguard, Type: vpn.Wireguard,
IP: net.IPv4(1, 1, 1, 1), IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194, Port: 1194,
Protocol: constants.UDP, Protocol: constants.UDP,
PubKey: "x", PubKey: "x",

View File

@@ -5,8 +5,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
"strconv" "strconv"
"time" "time"
) )
@@ -32,10 +32,10 @@ type groupData struct {
} }
type serverData struct { type serverData struct {
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
IP net.IP `json:"ip"` IP netip.Addr `json:"ip"`
IP2 net.IP `json:"ip2"` IP2 netip.Addr `json:"ip2"`
IP3 net.IP `json:"ip3"` IP3 netip.Addr `json:"ip3"`
} }
func fetchAPI(ctx context.Context, client *http.Client) ( func fetchAPI(ctx context.Context, client *http.Client) (

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"sort" "sort"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
@@ -30,11 +30,11 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
x5090Name := group.OvpnX509 x5090Name := group.OvpnX509
wgPubKey := group.WgPubKey wgPubKey := group.WgPubKey
for _, node := range group.Nodes { for _, node := range group.Nodes {
ips := make([]net.IP, 0, 2) //nolint:gomnd ips := make([]netip.Addr, 0, 2) //nolint:gomnd
if node.IP != nil { if node.IP.IsValid() {
ips = append(ips, node.IP) ips = append(ips, node.IP)
} }
if node.IP2 != nil { if node.IP2.IsValid() {
ips = append(ips, node.IP2) ips = append(ips, node.IP2)
} }
server := models.Server{ server := models.Server{
@@ -49,7 +49,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
} }
servers = append(servers, server) servers = append(servers, server)
if node.IP3 == nil { // Wireguard + Stealth if !node.IP3.IsValid() { // Wireguard + Stealth
continue continue
} else if wgPubKey == "" { } else if wgPubKey == "" {
return nil, fmt.Errorf("%w: for node %s", ErrNoWireguardKey, node.Hostname) return nil, fmt.Errorf("%w: for node %s", ErrNoWireguardKey, node.Hostname)
@@ -60,7 +60,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
server.TCP = false server.TCP = false
server.OvpnX509 = "" server.OvpnX509 = ""
server.WgPubKey = wgPubKey server.WgPubKey = wgPubKey
server.IPs = []net.IP{node.IP3} server.IPs = []netip.Addr{node.IP3}
servers = append(servers, server) servers = append(servers, server)
} }
} }

View File

@@ -2,12 +2,12 @@ package publicip
import ( import (
"context" "context"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/publicip/ipinfo" "github.com/qdm12/gluetun/internal/publicip/ipinfo"
) )
type Fetcher interface { type Fetcher interface {
FetchInfo(ctx context.Context, ip net.IP) ( FetchInfo(ctx context.Context, ip netip.Addr) (
result ipinfo.Response, err error) result ipinfo.Response, err error)
} }

View File

@@ -5,8 +5,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net"
"net/http" "net/http"
"net/netip"
"strings" "strings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
@@ -28,13 +28,13 @@ var (
) )
// FetchInfo obtains information on the ip address provided // FetchInfo obtains information on the ip address provided
// using the ipinfo.io API. If the ip is nil, the public IP address // using the ipinfo.io API. If the ip is the zero value, the public IP address
// of the machine is used as the IP. // of the machine is used as the IP.
func (f *Fetch) FetchInfo(ctx context.Context, ip net.IP) ( func (f *Fetch) FetchInfo(ctx context.Context, ip netip.Addr) (
result Response, err error) { result Response, err error) {
const baseURL = "https://ipinfo.io/" const baseURL = "https://ipinfo.io/"
url := baseURL url := baseURL
if ip != nil { if ip.IsValid() {
url += ip.String() url += ip.String()
} }

View File

@@ -1,26 +1,26 @@
package ipinfo package ipinfo
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
type Response struct { type Response struct {
IP net.IP `json:"ip,omitempty"` IP netip.Addr `json:"ip,omitempty"`
Region string `json:"region,omitempty"` Region string `json:"region,omitempty"`
Country string `json:"country,omitempty"` Country string `json:"country,omitempty"`
City string `json:"city,omitempty"` City string `json:"city,omitempty"`
Hostname string `json:"hostname,omitempty"` Hostname string `json:"hostname,omitempty"`
Loc string `json:"loc,omitempty"` Loc string `json:"loc,omitempty"`
Org string `json:"org,omitempty"` Org string `json:"org,omitempty"`
Postal string `json:"postal,omitempty"` Postal string `json:"postal,omitempty"`
Timezone string `json:"timezone,omitempty"` Timezone string `json:"timezone,omitempty"`
} }
func (r *Response) ToPublicIPModel() (model models.PublicIP) { func (r *Response) ToPublicIPModel() (model models.PublicIP) {
model = models.PublicIP{ return models.PublicIP{
IP: make(net.IP, len(r.IP)), IP: r.IP,
Region: r.Region, Region: r.Region,
Country: r.Country, Country: r.Country,
City: r.City, City: r.City,
@@ -30,6 +30,4 @@ func (r *Response) ToPublicIPModel() (model models.PublicIP) {
PostalCode: r.Postal, PostalCode: r.Postal,
Timezone: r.Timezone, Timezone: r.Timezone,
} }
copy(model.IP, r.IP)
return model
} }

View File

@@ -2,7 +2,7 @@ package ipinfo
import ( import (
"context" "context"
"net" "net/netip"
) )
// FetchMultiInfo obtains the public IP address information for every IP // FetchMultiInfo obtains the public IP address information for every IP
@@ -11,7 +11,7 @@ import (
// If an error is encountered, all the operations are canceled and // If an error is encountered, all the operations are canceled and
// an error is returned, so the results returned should be considered // an error is returned, so the results returned should be considered
// incomplete in this case. // incomplete in this case.
func (f *Fetch) FetchMultiInfo(ctx context.Context, ips []net.IP) ( func (f *Fetch) FetchMultiInfo(ctx context.Context, ips []netip.Addr) (
results []Response, err error) { results []Response, err error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
@@ -23,7 +23,7 @@ func (f *Fetch) FetchMultiInfo(ctx context.Context, ips []net.IP) (
resultsCh := make(chan asyncResult) resultsCh := make(chan asyncResult)
for i, ip := range ips { for i, ip := range ips {
go func(index int, ip net.IP) { go func(index int, ip netip.Addr) {
aResult := asyncResult{ aResult := asyncResult{
index: index, index: index,
} }

View File

@@ -3,6 +3,7 @@ package publicip
import ( import (
"context" "context"
"errors" "errors"
"net/netip"
"os" "os"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
@@ -26,7 +27,7 @@ func (l *Loop) Run(ctx context.Context, done chan<- struct{}) {
resultCh := make(chan models.PublicIP) resultCh := make(chan models.PublicIP)
errorCh := make(chan error) errorCh := make(chan error)
go func() { go func() {
result, err := l.fetcher.FetchInfo(getCtx, nil) result, err := l.fetcher.FetchInfo(getCtx, netip.Addr{})
if err != nil { if err != nil {
if getCtx.Err() == nil { if getCtx.Err() == nil {
errorCh <- err errorCh <- err

View File

@@ -3,7 +3,7 @@ package routing
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
) )
@@ -14,8 +14,8 @@ var (
type DefaultRoute struct { type DefaultRoute struct {
NetInterface string NetInterface string
Gateway net.IP Gateway netip.Addr
AssignedIP net.IP AssignedIP netip.Addr
Family int Family int
} }
@@ -35,7 +35,7 @@ func (r *Routing) DefaultRoutes() (defaultRoutes []DefaultRoute, err error) {
continue continue
} }
defaultRoute := DefaultRoute{ defaultRoute := DefaultRoute{
Gateway: route.Gw, Gateway: netIPToNetipAddress(route.Gw),
Family: route.Family, Family: route.Family,
} }
linkIndex := route.LinkIndex linkIndex := route.LinkIndex

View File

@@ -62,7 +62,7 @@ func (r *Routing) unrouteInboundFromDefault(defaultRoutes []DefaultRoute) (err e
func (r *Routing) addRuleInboundFromDefault(table int, defaultRoutes []DefaultRoute) (err error) { func (r *Routing) addRuleInboundFromDefault(table int, defaultRoutes []DefaultRoute) (err error) {
for _, defaultRoute := range defaultRoutes { for _, defaultRoute := range defaultRoutes {
assignedIP := netIPToNetipAddress(defaultRoute.AssignedIP) assignedIP := defaultRoute.AssignedIP
bits := 32 bits := 32
if assignedIP.Is6() { if assignedIP.Is6() {
bits = 128 bits = 128
@@ -82,7 +82,7 @@ func (r *Routing) addRuleInboundFromDefault(table int, defaultRoutes []DefaultRo
func (r *Routing) delRuleInboundFromDefault(table int, defaultRoutes []DefaultRoute) (err error) { func (r *Routing) delRuleInboundFromDefault(table int, defaultRoutes []DefaultRoute) (err error) {
for _, defaultRoute := range defaultRoutes { for _, defaultRoute := range defaultRoutes {
assignedIP := netIPToNetipAddress(defaultRoute.AssignedIP) assignedIP := defaultRoute.AssignedIP
bits := 32 bits := 32
if assignedIP.Is6() { if assignedIP.Is6() {
bits = 128 bits = 128

View File

@@ -4,11 +4,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/netip"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
) )
func IPIsPrivate(ip net.IP) bool { func IPIsPrivate(ip netip.Addr) bool {
return ip.IsPrivate() || ip.IsLoopback() || return ip.IsPrivate() || ip.IsLoopback() ||
ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast()
} }
@@ -17,38 +18,26 @@ var (
errInterfaceIPNotFound = errors.New("IP address not found for interface") errInterfaceIPNotFound = errors.New("IP address not found for interface")
) )
func ipMatchesFamily(ip net.IP, family int) bool { func ipMatchesFamily(ip netip.Addr, family int) bool {
return (family == netlink.FAMILY_V6 && ip.To4() == nil) || return (family == netlink.FAMILY_V6 && ip.Is6()) ||
(family == netlink.FAMILY_V4 && ip.To4() != nil) (family == netlink.FAMILY_V4 && (ip.Is4() || ip.Is4In6()))
} }
func ensureNoIPv6WrappedIPv4(candidateIP net.IP) (resultIP net.IP) { func (r *Routing) assignedIP(interfaceName string, family int) (ip netip.Addr, err error) {
const ipv4Size = 4
if candidateIP.To4() == nil || len(candidateIP) == ipv4Size { // ipv6 or ipv4
return candidateIP
}
// ipv6-wrapped ipv4
resultIP = make(net.IP, ipv4Size)
copy(resultIP, candidateIP[12:16])
return resultIP
}
func (r *Routing) assignedIP(interfaceName string, family int) (ip net.IP, err error) {
iface, err := net.InterfaceByName(interfaceName) iface, err := net.InterfaceByName(interfaceName)
if err != nil { if err != nil {
return nil, fmt.Errorf("network interface %s not found: %w", interfaceName, err) return ip, fmt.Errorf("network interface %s not found: %w", interfaceName, err)
} }
addresses, err := iface.Addrs() addresses, err := iface.Addrs()
if err != nil { if err != nil {
return nil, fmt.Errorf("listing interface %s addresses: %w", interfaceName, err) return ip, fmt.Errorf("listing interface %s addresses: %w", interfaceName, err)
} }
for _, address := range addresses { for _, address := range addresses {
switch value := address.(type) { switch value := address.(type) {
case *net.IPAddr: case *net.IPAddr:
ip = value.IP ip = netIPToNetipAddress(value.IP)
case *net.IPNet: case *net.IPNet:
ip = value.IP ip = netIPToNetipAddress(value.IP)
default: default:
continue continue
} }
@@ -60,9 +49,8 @@ func (r *Routing) assignedIP(interfaceName string, family int) (ip net.IP, err e
// Ensure we don't return an IPv6-wrapped IPv4 address // Ensure we don't return an IPv6-wrapped IPv4 address
// since netip.Address String method works differently than // since netip.Address String method works differently than
// net.IP String method for this kind of addresses. // net.IP String method for this kind of addresses.
ip = ensureNoIPv6WrappedIPv4(ip) return ip.Unmap(), nil
return ip, nil
} }
return nil, fmt.Errorf("%w: interface %s in %d addresses", return ip, fmt.Errorf("%w: interface %s in %d addresses",
errInterfaceIPNotFound, interfaceName, len(addresses)) errInterfaceIPNotFound, interfaceName, len(addresses))
} }

View File

@@ -1,7 +1,7 @@
package routing package routing
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -87,8 +87,8 @@ func Test_IPIsPrivate(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
t.Parallel() t.Parallel()
ip := net.ParseIP(testCase.ipString) ip, err := netip.ParseAddr(testCase.ipString)
require.NotNil(t, ip) require.NoError(t, err)
isPrivate := IPIsPrivate(ip) isPrivate := IPIsPrivate(ip)
@@ -96,35 +96,3 @@ func Test_IPIsPrivate(t *testing.T) {
}) })
} }
} }
func Test_ensureNoIPv6WrappedIPv4(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
candidateIP net.IP
resultIP net.IP
}{
"nil": {},
"ipv6": {
candidateIP: net.IPv6loopback,
resultIP: net.IPv6loopback,
},
"ipv4": {
candidateIP: net.IP{1, 2, 3, 4},
resultIP: net.IP{1, 2, 3, 4},
},
"ipv6_wrapped_ipv4": {
candidateIP: net.IPv4(1, 2, 3, 4),
resultIP: net.IP{1, 2, 3, 4},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
resultIP := ensureNoIPv6WrappedIPv4(testCase.candidateIP)
assert.Equal(t, testCase.resultIP, resultIP)
})
}
}

View File

@@ -3,7 +3,6 @@ package routing
import ( import (
"errors" "errors"
"fmt" "fmt"
"net"
"net/netip" "net/netip"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
@@ -18,7 +17,7 @@ var (
type LocalNetwork struct { type LocalNetwork struct {
IPNet netip.Prefix IPNet netip.Prefix
InterfaceName string InterfaceName string
IP net.IP IP netip.Addr
} }
func (r *Routing) LocalNetworks() (localNetworks []LocalNetwork, err error) { func (r *Routing) LocalNetworks() (localNetworks []LocalNetwork, err error) {

View File

@@ -2,14 +2,13 @@ package routing
import ( import (
"fmt" "fmt"
"net"
"net/netip" "net/netip"
"strconv" "strconv"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
) )
func (r *Routing) addRouteVia(destination netip.Prefix, gateway net.IP, func (r *Routing) addRouteVia(destination netip.Prefix, gateway netip.Addr,
iface string, table int) error { iface string, table int) error {
destinationStr := destination.String() destinationStr := destination.String()
r.logger.Info("adding route for " + destinationStr) r.logger.Info("adding route for " + destinationStr)
@@ -25,7 +24,7 @@ func (r *Routing) addRouteVia(destination netip.Prefix, gateway net.IP,
route := netlink.Route{ route := netlink.Route{
Dst: NetipPrefixToIPNet(&destination), Dst: NetipPrefixToIPNet(&destination),
Gw: gateway, Gw: gateway.AsSlice(),
LinkIndex: link.Attrs().Index, LinkIndex: link.Attrs().Index,
Table: table, Table: table,
} }
@@ -37,7 +36,7 @@ func (r *Routing) addRouteVia(destination netip.Prefix, gateway net.IP,
return nil return nil
} }
func (r *Routing) deleteRouteVia(destination netip.Prefix, gateway net.IP, func (r *Routing) deleteRouteVia(destination netip.Prefix, gateway netip.Addr,
iface string, table int) (err error) { iface string, table int) (err error) {
destinationStr := destination.String() destinationStr := destination.String()
r.logger.Info("deleting route for " + destinationStr) r.logger.Info("deleting route for " + destinationStr)
@@ -53,7 +52,7 @@ func (r *Routing) deleteRouteVia(destination netip.Prefix, gateway net.IP,
route := netlink.Route{ route := netlink.Route{
Dst: NetipPrefixToIPNet(&destination), Dst: NetipPrefixToIPNet(&destination),
Gw: gateway, Gw: gateway.AsSlice(),
LinkIndex: link.Attrs().Index, LinkIndex: link.Attrs().Index,
Table: table, Table: table,
} }

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/netip"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
) )
@@ -14,10 +15,10 @@ var (
ErrVPNLocalGatewayIPNotFound = errors.New("VPN local gateway IP address not found") ErrVPNLocalGatewayIPNotFound = errors.New("VPN local gateway IP address not found")
) )
func (r *Routing) VPNDestinationIP() (ip net.IP, err error) { func (r *Routing) VPNDestinationIP() (ip netip.Addr, err error) {
routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_ALL) routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_ALL)
if err != nil { if err != nil {
return nil, fmt.Errorf("listing routes: %w", err) return ip, fmt.Errorf("listing routes: %w", err)
} }
defaultLinkIndex := -1 defaultLinkIndex := -1
@@ -28,36 +29,36 @@ func (r *Routing) VPNDestinationIP() (ip net.IP, err error) {
} }
} }
if defaultLinkIndex == -1 { if defaultLinkIndex == -1 {
return nil, fmt.Errorf("%w: in %d route(s)", ErrLinkDefaultNotFound, len(routes)) return ip, fmt.Errorf("%w: in %d route(s)", ErrLinkDefaultNotFound, len(routes))
} }
for _, route := range routes { for _, route := range routes {
if route.LinkIndex == defaultLinkIndex && if route.LinkIndex == defaultLinkIndex &&
route.Dst != nil && route.Dst != nil &&
!IPIsPrivate(route.Dst.IP) && !IPIsPrivate(netIPToNetipAddress(route.Dst.IP)) &&
bytes.Equal(route.Dst.Mask, net.IPMask{255, 255, 255, 255}) { bytes.Equal(route.Dst.Mask, net.IPMask{255, 255, 255, 255}) {
return route.Dst.IP, nil return netIPToNetipAddress(route.Dst.IP), nil
} }
} }
return nil, fmt.Errorf("%w: in %d routes", ErrVPNDestinationIPNotFound, len(routes)) return ip, fmt.Errorf("%w: in %d routes", ErrVPNDestinationIPNotFound, len(routes))
} }
func (r *Routing) VPNLocalGatewayIP(vpnIntf string) (ip net.IP, err error) { func (r *Routing) VPNLocalGatewayIP(vpnIntf string) (ip netip.Addr, err error) {
routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_ALL) routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_ALL)
if err != nil { if err != nil {
return nil, fmt.Errorf("listing routes: %w", err) return ip, fmt.Errorf("listing routes: %w", err)
} }
for _, route := range routes { for _, route := range routes {
link, err := r.netLinker.LinkByIndex(route.LinkIndex) link, err := r.netLinker.LinkByIndex(route.LinkIndex)
if err != nil { if err != nil {
return nil, fmt.Errorf("finding link at index %d: %w", route.LinkIndex, err) return ip, fmt.Errorf("finding link at index %d: %w", route.LinkIndex, err)
} }
interfaceName := link.Attrs().Name interfaceName := link.Attrs().Name
if interfaceName == vpnIntf && if interfaceName == vpnIntf &&
route.Dst != nil && route.Dst != nil &&
route.Dst.IP.Equal(net.IP{0, 0, 0, 0}) { route.Dst.IP.Equal(net.IP{0, 0, 0, 0}) {
return route.Gw, nil return netIPToNetipAddress(route.Gw), nil
} }
} }
return nil, fmt.Errorf("%w: in %d routes", ErrVPNLocalGatewayIPNotFound, len(routes)) return ip, fmt.Errorf("%w: in %d routes", ErrVPNLocalGatewayIPNotFound, len(routes))
} }

View File

@@ -1,7 +1,7 @@
package storage package storage
import ( import (
"net" "net/netip"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
@@ -12,21 +12,12 @@ func copyServer(server models.Server) (serverCopy models.Server) {
return serverCopy return serverCopy
} }
func copyIPs(toCopy []net.IP) (copied []net.IP) { func copyIPs(toCopy []netip.Addr) (copied []netip.Addr) {
if toCopy == nil { if toCopy == nil {
return nil return nil
} }
copied = make([]net.IP, len(toCopy)) copied = make([]netip.Addr, len(toCopy))
for i := range toCopy {
copied[i] = copyIP(toCopy[i])
}
return copied
}
func copyIP(toCopy net.IP) (copied net.IP) {
copied = make(net.IP, len(toCopy))
copy(copied, toCopy) copy(copied, toCopy)
return copied return copied
} }

View File

@@ -1,12 +1,11 @@
package storage package storage
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func Test_copyServer(t *testing.T) { func Test_copyServer(t *testing.T) {
@@ -14,14 +13,14 @@ func Test_copyServer(t *testing.T) {
server := models.Server{ server := models.Server{
Country: "a", Country: "a",
IPs: []net.IP{{1, 2, 3, 4}}, IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 2, 3, 4})},
} }
serverCopy := copyServer(server) serverCopy := copyServer(server)
assert.Equal(t, server, serverCopy) assert.Equal(t, server, serverCopy)
// Check for mutation // Check for mutation
serverCopy.IPs[0][0] = 9 serverCopy.IPs[0] = netip.AddrFrom4([4]byte{9, 9, 9, 9})
assert.NotEqual(t, server, serverCopy) assert.NotEqual(t, server, serverCopy)
} }
@@ -29,21 +28,21 @@ func Test_copyIPs(t *testing.T) {
t.Parallel() t.Parallel()
testCases := map[string]struct { testCases := map[string]struct {
toCopy []net.IP toCopy []netip.Addr
copied []net.IP copied []netip.Addr
}{ }{
"nil": {}, "nil": {},
"empty": { "empty": {
toCopy: []net.IP{}, toCopy: []netip.Addr{},
copied: []net.IP{}, copied: []netip.Addr{},
}, },
"single IP": { "single IP": {
toCopy: []net.IP{{1, 1, 1, 1}}, toCopy: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
copied: []net.IP{{1, 1, 1, 1}}, copied: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
}, },
"two IPs": { "two IPs": {
toCopy: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}, toCopy: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
copied: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}, copied: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
}, },
} }
@@ -52,23 +51,13 @@ func Test_copyIPs(t *testing.T) {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
t.Parallel() t.Parallel()
// Reserver leading 9 for copy modifications below
for _, ipToCopy := range testCase.toCopy {
require.NotEqual(t, 9, ipToCopy[0])
}
copied := copyIPs(testCase.toCopy) copied := copyIPs(testCase.toCopy)
assert.Equal(t, testCase.copied, copied) assert.Equal(t, testCase.copied, copied)
if len(copied) > 0 { if len(copied) > 0 {
original := testCase.toCopy[0][0] testCase.toCopy[0] = netip.AddrFrom4([4]byte{9, 9, 9, 9})
testCase.toCopy[0][0] = 9 assert.NotEqual(t, testCase.toCopy[0], testCase.copied[0])
assert.NotEqual(t, 9, copied[0][0])
testCase.toCopy[0][0] = original
copied[0][0] = 9
assert.NotEqual(t, 9, testCase.toCopy[0][0])
} }
}) })
} }

View File

@@ -3,7 +3,7 @@ package openvpn
import ( import (
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
"sort" "sort"
"strings" "strings"
) )
@@ -54,7 +54,7 @@ func ExtractHost(b []byte) (host, warning string, err error) {
return hosts[0], warning, nil return hosts[0], warning, nil
} }
func ExtractIPs(b []byte) (ips []net.IP, err error) { func ExtractIPs(b []byte) (ips []netip.Addr, err error) {
const rejectIP, rejectDomain = false, true const rejectIP, rejectDomain = false, true
ipStrings := extractRemoteHosts(b, rejectIP, rejectDomain) ipStrings := extractRemoteHosts(b, rejectIP, rejectDomain)
if len(ipStrings) == 0 { if len(ipStrings) == 0 {
@@ -65,9 +65,12 @@ func ExtractIPs(b []byte) (ips []net.IP, err error) {
return ipStrings[i] < ipStrings[j] return ipStrings[i] < ipStrings[j]
}) })
ips = make([]net.IP, len(ipStrings)) ips = make([]netip.Addr, len(ipStrings))
for i := range ipStrings { for i := range ipStrings {
ips[i] = net.ParseIP(ipStrings[i]) ips[i], err = netip.ParseAddr(ipStrings[i])
if err != nil {
return nil, fmt.Errorf("parsing IP address: %w", err)
}
} }
return ips, nil return ips, nil
@@ -85,9 +88,9 @@ func extractRemoteHosts(content []byte, rejectIP, rejectDomain bool) (hosts []st
continue continue
} }
host := fields[1] host := fields[1]
parsedIP := net.ParseIP(host) _, err := netip.ParseAddr(host)
if (rejectIP && parsedIP != nil) || if (rejectIP && err == nil) ||
(rejectDomain && parsedIP == nil) { (rejectDomain && err != nil) {
continue continue
} }
hosts = append(hosts, host) hosts = append(hosts, host)

View File

@@ -1,15 +1,20 @@
package resolver package resolver
import "net" import (
"net/netip"
)
func uniqueIPsToSlice(uniqueIPs map[string]struct{}) (ips []net.IP) { func uniqueIPsToSlice(uniqueIPs map[string]struct{}) (ips []netip.Addr) {
ips = make([]net.IP, 0, len(uniqueIPs)) ips = make([]netip.Addr, 0, len(uniqueIPs))
for key := range uniqueIPs { for key := range uniqueIPs {
IP := net.ParseIP(key) ip, err := netip.ParseAddr(key)
if IPv4 := IP.To4(); IPv4 != nil { if err != nil {
IP = IPv4 panic(err)
} }
ips = append(ips, IP) if ip.Is4In6() {
ip = netip.AddrFrom4(ip.As4())
}
ips = append(ips, ip)
} }
return ips return ips
} }

View File

@@ -1,7 +1,7 @@
package resolver package resolver
import ( import (
"net" "net/netip"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -11,23 +11,23 @@ func Test_uniqueIPsToSlice(t *testing.T) {
t.Parallel() t.Parallel()
testCases := map[string]struct { testCases := map[string]struct {
inputIPs map[string]struct{} inputIPs map[string]struct{}
outputIPs []net.IP outputIPs []netip.Addr
}{ }{
"nil": { "nil": {
inputIPs: nil, inputIPs: nil,
outputIPs: []net.IP{}, outputIPs: []netip.Addr{},
}, },
"empty": { "empty": {
inputIPs: map[string]struct{}{}, inputIPs: map[string]struct{}{},
outputIPs: []net.IP{}, outputIPs: []netip.Addr{},
}, },
"single IPv4": { "single IPv4": {
inputIPs: map[string]struct{}{"1.1.1.1": {}}, inputIPs: map[string]struct{}{"1.1.1.1": {}},
outputIPs: []net.IP{{1, 1, 1, 1}}, outputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
}, },
"two IPv4s": { "two IPv4s": {
inputIPs: map[string]struct{}{"1.1.1.1": {}, "1.1.2.1": {}}, inputIPs: map[string]struct{}{"1.1.1.1": {}, "1.1.2.1": {}},
outputIPs: []net.IP{{1, 1, 1, 1}, {1, 1, 2, 1}}, outputIPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{1, 1, 2, 1})},
}, },
} }
for name, testCase := range testCases { for name, testCase := range testCases {

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net" "net/netip"
) )
type Parallel struct { type Parallel struct {
@@ -31,7 +31,7 @@ type ParallelSettings struct {
type parallelResult struct { type parallelResult struct {
host string host string
IPs []net.IP IPs []netip.Addr
} }
var ( var (
@@ -40,7 +40,7 @@ var (
) )
func (pr *Parallel) Resolve(ctx context.Context, settings ParallelSettings) ( func (pr *Parallel) Resolve(ctx context.Context, settings ParallelSettings) (
hostToIPs map[string][]net.IP, warnings []string, err error) { hostToIPs map[string][]netip.Addr, warnings []string, err error) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@@ -53,7 +53,7 @@ func (pr *Parallel) Resolve(ctx context.Context, settings ParallelSettings) (
go pr.resolveAsync(ctx, host, settings.Repeat, results, errors) go pr.resolveAsync(ctx, host, settings.Repeat, results, errors)
} }
hostToIPs = make(map[string][]net.IP, len(settings.Hosts)) hostToIPs = make(map[string][]netip.Addr, len(settings.Hosts))
maxFails := int(settings.MaxFailRatio * float64(len(settings.Hosts))) maxFails := int(settings.MaxFailRatio * float64(len(settings.Hosts)))
for range settings.Hosts { for range settings.Hosts {

View File

@@ -1,11 +1,11 @@
package resolver package resolver
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/netip"
"sort" "sort"
"time" "time"
) )
@@ -31,7 +31,7 @@ type RepeatSettings struct {
} }
func (r *Repeat) Resolve(ctx context.Context, host string, settings RepeatSettings) ( func (r *Repeat) Resolve(ctx context.Context, host string, settings RepeatSettings) (
ips []net.IP, err error) { ips []netip.Addr, err error) {
timedCtx, cancel := context.WithTimeout(ctx, settings.MaxDuration) timedCtx, cancel := context.WithTimeout(ctx, settings.MaxDuration)
defer cancel() defer cancel()
@@ -54,7 +54,7 @@ func (r *Repeat) Resolve(ctx context.Context, host string, settings RepeatSettin
if settings.SortIPs { if settings.SortIPs {
sort.Slice(ips, func(i, j int) bool { sort.Slice(ips, func(i, j int) bool {
return bytes.Compare(ips[i], ips[j]) < 1 return ips[i].Compare(ips[j]) < 1
}) })
} }
@@ -121,15 +121,15 @@ func (r *Repeat) resolveOnce(ctx, timedCtx context.Context, host string,
} }
} }
func (r *Repeat) lookupIPs(ctx context.Context, host string) (ips []net.IP, err error) { func (r *Repeat) lookupIPs(ctx context.Context, host string) (ips []netip.Addr, err error) {
addresses, err := r.resolver.LookupIPAddr(ctx, host) addresses, err := r.resolver.LookupIPAddr(ctx, host)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ips = make([]net.IP, 0, len(addresses)) ips = make([]netip.Addr, 0, len(addresses))
for i := range addresses { for i := range addresses {
ip := addresses[i].IP ip, ok := netip.AddrFromSlice(addresses[i].IP)
if ip == nil { if !ok {
continue continue
} }
ips = append(ips, ip) ips = append(ips, ip)

View File

@@ -2,7 +2,7 @@ package vpn
import ( import (
"context" "context"
"net" "net/netip"
"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"
@@ -18,7 +18,7 @@ type Firewall interface {
} }
type Routing interface { type Routing interface {
VPNLocalGatewayIP(vpnInterface string) (gateway net.IP, err error) VPNLocalGatewayIP(vpnInterface string) (gateway netip.Addr, err error)
} }
type PortForward interface { type PortForward interface {