diff --git a/README.md b/README.md index 9c32693b..0b9e2870 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy* - Based on Alpine 3.14 for a small Docker image of 31MB - Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers - Supports OpenVPN -- Supports Wireguard for **Mullvad** and **Windscribe** (more in progress, see #134) +- Supports Wireguard for **Mullvad**, **Ivpn** and **Windscribe** (more in progress, see #134) - DNS over TLS baked in with service provider(s) of your choice - DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours - Choose the vpn network protocol, `udp` or `tcp` diff --git a/internal/configuration/ivpn.go b/internal/configuration/ivpn.go index 87bae828..09bf32e9 100644 --- a/internal/configuration/ivpn.go +++ b/internal/configuration/ivpn.go @@ -35,7 +35,12 @@ func (settings *Provider) readIvpn(r reader) (err error) { return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err) } - return settings.ServerSelection.OpenVPN.readIVPN(r.env) + err = settings.ServerSelection.OpenVPN.readIVPN(r.env) + if err != nil { + return err + } + + return settings.ServerSelection.Wireguard.readIVPN(r.env) } func (settings *OpenVPNSelection) readIVPN(env params.Interface) (err error) { @@ -52,3 +57,13 @@ func (settings *OpenVPNSelection) readIVPN(env params.Interface) (err error) { return nil } + +func (settings *WireguardSelection) readIVPN(env params.Interface) (err error) { + settings.CustomPort, err = readWireguardCustomPort(env, + []uint16{2049, 2050, 53, 30587, 41893, 48574, 58237}) + if err != nil { + return err + } + + return nil +} diff --git a/internal/configuration/ivpn_test.go b/internal/configuration/ivpn_test.go index a4d3c90b..b8c2aa98 100644 --- a/internal/configuration/ivpn_test.go +++ b/internal/configuration/ivpn_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" ) -func Test_Provider_readIvpn(t *testing.T) { +func Test_Provider_readIvpn(t *testing.T) { //nolint:gocognit t.Parallel() var errDummy = errors.New("dummy test error") @@ -23,10 +23,13 @@ func Test_Provider_readIvpn(t *testing.T) { err error } - type singleUint16Call struct { - call bool - value uint16 - err error + type portCall struct { + getCall bool + getValue string // "" or "0" + getErr error + portCall bool + portValue uint16 + portErr error } type sliceStringCall struct { @@ -42,8 +45,8 @@ func Test_Provider_readIvpn(t *testing.T) { isps sliceStringCall hostnames sliceStringCall protocol singleStringCall - portGet singleStringCall - portPort singleUint16Call + ovpnPort portCall + wgPort portCall settings Provider err error }{ @@ -92,7 +95,7 @@ func Test_Provider_readIvpn(t *testing.T) { }, err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"), }, - "protocol error": { + "openvpn protocol error": { targetIP: singleStringCall{call: true}, countries: sliceStringCall{call: true}, cities: sliceStringCall{call: true}, @@ -104,19 +107,33 @@ func Test_Provider_readIvpn(t *testing.T) { }, err: errors.New("environment variable PROTOCOL: dummy test error"), }, - "custom port error": { + "openvpn custom port error": { targetIP: singleStringCall{call: true}, countries: sliceStringCall{call: true}, cities: sliceStringCall{call: true}, isps: sliceStringCall{call: true}, hostnames: sliceStringCall{call: true}, protocol: singleStringCall{call: true}, - portGet: singleStringCall{call: true, err: errDummy}, + ovpnPort: portCall{getCall: true, getErr: errDummy}, settings: Provider{ Name: constants.Ivpn, }, err: errors.New("environment variable PORT: dummy test error"), }, + "wireguard custom port error": { + targetIP: singleStringCall{call: true}, + countries: sliceStringCall{call: true}, + cities: sliceStringCall{call: true}, + isps: sliceStringCall{call: true}, + hostnames: sliceStringCall{call: true}, + protocol: singleStringCall{call: true}, + ovpnPort: portCall{getCall: true, getValue: "0"}, + wgPort: portCall{getCall: true, getErr: errDummy}, + settings: Provider{ + Name: constants.Ivpn, + }, + err: errors.New("environment variable WIREGUARD_PORT: dummy test error"), + }, "default settings": { targetIP: singleStringCall{call: true}, countries: sliceStringCall{call: true}, @@ -124,7 +141,8 @@ func Test_Provider_readIvpn(t *testing.T) { isps: sliceStringCall{call: true}, hostnames: sliceStringCall{call: true}, protocol: singleStringCall{call: true}, - portGet: singleStringCall{call: true, value: "0"}, + ovpnPort: portCall{getCall: true, getValue: "0"}, + wgPort: portCall{getCall: true, getValue: "0"}, settings: Provider{ Name: constants.Ivpn, }, @@ -136,8 +154,8 @@ func Test_Provider_readIvpn(t *testing.T) { isps: sliceStringCall{call: true, values: []string{"ISP 1"}}, hostnames: sliceStringCall{call: true, values: []string{"E", "F"}}, protocol: singleStringCall{call: true, value: constants.TCP}, - portGet: singleStringCall{call: true}, - portPort: singleUint16Call{call: true, value: 443}, + ovpnPort: portCall{getCall: true, portCall: true, portValue: 443}, + wgPort: portCall{getCall: true, portCall: true, portValue: 2049}, settings: Provider{ Name: constants.Ivpn, ServerSelection: ServerSelection{ @@ -145,6 +163,9 @@ func Test_Provider_readIvpn(t *testing.T) { TCP: true, CustomPort: 443, }, + Wireguard: WireguardSelection{ + CustomPort: 2049, + }, TargetIP: net.IPv4(1, 2, 3, 4), Countries: []string{"A", "B"}, Cities: []string{"C", "D"}, @@ -161,6 +182,7 @@ func Test_Provider_readIvpn(t *testing.T) { ctrl := gomock.NewController(t) env := mock_params.NewMockInterface(ctrl) + if testCase.targetIP.call { env.EXPECT().Get("OPENVPN_TARGET_IP"). Return(testCase.targetIP.value, testCase.targetIP.err) @@ -185,13 +207,21 @@ func Test_Provider_readIvpn(t *testing.T) { env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()). Return(testCase.protocol.value, testCase.protocol.err) } - if testCase.portGet.call { + if testCase.ovpnPort.getCall { env.EXPECT().Get("PORT", gomock.Any()). - Return(testCase.portGet.value, testCase.portGet.err) + Return(testCase.ovpnPort.getValue, testCase.ovpnPort.getErr) } - if testCase.portPort.call { + if testCase.ovpnPort.portCall { env.EXPECT().Port("PORT"). - Return(testCase.portPort.value, testCase.portPort.err) + Return(testCase.ovpnPort.portValue, testCase.ovpnPort.portErr) + } + if testCase.wgPort.getCall { + env.EXPECT().Get("WIREGUARD_PORT", gomock.Any()). + Return(testCase.wgPort.getValue, testCase.wgPort.getErr) + } + if testCase.wgPort.portCall { + env.EXPECT().Port("WIREGUARD_PORT"). + Return(testCase.wgPort.portValue, testCase.wgPort.portErr) } r := reader{env: env} diff --git a/internal/configuration/provider.go b/internal/configuration/provider.go index f84d4735..d6a30f13 100644 --- a/internal/configuration/provider.go +++ b/internal/configuration/provider.go @@ -103,7 +103,8 @@ func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err "privado", "pia", "private internet access", "privatevpn", "protonvpn", "purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"} case constants.Wireguard: - allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe} + allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe, + constants.Ivpn} } vpnsp, err := r.env.Inside("VPNSP", allowedVPNServiceProviders, diff --git a/internal/constants/servers.json b/internal/constants/servers.json index 56460e97..09762525 100644 --- a/internal/constants/servers.json +++ b/internal/constants/servers.json @@ -25970,10 +25970,11 @@ ] }, "ivpn": { - "version": 2, - "timestamp": 1629725441, + "version": 3, + "timestamp": 1629732504, "servers": [ { + "vpn": "openvpn", "country": "Australia", "city": "Sydney", "isp": "M247", @@ -25985,6 +25986,7 @@ ] }, { + "vpn": "openvpn", "country": "Austria", "city": "Vienna", "isp": "M247", @@ -25996,6 +25998,7 @@ ] }, { + "vpn": "openvpn", "country": "Belgium", "city": "Brussels", "isp": "M247", @@ -26007,6 +26010,7 @@ ] }, { + "vpn": "openvpn", "country": "Brazil", "city": "Franca", "isp": "Qnax", @@ -26018,6 +26022,7 @@ ] }, { + "vpn": "openvpn", "country": "Bulgaria", "city": "Sofia", "isp": "M247", @@ -26029,6 +26034,7 @@ ] }, { + "vpn": "openvpn", "country": "Canada", "city": "Montreal", "isp": "M247", @@ -26040,6 +26046,20 @@ ] }, { + "vpn": "wireguard", + "country": "Canada", + "city": "Montreal", + "isp": "M247", + "hostname": "ca1.wg.ivpn.net", + "wgpubkey": "rg+GGDmjM4Vxo1hURvKmgm9yonb6qcoKbPCP/DNDBnI=", + "tcp": false, + "udp": true, + "ips": [ + "37.120.130.58" + ] + }, + { + "vpn": "openvpn", "country": "Canada", "city": "Toronto", "isp": "Amanah", @@ -26051,6 +26071,7 @@ ] }, { + "vpn": "openvpn", "country": "Canada", "city": "Toronto", "isp": "Amanah", @@ -26062,6 +26083,7 @@ ] }, { + "vpn": "openvpn", "country": "Czech Republic", "city": "Prague", "isp": "Datapacket", @@ -26073,6 +26095,7 @@ ] }, { + "vpn": "openvpn", "country": "Denmark", "city": "Copenhagen", "isp": "M247", @@ -26084,6 +26107,7 @@ ] }, { + "vpn": "openvpn", "country": "Finland", "city": "Helsinki", "isp": "Creanova", @@ -26095,6 +26119,7 @@ ] }, { + "vpn": "openvpn", "country": "France", "city": "Paris", "isp": "Datapacket", @@ -26106,6 +26131,7 @@ ] }, { + "vpn": "openvpn", "country": "Germany", "city": "Frankfurt", "isp": "Leaseweb", @@ -26117,6 +26143,20 @@ ] }, { + "vpn": "wireguard", + "country": "Germany", + "city": "Frankfurt", + "isp": "Datapacket", + "hostname": "de1.wg.ivpn.net", + "wgpubkey": "mS3/WpXjnMAMmXjSpd4nFzx9HSE3ubv2WyjpyH2REgs=", + "tcp": false, + "udp": true, + "ips": [ + "185.102.219.26" + ] + }, + { + "vpn": "openvpn", "country": "Germany", "city": "Frankfurt", "isp": "Leaseweb", @@ -26128,6 +26168,7 @@ ] }, { + "vpn": "openvpn", "country": "Hong Kong", "city": "Hong Kong", "isp": "Leaseweb", @@ -26139,6 +26180,7 @@ ] }, { + "vpn": "openvpn", "country": "Hong Kong", "city": "Hong Kong", "isp": "Leaseweb", @@ -26150,6 +26192,7 @@ ] }, { + "vpn": "openvpn", "country": "Hungary", "city": "Budapest", "isp": "M247", @@ -26161,6 +26204,7 @@ ] }, { + "vpn": "openvpn", "country": "Iceland", "city": "Reykjavik", "isp": "Advania", @@ -26172,6 +26216,7 @@ ] }, { + "vpn": "openvpn", "country": "Israel", "city": "Holon, Tel Aviv", "isp": "HQServ", @@ -26183,6 +26228,7 @@ ] }, { + "vpn": "openvpn", "country": "Italy", "city": "Milan", "isp": "SEFlow", @@ -26194,6 +26240,20 @@ ] }, { + "vpn": "wireguard", + "country": "Italy", + "city": "Milan", + "isp": "M247", + "hostname": "it1.wg.ivpn.net", + "wgpubkey": "Aj6b81yrDk7I913R+fuSW/NAmIl87N73vHgY5/WQY0Q=", + "tcp": false, + "udp": true, + "ips": [ + "82.102.21.90" + ] + }, + { + "vpn": "openvpn", "country": "Japan", "city": "Tokyo", "isp": "M247", @@ -26205,6 +26265,7 @@ ] }, { + "vpn": "openvpn", "country": "Luxembourg", "city": "Luxembourg", "isp": "Evoluso", @@ -26216,6 +26277,20 @@ ] }, { + "vpn": "wireguard", + "country": "Netherlands", + "city": "Amsterdam", + "isp": "Datapacket", + "hostname": "nl1.wg.ivpn.net", + "wgpubkey": "AsMT2FqpkZbjzWeDch6GwufF5odl259W/hIkGytVfWo=", + "tcp": false, + "udp": true, + "ips": [ + "185.102.218.104" + ] + }, + { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26227,6 +26302,7 @@ ] }, { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26238,6 +26314,7 @@ ] }, { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26249,6 +26326,7 @@ ] }, { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26260,6 +26338,7 @@ ] }, { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26271,6 +26350,7 @@ ] }, { + "vpn": "openvpn", "country": "Netherlands", "city": "Amsterdam", "isp": "Leaseweb", @@ -26282,6 +26362,7 @@ ] }, { + "vpn": "openvpn", "country": "Norway", "city": "Oslo", "isp": "Servethewrld", @@ -26293,6 +26374,7 @@ ] }, { + "vpn": "openvpn", "country": "Poland", "city": "Warsaw", "isp": "Datapacket", @@ -26304,6 +26386,7 @@ ] }, { + "vpn": "openvpn", "country": "Portugal", "city": "Lisbon", "isp": "Hostwebis", @@ -26315,6 +26398,7 @@ ] }, { + "vpn": "openvpn", "country": "Romania", "city": "Bucharest", "isp": "M247", @@ -26326,6 +26410,7 @@ ] }, { + "vpn": "openvpn", "country": "Serbia", "city": "Belgrade", "isp": "M247", @@ -26337,6 +26422,7 @@ ] }, { + "vpn": "openvpn", "country": "Singapore", "city": "Singapore", "isp": "M247", @@ -26348,6 +26434,20 @@ ] }, { + "vpn": "wireguard", + "country": "Singapore", + "city": "Singapore", + "isp": "M247", + "hostname": "sg1.wg.ivpn.net", + "wgpubkey": "hSg0At4uwuIhmTy5UT4fRbi5AN6JO2ZWTuIvqd4nHCE=", + "tcp": false, + "udp": true, + "ips": [ + "37.120.151.122" + ] + }, + { + "vpn": "openvpn", "country": "Slovakia", "city": "Bratislava", "isp": "M247", @@ -26359,6 +26459,7 @@ ] }, { + "vpn": "openvpn", "country": "Spain", "city": "Madrid", "isp": "Datapacket", @@ -26370,6 +26471,7 @@ ] }, { + "vpn": "openvpn", "country": "Sweden", "city": "Stockholm", "isp": "GleSyS", @@ -26381,6 +26483,20 @@ ] }, { + "vpn": "wireguard", + "country": "Sweden", + "city": "Stockholm", + "isp": "M247", + "hostname": "se1.wg.ivpn.net", + "wgpubkey": "2n0nFE1g/+vQr2AOQPm9Igyiy0zh9uTTultvOOSkMRo=", + "tcp": false, + "udp": true, + "ips": [ + "37.120.153.226" + ] + }, + { + "vpn": "openvpn", "country": "Switzerland", "city": "Zurich", "isp": "M247", @@ -26392,6 +26508,20 @@ ] }, { + "vpn": "wireguard", + "country": "Switzerland", + "city": "Zurich", + "isp": "Privatelayer", + "hostname": "ch1.wg.ivpn.net", + "wgpubkey": "jVZJ61i1xxkAfriDHpwvF/GDuTvZUqhwoWSjkOJvaUA=", + "tcp": false, + "udp": true, + "ips": [ + "141.255.164.66" + ] + }, + { + "vpn": "openvpn", "country": "Switzerland", "city": "Zurich", "isp": "Privatelayer", @@ -26403,6 +26533,7 @@ ] }, { + "vpn": "openvpn", "country": "Ukraine", "city": "Kharkiv", "isp": "Xservers", @@ -26414,6 +26545,7 @@ ] }, { + "vpn": "openvpn", "country": "United Kingdom", "city": "London", "isp": "Datapacket", @@ -26425,6 +26557,20 @@ ] }, { + "vpn": "wireguard", + "country": "United Kingdom", + "city": "London", + "isp": "M247", + "hostname": "gb1.wg.ivpn.net", + "wgpubkey": "7+jos+Eg+hMEOQE4Std6OJ+WVnCcmbqS1/EbPwn9w3s=", + "tcp": false, + "udp": true, + "ips": [ + "81.92.202.114" + ] + }, + { + "vpn": "openvpn", "country": "United Kingdom", "city": "London", "isp": "Datapacket", @@ -26436,6 +26582,7 @@ ] }, { + "vpn": "openvpn", "country": "United Kingdom", "city": "Manchester", "isp": "M247", @@ -26447,6 +26594,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Atlanta, GA", "isp": "Quadranet", @@ -26458,6 +26606,20 @@ ] }, { + "vpn": "wireguard", + "country": "United States", + "city": "Atlanta, GA", + "isp": "Datapacket", + "hostname": "us-ga1.wg.ivpn.net", + "wgpubkey": "jD8h+pL5/d6fmYcTzl0lR8AWzQVN5XkwRFSmM/3NcDM=", + "tcp": false, + "udp": true, + "ips": [ + "185.93.0.212" + ] + }, + { + "vpn": "openvpn", "country": "United States", "city": "Atlanta, GA", "isp": "Quadranet", @@ -26469,6 +26631,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Chicago, IL", "isp": "Quadranet", @@ -26480,6 +26643,20 @@ ] }, { + "vpn": "wireguard", + "country": "United States", + "city": "Chicago, IL", + "isp": "Datapacket", + "hostname": "us-il1.wg.ivpn.net", + "wgpubkey": "hku9gjamhoii8OvxZgx+TdUDIkOAQYFu39qbav2AyUQ=", + "tcp": false, + "udp": true, + "ips": [ + "89.187.181.116" + ] + }, + { + "vpn": "openvpn", "country": "United States", "city": "Chicago, IL", "isp": "Quadranet", @@ -26491,6 +26668,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Dallas, TX", "isp": "Quadranet", @@ -26502,6 +26680,20 @@ ] }, { + "vpn": "wireguard", + "country": "United States", + "city": "Dallas, TX", + "isp": "Quadranet", + "hostname": "us-tx1.wg.ivpn.net", + "wgpubkey": "JPT1veXLmasj2uQDstX24mpR7VWD+GmV8JDkidkz91Q=", + "tcp": false, + "udp": true, + "ips": [ + "198.55.124.114" + ] + }, + { + "vpn": "openvpn", "country": "United States", "city": "Dallas, TX", "isp": "Quadranet", @@ -26513,6 +26705,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Las Vegas, NV", "isp": "M247", @@ -26524,6 +26717,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Los Angeles, CA", "isp": "Quadranet", @@ -26535,6 +26729,20 @@ ] }, { + "vpn": "wireguard", + "country": "United States", + "city": "Los Angeles, CA", + "isp": "Datapacket", + "hostname": "us-ca1.wg.ivpn.net", + "wgpubkey": "FGl78s9Ct6xNamQ2/CtAyXwGePrrU0kiZxfM27pm8XA=", + "tcp": false, + "udp": true, + "ips": [ + "185.180.13.41" + ] + }, + { + "vpn": "openvpn", "country": "United States", "city": "Los Angeles, CA", "isp": "Quadranet", @@ -26546,6 +26754,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Los Angeles, CA", "isp": "Leaseweb", @@ -26557,6 +26766,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Los Angeles, CA", "isp": "Quadranet", @@ -26568,6 +26778,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Miami, FL", "isp": "Quadranet", @@ -26579,6 +26790,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "New Jersey, NJ", "isp": "Quadranet", @@ -26590,6 +26802,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "New Jersey, NJ", "isp": "M247", @@ -26601,6 +26814,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "New York, NY", "isp": "Leaseweb", @@ -26612,6 +26826,20 @@ ] }, { + "vpn": "wireguard", + "country": "United States", + "city": "New York, NY", + "isp": "M247", + "hostname": "us-ny1.wg.ivpn.net", + "wgpubkey": "6/tjvgb7HFl7UuvBSegolxa1zKr3iSlDrlCexCmhAGE=", + "tcp": false, + "udp": true, + "ips": [ + "91.132.137.170" + ] + }, + { + "vpn": "openvpn", "country": "United States", "city": "New York, NY", "isp": "Leaseweb", @@ -26623,6 +26851,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Phoenix, AZ", "isp": "M247", @@ -26634,6 +26863,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Salt Lake City, UT", "isp": "100TB", @@ -26645,6 +26875,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Seattle, WA", "isp": "Leaseweb", @@ -26656,6 +26887,7 @@ ] }, { + "vpn": "openvpn", "country": "United States", "city": "Washington, DC", "isp": "Leaseweb", @@ -118456,4 +118688,4 @@ } ] } -} \ No newline at end of file +} diff --git a/internal/constants/servers_test.go b/internal/constants/servers_test.go index c58a6dfc..a81dccdb 100644 --- a/internal/constants/servers_test.go +++ b/internal/constants/servers_test.go @@ -68,7 +68,7 @@ func Test_versions(t *testing.T) { "Ivpn": { model: models.IvpnServer{}, version: allServers.Ivpn.Version, - digest: "abdc2848", + digest: "88074ceb", }, "Mullvad": { model: models.MullvadServer{}, diff --git a/internal/models/server.go b/internal/models/server.go index 9b1dc673..335da83d 100644 --- a/internal/models/server.go +++ b/internal/models/server.go @@ -39,10 +39,12 @@ type IpvanishServer struct { } type IvpnServer struct { + VPN string `json:"vpn"` Country string `json:"country"` City string `json:"city"` ISP string `json:"isp"` Hostname string `json:"hostname"` + WgPubKey string `json:"wgpubkey,omitempty"` TCP bool `json:"tcp"` UDP bool `json:"udp"` IPs []net.IP `json:"ips"` diff --git a/internal/provider/ivpn/connection.go b/internal/provider/ivpn/connection.go index 849a6adb..cb65a74b 100644 --- a/internal/provider/ivpn/connection.go +++ b/internal/provider/ivpn/connection.go @@ -10,7 +10,7 @@ import ( func (i *Ivpn) GetConnection(selection configuration.ServerSelection) ( connection models.Connection, err error) { port := getPort(selection) - protocol := getProtocol(selection.OpenVPN.TCP) + protocol := getProtocol(selection) servers, err := i.filterServers(selection) if err != nil { @@ -26,6 +26,7 @@ func (i *Ivpn) GetConnection(selection configuration.ServerSelection) ( Port: port, Protocol: protocol, Hostname: server.Hostname, + PubKey: server.WgPubKey, // Wireguard only } connections = append(connections, connection) } @@ -39,19 +40,29 @@ func (i *Ivpn) GetConnection(selection configuration.ServerSelection) ( } func getPort(selection configuration.ServerSelection) (port uint16) { - customPort := selection.OpenVPN.CustomPort - if customPort > 0 { - return customPort + switch selection.VPN { + case constants.Wireguard: + customPort := selection.Wireguard.CustomPort + if customPort > 0 { + return customPort + } + const defaultPort = 58237 + return defaultPort + default: // OpenVPN + customPort := selection.OpenVPN.CustomPort + if customPort > 0 { + return customPort + } + port = 1194 + if selection.OpenVPN.TCP { + port = 443 + } + return port } - port = 1194 - if selection.OpenVPN.TCP { - port = 443 - } - return port } -func getProtocol(tcp bool) (protocol string) { - if tcp { +func getProtocol(selection configuration.ServerSelection) (protocol string) { + if selection.VPN == constants.OpenVPN && selection.OpenVPN.TCP { return constants.TCP } return constants.UDP diff --git a/internal/provider/ivpn/connection_test.go b/internal/provider/ivpn/connection_test.go index c32e7e1f..bbf634c8 100644 --- a/internal/provider/ivpn/connection_test.go +++ b/internal/provider/ivpn/connection_test.go @@ -130,6 +130,21 @@ func Test_getPort(t *testing.T) { }, port: 1234, }, + "Wireguard": { + selection: configuration.ServerSelection{ + VPN: constants.Wireguard, + }, + port: 58237, + }, + "Wireguard custom port": { + selection: configuration.ServerSelection{ + VPN: constants.Wireguard, + Wireguard: configuration.WireguardSelection{ + CustomPort: 1234, + }, + }, + port: 1234, + }, } for name, testCase := range testCases { @@ -148,16 +163,27 @@ func Test_getProtocol(t *testing.T) { t.Parallel() testCases := map[string]struct { - tcp bool - protocol string + selection configuration.ServerSelection + protocol string }{ - "UDP": { + "OpenVPN UDP": { protocol: constants.UDP, }, - "TCP": { - tcp: true, + "OpenVPN TCP": { + selection: configuration.ServerSelection{ + VPN: constants.OpenVPN, + OpenVPN: configuration.OpenVPNSelection{ + TCP: true, + }, + }, protocol: constants.TCP, }, + "Wireguard": { + selection: configuration.ServerSelection{ + VPN: constants.Wireguard, + }, + protocol: constants.UDP, + }, } for name, testCase := range testCases { @@ -165,7 +191,7 @@ func Test_getProtocol(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - protocol := getProtocol(testCase.tcp) + protocol := getProtocol(testCase.selection) assert.Equal(t, testCase.protocol, protocol) }) diff --git a/internal/provider/ivpn/filter.go b/internal/provider/ivpn/filter.go index 74e1617b..580de4bf 100644 --- a/internal/provider/ivpn/filter.go +++ b/internal/provider/ivpn/filter.go @@ -11,6 +11,7 @@ func (i *Ivpn) filterServers(selection configuration.ServerSelection) ( for _, server := range i.servers { switch { case + server.VPN != selection.VPN, utils.FilterByPossibilities(server.ISP, selection.ISPs), utils.FilterByPossibilities(server.Country, selection.Countries), utils.FilterByPossibilities(server.City, selection.Cities), diff --git a/internal/updater/providers/ivpn/api.go b/internal/updater/providers/ivpn/api.go index 3f02820f..766000be 100644 --- a/internal/updater/providers/ivpn/api.go +++ b/internal/updater/providers/ivpn/api.go @@ -26,10 +26,12 @@ type apiServer struct { Country string `json:"country"` City string `json:"city"` ISP string `json:"isp"` + WgPubKey string `json:"wg_public_key"` } type apiHostnames struct { - OpenVPN string `json:"openvpn"` + OpenVPN string `json:"openvpn"` + Wireguard string `json:"wireguard"` } func fetchAPI(ctx context.Context, client *http.Client) ( diff --git a/internal/updater/providers/ivpn/servers.go b/internal/updater/providers/ivpn/servers.go index acb18a63..596ac9fc 100644 --- a/internal/updater/providers/ivpn/servers.go +++ b/internal/updater/providers/ivpn/servers.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" + "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/updater/resolver" ) @@ -28,13 +29,15 @@ func GetServers(ctx context.Context, client *http.Client, hosts := make([]string, 0, len(data.Servers)) for _, serverData := range data.Servers { - host := serverData.Hostnames.OpenVPN - - if host == "" { - continue // Wireguard + openVPNHost := serverData.Hostnames.OpenVPN + if openVPNHost != "" { + hosts = append(hosts, openVPNHost) } - hosts = append(hosts, host) + wireguardHost := serverData.Hostnames.Wireguard + if wireguardHost != "" { + hosts = append(hosts, wireguardHost) + } } if len(hosts) < minServers { @@ -49,19 +52,27 @@ func GetServers(ctx context.Context, client *http.Client, servers = make([]models.IvpnServer, 0, len(hosts)) for _, serverData := range data.Servers { - host := serverData.Hostnames.OpenVPN - if serverData.Hostnames.OpenVPN == "" { - continue // Wireguard + vpnType := constants.OpenVPN + hostname := serverData.Hostnames.OpenVPN + tcp := true + wgPubKey := "" + if hostname == "" { + vpnType = constants.Wireguard + hostname = serverData.Hostnames.Wireguard + tcp = false + wgPubKey = serverData.WgPubKey } server := models.IvpnServer{ + VPN: vpnType, Country: serverData.Country, City: serverData.City, ISP: serverData.ISP, - Hostname: serverData.Hostnames.OpenVPN, - TCP: true, + Hostname: hostname, + WgPubKey: wgPubKey, + TCP: tcp, UDP: true, - IPs: hostToIPs[host], + IPs: hostToIPs[hostname], } servers = append(servers, server) } diff --git a/internal/updater/providers/ivpn/servers_test.go b/internal/updater/providers/ivpn/servers_test.go index 8724e6aa..64d100e9 100644 --- a/internal/updater/providers/ivpn/servers_test.go +++ b/internal/updater/providers/ivpn/servers_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/golang/mock/gomock" + "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/updater/resolver" "github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver" @@ -70,23 +71,31 @@ func Test_GetServers(t *testing.T) { minServers: 1, responseBody: `{"servers":[ {"country":"Country1","city":"City A","hostnames":{"openvpn":"hosta"}}, - {"country":"Country2","city":"City B","hostnames":{"openvpn":"hostb"}}, - {"country":"Country3","city":"City C","hostnames":{"wireguard":"hostc"}} + {"country":"Country2","city":"City B","hostnames":{"openvpn":"hostb"},"wg_public_key":"xyz"}, + {"country":"Country3","city":"City C","hostnames":{"wireguard":"hostc"},"wg_public_key":"xyz"} ]}`, responseStatus: http.StatusOK, expectResolve: true, - hostsToResolve: []string{"hosta", "hostb"}, + hostsToResolve: []string{"hosta", "hostb", "hostc"}, resolveSettings: getResolveSettings(1), hostToIPs: map[string][]net.IP{ "hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}}, "hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}}, + "hostc": {{5, 5, 5, 5}, {6, 6, 6, 6}}, }, resolveWarnings: []string{"resolve warning"}, servers: []models.IvpnServer{ - {Country: "Country1", City: "City A", Hostname: "hosta", - TCP: true, UDP: true, IPs: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}}, - {Country: "Country2", City: "City B", Hostname: "hostb", - TCP: true, UDP: true, IPs: []net.IP{{3, 3, 3, 3}, {4, 4, 4, 4}}}, + {VPN: constants.OpenVPN, Country: "Country1", + City: "City A", Hostname: "hosta", TCP: true, UDP: true, + IPs: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}}, + {VPN: constants.OpenVPN, Country: "Country2", + City: "City B", Hostname: "hostb", TCP: true, UDP: true, + IPs: []net.IP{{3, 3, 3, 3}, {4, 4, 4, 4}}}, + {VPN: constants.Wireguard, + Country: "Country3", City: "City C", + Hostname: "hostc", UDP: true, + WgPubKey: "xyz", + IPs: []net.IP{{5, 5, 5, 5}, {6, 6, 6, 6}}}, }, warnings: []string{"resolve warning"}, }, diff --git a/internal/updater/providers/ivpn/sort.go b/internal/updater/providers/ivpn/sort.go index 520510ad..179d9bb7 100644 --- a/internal/updater/providers/ivpn/sort.go +++ b/internal/updater/providers/ivpn/sort.go @@ -10,6 +10,9 @@ func sortServers(servers []models.IvpnServer) { sort.Slice(servers, func(i, j int) bool { if servers[i].Country == servers[j].Country { if servers[i].City == servers[j].City { + if servers[i].Hostname == servers[j].Hostname { + return servers[i].VPN < servers[j].VPN + } return servers[i].Hostname < servers[j].Hostname } return servers[i].City < servers[j].City