Uniformize server selection filtering

This commit is contained in:
Quentin McGaw
2020-07-23 01:46:28 +00:00
parent a5c35455d1
commit fec1249293
8 changed files with 245 additions and 184 deletions

View File

@@ -13,7 +13,7 @@ const (
func MullvadCountryChoices() (choices []string) { func MullvadCountryChoices() (choices []string) {
uniqueChoices := map[string]struct{}{} uniqueChoices := map[string]struct{}{}
for _, server := range mullvadServers() { for _, server := range MullvadServers() {
uniqueChoices[server.Country] = struct{}{} uniqueChoices[server.Country] = struct{}{}
} }
for choice := range uniqueChoices { for choice := range uniqueChoices {
@@ -27,7 +27,7 @@ func MullvadCountryChoices() (choices []string) {
func MullvadCityChoices() (choices []string) { func MullvadCityChoices() (choices []string) {
uniqueChoices := map[string]struct{}{} uniqueChoices := map[string]struct{}{}
for _, server := range mullvadServers() { for _, server := range MullvadServers() {
uniqueChoices[server.City] = struct{}{} uniqueChoices[server.City] = struct{}{}
} }
for choice := range uniqueChoices { for choice := range uniqueChoices {
@@ -41,7 +41,7 @@ func MullvadCityChoices() (choices []string) {
func MullvadISPChoices() (choices []string) { func MullvadISPChoices() (choices []string) {
uniqueChoices := map[string]struct{}{} uniqueChoices := map[string]struct{}{}
for _, server := range mullvadServers() { for _, server := range MullvadServers() {
uniqueChoices[server.ISP] = struct{}{} uniqueChoices[server.ISP] = struct{}{}
} }
for choice := range uniqueChoices { for choice := range uniqueChoices {
@@ -53,25 +53,7 @@ func MullvadISPChoices() (choices []string) {
return choices return choices
} }
func MullvadServerFilter(country, city, isp string) (servers []models.MullvadServer) { func MullvadServers() []models.MullvadServer {
for _, server := range mullvadServers() {
if len(country) == 0 {
server.Country = ""
}
if len(city) == 0 {
server.City = ""
}
if len(isp) == 0 {
server.ISP = ""
}
if server.Country == country && server.City == city && server.ISP == isp {
servers = append(servers, server)
}
}
return servers
}
func mullvadServers() []models.MullvadServer {
return []models.MullvadServer{ return []models.MullvadServer{
{ {
Country: "united arab emirates", Country: "united arab emirates",

View File

@@ -2,7 +2,6 @@ package provider
import ( import (
"fmt" "fmt"
"net"
"strings" "strings"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
@@ -16,32 +15,48 @@ func newCyberghost() *cyberghost {
return &cyberghost{} return &cyberghost{}
} }
func (c *cyberghost) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { func (c *cyberghost) filterServers(region, group string) (servers []models.CyberghostServer) {
var IPs []net.IP allServers := constants.CyberghostServers()
for _, server := range constants.CyberghostServers() { for i, server := range allServers {
if strings.EqualFold(server.Region, selection.Region) && strings.EqualFold(server.Group, selection.Group) { if len(region) == 0 {
IPs = server.IPs server.Region = ""
}
if len(group) == 0 {
server.Group = ""
}
if strings.EqualFold(server.Region, region) && strings.EqualFold(server.Group, group) {
servers = append(servers, allServers[i])
} }
} }
if len(IPs) == 0 { return servers
return nil, fmt.Errorf("no IP found for group %q and region %q", selection.Group, selection.Region) }
func (c *cyberghost) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
servers := c.filterServers(selection.Region, selection.Group)
if len(servers) == 0 {
return nil, fmt.Errorf("no server found for region %q and group %q", selection.Region, selection.Group)
} }
if selection.TargetIP != nil {
found := false for _, server := range servers {
for i := range IPs { for _, IP := range server.IPs {
if IPs[i].Equal(selection.TargetIP) { if selection.TargetIP != nil {
found = true if selection.TargetIP.Equal(IP) {
break return []models.OpenVPNConnection{{IP: IP, Port: 443, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: 443, Protocol: selection.Protocol})
} }
} }
if !found {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
}
IPs = []net.IP{selection.TargetIP}
} }
for _, IP := range IPs {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: 443, Protocol: selection.Protocol}) if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
} }
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }

View File

@@ -14,11 +14,31 @@ func newMullvad() *mullvad {
return &mullvad{} return &mullvad{}
} }
func (m *mullvad) filterServers(country, city, isp string) (servers []models.MullvadServer) {
allServers := constants.MullvadServers()
for i, server := range allServers {
if len(country) == 0 {
server.Country = ""
}
if len(city) == 0 {
server.City = ""
}
if len(isp) == 0 {
server.ISP = ""
}
if server.Country == country && server.City == city && server.ISP == isp {
servers = append(servers, allServers[i])
}
}
return servers
}
func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
servers := constants.MullvadServerFilter(selection.Country, selection.City, selection.ISP) servers := m.filterServers(selection.Country, selection.City, selection.ISP)
if len(servers) == 0 { if len(servers) == 0 {
return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", selection.Country, selection.City, selection.ISP) return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", selection.Country, selection.City, selection.ISP)
} }
for _, server := range servers { for _, server := range servers {
port := server.DefaultPort port := server.DefaultPort
if selection.CustomPort > 0 { if selection.CustomPort > 0 {
@@ -34,9 +54,15 @@ func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (conne
} }
} }
} }
if selection.TargetIP != nil { if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP) return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
} }
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }

View File

@@ -2,8 +2,6 @@ package provider
import ( import (
"fmt" "fmt"
"net"
"strings"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
@@ -16,60 +14,34 @@ func newNordvpn() *nordvpn {
return &nordvpn{} return &nordvpn{}
} }
func findServers(selection models.ServerSelection) (servers []models.NordvpnServer) { func (n *nordvpn) filterServers(region string, protocol models.NetworkProtocol, number uint16) (servers []models.NordvpnServer) {
for _, server := range constants.NordvpnServers() { allServers := constants.NordvpnServers()
if strings.EqualFold(server.Region, selection.Region) { for i, server := range allServers {
if (selection.Protocol == constants.TCP && !server.TCP) || (selection.Protocol == constants.UDP && !server.UDP) { if len(region) == 0 {
continue server.Region = ""
} }
if selection.Number > 0 && server.Number == selection.Number { if number == 0 {
return []models.NordvpnServer{server} server.Number = 0
} }
servers = append(servers, server)
if protocol == constants.TCP && !server.TCP {
continue
} else if protocol == constants.UDP && !server.UDP {
continue
}
if server.Region == region && server.Number == number {
servers = append(servers, allServers[i])
} }
} }
return servers return servers
} }
func extractIPsFromServers(servers []models.NordvpnServer) (ips []net.IP) {
ips = make([]net.IP, len(servers))
for i := range servers {
ips[i] = servers[i].IP
}
return ips
}
func targetIPInIps(targetIP net.IP, ips []net.IP) error {
for i := range ips {
if targetIP.Equal(ips[i]) {
return nil
}
}
ipsString := make([]string, len(ips))
for i := range ips {
ipsString[i] = ips[i].String()
}
return fmt.Errorf("target IP address %s not found in IP addresses %s", targetIP, strings.Join(ipsString, ", "))
}
func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
servers := findServers(selection) servers := n.filterServers(selection.Region, selection.Protocol, selection.Number)
ips := extractIPsFromServers(servers) if len(servers) == 0 {
if len(ips) == 0 { return nil, fmt.Errorf("no server found for region %q, protocol %s and number %d", selection.Region, selection.Protocol, selection.Number)
if selection.Number > 0 {
return nil, fmt.Errorf("no IP found for region %q, protocol %s and number %d", selection.Region, selection.Protocol, selection.Number)
}
return nil, fmt.Errorf("no IP found for region %q, protocol %s", selection.Region, selection.Protocol)
}
var IP net.IP
if selection.TargetIP != nil {
if err := targetIPInIps(selection.TargetIP, ips); err != nil {
return nil, err
}
IP = selection.TargetIP
} else {
IP = ips[0]
} }
var port uint16 var port uint16
switch { switch {
case selection.Protocol == constants.UDP: case selection.Protocol == constants.UDP:
@@ -79,7 +51,26 @@ func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (conne
default: default:
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol) return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
} }
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
for _, server := range servers {
if selection.TargetIP != nil {
if selection.TargetIP.Equal(server.IP) {
return []models.OpenVPNConnection{{IP: server.IP, Port: port, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: server.IP, Port: port, Protocol: selection.Protocol})
}
}
if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
}
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil
} }
func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
@@ -97,7 +88,6 @@ func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, u
"remote-cert-tls server", "remote-cert-tls server",
// Nordvpn specific // Nordvpn specific
"resolv-retry infinite",
"tun-mtu 1500", "tun-mtu 1500",
"tun-mtu-extra 32", "tun-mtu-extra 32",
"mssfix 1450", "mssfix 1450",

View File

@@ -4,7 +4,6 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"net/http" "net/http"
"strings" "strings"
@@ -24,29 +23,24 @@ func newPrivateInternetAccess() *pia {
} }
} }
func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { func (p *pia) filterServers(region string) (servers []models.PIAServer) {
var IPs []net.IP if len(region) == 0 {
return constants.PIAServers()
}
for _, server := range constants.PIAServers() { for _, server := range constants.PIAServers() {
if strings.EqualFold(server.Region, selection.Region) { if strings.EqualFold(server.Region, region) {
IPs = server.IPs return []models.PIAServer{server}
} }
} }
if len(IPs) == 0 { return nil
return nil, fmt.Errorf("no IP found for region %q", selection.Region) }
}
if selection.TargetIP != nil { func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
found := false servers := p.filterServers(selection.Region)
for i := range IPs { if len(servers) == 0 {
if IPs[i].Equal(selection.TargetIP) { return nil, fmt.Errorf("no server found for region %q", selection.Region)
found = true
break
}
}
if !found {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
}
IPs = []net.IP{selection.TargetIP}
} }
var port uint16 var port uint16
switch selection.Protocol { switch selection.Protocol {
case constants.TCP: case constants.TCP:
@@ -67,9 +61,27 @@ func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connectio
if port == 0 { if port == 0 {
return nil, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset) return nil, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset)
} }
for _, IP := range IPs {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) for _, server := range servers {
for _, IP := range server.IPs {
if selection.TargetIP != nil {
if selection.TargetIP.Equal(IP) {
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
}
}
} }
if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
}
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }

View File

@@ -2,7 +2,6 @@ package provider
import ( import (
"fmt" "fmt"
"net"
"strings" "strings"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
@@ -16,29 +15,24 @@ func newSurfshark() *surfshark {
return &surfshark{} return &surfshark{}
} }
func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl func (s *surfshark) filterServers(region string) (servers []models.SurfsharkServer) {
var IPs []net.IP if len(region) == 0 {
return constants.SurfsharkServers()
}
for _, server := range constants.SurfsharkServers() { for _, server := range constants.SurfsharkServers() {
if strings.EqualFold(server.Region, selection.Region) { if strings.EqualFold(server.Region, region) {
IPs = server.IPs return []models.SurfsharkServer{server}
} }
} }
if len(IPs) == 0 { return nil
return nil, fmt.Errorf("no IP found for region %q", selection.Region) }
}
if selection.TargetIP != nil { func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
found := false servers := s.filterServers(selection.Region)
for i := range IPs { if len(servers) == 0 {
if IPs[i].Equal(selection.TargetIP) { return nil, fmt.Errorf("no server found for region %q", selection.Region)
found = true
break
}
}
if !found {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
}
IPs = []net.IP{selection.TargetIP}
} }
var port uint16 var port uint16
switch { switch {
case selection.Protocol == constants.TCP: case selection.Protocol == constants.TCP:
@@ -48,9 +42,27 @@ func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (con
default: default:
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol) return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
} }
for _, IP := range IPs {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) for _, server := range servers {
for _, IP := range server.IPs {
if selection.TargetIP != nil {
if selection.TargetIP.Equal(IP) {
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
}
}
} }
if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
}
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }

View File

@@ -2,7 +2,6 @@ package provider
import ( import (
"fmt" "fmt"
"net"
"strings" "strings"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
@@ -16,29 +15,24 @@ func newVyprvpn() *vyprvpn {
return &vyprvpn{} return &vyprvpn{}
} }
func (s *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { func (v *vyprvpn) filterServers(region string) (servers []models.VyprvpnServer) {
var IPs []net.IP if len(region) == 0 {
return constants.VyprvpnServers()
}
for _, server := range constants.VyprvpnServers() { for _, server := range constants.VyprvpnServers() {
if strings.EqualFold(server.Region, selection.Region) { if strings.EqualFold(server.Region, region) {
IPs = server.IPs return []models.VyprvpnServer{server}
} }
} }
if len(IPs) == 0 { return nil
return nil, fmt.Errorf("no IP found for region %q", selection.Region) }
}
if selection.TargetIP != nil { func (v *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
found := false servers := v.filterServers(selection.Region)
for i := range IPs { if len(servers) == 0 {
if IPs[i].Equal(selection.TargetIP) { return nil, fmt.Errorf("no server found for region %q", selection.Region)
found = true
break
}
}
if !found {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
}
IPs = []net.IP{selection.TargetIP}
} }
var port uint16 var port uint16
switch { switch {
case selection.Protocol == constants.TCP: case selection.Protocol == constants.TCP:
@@ -48,13 +42,31 @@ func (s *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (conne
default: default:
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol) return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
} }
for _, IP := range IPs {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) for _, server := range servers {
for _, IP := range server.IPs {
if selection.TargetIP != nil {
if selection.TargetIP.Equal(IP) {
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
}
}
} }
if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
}
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }
func (s *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { func (v *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
if len(cipher) == 0 { if len(cipher) == 0 {
cipher = aes256cbc cipher = aes256cbc
} }
@@ -105,6 +117,6 @@ func (s *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, u
return lines return lines
} }
func (s *vyprvpn) GetPortForward(client network.Client) (port uint16, err error) { func (v *vyprvpn) GetPortForward(client network.Client) (port uint16, err error) {
panic("port forwarding is not supported for vyprvpn") panic("port forwarding is not supported for vyprvpn")
} }

View File

@@ -2,7 +2,6 @@ package provider
import ( import (
"fmt" "fmt"
"net"
"strings" "strings"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
@@ -16,29 +15,24 @@ func newWindscribe() *windscribe {
return &windscribe{} return &windscribe{}
} }
func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { func (w *windscribe) filterServers(region string) (servers []models.WindscribeServer) {
var IPs []net.IP if len(region) == 0 {
return constants.WindscribeServers()
}
for _, server := range constants.WindscribeServers() { for _, server := range constants.WindscribeServers() {
if strings.EqualFold(server.Region, selection.Region) { if strings.EqualFold(server.Region, region) {
IPs = server.IPs return []models.WindscribeServer{server}
} }
} }
if len(IPs) == 0 { return nil
return nil, fmt.Errorf("no IP found for region %q", selection.Region) }
}
if selection.TargetIP != nil { func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
found := false servers := w.filterServers(selection.Region)
for i := range IPs { if len(servers) == 0 {
if IPs[i].Equal(selection.TargetIP) { return nil, fmt.Errorf("no server found for region %q", selection.Region)
found = true
break
}
}
if !found {
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
}
IPs = []net.IP{selection.TargetIP}
} }
var port uint16 var port uint16
switch { switch {
case selection.CustomPort > 0: case selection.CustomPort > 0:
@@ -50,9 +44,27 @@ func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (co
default: default:
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol) return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
} }
for _, IP := range IPs {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol}) for _, server := range servers {
for _, IP := range server.IPs {
if selection.TargetIP != nil {
if selection.TargetIP.Equal(IP) {
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
}
} else {
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
}
}
} }
if selection.TargetIP != nil {
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
}
if len(connections) > 64 {
connections = connections[:64]
}
return connections, nil return connections, nil
} }