From d8326d6fe871a3bc6f8614522a3f1b29975b0f60 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 7 Jun 2022 14:03:03 +0200 Subject: [PATCH 001/581] feat(settings): parse ports in VPNServerList.swift --- IVPNClient/Models/VPNServerList.swift | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/IVPNClient/Models/VPNServerList.swift b/IVPNClient/Models/VPNServerList.swift index 0328e880d..20e34ba57 100644 --- a/IVPNClient/Models/VPNServerList.swift +++ b/IVPNClient/Models/VPNServerList.swift @@ -31,6 +31,7 @@ class VPNServerList { // MARK: - Properties - open private(set) var servers: [VPNServer] + open private(set) var ports: [ConnectionSettings] var filteredFastestServers: [VPNServer] { var serversArray = getServers() @@ -84,6 +85,7 @@ class VPNServerList { // and optionally save it to the cache file for later access init(withJSONData data: Data?, storeInCache: Bool = false) { servers = [VPNServer]() + ports = [ConnectionSettings]() if let jsonData = data { var serversList: [[String: Any]]? @@ -140,6 +142,27 @@ class VPNServerList { UserDefaults.shared.set(ips, forKey: UserDefaults.Key.ipv6HostNames) } } + + if let portsObj = config["ports"] as? [String: Any] { + ports.append(ConnectionSettings.ipsec) + + if let openvpn = portsObj["openvpn"] as? [[String: Any]] { + for port in openvpn { + let portNumber = port["port"] as? Int ?? 0 + if port["type"] as? String == "TCP" { + ports.append(ConnectionSettings.openvpn(.tcp, portNumber)) + } else { + ports.append(ConnectionSettings.openvpn(.udp, portNumber)) + } + } + } + if let openvpn = portsObj["wireguard"] as? [[String: Any]] { + for port in openvpn { + let portNumber = port["port"] as? Int ?? 0 + ports.append(ConnectionSettings.wireguard(.udp, portNumber)) + } + } + } } } } From 96159f08bab3a8966d6a13dcffb744179b101b45 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 7 Jun 2022 14:42:36 +0200 Subject: [PATCH 002/581] refactor: update getSavedProtocol method in ConnectionSettings.swift --- IVPNClient/Enums/ConnectionSettings.swift | 33 ++++++++++++++++--- IVPNClient/Models/Settings.swift | 4 --- .../Extensions/UserDefaults+Ext.swift | 2 -- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/IVPNClient/Enums/ConnectionSettings.swift b/IVPNClient/Enums/ConnectionSettings.swift index 401f7b7a7..fad6859eb 100644 --- a/IVPNClient/Enums/ConnectionSettings.swift +++ b/IVPNClient/Enums/ConnectionSettings.swift @@ -146,11 +146,36 @@ enum ConnectionSettings { } static func getSavedProtocol() -> ConnectionSettings { - let protocolIndex = UserDefaults.standard.integer(forKey: UserDefaults.Key.selectedProtocolIndex) + var name = "" + var proto = "" + var port = 0 + let components = UserDefaults.standard.string(forKey: UserDefaults.Key.selectedProtocol)?.components(separatedBy: "-") - if Config.supportedProtocols.indices.contains(protocolIndex) && UserDefaults.standard.object(forKey: UserDefaults.Key.selectedProtocolIndex) != nil || !(KeyChain.sessionToken ?? "").isEmpty { - return Config.supportedProtocols[protocolIndex] - } else { + if let protocolName = components?[0] { + name = protocolName + } + if let protocolProto = components?[1] { + proto = protocolProto + } + if let protocolPort = components?[2] { + port = Int(protocolPort) ?? 0 + } + + switch name { + case "ikev2": + return .ipsec + case "openvpn": + switch proto { + case "tcp": + return .openvpn(.tcp, port) + case "udp": + return .openvpn(.udp, port) + default: + return Config.defaultProtocol + } + case "wireguard": + return .wireguard(.udp, port) + default: return Config.defaultProtocol } } diff --git a/IVPNClient/Models/Settings.swift b/IVPNClient/Models/Settings.swift index 22e2f0077..16b83783a 100644 --- a/IVPNClient/Models/Settings.swift +++ b/IVPNClient/Models/Settings.swift @@ -118,10 +118,6 @@ class Settings { } func saveConnectionProtocol() { - if let index = Config.supportedProtocols.firstIndex(where: {$0 == connectionProtocol}) { - UserDefaults.standard.set(index, forKey: UserDefaults.Key.selectedProtocolIndex) - } - UserDefaults.standard.set(connectionProtocol.formatSave(), forKey: UserDefaults.Key.selectedProtocol) } diff --git a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift index 7e444e231..a87393cca 100644 --- a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift @@ -60,7 +60,6 @@ extension UserDefaults { static let keepAlive = "keepAlive" static let serversSort = "serversSort" static let notAskToReconnect = "notAskToReconnect" - static let selectedProtocolIndex = "selectedProtocolIndex" static let selectedProtocol = "selectedProtocol" static let resolvedDNSInsideVPN = "resolvedDNSInsideVPN" static let resolvedDNSOutsideVPN = "resolvedDNSOutsideVPN" @@ -240,7 +239,6 @@ extension UserDefaults { standard.removeObject(forKey: Key.selectedServerFastest) standard.removeObject(forKey: Key.fastestServerConfigured) standard.removeObject(forKey: Key.showIPv4Servers) - standard.removeObject(forKey: Key.selectedProtocolIndex) standard.removeObject(forKey: Key.selectedProtocol) standard.synchronize() } From a1c79f48439089db4f5ce02452d933e8d6deb02b Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 7 Jun 2022 14:43:37 +0200 Subject: [PATCH 003/581] refactor: update supportedProtocolsFormat method --- IVPNClient/Enums/ConnectionSettings.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IVPNClient/Enums/ConnectionSettings.swift b/IVPNClient/Enums/ConnectionSettings.swift index fad6859eb..c58a78020 100644 --- a/IVPNClient/Enums/ConnectionSettings.swift +++ b/IVPNClient/Enums/ConnectionSettings.swift @@ -137,7 +137,7 @@ enum ConnectionSettings { } func supportedProtocolsFormat(protocols: [ConnectionSettings]) -> [String] { - let protocols = supportedProtocols(protocols: Config.supportedProtocols) + let protocols = supportedProtocols(protocols: protocols) return protocols.map({ $0.formatProtocol() }) } From e2c5fb77db6d00db5aeee7c4f348af244ecdd7f8 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 7 Jun 2022 21:28:24 +0200 Subject: [PATCH 004/581] refactor: update getSavedProtocol method --- IVPNClient/Enums/ConnectionSettings.swift | 6 +++--- .../Scenes/ViewControllers/ProtocolViewController.swift | 5 +++-- IVPNClient/Utilities/Extensions/Array+Ext.swift | 8 ++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/IVPNClient/Enums/ConnectionSettings.swift b/IVPNClient/Enums/ConnectionSettings.swift index c58a78020..ea9723f61 100644 --- a/IVPNClient/Enums/ConnectionSettings.swift +++ b/IVPNClient/Enums/ConnectionSettings.swift @@ -151,13 +151,13 @@ enum ConnectionSettings { var port = 0 let components = UserDefaults.standard.string(forKey: UserDefaults.Key.selectedProtocol)?.components(separatedBy: "-") - if let protocolName = components?[0] { + if let protocolName = components?[safeIndex: 0] { name = protocolName } - if let protocolProto = components?[1] { + if let protocolProto = components?[safeIndex: 1] { proto = protocolProto } - if let protocolPort = components?[2] { + if let protocolPort = components?[safeIndex: 2] { port = Int(protocolPort) ?? 0 } diff --git a/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift b/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift index b76622fe3..eeb513cad 100644 --- a/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift @@ -138,9 +138,10 @@ class ProtocolViewController: UITableViewController { } func selectPreferredProtocolAndPort(connectionProtocol: ConnectionSettings) { + let ports = Application.shared.serverList.ports let selected = Application.shared.settings.connectionProtocol.formatProtocol() - let protocols = connectionProtocol.supportedProtocols(protocols: Config.supportedProtocols) - let actions = connectionProtocol.supportedProtocolsFormat(protocols: Config.supportedProtocols) + let protocols = connectionProtocol.supportedProtocols(protocols: ports) + let actions = connectionProtocol.supportedProtocolsFormat(protocols: ports) showActionSheet(image: nil, selected: selected, largeText: true, centered: true, title: "Preferred protocol & port", actions: actions, sourceView: view) { [self] index in guard index > -1 else { diff --git a/IVPNClient/Utilities/Extensions/Array+Ext.swift b/IVPNClient/Utilities/Extensions/Array+Ext.swift index 8fee669ec..3f1602a93 100644 --- a/IVPNClient/Utilities/Extensions/Array+Ext.swift +++ b/IVPNClient/Utilities/Extensions/Array+Ext.swift @@ -42,4 +42,12 @@ extension Array where Element: Equatable { insert(remove(at: index), at: newIndex) } + public subscript(safeIndex index: Int) -> Element? { + guard index >= 0, index < endIndex else { + return nil + } + + return self[index] + } + } From e18041c6c66ec861b7796328ca465e3b62c3c264 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 8 Jun 2022 09:09:00 +0200 Subject: [PATCH 005/581] refactor: update formatMultiHop method --- IVPNClient/Enums/ConnectionSettings.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IVPNClient/Enums/ConnectionSettings.swift b/IVPNClient/Enums/ConnectionSettings.swift index ea9723f61..7410b3d2a 100644 --- a/IVPNClient/Enums/ConnectionSettings.swift +++ b/IVPNClient/Enums/ConnectionSettings.swift @@ -56,7 +56,7 @@ enum ConnectionSettings { case .udp: return "OpenVPN, UDP" } - case .wireguard(_, _): + case .wireguard: return "WireGuard, UDP" } } From c19435942fab1cb180b3dc9026157da68cd5e3ad Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 8 Jun 2022 09:15:43 +0200 Subject: [PATCH 006/581] refactor: remove supportedProtocols in Config.swift --- IVPNClient/Config/Config.swift | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/IVPNClient/Config/Config.swift b/IVPNClient/Config/Config.swift index a3fd10fbd..3548fd594 100644 --- a/IVPNClient/Config/Config.swift +++ b/IVPNClient/Config/Config.swift @@ -65,29 +65,6 @@ struct Config { static let stableVPNStatusInterval: TimeInterval = 0.5 static let defaultProtocol = ConnectionSettings.wireguard(.udp, 2049) - static let supportedProtocols = [ - ConnectionSettings.ipsec, - ConnectionSettings.openvpn(.udp, 2049), - ConnectionSettings.openvpn(.udp, 2050), - ConnectionSettings.openvpn(.udp, 53), - // ConnectionSettings.openvpn(.udp, 80), - // ConnectionSettings.openvpn(.udp, 443), - ConnectionSettings.openvpn(.udp, 1194), - ConnectionSettings.openvpn(.tcp, 443), - ConnectionSettings.openvpn(.tcp, 1443), - ConnectionSettings.openvpn(.tcp, 80), - ConnectionSettings.wireguard(.udp, 2049), - ConnectionSettings.wireguard(.udp, 2050), - ConnectionSettings.wireguard(.udp, 53), - // ConnectionSettings.wireguard(.udp, 80), - // ConnectionSettings.wireguard(.udp, 443), - ConnectionSettings.wireguard(.udp, 1194), - ConnectionSettings.wireguard(.udp, 30587), - ConnectionSettings.wireguard(.udp, 41893), - ConnectionSettings.wireguard(.udp, 48574), - ConnectionSettings.wireguard(.udp, 58237) - ] - static let supportedProtocolTypes = [ ConnectionSettings.wireguard(.udp, 2049), ConnectionSettings.ipsec, From c8e277d08688e36bbd92639209d871a0e742e760 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 29 Jun 2022 22:00:19 +0200 Subject: [PATCH 007/581] feat(settings): parse port as string in VPNServerList.swift --- IVPNClient/Models/VPNServerList.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IVPNClient/Models/VPNServerList.swift b/IVPNClient/Models/VPNServerList.swift index 20e34ba57..4b8a24228 100644 --- a/IVPNClient/Models/VPNServerList.swift +++ b/IVPNClient/Models/VPNServerList.swift @@ -148,11 +148,11 @@ class VPNServerList { if let openvpn = portsObj["openvpn"] as? [[String: Any]] { for port in openvpn { - let portNumber = port["port"] as? Int ?? 0 + let portNumber = port["port"] as? String ?? "0" if port["type"] as? String == "TCP" { - ports.append(ConnectionSettings.openvpn(.tcp, portNumber)) + ports.append(ConnectionSettings.openvpn(.tcp, Int(portNumber) ?? 0)) } else { - ports.append(ConnectionSettings.openvpn(.udp, portNumber)) + ports.append(ConnectionSettings.openvpn(.udp, Int(portNumber) ?? 0)) } } } From 8c2acd7b13f96907c24f2ed7d57a5ecb1260e1c2 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Thu, 30 Jun 2022 10:35:40 +0200 Subject: [PATCH 008/581] feat(settings): update port information in VPNServerList.swift --- IVPNClient/Models/VPNServerList.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IVPNClient/Models/VPNServerList.swift b/IVPNClient/Models/VPNServerList.swift index 4b8a24228..20e34ba57 100644 --- a/IVPNClient/Models/VPNServerList.swift +++ b/IVPNClient/Models/VPNServerList.swift @@ -148,11 +148,11 @@ class VPNServerList { if let openvpn = portsObj["openvpn"] as? [[String: Any]] { for port in openvpn { - let portNumber = port["port"] as? String ?? "0" + let portNumber = port["port"] as? Int ?? 0 if port["type"] as? String == "TCP" { - ports.append(ConnectionSettings.openvpn(.tcp, Int(portNumber) ?? 0)) + ports.append(ConnectionSettings.openvpn(.tcp, portNumber)) } else { - ports.append(ConnectionSettings.openvpn(.udp, Int(portNumber) ?? 0)) + ports.append(ConnectionSettings.openvpn(.udp, portNumber)) } } } From 93c9a201ac84be399185f1a7eb178de5afe7452a Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 6 Jul 2022 11:43:43 +0200 Subject: [PATCH 009/581] feat(settings): update parsing ports in VPNServerList --- IVPNClient/Models/VPNServerList.swift | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/IVPNClient/Models/VPNServerList.swift b/IVPNClient/Models/VPNServerList.swift index 20e34ba57..1a7f79a52 100644 --- a/IVPNClient/Models/VPNServerList.swift +++ b/IVPNClient/Models/VPNServerList.swift @@ -148,18 +148,20 @@ class VPNServerList { if let openvpn = portsObj["openvpn"] as? [[String: Any]] { for port in openvpn { - let portNumber = port["port"] as? Int ?? 0 - if port["type"] as? String == "TCP" { - ports.append(ConnectionSettings.openvpn(.tcp, portNumber)) - } else { - ports.append(ConnectionSettings.openvpn(.udp, portNumber)) + if let portNumber = port["port"] as? Int { + if port["type"] as? String == "TCP" { + ports.append(ConnectionSettings.openvpn(.tcp, portNumber)) + } else { + ports.append(ConnectionSettings.openvpn(.udp, portNumber)) + } } } } if let openvpn = portsObj["wireguard"] as? [[String: Any]] { for port in openvpn { - let portNumber = port["port"] as? Int ?? 0 - ports.append(ConnectionSettings.wireguard(.udp, portNumber)) + if let portNumber = port["port"] as? Int { + ports.append(ConnectionSettings.wireguard(.udp, portNumber)) + } } } } From 8ddc923f852ba6b014997874b2728a7bf1a20fd3 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Mon, 11 Jul 2022 16:36:02 +0200 Subject: [PATCH 010/581] feat(settings): create PortViewController.swift --- IVPNClient.xcodeproj/project.pbxproj | 8 ++++ .../ViewControllers/PortViewController.swift | 44 +++++++++++++++++++ IVPNClient/ViewModels/PortViewModel.swift | 28 ++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 IVPNClient/Scenes/ViewControllers/PortViewController.swift create mode 100644 IVPNClient/ViewModels/PortViewModel.swift diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index fa2e33aa8..33808367e 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -39,6 +39,8 @@ 821429BB22FC36100056B8FF /* ApiRequestDI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821429BA22FC36100056B8FF /* ApiRequestDI.swift */; }; 821AFA1323602B71001EF617 /* SettingsScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821AFA1223602B71001EF617 /* SettingsScreenTests.swift */; }; 821BDE02224A6EC700F592BF /* AppKeyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821BDE01224A6EC700F592BF /* AppKeyManagerTests.swift */; }; + 821CA2D7287C5AB20067F70D /* PortViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821CA2D6287C5AB20067F70D /* PortViewController.swift */; }; + 821CA2D9287C6A820067F70D /* PortViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821CA2D8287C6A820067F70D /* PortViewModel.swift */; }; 821F1C7E21FF544200107311 /* VPNServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821F1C7D21FF544200107311 /* VPNServerViewModel.swift */; }; 821F604A240D21E3008072D7 /* ControlPanelViewController+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821F6049240D21E3008072D7 /* ControlPanelViewController+Ext.swift */; }; 8221377B2227E75E001E1BF5 /* CustomDNSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8221377A2227E75E001E1BF5 /* CustomDNSViewController.swift */; }; @@ -436,6 +438,8 @@ 821429BA22FC36100056B8FF /* ApiRequestDI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiRequestDI.swift; sourceTree = ""; }; 821AFA1223602B71001EF617 /* SettingsScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenTests.swift; sourceTree = ""; }; 821BDE01224A6EC700F592BF /* AppKeyManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppKeyManagerTests.swift; sourceTree = ""; }; + 821CA2D6287C5AB20067F70D /* PortViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortViewController.swift; sourceTree = ""; }; + 821CA2D8287C6A820067F70D /* PortViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortViewModel.swift; sourceTree = ""; }; 821F1C7D21FF544200107311 /* VPNServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNServerViewModel.swift; sourceTree = ""; }; 821F6049240D21E3008072D7 /* ControlPanelViewController+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ControlPanelViewController+Ext.swift"; sourceTree = ""; }; 8221377A2227E75E001E1BF5 /* CustomDNSViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDNSViewController.swift; sourceTree = ""; }; @@ -850,6 +854,7 @@ 824BC465240906ED00A61B29 /* VPNStatusViewModel.swift */, 8270D267241BB3D000B17B65 /* InfoAlertViewModel.swift */, 826E6149242A1CA80064F195 /* AccountViewModel.swift */, + 821CA2D8287C6A820067F70D /* PortViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -1187,6 +1192,7 @@ 8269CAC22264962F00CF488A /* AntiTrackerViewController.swift */, 82F917382344861A0025ED3A /* TermsOfServiceViewController.swift */, 8201A5032356536B008C83DB /* UpgradePlanViewController.swift */, + 821CA2D6287C5AB20067F70D /* PortViewController.swift */, ); path = ViewControllers; sourceTree = ""; @@ -2251,6 +2257,7 @@ 9CB2CE411DB2594A007A4D2D /* VPNServerList.swift in Sources */, 823FFB072338DF1800F91A5D /* Capability.swift in Sources */, 82061F65238D2730009DDF4D /* Ping.swift in Sources */, + 821CA2D9287C6A820067F70D /* PortViewModel.swift in Sources */, 82AAF0E92253A4A8005E792F /* StaticWebViewController.swift in Sources */, 8282482A225C7312001314F8 /* WireGuardRegenerationRateCell.swift in Sources */, 824777EA21A6BC3A001EEFAF /* Network+CoreDataProperties.swift in Sources */, @@ -2299,6 +2306,7 @@ 82AA8818231E330A00E18ECB /* SessionStatus.swift in Sources */, 9C28337E1D9D3F060024C553 /* Config.swift in Sources */, 82DAB37F2457260000302F4C /* ServiceTableViewCell.swift in Sources */, + 821CA2D7287C5AB20067F70D /* PortViewController.swift in Sources */, 82061F66238D2730009DDF4D /* ICMPHeader.swift in Sources */, 826F7F0C23A79F1500777DB9 /* UserDefaultsTodayExtension+Ext.swift in Sources */, 824BC466240906ED00A61B29 /* VPNStatusViewModel.swift in Sources */, diff --git a/IVPNClient/Scenes/ViewControllers/PortViewController.swift b/IVPNClient/Scenes/ViewControllers/PortViewController.swift new file mode 100644 index 000000000..bd6b68547 --- /dev/null +++ b/IVPNClient/Scenes/ViewControllers/PortViewController.swift @@ -0,0 +1,44 @@ +// +// PortViewController.swift +// IVPN iOS app +// https://github.com/ivpn/ios-app +// +// Created by Juraj Hilje on 2022-07-11. +// Copyright (c) 2022 Privatus Limited. +// +// This file is part of the IVPN iOS app. +// +// The IVPN iOS app is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// The IVPN iOS app is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License +// along with the IVPN iOS app. If not, see . +// + +import UIKit + +class PortViewController: UITableViewController { + + // MARK: - Properties - + + var viewModel = PortViewModel() + var ports = [ConnectionSettings]() + var connectionProtocol = ConnectionSettings.wireguard(.udp, 0) { + didSet { + + } + } + + // MARK: - View Lifecycle - + + override func viewDidLoad() { + super.viewDidLoad() + } + +} diff --git a/IVPNClient/ViewModels/PortViewModel.swift b/IVPNClient/ViewModels/PortViewModel.swift new file mode 100644 index 000000000..fa9fa3b2a --- /dev/null +++ b/IVPNClient/ViewModels/PortViewModel.swift @@ -0,0 +1,28 @@ +// +// PortViewModel.swift +// IVPN iOS app +// https://github.com/ivpn/ios-app +// +// Created by Juraj Hilje on 2022-07-11. +// Copyright (c) 2022 Privatus Limited. +// +// This file is part of the IVPN iOS app. +// +// The IVPN iOS app is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// The IVPN iOS app is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License +// along with the IVPN iOS app. If not, see . +// + +import Foundation + +struct PortViewModel { + +} From b2cbcd49cf94794ea871ba1fac417358c117e3c8 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Mon, 11 Jul 2022 17:02:46 +0200 Subject: [PATCH 011/581] feat(settings): update PortViewController.swift --- .../ViewControllers/PortViewController.swift | 55 ++++++++++++++++++- .../ProtocolViewController.swift | 12 +++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/IVPNClient/Scenes/ViewControllers/PortViewController.swift b/IVPNClient/Scenes/ViewControllers/PortViewController.swift index bd6b68547..7fbc0f71c 100644 --- a/IVPNClient/Scenes/ViewControllers/PortViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/PortViewController.swift @@ -28,10 +28,10 @@ class PortViewController: UITableViewController { // MARK: - Properties - var viewModel = PortViewModel() - var ports = [ConnectionSettings]() - var connectionProtocol = ConnectionSettings.wireguard(.udp, 0) { + var collection = [ConnectionSettings]() + var selectedPort = ConnectionSettings.wireguard(.udp, 0) { didSet { - + collection = selectedPort.supportedProtocols(protocols: Application.shared.serverList.ports) } } @@ -42,3 +42,52 @@ class PortViewController: UITableViewController { } } + +// MARK: - UITableViewDataSource - + +extension PortViewController { + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return collection.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath) + + if collection[indexPath.row] == selectedPort { + cell.accessoryType = .checkmark + } else { + cell.accessoryType = .none + } + + return cell + } + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + switch section { + case 0: + return "Select port" + default: + return "" + } + } + +} + +// MARK: - UITableViewDelegate - + +extension PortViewController { + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + selectedPort = collection[indexPath.row] + tableView.reloadData() + Application.shared.settings.connectionProtocol = selectedPort + NotificationCenter.default.post(name: Notification.Name.ProtocolSelected, object: nil) + navigationController?.popViewController(animated: true) + } + +} diff --git a/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift b/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift index eeb513cad..ce0fd9d02 100644 --- a/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/ProtocolViewController.swift @@ -41,6 +41,7 @@ class ProtocolViewController: UITableViewController { keyManager.delegate = self updateCollection(connectionProtocol: Application.shared.settings.connectionProtocol) initNavigationBar() + addObservers() } override func viewWillAppear(_ animated: Bool) { @@ -48,6 +49,12 @@ class ProtocolViewController: UITableViewController { tableView.reloadData() } + // MARK: - Observers - + + private func addObservers() { + NotificationCenter.default.addObserver(self, selector: #selector(protocolSelected), name: Notification.Name.ProtocolSelected, object: nil) + } + // MARK: - Methods - private func initNavigationBar() { @@ -168,10 +175,13 @@ class ProtocolViewController: UITableViewController { Application.shared.settings.connectionProtocol = protocols[index] tableView.reloadData() NotificationCenter.default.post(name: Notification.Name.ProtocolSelected, object: nil) - evaluateReconnect(sender: view) } } + @objc private func protocolSelected() { + evaluateReconnect(sender: view) + } + } // MARK: - UITableViewDataSource - From be6b1ace5f49a5015e94b57c84d7b034632e6a7b Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Mon, 11 Jul 2022 20:40:04 +0200 Subject: [PATCH 012/581] feat(settings): create PortViewController UI --- IVPNClient/Scenes/Base.lproj/Main.storyboard | 56 ++++++++++++++----- .../ViewControllers/PortViewController.swift | 41 +++++++++++--- .../ProtocolViewController.swift | 30 +++++----- .../WireGuardSettingsViewController.swift | 2 +- 4 files changed, 94 insertions(+), 35 deletions(-) diff --git a/IVPNClient/Scenes/Base.lproj/Main.storyboard b/IVPNClient/Scenes/Base.lproj/Main.storyboard index 9e6cffb9c..1a466e32e 100644 --- a/IVPNClient/Scenes/Base.lproj/Main.storyboard +++ b/IVPNClient/Scenes/Base.lproj/Main.storyboard @@ -21,7 +21,7 @@ - + - + @@ -1051,14 +1051,14 @@ - + - + - + - + @@ -2252,7 +2384,7 @@ - + - + - + - + - + @@ -2340,7 +2472,7 @@ - + @@ -2360,7 +2492,7 @@ - + @@ -2433,14 +2565,14 @@ - + - + - + @@ -2460,7 +2592,7 @@ - + - + - + - + - + @@ -2825,7 +2957,7 @@ - + @@ -3006,7 +3138,7 @@ - + @@ -3214,7 +3346,7 @@ - + @@ -3239,7 +3371,7 @@ - + @@ -3275,7 +3407,7 @@ - + @@ -3308,7 +3440,7 @@ - + @@ -3344,7 +3476,7 @@ - + @@ -3380,7 +3512,7 @@ - + @@ -3492,7 +3624,7 @@ Hardcore mode blocks the leading companies with business models relying on user surveillance (currently: Google and Facebook). Learn more - + @@ -3624,21 +3756,21 @@ - + - + @@ -1573,14 +1585,14 @@ - + - + - + @@ -2222,13 +2234,13 @@ - + + @@ -2234,13 +2243,13 @@ - @@ -4190,6 +4199,7 @@ + diff --git a/IVPNClient/Scenes/TableCells/ServerTableViewCell.swift b/IVPNClient/Scenes/TableCells/ServerTableViewCell.swift index 8240024a9..f03b0c104 100644 --- a/IVPNClient/Scenes/TableCells/ServerTableViewCell.swift +++ b/IVPNClient/Scenes/TableCells/ServerTableViewCell.swift @@ -28,11 +28,13 @@ class ServerTableViewCell: UITableViewCell { @IBOutlet weak var flagImage: FlagImageView! @IBOutlet weak var serverLeftConstraint: NSLayoutConstraint! @IBOutlet weak var serverName: UILabel! + @IBOutlet weak var countryLabel: UILabel! @IBOutlet weak var pingImage: UIImageView! @IBOutlet weak var pingTimeMs: UILabel! @IBOutlet weak var configureButton: UIButton! @IBOutlet weak var ipv6Label: UILabel! @IBOutlet weak var expandButton: UIButton! + @IBOutlet weak var favoriteButton: UIButton! var viewModel: VPNServerViewModel! { didSet { @@ -84,11 +86,16 @@ class ServerTableViewCell: UITableViewCell { var isMultiHop: Bool! + // MARK: - IBActions - + + @IBAction func toggleFavorite(_ sender: UIButton) { + sender.setImage(UIImage.init(named: "icon-star-on"), for: .normal) + } + // MARK: - Methods - private func setCellAppearance() { flagImage.updateUpFlagIcon() - serverName.sizeToFit() ipv6Label.isHidden = !viewModel.showIPv6Label expandButton.tintColor = UIColor.init(named: Theme.ivpnGray6) } @@ -100,6 +107,8 @@ class ServerTableViewCell: UITableViewCell { configureButton.isHidden = false configureButton.isUserInteractionEnabled = true expandButton.isHidden = true + favoriteButton.isHidden = true + countryLabel.isHidden = true } private func setRandomServerCell() { @@ -109,6 +118,8 @@ class ServerTableViewCell: UITableViewCell { configureButton.isHidden = true configureButton.isUserInteractionEnabled = true expandButton.isHidden = true + favoriteButton.isHidden = true + countryLabel.isHidden = true } private func setGatewayServerCell() { @@ -116,9 +127,12 @@ class ServerTableViewCell: UITableViewCell { flagImage.image = viewModel.imageForCountryCode flagImage.image?.accessibilityIdentifier = "" serverName.text = viewModel.formattedServerName(sort: sort) + countryLabel.text = viewModel.server.country configureButton.isHidden = true configureButton.isUserInteractionEnabled = false expandButton.isHidden = !UserDefaults.shared.selectHost + favoriteButton.isHidden = false + countryLabel.isHidden = false } private func setHostServerCell() { @@ -128,6 +142,8 @@ class ServerTableViewCell: UITableViewCell { flagImage.image = nil flagImage.image?.accessibilityIdentifier = "" expandButton.isHidden = true + favoriteButton.isHidden = false + countryLabel.isHidden = true } private func setPingTime() { diff --git a/IVPNClient/ViewModels/VPNServerViewModel.swift b/IVPNClient/ViewModels/VPNServerViewModel.swift index c3b1856f6..ff425eac4 100644 --- a/IVPNClient/ViewModels/VPNServerViewModel.swift +++ b/IVPNClient/ViewModels/VPNServerViewModel.swift @@ -143,7 +143,7 @@ struct VPNServerViewModel { return "\(server.countryCode.uppercased()), \(server.city)" } - return "\(server.city), \(server.countryCode.uppercased())" + return server.city } } From 803a5c55b61794193cf4a3bf18fc60d1f2cb703e Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 3 Jan 2023 10:16:24 +0100 Subject: [PATCH 097/581] tests: update VPNServerViewModelTests.swift --- UnitTests/ViewModels/VPNServerViewModelTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UnitTests/ViewModels/VPNServerViewModelTests.swift b/UnitTests/ViewModels/VPNServerViewModelTests.swift index c2dc43e26..1b3d37ea4 100644 --- a/UnitTests/ViewModels/VPNServerViewModelTests.swift +++ b/UnitTests/ViewModels/VPNServerViewModelTests.swift @@ -52,9 +52,9 @@ class VPNServerViewModelTests: XCTestCase { } func test_formattedServerNameSort() { - XCTAssertEqual(viewModel.formattedServerName(sort: .city), "Amsterdam, NL") - XCTAssertEqual(viewModel.formattedServerName(sort: .latency), "Amsterdam, NL") - XCTAssertEqual(viewModel.formattedServerName(sort: .proximity), "Amsterdam, NL") + XCTAssertEqual(viewModel.formattedServerName(sort: .city), "Amsterdam") + XCTAssertEqual(viewModel.formattedServerName(sort: .latency), "Amsterdam") + XCTAssertEqual(viewModel.formattedServerName(sort: .proximity), "Amsterdam") XCTAssertEqual(viewModel.formattedServerName(sort: .country), "NL, Amsterdam") } From 88d85ef73a1743344e88af38b0cae3c4707b2f36 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 3 Jan 2023 14:36:16 +0100 Subject: [PATCH 098/581] feat: add segmented control in server list --- IVPNClient/Scenes/Base.lproj/Main.storyboard | 67 ++++++++++++++------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/IVPNClient/Scenes/Base.lproj/Main.storyboard b/IVPNClient/Scenes/Base.lproj/Main.storyboard index 5f79854ca..77b19cf83 100644 --- a/IVPNClient/Scenes/Base.lproj/Main.storyboard +++ b/IVPNClient/Scenes/Base.lproj/Main.storyboard @@ -804,28 +804,57 @@ - + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + - + @@ -2243,13 +2272,13 @@ - + + @@ -1650,14 +1665,14 @@ - + - + - + @@ -2482,13 +2497,13 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2314,13 +2432,13 @@ - From f15fe08930978c55ffc729fee3b2188c54ea204e Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Sun, 19 Feb 2023 14:17:05 +0100 Subject: [PATCH 166/581] build: update today-extension.template.xcconfig --- .../Config/today-extension-release.template.xcconfig | 2 -- .../Config/today-extension-staging.template.xcconfig | 2 -- 2 files changed, 4 deletions(-) diff --git a/today-extension/Config/today-extension-release.template.xcconfig b/today-extension/Config/today-extension-release.template.xcconfig index 62994d651..1823d5545 100644 --- a/today-extension/Config/today-extension-release.template.xcconfig +++ b/today-extension/Config/today-extension-release.template.xcconfig @@ -1,4 +1,2 @@ -#include "Pods/Target Support Files/Pods-today-extension/Pods-today-extension.release.xcconfig" - ApiHostName = api.ivpn.net TlsHostName = ivpn.net \ No newline at end of file diff --git a/today-extension/Config/today-extension-staging.template.xcconfig b/today-extension/Config/today-extension-staging.template.xcconfig index 3929e2225..0efea8050 100644 --- a/today-extension/Config/today-extension-staging.template.xcconfig +++ b/today-extension/Config/today-extension-staging.template.xcconfig @@ -1,4 +1,2 @@ -#include "Pods/Target Support Files/Pods-today-extension/Pods-today-extension.staging.xcconfig" - ApiHostName = TlsHostName = \ No newline at end of file From 28bac675b12ac51217a3dc11d648aede0f45332b Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Sun, 19 Feb 2023 14:39:27 +0100 Subject: [PATCH 167/581] chore: update servers.json --- IVPNClient/Config/servers.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IVPNClient/Config/servers.json b/IVPNClient/Config/servers.json index f8db048be..abaa1f15c 100644 --- a/IVPNClient/Config/servers.json +++ b/IVPNClient/Config/servers.json @@ -1 +1 @@ -{"wireguard":[{"gateway":"ca-qc.wg.ivpn.net","country_code":"CA","country":"Canada","city":"Montreal","latitude":45.5,"longitude":-73.5833,"isp":"M247","hosts":[{"hostname":"ca1.wg.ivpn.net","host":"37.120.130.58","public_key":"rg+GGDmjM4Vxo1hURvKmgm9yonb6qcoKbPCP/DNDBnI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":14.41,"multihop_port":23810},{"hostname":"ca-qc1.wg.ivpn.net","host":"87.101.92.29","public_key":"98JU1mdCR8vD1aNZg017/NjBeTjuuCKUaLw0zfz/CUE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":19.88,"multihop_port":27001}]},{"gateway":"ch.wg.ivpn.net","country_code":"CH","country":"Switzerland","city":"Zurich","latitude":47.38,"longitude":8.55,"isp":"Privatelayer","hosts":[{"hostname":"ch1.wg.ivpn.net","host":"141.255.164.66","public_key":"jVZJ61i1xxkAfriDHpwvF/GDuTvZUqhwoWSjkOJvaUA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":23.37,"multihop_port":23610},{"hostname":"ch01.wg.ivpn.net","host":"185.212.170.141","public_key":"dU7gLfcupYd37LW0q6cxC6PHMba+eUFAUOoU/ryXZkY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.56,"multihop_port":23601},{"hostname":"ch3.wg.ivpn.net","host":"141.255.166.198","public_key":"JBpgBKtqIneRuEga7mbP2PAk/e4HPRaC11H0A0+R3lA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":26.89,"multihop_port":22901}]},{"gateway":"de.wg.ivpn.net","country_code":"DE","country":"Germany","city":"Frankfurt","latitude":50.1,"longitude":8.675,"isp":"Datapacket","hosts":[{"hostname":"de1.wg.ivpn.net","host":"185.102.219.26","public_key":"mS3/WpXjnMAMmXjSpd4nFzx9HSE3ubv2WyjpyH2REgs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.93,"multihop_port":23010},{"hostname":"de01.wg.ivpn.net","host":"178.162.212.24","public_key":"Sc5AUZieg0qX8kyCy9p0OHRES4n0CHtHHM+ZPyERFTc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":31.78,"multihop_port":23001},{"hostname":"de2.wg.ivpn.net","host":"37.58.60.151","public_key":"QhY3OtBf4FFafKtLO33e6k8JnAl8e6ktFcRUyLjCDVY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":22.81,"multihop_port":22001}]},{"gateway":"gb.wg.ivpn.net","country_code":"GB","country":"United Kingdom","city":"London","latitude":51.5,"longitude":-0.1167,"isp":"M247","hosts":[{"hostname":"gb1.wg.ivpn.net","host":"81.92.202.114","public_key":"7+jos+Eg+hMEOQE4Std6OJ+WVnCcmbqS1/EbPwn9w3s=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":13.88,"multihop_port":20810},{"hostname":"gb01.wg.ivpn.net","host":"185.59.221.140","public_key":"yKK5x+D17Jr3Q12T/UBaDjNVmNdZBsqpvTqH6YfsGHg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":27.36,"multihop_port":20801},{"hostname":"gb2.wg.ivpn.net","host":"185.59.221.225","public_key":"x0BTRaxsdxAd58ZyU2YMX4bmuj+Eg+8/urT2F3Vs1n8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.94,"multihop_port":24201}]},{"gateway":"it.wg.ivpn.net","country_code":"IT","country":"Italy","city":"Milan","latitude":45.47,"longitude":9.205,"isp":"M247","hosts":[{"hostname":"it1.wg.ivpn.net","host":"82.102.21.90","public_key":"Aj6b81yrDk7I913R+fuSW/NAmIl87N73vHgY5/WQY0Q=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.46,"multihop_port":24310},{"hostname":"it01.wg.ivpn.net","host":"158.58.172.89","public_key":"QTzR5R6jeDI/cQ0CXPIqOby9GR5nn+4Bcf4bK536Vy0=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.57,"multihop_port":24301}]},{"gateway":"nl.wg.ivpn.net","country_code":"NL","country":"Netherlands","city":"Amsterdam","latitude":52.35,"longitude":4.9166,"isp":"Datapacket","hosts":[{"hostname":"nl1.wg.ivpn.net","host":"185.102.218.104","public_key":"AsMT2FqpkZbjzWeDch6GwufF5odl259W/hIkGytVfWo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.94,"multihop_port":20301},{"hostname":"nl3.wg.ivpn.net","host":"95.211.95.9","public_key":"XDU6Syq1DY82IMatsHV0x/TAtbLiRwh/SdFCXlEn40c=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.45,"multihop_port":23101},{"hostname":"nl4.wg.ivpn.net","host":"95.211.95.19","public_key":"cVB66gPq5cZ9dfXY+e2pbsCyih5o1zk04l5c5VCsV1g=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.73,"multihop_port":23201},{"hostname":"nl5.wg.ivpn.net","host":"95.211.243.162","public_key":"NCagAawwRixI6Iw/NWiGD8lbjDNCl0aTICZKJtO/1HA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":35.96,"multihop_port":23901},{"hostname":"nl6.wg.ivpn.net","host":"95.211.243.182","public_key":"hMWpqb3FEATHIbImPVWB/5z2nWIXghwpnJjevPY+1H0=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":24.22,"multihop_port":24101},{"hostname":"nl7.wg.ivpn.net","host":"95.211.172.105","public_key":"hQNYqtfOOAEz0IGshLx/TI9hUrfR9gIIkjVm4VsCbBM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":46.91,"multihop_port":22501},{"hostname":"nl8.wg.ivpn.net","host":"95.211.198.167","public_key":"/nY1/OhVhdHtbnU/s31zYUuPBH0pizv4DemW5KDOUkg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":12.83,"multihop_port":22801}]},{"gateway":"se.wg.ivpn.net","country_code":"SE","country":"Sweden","city":"Stockholm","latitude":59.3508,"longitude":18.0973,"isp":"M247","hosts":[{"hostname":"se1.wg.ivpn.net","host":"37.120.153.226","public_key":"2n0nFE1g/+vQr2AOQPm9Igyiy0zh9uTTultvOOSkMRo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.22,"multihop_port":24010},{"hostname":"se01.wg.ivpn.net","host":"80.67.10.141","public_key":"u8VHnYEpoEjJWDAF9NAUkU6s810RnkMuhEfFD9U0cGo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.66,"multihop_port":24001}]},{"gateway":"sg.wg.ivpn.net","country_code":"SG","country":"Singapore","city":"Singapore","latitude":1.293,"longitude":103.8558,"isp":"M247","hosts":[{"hostname":"sg1.wg.ivpn.net","host":"37.120.151.122","public_key":"hSg0At4uwuIhmTy5UT4fRbi5AN6JO2ZWTuIvqd4nHCE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.76,"multihop_port":26110},{"hostname":"sg01.wg.ivpn.net","host":"185.128.24.189","public_key":"pWk0u1Xq8FHC+xpkN+C6yEKOTEanorR5zMCSfHlLzFw=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":23.44,"multihop_port":26101}]},{"gateway":"us-ca.wg.ivpn.net","country_code":"US","country":"United States","city":"Los Angeles, CA","latitude":34.1139,"longitude":-118.4068,"isp":"Datapacket","hosts":[{"hostname":"us-ca1.wg.ivpn.net","host":"185.180.13.41","public_key":"FGl78s9Ct6xNamQ2/CtAyXwGePrrU0kiZxfM27pm8XA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.76,"multihop_port":22210},{"hostname":"us-ca01.wg.ivpn.net","host":"216.144.236.44","public_key":"B+qXdkIuETpzI0bfhGUAHN4SU91Tjs6ItdFlu93S42I=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.34,"multihop_port":22201},{"hostname":"us-ca2.wg.ivpn.net","host":"216.144.236.68","public_key":"qv4Tupfon5NUSwzDpM8zPizSwJZn2h+9CqrufcyDOko=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.26,"multihop_port":22401},{"hostname":"us-ca3.wg.ivpn.net","host":"198.54.129.100","public_key":"J5+Bx84LxNPdWEhewOvBV/fGWiDluIBlAcr1QlJZil8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":12.79,"multihop_port":21301},{"hostname":"us-ca4.wg.ivpn.net","host":"216.144.237.83","public_key":"dYPXYr6HSRJPe3MhALwGWNtdEy1+EPE9Kqv7cTrUXk8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.2,"multihop_port":21901}]},{"gateway":"us-ga.wg.ivpn.net","country_code":"US","country":"United States","city":"Atlanta, GA","latitude":33.7627,"longitude":-84.4225,"isp":"Datapacket","hosts":[{"hostname":"us-ga1.wg.ivpn.net","host":"185.93.0.212","public_key":"jD8h+pL5/d6fmYcTzl0lR8AWzQVN5XkwRFSmM/3NcDM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.79,"multihop_port":24510},{"hostname":"us-ga01.wg.ivpn.net","host":"104.129.24.149","public_key":"EJFl28aYpZKfmJqb1jxxTEnGx6kaH2USVrigpHKKXhs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.4,"multihop_port":24501},{"hostname":"us-ga2.wg.ivpn.net","host":"107.150.22.77","public_key":"hr2uQOEGCvGeDkoCQJ2dCI8dM8Iu5aKhb1PIvJ9q72E=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9,"multihop_port":24810}]},{"gateway":"us-il.wg.ivpn.net","country_code":"US","country":"United States","city":"Chicago, IL","latitude":41.8373,"longitude":-87.6862,"isp":"Datapacket","hosts":[{"hostname":"us-il1.wg.ivpn.net","host":"89.187.181.116","public_key":"hku9gjamhoii8OvxZgx+TdUDIkOAQYFu39qbav2AyUQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.19,"multihop_port":21410},{"hostname":"us-il01.wg.ivpn.net","host":"72.11.137.158","public_key":"Uy5a8JOqneAUY1dC5s9jubLnotbyIfBsLP2nZuzRbHs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":13.31,"multihop_port":21401},{"hostname":"us-il2.wg.ivpn.net","host":"72.11.137.148","public_key":"ANhVUMAQgStPVNRHW8mg0ZtN1YI1QHyXfNCO8+USNQQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.21,"multihop_port":24901}]},{"gateway":"us-ny.wg.ivpn.net","country_code":"US","country":"United States","city":"New York, NY","latitude":40.6943,"longitude":-73.9249,"isp":"M247","hosts":[{"hostname":"us-ny1.wg.ivpn.net","host":"91.132.137.170","public_key":"6/tjvgb7HFl7UuvBSegolxa1zKr3iSlDrlCexCmhAGE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":36.4,"multihop_port":21210},{"hostname":"us-ny2.wg.ivpn.net","host":"212.103.48.195","public_key":"c7DwY2uT+6ulWAJ5u8qJNWHroA0qyJLcdNzf/f2kkhs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.1,"multihop_port":21801},{"hostname":"us-ny3.wg.ivpn.net","host":"89.187.178.145","public_key":"m5/Ssw9SN3WuE+yD/fAsH5G8iuI8TcDGEiZZnPgiMCc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.14,"multihop_port":27601}]},{"gateway":"us-tx.wg.ivpn.net","country_code":"US","country":"United States","city":"Dallas, TX","latitude":32.7936,"longitude":-96.7662,"isp":"Quadranet","hosts":[{"hostname":"us-tx1.wg.ivpn.net","host":"198.55.124.114","public_key":"JPT1veXLmasj2uQDstX24mpR7VWD+GmV8JDkidkz91Q=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.41,"multihop_port":21010},{"hostname":"us-tx01.wg.ivpn.net","host":"96.44.189.197","public_key":"LvWf548mFddi8PTrIGL6uD1/l85LU8z0Rc8tpvw2Vls=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":13.06,"multihop_port":21001},{"hostname":"us-tx2.wg.ivpn.net","host":"96.44.142.77","public_key":"om8hOGUcEvoOhHvJZoBHxNF4jxY/+Ml9Iy1WOSC/pFo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.52,"multihop_port":25001}]},{"gateway":"at.wg.ivpn.net","country_code":"AT","country":"Austria","city":"Vienna","latitude":48.2,"longitude":16.3666,"isp":"M247","hosts":[{"hostname":"at1.wg.ivpn.net","host":"185.244.212.69","public_key":"83LUBnP97SFpnS0y1MpEAFcg8MIiQJgW1FRv/8Mc40g=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":28.58,"multihop_port":25601}]},{"gateway":"au-nsw.wg.ivpn.net","country_code":"AU","country":"Australia","city":"Sydney","latitude":-33.92,"longitude":151.1852,"isp":"M247","hosts":[{"hostname":"au-nsw1.wg.ivpn.net","host":"46.102.153.246","public_key":"KmSrG48t5xw9CJCPlYLBG3JnmiY0CnUgyRM5TUEwZhM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":98.95,"multihop_port":26601},{"hostname":"au-nsw2.wg.ivpn.net","host":"146.70.78.75","public_key":"q+wbp7GjiTszp5G16rNpGCqxkL0qSY3CH4pcgD6UsVQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":71.28,"multihop_port":27901}]},{"gateway":"be.wg.ivpn.net","country_code":"BE","country":"Belgium","city":"Brussels","latitude":50.8333,"longitude":4.3333,"isp":"M247","hosts":[{"hostname":"be1.wg.ivpn.net","host":"194.187.251.13","public_key":"awriP5lpdxEMWKuG+A1DOg+vb1M5jd3WhynIMB61BhU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":64.31,"multihop_port":25701}]},{"gateway":"bg.wg.ivpn.net","country_code":"BG","country":"Bulgaria","city":"Sofia","latitude":42.6833,"longitude":23.3167,"isp":"M247","hosts":[{"hostname":"bg1.wg.ivpn.net","host":"82.102.23.21","public_key":"WDSsdJE6wvATIWfzQwayPtE/0DaXBQgW/hPm7sQSJmU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":78.13,"multihop_port":25901}]},{"gateway":"br.wg.ivpn.net","country_code":"BR","country":"Brazil","city":"Franca","latitude":-20.53,"longitude":-47.39,"isp":"Qnax","hosts":[{"hostname":"br1.wg.ivpn.net","host":"45.162.229.133","public_key":"eN1f15S3YzRyYCALiPGRQcjkQO9xntcdqPhJJ6TOymc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.54,"multihop_port":26701}]},{"gateway":"ca.wg.ivpn.net","country_code":"CA","country":"Canada","city":"Toronto","latitude":43.7,"longitude":-79.42,"isp":"Amanah","hosts":[{"hostname":"ca01.wg.ivpn.net","host":"104.254.90.181","public_key":"mdGnCZwinuOVGg46zsWnFhhenfFId6jht9GBTKB+xUA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":41.78,"multihop_port":23801},{"hostname":"ca2.wg.ivpn.net","host":"172.86.186.173","public_key":"5qHV10ZbFgEGnF6wg9QpKeh1l6Di2JUG/5PdNaaoNW8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":55.09,"multihop_port":22101}]},{"gateway":"cz.wg.ivpn.net","country_code":"CZ","country":"Czech Republic","city":"Prague","latitude":50.0833,"longitude":14.466,"isp":"Datapacket","hosts":[{"hostname":"cz1.wg.ivpn.net","host":"185.180.14.41","public_key":"gVbEq2cGRzwCSGPqT2oRSYYN+P6IK3uvvRffErASDSk=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":13.04,"multihop_port":25201}]},{"gateway":"dk.wg.ivpn.net","country_code":"DK","country":"Denmark","city":"Copenhagen","latitude":55.6786,"longitude":12.5635,"isp":"M247","hosts":[{"hostname":"dk1.wg.ivpn.net","host":"185.245.84.229","public_key":"jTsV5gOD7lT4egDj9rhKwO2OO2X7bKs2EQPcZEnUWDE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":61.97,"multihop_port":25501}]},{"gateway":"es.wg.ivpn.net","country_code":"ES","country":"Spain","city":"Madrid","latitude":40.4,"longitude":-3.6834,"isp":"Datapacket","hosts":[{"hostname":"es1.wg.ivpn.net","host":"84.17.62.98","public_key":"w7umiArTtlJ4Pk6Ii9WX5VXK5vw/Qu+Z37/icKlIYWo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.51,"multihop_port":21501}]},{"gateway":"fi.wg.ivpn.net","country_code":"FI","country":"Finland","city":"Helsinki","latitude":60.1756,"longitude":24.9341,"isp":"Creanova","hosts":[{"hostname":"fi1.wg.ivpn.net","host":"194.34.134.63","public_key":"mIxEzfjZ2wV6jJVj30w38ECd2LSH4bw/HLMnM2ICHiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":99.96,"multihop_port":26001}]},{"gateway":"fr.wg.ivpn.net","country_code":"FR","country":"France","city":"Paris","latitude":48.8667,"longitude":2.3333,"isp":"Datapacket","hosts":[{"hostname":"fr1.wg.ivpn.net","host":"185.246.211.185","public_key":"g7BuMzj3r/noLiLR4qhQMcvU6GSIY8RGEnaYtdYsFX4=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":16.85,"multihop_port":23401}]},{"gateway":"gb-man.wg.ivpn.net","country_code":"GB","country":"United Kingdom","city":"Manchester","latitude":53.5004,"longitude":-2.248,"isp":"M247","hosts":[{"hostname":"gb-man1.wg.ivpn.net","host":"89.238.141.231","public_key":"+hf4DYilNEIjTdSOuCNcWdqVyaRoxGzXw7wvNl7f7Rg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.95,"multihop_port":26901}]},{"gateway":"hk.wg.ivpn.net","country_code":"HK","country":"Hong Kong","city":"Hong Kong","latitude":22.305,"longitude":114.185,"isp":"Leaseweb","hosts":[{"hostname":"hk2.wg.ivpn.net","host":"64.120.120.239","public_key":"kyolyq4cJydI3vQB2ESTIUAy2Fq0bpOf+Qe7GIq6XEA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.47,"multihop_port":27501},{"hostname":"hk3.wg.ivpn.net","host":"118.107.244.206","public_key":"qq1simsFNm2FpZM0J8u8Aa0rkk5HEasvLksPyLv+0Sk=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.07,"multihop_port":20800}]},{"gateway":"hu.wg.ivpn.net","country_code":"HU","country":"Hungary","city":"Budapest","latitude":47.5,"longitude":19.0833,"isp":"M247","hosts":[{"hostname":"hu1.wg.ivpn.net","host":"185.189.114.189","public_key":"G30fNdXrnlqtqqOLF23QXWzFdLIKDxLW60HoYPvqml8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":100,"multihop_port":25401}]},{"gateway":"il.wg.ivpn.net","country_code":"IL","country":"Israel","city":"Holon, Tel Aviv","latitude":32.08,"longitude":34.77,"isp":"HQServ","hosts":[{"hostname":"il01.wg.ivpn.net","host":"185.191.207.197","public_key":"HR9gAjpxXU3YVt6kehBw5n8yVYVE0iIgJdc4HTqOzEE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":49.46,"multihop_port":27301}]},{"gateway":"is.wg.ivpn.net","country_code":"IS","country":"Iceland","city":"Reykjavik","latitude":64.15,"longitude":-21.95,"isp":"Advania","hosts":[{"hostname":"is1.wg.ivpn.net","host":"82.221.107.185","public_key":"nZZT6TlQ2dXlVe3P3B5ozEScHYMWH4JY4y3to8w5dz0=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":88.98,"multihop_port":23501}]},{"gateway":"jp.wg.ivpn.net","country_code":"JP","country":"Japan","city":"Tokyo","latitude":35.685,"longitude":139.7514,"isp":"M247","hosts":[{"hostname":"jp1.wg.ivpn.net","host":"91.207.174.237","public_key":"tb9WdC3LSho3d1rI5N7kfG9e42/d+u4LPVdEYERPsSQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":30.88,"multihop_port":26201},{"hostname":"jp2.wg.ivpn.net","host":"185.135.77.81","public_key":"YuhEd9+a90/+uucZC+qzsyMHkfe/GiwG1dq7g2HegXQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.66,"multihop_port":20830}]},{"gateway":"lu.wg.ivpn.net","country_code":"LU","country":"Luxembourg","city":"Luxembourg","latitude":49.6117,"longitude":6.13,"isp":"Evoluso","hosts":[{"hostname":"lu1.wg.ivpn.net","host":"92.223.89.57","public_key":"hUS1OAFLGwpba8+oc5mifYtohZt/RTro5dMyYBLYHjI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":13.08,"multihop_port":27201}]},{"gateway":"my.wg.ivpn.net","country_code":"MY","country":"Malaysia","city":"Kuala Lumpur","latitude":3.1494,"longitude":101.706,"isp":"TheGigabit","hosts":[{"hostname":"my1.wg.ivpn.net","host":"61.4.97.153","public_key":"M9SsMCpUw7ad6YbqQr8r2saBK2zAf3tBj82DzsQjgkY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.48,"multihop_port":20810}]},{"gateway":"no.wg.ivpn.net","country_code":"NO","country":"Norway","city":"Oslo","latitude":59.9167,"longitude":10.75,"isp":"Servetheworld","hosts":[{"hostname":"no1.wg.ivpn.net","host":"91.189.177.156","public_key":"xFO6ksbO3Gr05rRgAW0O5Veoi4bpTgz2G9RvtBzK7Cg=","local_ip":"172.16.0.1/12","ipv6":{},"load":0,"multihop_port":25301}]},{"gateway":"pl.wg.ivpn.net","country_code":"PL","country":"Poland","city":"Warsaw","latitude":52.25,"longitude":21,"isp":"Datapacket","hosts":[{"hostname":"pl1.wg.ivpn.net","host":"185.246.208.109","public_key":"1JDmF79rWj5C+kHp71AbdHne/yGaizWCd2bLfSFvYjo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":36.56,"multihop_port":25101}]},{"gateway":"pt.wg.ivpn.net","country_code":"PT","country":"Portugal","city":"Lisbon","latitude":38.7227,"longitude":-9.1449,"isp":"Hostwebis","hosts":[{"hostname":"pt1.wg.ivpn.net","host":"94.46.175.113","public_key":"nMnA82YVrvEK80GVoY/0Z9McWeqjcLzuMYSL+86j5nU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.94,"multihop_port":27101}]},{"gateway":"ro.wg.ivpn.net","country_code":"RO","country":"Romania","city":"Bucharest","latitude":44.4334,"longitude":26.0999,"isp":"M247","hosts":[{"hostname":"ro1.wg.ivpn.net","host":"37.120.206.53","public_key":"F2uQ57hysZTlw8WYELnyCw9Lga80wNYoYwkrrxyXKmw=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":43.52,"multihop_port":22301}]},{"gateway":"rs.wg.ivpn.net","country_code":"RS","country":"Serbia","city":"Belgrade","latitude":44.8186,"longitude":20.468,"isp":"M247","hosts":[{"hostname":"rs1.wg.ivpn.net","host":"141.98.103.253","public_key":"xLN/lpQThQ3z3tvYf7VqdAsRL/nton1Vhv2kCZlQtWE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":65.32,"multihop_port":26801}]},{"gateway":"sk.wg.ivpn.net","country_code":"SK","country":"Slovakia","city":"Bratislava","latitude":48.15,"longitude":17.117,"isp":"M247","hosts":[{"hostname":"sk1.wg.ivpn.net","host":"185.245.85.253","public_key":"MOBWWpEgNsKbFj4BEyWSDFLlkBs5iUFiqdSdTFTDBko=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":100,"multihop_port":25801}]},{"gateway":"tw.wg.ivpn.net","country_code":"TW","country":"Taiwan","city":"Taipei","latitude":25.073,"longitude":121.578,"isp":"TheGigabit","hosts":[{"hostname":"tw1.wg.ivpn.net","host":"185.189.160.59","public_key":"fMTCCbbKqPp60fkqnaQvJ9mX2r6zBlt7xhUp8sGfJQY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.89,"multihop_port":20820}]},{"gateway":"ua.wg.ivpn.net","country_code":"UA","country":"Ukraine","city":"Kharkiv","latitude":50,"longitude":36.25,"isp":"Xservers","hosts":[{"hostname":"ua1.wg.ivpn.net","host":"176.103.57.129","public_key":"mIxEzfjZ2wV6jJVj30w38ECd2LSH4bw/HLMnM2ICHiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.43,"multihop_port":26301}]},{"gateway":"us-az.wg.ivpn.net","country_code":"US","country":"United States","city":"Phoenix, AZ","latitude":33.5722,"longitude":-112.0891,"isp":"M247","hosts":[{"hostname":"us-az1.wg.ivpn.net","host":"193.37.254.133","public_key":"Ts4MGazxpxL9rrYbERjgxa+kCEX85ou9gHoaJvDsRiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.52,"multihop_port":26401}]},{"gateway":"us-fl.wg.ivpn.net","country_code":"US","country":"United States","city":"Miami, FL","latitude":25.7839,"longitude":-80.2102,"isp":"Quadranet","hosts":[{"hostname":"us-fl1.wg.ivpn.net","host":"173.44.49.93","public_key":"Rkzo9WgxJBiKyEbkZvqGWtOVh9Gk9Vd7wL49SHXdHig=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.5,"multihop_port":24601}]},{"gateway":"us-nj.wg.ivpn.net","country_code":"US","country":"United States","city":"New Jersey, NJ","latitude":40.737764,"longitude":-74.151747,"isp":"Quadranet","hosts":[{"hostname":"us-nj3.wg.ivpn.net","host":"23.226.128.21","public_key":"AX7C1LO0ECUcHRYgX4/tIDYdR8npvfB/+pf4AfI3OHU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.66,"multihop_port":21610},{"hostname":"us-nj4.wg.ivpn.net","host":"194.36.111.54","public_key":"1Te4AfL1yKo2k4jzPALnRPfKE3YSzXKo4XIRHPz5FxI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":14.38,"multihop_port":27401}]},{"gateway":"us-nv.wg.ivpn.net","country_code":"US","country":"United States","city":"Las Vegas, NV","latitude":36.2333,"longitude":-115.2654,"isp":"M247","hosts":[{"hostname":"us-nv1.wg.ivpn.net","host":"185.242.5.37","public_key":"PRpvAZyoNWNm/KHlqafjtYoZtn1PkIPylUE4WbuYmgM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.82,"multihop_port":26501}]},{"gateway":"us-ut.wg.ivpn.net","country_code":"US","country":"United States","city":"Salt Lake City, UT","latitude":40.7774,"longitude":-111.93,"isp":"100TB","hosts":[{"hostname":"us-ut1.wg.ivpn.net","host":"206.190.145.92","public_key":"KirI7bpxD186CuYiOqNHF+QUe6YmRYf6CN3pXWOJT2k=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.91,"multihop_port":24401}]},{"gateway":"us-va.wg.ivpn.net","country_code":"US","country":"United States","city":"Ashburn, VA","latitude":39.0437,"longitude":-77.4875,"isp":"Datapacket","hosts":[{"hostname":"us-va1.wg.ivpn.net","host":"37.19.206.106","public_key":"ZCnZK6U+cRuP/WgzIDb/P6UG2rX/KyCRd5vJ1hAbr2E=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":22.97,"multihop_port":27701}]},{"gateway":"us-wa.wg.ivpn.net","country_code":"US","country":"United States","city":"Seattle, WA","latitude":47.6211,"longitude":-122.3244,"isp":"Tzulo","hosts":[{"hostname":"us-wa2.wg.ivpn.net","host":"198.44.131.4","public_key":"VcrOOozBUCIURU0AnqMAE7AkMmC7Qrp+j/PzPbgbalU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":14.58,"multihop_port":27801}]},{"gateway":"za.wg.ivpn.net","country_code":"ZA","country":"South Africa","city":"Johannesburg","latitude":-26.195,"longitude":28.034,"isp":"Datapacket","hosts":[{"hostname":"za1.wg.ivpn.net","host":"169.150.238.108","public_key":"tgrAA+uJZppS9esgOi0pe3rHajQQ7c/KF8WPOua6qy4=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.1,"multihop_port":20840}]}],"openvpn":[{"gateway":"at.gw.ivpn.net","country_code":"AT","country":"Austria","city":"Vienna","latitude":48.2,"longitude":16.3666,"isp":"M247","hosts":[{"hostname":"at1.gw.ivpn.net","host":"185.244.212.66","load":28.58,"multihop_port":25601,"obfs":{"obfs3_multihop_port":25602,"obfs4_multihop_port":25603,"obfs4_key":"75HhQC6n6ctp9Fa9wCvEnc6ip5FnEfuIGc+dVNLH4M15FjB/Ve6bI1b8lYFhk6T+4/HkDQ"}}]},{"gateway":"au-nsw.gw.ivpn.net","country_code":"AU","country":"Australia","city":"Sydney","latitude":-33.92,"longitude":151.1852,"isp":"M247","hosts":[{"hostname":"au-nsw1.gw.ivpn.net","host":"46.102.153.242","load":98.95,"multihop_port":26601,"obfs":{"obfs3_multihop_port":26602,"obfs4_multihop_port":26603,"obfs4_key":"/rjoeDjduOFq1UvT332vhS398h1RP5hC3m7sDJKNSyJ6TO8mkcxWAYILw0i+bgS/3JD5YA"}},{"hostname":"au-nsw2.gw.ivpn.net","host":"146.70.78.74","load":71.28,"multihop_port":27901,"obfs":{"obfs3_multihop_port":27902,"obfs4_multihop_port":27903,"obfs4_key":"qtdQ5krD9EQFR98xNo/v5cmGb10wqt0Om9pYMIHWQh4oz5xcAXj32rViEyN0bnkkhaZnBA"}}]},{"gateway":"be.gw.ivpn.net","country_code":"BE","country":"Belgium","city":"Brussels","latitude":50.8333,"longitude":4.3333,"isp":"M247","hosts":[{"hostname":"be1.gw.ivpn.net","host":"194.187.251.10","load":64.31,"multihop_port":25701,"obfs":{"obfs3_multihop_port":25702,"obfs4_multihop_port":25703,"obfs4_key":"cN8i60FUVy2mmGpy+tkQAz8hu/N0EGPq8cZwIotEDwdhAYdLV+ATes/AEjzdub2K68TlYg"}}]},{"gateway":"bg.gw.ivpn.net","country_code":"BG","country":"Bulgaria","city":"Sofia","latitude":42.6833,"longitude":23.3167,"isp":"M247","hosts":[{"hostname":"bg1.gw.ivpn.net","host":"82.102.23.18","load":78.13,"multihop_port":25901,"obfs":{"obfs3_multihop_port":25902,"obfs4_multihop_port":25903,"obfs4_key":"K+mCw9+zy/8pBQt6IUKRlg2eJ3DCnJ1BvIccLq/6A2D6HoZddyDnZQYb2Sb2e464dVgBWw"}}]},{"gateway":"br.gw.ivpn.net","country_code":"BR","country":"Brazil","city":"Franca","latitude":-20.53,"longitude":-47.39,"isp":"Qnax","hosts":[{"hostname":"br1.gw.ivpn.net","host":"45.162.229.130","load":11.54,"multihop_port":26701,"obfs":{"obfs3_multihop_port":26702,"obfs4_multihop_port":26703,"obfs4_key":"h4bBkocahWveuv/nWPRMYXBTw95ExTiXwmoydkNlV6hgfy8/ZjaKc34rqTuOyOH+CK7OZw"}}]},{"gateway":"ca-qc.gw.ivpn.net","country_code":"CA","country":"Canada","city":"Montreal","latitude":45.5,"longitude":-73.5833,"isp":"M247","hosts":[{"hostname":"ca-qc1.gw.ivpn.net","host":"87.101.92.26","load":19.88,"multihop_port":27001,"obfs":{"obfs3_multihop_port":27002,"obfs4_multihop_port":27003,"obfs4_key":"E97qdaar8flBavysmvdIui7WQEFKkbmNi/ITTo8bPLvv39vnaBRzFj4vjMwpzXV2jXEGRQ"}}]},{"gateway":"ca.gw.ivpn.net","country_code":"CA","country":"Canada","city":"Toronto","latitude":43.7,"longitude":-79.42,"isp":"Amanah","hosts":[{"hostname":"ca1.gw.ivpn.net","host":"104.254.90.178","load":41.78,"multihop_port":23801,"obfs":{"obfs3_multihop_port":23802,"obfs4_multihop_port":23803,"obfs4_key":"49WDCCK1QGpOTSEVflRzIIaOdCT1BLB3jr/yNUJsbaUFrq7NuoB1E3wAdArNxQq9p5otTw"}},{"hostname":"ca2.gw.ivpn.net","host":"172.86.186.170","load":55.09,"multihop_port":22101,"obfs":{"obfs3_multihop_port":22102,"obfs4_multihop_port":22103,"obfs4_key":"xNkQbCkA0VCe2i4WvS2CPq2eBSMydIjsHH36E+Yg0C+gOPo3SwZyN51kpB+kwsYVS32fOQ"}}]},{"gateway":"ch.gw.ivpn.net","country_code":"CH","country":"Switzerland","city":"Zurich","latitude":47.38,"longitude":8.55,"isp":"M247","hosts":[{"hostname":"ch1.gw.ivpn.net","host":"185.212.170.138","load":17.56,"multihop_port":23601,"obfs":{"obfs3_multihop_port":23602,"obfs4_multihop_port":23603,"obfs4_key":"ELnV4JNKu0vUNd3J+QDn64yfZtqM0hNN6O5n6RkDLHbeSDBZmxP1N4dlwwChV/uySX+DEQ"}},{"hostname":"ch3.gw.ivpn.net","host":"141.255.166.194","load":26.89,"multihop_port":22901,"obfs":{"obfs3_multihop_port":22902,"obfs4_multihop_port":22903,"obfs4_key":"oNaH5sHCPGGk5m3/VMOrTDL+m1qsJrze+bqDs78vhOYBpjx5Jjq5TXu1dXNfDJCKNmKnUA"}}]},{"gateway":"cz.gw.ivpn.net","country_code":"CZ","country":"Czech Republic","city":"Prague","latitude":50.0833,"longitude":14.466,"isp":"Datapacket","hosts":[{"hostname":"cz1.gw.ivpn.net","host":"195.181.160.167","load":13.04,"multihop_port":25201,"obfs":{"obfs3_multihop_port":25202,"obfs4_multihop_port":25203,"obfs4_key":"JZ3PtIyflM3VwVow2vqi08OxddOWSx9j6B6yZSGoZLs9QE0hzSAj3ZBWEsCKFeQ2RcAoCQ"}}]},{"gateway":"de.gw.ivpn.net","country_code":"DE","country":"Germany","city":"Frankfurt","latitude":50.1,"longitude":8.675,"isp":"Leaseweb","hosts":[{"hostname":"de1.gw.ivpn.net","host":"178.162.222.40","load":31.78,"multihop_port":23001,"obfs":{"obfs3_multihop_port":23002,"obfs4_multihop_port":23003,"obfs4_key":"PBhcWVcRNOCTMSWXbA2J+8eJBVzNd9H5HOr0YCF8QWwmKeSlEmqLSJQE8oDpKH5IbFH4Mw"}},{"hostname":"de2.gw.ivpn.net","host":"178.162.211.114","load":22.81,"multihop_port":22001,"obfs":{"obfs3_multihop_port":22002,"obfs4_multihop_port":22003,"obfs4_key":"dEhLA4ZsvVP8+PRvlSHKwmW8JyzR1Bwy7+BFKF7Ux4L2B5YvdqqOrv/8eHliEj2mm2Z8Iw"}}]},{"gateway":"dk.gw.ivpn.net","country_code":"DK","country":"Denmark","city":"Copenhagen","latitude":55.6786,"longitude":12.5635,"isp":"M247","hosts":[{"hostname":"dk1.gw.ivpn.net","host":"185.245.84.226","load":61.97,"multihop_port":25501,"obfs":{"obfs3_multihop_port":25502,"obfs4_multihop_port":25503,"obfs4_key":"ngjtv9UISX4tB5AkBnrEN2TrAnUqVwNZ688VqDlS4BDxQXJeJF3ynZtngRqeowhEahsccQ"}}]},{"gateway":"es.gw.ivpn.net","country_code":"ES","country":"Spain","city":"Madrid","latitude":40.4,"longitude":-3.6834,"isp":"Datapacket","hosts":[{"hostname":"es1.gw.ivpn.net","host":"185.93.3.193","load":9.51,"multihop_port":21501,"obfs":{"obfs3_multihop_port":21502,"obfs4_multihop_port":21503,"obfs4_key":"x4A9SBY5yzPKH1QOkEsGYcIR2JA/Pu393jv/ZSg4YO2DsVhr3TQFxcMO3QhD9iSF48smJA"}}]},{"gateway":"fi.gw.ivpn.net","country_code":"FI","country":"Finland","city":"Helsinki","latitude":60.1756,"longitude":24.9341,"isp":"Creanova","hosts":[{"hostname":"fi1.gw.ivpn.net","host":"185.112.82.12","load":99.96,"multihop_port":26001,"obfs":{"obfs3_multihop_port":26002,"obfs4_multihop_port":26003,"obfs4_key":"SvvSpGiFctjs4n2wZGnZUf9fAL8wag70SrA3FX+9f3Sq+KgBn+/8P6fE3239ezemg9svLA"}}]},{"gateway":"fr.gw.ivpn.net","country_code":"FR","country":"France","city":"Paris","latitude":48.8667,"longitude":2.3333,"isp":"Datapacket","hosts":[{"hostname":"fr1.gw.ivpn.net","host":"185.246.211.179","load":16.85,"multihop_port":23401,"obfs":{"obfs3_multihop_port":23402,"obfs4_multihop_port":23403,"obfs4_key":"CMf0pNZ46nFdG0Tpa3hE0cK9wtUAReJL7HN66G9Jq3tlrTSWrU0DLf7sCQgXV+WFoc8iaw"}}]},{"gateway":"gb-man.gw.ivpn.net","country_code":"GB","country":"United Kingdom","city":"Manchester","latitude":53.5004,"longitude":-2.248,"isp":"M247","hosts":[{"hostname":"gb-man1.gw.ivpn.net","host":"89.238.141.228","load":11.95,"multihop_port":26901,"obfs":{"obfs3_multihop_port":26902,"obfs4_multihop_port":26903,"obfs4_key":"WuP3pMrsQA+uAC72sV+Y62E1uvOWcnbTNJCmRHXqtWbbYzECF5swu62dzD/JOKoa5t0tGQ"}}]},{"gateway":"gb.gw.ivpn.net","country_code":"GB","country":"United Kingdom","city":"London","latitude":51.5,"longitude":-0.1167,"isp":"Datapacket","hosts":[{"hostname":"gb1.gw.ivpn.net","host":"185.59.221.133","load":27.36,"multihop_port":20801,"obfs":{"obfs3_multihop_port":20802,"obfs4_multihop_port":20803,"obfs4_key":"5whTESvZxQE28wKqJWZ9fQFy09d8//GNaPDeYHVR+FJZTyI+DMS6qX4Mt2FKSf/zBToaDg"}},{"hostname":"gb2.gw.ivpn.net","host":"185.59.221.88","load":8.94,"multihop_port":24201,"obfs":{"obfs3_multihop_port":24202,"obfs4_multihop_port":24203,"obfs4_key":"4hrCOgPsRfmnQ6cLvV5mtM2XZCRS/DXG/izYSg2qZC+WJ0GsnhTlKByPM2iJ555MaM8vJA"}}]},{"gateway":"hk.gw.ivpn.net","country_code":"HK","country":"Hong Kong","city":"Hong Kong","latitude":22.305,"longitude":114.185,"isp":"Leaseweb","hosts":[{"hostname":"hk2.gw.ivpn.net","host":"209.58.188.13","load":9.47,"multihop_port":27501,"obfs":{"obfs3_multihop_port":27502,"obfs4_multihop_port":27503,"obfs4_key":"GIunWjiq00Piv3Xf4VeMkmUQ8NzD8sxRkSIbA3bxrU4LhPVth+3qM2zQwI4GesQDCDY5RA"}},{"hostname":"hk3.gw.ivpn.net","host":"118.107.244.184","load":9.07,"multihop_port":20800,"obfs":{"obfs3_multihop_port":20801,"obfs4_multihop_port":20802,"obfs4_key":"wnI0gz3hLM9VhkABSncBIsGERgn16UzTxkj7dEeYYo/y2Wu0/w24rfriA5KL7ugpTyvEFg"}}]},{"gateway":"hu.gw.ivpn.net","country_code":"HU","country":"Hungary","city":"Budapest","latitude":47.5,"longitude":19.0833,"isp":"M247","hosts":[{"hostname":"hu1.gw.ivpn.net","host":"185.189.114.186","load":100,"multihop_port":25401,"obfs":{"obfs3_multihop_port":25402,"obfs4_multihop_port":25403,"obfs4_key":"2TwZqxAakni0S4S3ulOIqMZimqqug0KCr6pNREN6KytrtIh486nkJyiFRqaYZlx+FlxEcg"}}]},{"gateway":"il.gw.ivpn.net","country_code":"IL","country":"Israel","city":"Holon, Tel Aviv","latitude":32.08,"longitude":34.77,"isp":"HQServ","hosts":[{"hostname":"il1.gw.ivpn.net","host":"185.191.207.194","load":49.46,"multihop_port":27301,"obfs":{"obfs3_multihop_port":27302,"obfs4_multihop_port":27303,"obfs4_key":"DysuSM7UWjquj4BAVYf6mOUnRKfY1QXs17MXiV5aYapFfOkQPpx5nQPVQ2M+rLDxN9TSRg"}}]},{"gateway":"is.gw.ivpn.net","country_code":"IS","country":"Iceland","city":"Reykjavik","latitude":64.15,"longitude":-21.95,"isp":"Advania","hosts":[{"hostname":"is1.gw.ivpn.net","host":"82.221.107.178","load":88.98,"multihop_port":23501,"obfs":{"obfs3_multihop_port":23502,"obfs4_multihop_port":23503,"obfs4_key":"xx/Lor3q60/pVh4PKWi0GZaw64pPXFTkALnGlvRaBMiPRkFilr7KhYmPInDnZxzr4c4AIw"}}]},{"gateway":"it.gw.ivpn.net","country_code":"IT","country":"Italy","city":"Milan","latitude":45.47,"longitude":9.205,"isp":"SEFlow","hosts":[{"hostname":"it1.gw.ivpn.net","host":"158.58.172.73","load":7.57,"multihop_port":24301,"obfs":{"obfs3_multihop_port":24302,"obfs4_multihop_port":24303,"obfs4_key":"yJXSlTJloo6tlAxf0MI9Bu4schtcL2NlVqMPgbrhnrT/1pTZUaOUH7F7nLbVe4JSCSyeZg"}}]},{"gateway":"jp.gw.ivpn.net","country_code":"JP","country":"Japan","city":"Tokyo","latitude":35.685,"longitude":139.7514,"isp":"M247","hosts":[{"hostname":"jp1.gw.ivpn.net","host":"91.207.174.234","load":30.88,"multihop_port":26201,"obfs":{"obfs3_multihop_port":26202,"obfs4_multihop_port":26203,"obfs4_key":"CBqi0EpfoUzP/ijwYn9A9yEpItrhtX+BAKF0rvcUGv///UNzzXKNz+0RhBLdQayZx6y6TA"}},{"hostname":"jp2.gw.ivpn.net","host":"185.135.77.35","load":5.66,"multihop_port":20830,"obfs":{"obfs3_multihop_port":20831,"obfs4_multihop_port":20832,"obfs4_key":"giZJF4edg7wcjxbdgD2RjFcF9QAzExLHIJYjm2cLLtx7MrxP0p96mIFj9T8LSQotKB63fA"}}]},{"gateway":"lu.gw.ivpn.net","country_code":"LU","country":"Luxembourg","city":"Luxembourg","latitude":49.6117,"longitude":6.13,"isp":"Evoluso","hosts":[{"hostname":"lu1.gw.ivpn.net","host":"92.223.89.53","load":13.08,"multihop_port":27201,"obfs":{"obfs3_multihop_port":27202,"obfs4_multihop_port":27203,"obfs4_key":"auDmK8lVBI7fxq6UjXg7V0qoZJ3icACKm/9vruMGSr0lT6ViNsl28qMqYbjJRveHnx5eQw"}}]},{"gateway":"my.gw.ivpn.net","country_code":"MY","country":"Malaysia","city":"Kuala Lumpur","latitude":3.1494,"longitude":101.706,"isp":"TheGigabit","hosts":[{"hostname":"my1.gw.ivpn.net","host":"61.4.97.148","load":6.48,"multihop_port":20810,"obfs":{"obfs3_multihop_port":20811,"obfs4_multihop_port":20812,"obfs4_key":"k2hwCe8gDb24K5n2jNXYO5YCl5XCIEhuRwpYSsEhKWorah8OUM1C1crawbfstj+W2IQdOA"}}]},{"gateway":"nl.gw.ivpn.net","country_code":"NL","country":"Netherlands","city":"Amsterdam","latitude":52.35,"longitude":4.9166,"isp":"Leaseweb","hosts":[{"hostname":"nl3.gw.ivpn.net","host":"95.211.172.68","load":5.45,"multihop_port":23101,"obfs":{"obfs3_multihop_port":23102,"obfs4_multihop_port":23103,"obfs4_key":"eUXsScIg0K0LKVgA8yq2Mc++pfnTQ9nr3gnV8n1NIw7wRqinhO6uuXiSS5J19agQaPK1ew"}},{"hostname":"nl4.gw.ivpn.net","host":"95.211.172.95","load":6.73,"multihop_port":23201,"obfs":{"obfs3_multihop_port":23202,"obfs4_multihop_port":23203,"obfs4_key":"KEw6WJF+NDOQv7yMvq+dAAAkPbcYJ8PX6pffRd8EM3uaOy2QcpMcdHI7s700Kq/ZvV3HBQ"}},{"hostname":"nl5.gw.ivpn.net","host":"95.211.187.222","load":35.96,"multihop_port":23901,"obfs":{"obfs3_multihop_port":23902,"obfs4_multihop_port":23903,"obfs4_key":"fcWCrzzatLbk1LNKsuQZKpQrC3ZXwQ85GO5xRS467KJBRDrmvnyMb6ARbLGu+gYkTnNELQ"}},{"hostname":"nl6.gw.ivpn.net","host":"95.211.187.228","load":24.22,"multihop_port":24101,"obfs":{"obfs3_multihop_port":24102,"obfs4_multihop_port":24103,"obfs4_key":"lT3OGPQS1CwwqtalMExN7qxEoDDBLLlcoh5a6YW3DPj8esEBEG6wY5OfYonxltBzoVu4PA"}},{"hostname":"nl7.gw.ivpn.net","host":"95.211.95.22","load":46.91,"multihop_port":22501,"obfs":{"obfs3_multihop_port":22502,"obfs4_multihop_port":22503,"obfs4_key":"ffMnq7Gc/D7KWoLckJ4t8nf3zZqVdlffe2lVfUCceOyOTdRApkeJGgEai0TI1z76Yey9Lw"}},{"hostname":"nl8.gw.ivpn.net","host":"95.211.172.18","load":12.83,"multihop_port":22801,"obfs":{"obfs3_multihop_port":22802,"obfs4_multihop_port":22803,"obfs4_key":"h+u/6VkPDJXySoJ6QEM1hOjWPD58OS4AZPP9ofP/yCWGBQpPoMc78l7C74eFvqKKkFAXDw"}}]},{"gateway":"no.gw.ivpn.net","country_code":"NO","country":"Norway","city":"Oslo","latitude":59.9167,"longitude":10.75,"isp":"Servetheworld","hosts":[{"hostname":"no1.gw.ivpn.net","host":"194.242.10.150","load":15.17,"multihop_port":25301,"obfs":{"obfs3_multihop_port":25302,"obfs4_multihop_port":25303,"obfs4_key":"uhLy//KRu6DrYfgDJmwjC6Fxk5h+MRDNOwFe7qzGTjfOiHLWRSoRx6OdNvzjPPXq0ZJnZg"}}]},{"gateway":"pl.gw.ivpn.net","country_code":"PL","country":"Poland","city":"Warsaw","latitude":52.25,"longitude":21,"isp":"Datapacket","hosts":[{"hostname":"pl1.gw.ivpn.net","host":"185.246.208.86","load":36.56,"multihop_port":25101,"obfs":{"obfs3_multihop_port":25102,"obfs4_multihop_port":25103,"obfs4_key":"S9XZyigxYjF5jWcwYpMmV9HJq4Vni1yQvLKI03n0TJ7csrgsX7lPpFfECAGQruHh1wkMXg"}}]},{"gateway":"pt.gw.ivpn.net","country_code":"PT","country":"Portugal","city":"Lisbon","latitude":38.7227,"longitude":-9.1449,"isp":"Hostwebis","hosts":[{"hostname":"pt1.gw.ivpn.net","host":"94.46.175.112","load":5.94,"multihop_port":27101,"obfs":{"obfs3_multihop_port":27102,"obfs4_multihop_port":27103,"obfs4_key":"NqXqKMt8UF25hYDIwfh2K4Rr4a7F41HzZDGjX7SYwRaoOtrTL665yV6Z3h9wF+/R1YE8KQ"}}]},{"gateway":"ro.gw.ivpn.net","country_code":"RO","country":"Romania","city":"Bucharest","latitude":44.4334,"longitude":26.0999,"isp":"M247","hosts":[{"hostname":"ro1.gw.ivpn.net","host":"37.120.206.50","load":43.52,"multihop_port":22301,"obfs":{"obfs3_multihop_port":22302,"obfs4_multihop_port":22303,"obfs4_key":"lqfg/sP9uLakoQiA6YI5/kHQ4/FvQTp6jRgxSswjHwC8POOM23FijEWKyykngn1Eb3xfLA"}}]},{"gateway":"rs.gw.ivpn.net","country_code":"RS","country":"Serbia","city":"Belgrade","latitude":44.8186,"longitude":20.468,"isp":"M247","hosts":[{"hostname":"rs1.gw.ivpn.net","host":"141.98.103.250","load":65.32,"multihop_port":26801,"obfs":{"obfs3_multihop_port":26802,"obfs4_multihop_port":26803,"obfs4_key":"0MqgxLrLFQTlQWGAjY9es+Nv45d37/5lulWw0iEFoiUvtzOcbut8hK9AhCis17EXi+lUXw"}}]},{"gateway":"se.gw.ivpn.net","country_code":"SE","country":"Sweden","city":"Stockholm","latitude":59.3508,"longitude":18.0973,"isp":"GleSyS","hosts":[{"hostname":"se1.gw.ivpn.net","host":"80.67.10.138","load":5.66,"multihop_port":24001,"obfs":{"obfs3_multihop_port":24002,"obfs4_multihop_port":24003,"obfs4_key":"/yhTV2SsTXlwsG2mCS90ZAYIZivsSyloaFw6VDj0pnpJOuUxXcZBOgdyQ/lfWxJtvHZmPg"}}]},{"gateway":"sg.gw.ivpn.net","country_code":"SG","country":"Singapore","city":"Singapore","latitude":1.293,"longitude":103.8558,"isp":"M247","hosts":[{"hostname":"sg1.gw.ivpn.net","host":"185.128.24.186","load":23.44,"multihop_port":26101,"obfs":{"obfs3_multihop_port":26102,"obfs4_multihop_port":26103,"obfs4_key":"0N1ZmZlnyhS/3Y1OhvB0Bk3BGU2LFy0zyuWPYwM/P+mfX57w8zI7/YcBfIXZVgDiStt4MQ"}}]},{"gateway":"sk.gw.ivpn.net","country_code":"SK","country":"Slovakia","city":"Bratislava","latitude":48.15,"longitude":17.117,"isp":"M247","hosts":[{"hostname":"sk1.gw.ivpn.net","host":"185.245.85.250","load":100,"multihop_port":25801,"obfs":{"obfs3_multihop_port":25802,"obfs4_multihop_port":25803,"obfs4_key":"8sl7oPfNHdCd2xYi98xWC6mBXyPvzio34UbfUbCPEU+8wo7DVbrR9mf8goR0Ievqzax4Hw"}}]},{"gateway":"tw.gw.ivpn.net","country_code":"TW","country":"Taiwan","city":"Taipei","latitude":25.073,"longitude":121.578,"isp":"TheGigabit","hosts":[{"hostname":"tw1.gw.ivpn.net","host":"185.189.160.6","load":8.89,"multihop_port":20820,"obfs":{"obfs3_multihop_port":20821,"obfs4_multihop_port":20822,"obfs4_key":"/ilRlB3BkUzUG2yd+++6KeYEF9PEB+3T3XcQhVjfoF8wJH1kgjGXvikjS1j/1SknFpGPaA"}}]},{"gateway":"ua.gw.ivpn.net","country_code":"UA","country":"Ukraine","city":"Kharkiv","latitude":50,"longitude":36.25,"isp":"Xservers","hosts":[{"hostname":"ua1.gw.ivpn.net","host":"176.103.58.123","load":6.43,"multihop_port":26301,"obfs":{"obfs3_multihop_port":26302,"obfs4_multihop_port":26303,"obfs4_key":"RsW3q+FmLATkKnKHOheUntwvslkrXEiCBx3ajDjhyHiZMtQI+Uy7TmhFK0YaHg/qKoljYw"}}]},{"gateway":"us-az.gw.ivpn.net","country_code":"US","country":"United States","city":"Phoenix, AZ","latitude":33.5722,"longitude":-112.0891,"isp":"M247","hosts":[{"hostname":"us-az1.gw.ivpn.net","host":"193.37.254.130","load":11.52,"multihop_port":26401,"obfs":{"obfs3_multihop_port":26402,"obfs4_multihop_port":26403,"obfs4_key":"Y2klMvUi3NBIReXSALaKnNm8qI9IdWhFwgQrwl9ofUuVNuT6D93ohTTqbW//iKS5/lqndw"}}]},{"gateway":"us-ca.gw.ivpn.net","country_code":"US","country":"United States","city":"Los Angeles, CA","latitude":34.1139,"longitude":-118.4068,"isp":"Quadranet","hosts":[{"hostname":"us-ca1.gw.ivpn.net","host":"173.254.196.58","load":9.34,"multihop_port":22201,"obfs":{"obfs3_multihop_port":22202,"obfs4_multihop_port":22203,"obfs4_key":"C/Ct5AG8tkV0Yi7MnXv+bNvExY8Dgii4OeJ7DA7lIq3HptUa+WbG+IAR/UIDaMn8VeXDIg"}},{"hostname":"us-ca2.gw.ivpn.net","host":"69.12.80.146","load":6.26,"multihop_port":22401,"obfs":{"obfs3_multihop_port":22402,"obfs4_multihop_port":22403,"obfs4_key":"nvizO9jj1D3xMqCMTnP6XDIzTLy6KcYNsDSxvJjm5QwZ9Y+5gommAk9LIcCeX9o4FjlkVA"}},{"hostname":"us-ca3.gw.ivpn.net","host":"198.54.129.99","load":12.79,"multihop_port":21301,"obfs":{"obfs3_multihop_port":21302,"obfs4_multihop_port":21303,"obfs4_key":"rharPyhkUzYwmCP8ZzeaCwnJAmwOqwDTLOlJqzi/kAxMn4OVXtbzCk9Ww8XR31D2rmk3MA"}},{"hostname":"us-ca4.gw.ivpn.net","host":"173.254.204.202","load":8.2,"multihop_port":21901,"obfs":{"obfs3_multihop_port":21902,"obfs4_multihop_port":21903,"obfs4_key":"2Sdam2VI658TdQRvj5bxwKPFljrsKgwBDv/mqhXNYgDQGs+WVhAz508b2oWVgHed3Ki8dQ"}}]},{"gateway":"us-fl.gw.ivpn.net","country_code":"US","country":"United States","city":"Miami, FL","latitude":25.7839,"longitude":-80.2102,"isp":"Quadranet","hosts":[{"hostname":"us-fl1.gw.ivpn.net","host":"173.44.49.90","load":8.5,"multihop_port":24601,"obfs":{"obfs3_multihop_port":24602,"obfs4_multihop_port":24603,"obfs4_key":"vS7u4rijvWECRS/Mo2KOpl8kx0NOozp3kF/FMxGmCZILE46etitrheYI2hCpNsYUg3YTBQ"}}]},{"gateway":"us-ga.gw.ivpn.net","country_code":"US","country":"United States","city":"Atlanta, GA","latitude":33.7627,"longitude":-84.4225,"isp":"Quadranet","hosts":[{"hostname":"us-ga1.gw.ivpn.net","host":"104.129.24.146","load":5.4,"multihop_port":24501,"obfs":{"obfs3_multihop_port":24502,"obfs4_multihop_port":24503,"obfs4_key":"+No53UtdyPN4uT89vMlvRTjFnxtMKol+oOld9I9WMnlK7BU+y10oXWofzcI4eRgkm195FQ"}},{"hostname":"us-ga2.gw.ivpn.net","host":"107.150.22.74","load":9,"multihop_port":24810,"obfs":{"obfs3_multihop_port":24811,"obfs4_multihop_port":24812,"obfs4_key":"3viWXkxZx1KZF9uzd5tRxb5lNMMnRZ90PqwLUaZdkZuaouj+Vb20t5uk3BVz/YyZkrSoGw"}}]},{"gateway":"us-il.gw.ivpn.net","country_code":"US","country":"United States","city":"Chicago, IL","latitude":41.8373,"longitude":-87.6862,"isp":"Quadranet","hosts":[{"hostname":"us-il1.gw.ivpn.net","host":"107.150.28.82","load":13.31,"multihop_port":21401,"obfs":{"obfs3_multihop_port":21402,"obfs4_multihop_port":21403,"obfs4_key":"6PpxOt8CwINAjun8o/wsf/cAidNbJZM/Pg4im1Cx9kCBV/lau3XFq3bMwBW0SzptZ/5WdA"}},{"hostname":"us-il2.gw.ivpn.net","host":"72.11.137.146","load":7.21,"multihop_port":24901,"obfs":{"obfs3_multihop_port":24902,"obfs4_multihop_port":24903,"obfs4_key":"cfvJR/gplqAbFx8myJSW/cPC3hN1782PPma2v5YKJR5LyekWX+AHTJjzdz8xSr2mM6IGQw"}}]},{"gateway":"us-nj.gw.ivpn.net","country_code":"US","country":"United States","city":"New Jersey, NJ","latitude":40.737764,"longitude":-74.151747,"isp":"Quadranet","hosts":[{"hostname":"us-nj3.gw.ivpn.net","host":"23.226.128.18","load":17.66,"multihop_port":21610,"obfs":{"obfs3_multihop_port":21611,"obfs4_multihop_port":21612,"obfs4_key":"JtB/8Lv8MOq9+bpYC751voS2CwoEwf9ku2CziwJScn3Gc1F/BTul6ehnrGiedmpkQXAtJw"}},{"hostname":"us-nj4.gw.ivpn.net","host":"194.36.111.50","load":14.38,"multihop_port":27401,"obfs":{"obfs3_multihop_port":27402,"obfs4_multihop_port":27403,"obfs4_key":"lHDLT6cTgt0bh3ysogDdiXL4eWGRtJZ0cZGJmvpeK0YLUAsBfsOzKv46V0iv5ykwRPm6Mg"}}]},{"gateway":"us-nv.gw.ivpn.net","country_code":"US","country":"United States","city":"Las Vegas, NV","latitude":36.2333,"longitude":-115.2654,"isp":"M247","hosts":[{"hostname":"us-nv1.gw.ivpn.net","host":"185.242.5.34","load":8.82,"multihop_port":26501,"obfs":{"obfs3_multihop_port":26502,"obfs4_multihop_port":26503,"obfs4_key":"Kux7OTSrUOkklATpG67hJPz7xCWpW6eD9Qdw2GNKAmaaPA5zvPC3SXQRvyrYdyAAqMXMfg"}}]},{"gateway":"us-ny.gw.ivpn.net","country_code":"US","country":"United States","city":"New York, NY","latitude":40.6943,"longitude":-73.9249,"isp":"M247","hosts":[{"hostname":"us-ny2.gw.ivpn.net","host":"212.103.48.194","load":8.1,"multihop_port":21801,"obfs":{"obfs3_multihop_port":21802,"obfs4_multihop_port":21803,"obfs4_key":"GtK9yCXTtrLOrf0MTWdWqjzQ1vd1eKsVjiOuR5CiVaDf4dCSalyJ+kmik4nfU9Gj6UwcCg"}},{"hostname":"us-ny3.gw.ivpn.net","host":"89.187.178.144","load":5.14,"multihop_port":27601,"obfs":{"obfs3_multihop_port":27602,"obfs4_multihop_port":27603,"obfs4_key":"eL/9iKx6f5bHowNJBsT2E/Aag5w8Cvtb3DduySudJmuK2GtIOUwNzS33lFZwSUEnJIYwLg"}}]},{"gateway":"us-tx.gw.ivpn.net","country_code":"US","country":"United States","city":"Dallas, TX","latitude":32.7936,"longitude":-96.7662,"isp":"Quadranet","hosts":[{"hostname":"us-tx1.gw.ivpn.net","host":"96.44.189.194","load":13.06,"multihop_port":21001,"obfs":{"obfs3_multihop_port":21002,"obfs4_multihop_port":21003,"obfs4_key":"GBDWrGN71fGa7a7S8b2tHzjYQMhnA2vJW5yq3iID+VoSzA1xIAgHiOxISEU93v+CBTCXWg"}},{"hostname":"us-tx2.gw.ivpn.net","host":"96.44.142.74","load":10.52,"multihop_port":25001,"obfs":{"obfs3_multihop_port":25002,"obfs4_multihop_port":25003,"obfs4_key":"VYfEVELWNqOm7kyO19usXm3GSK9wawRObopQLOLDbLodKnmX/jPah+IlGkL2xYiNxEzUKw"}}]},{"gateway":"us-ut.gw.ivpn.net","country_code":"US","country":"United States","city":"Salt Lake City, UT","latitude":40.7774,"longitude":-111.93,"isp":"100TB","hosts":[{"hostname":"us-ut1.gw.ivpn.net","host":"198.105.216.28","load":15.91,"multihop_port":24401,"obfs":{"obfs3_multihop_port":24402,"obfs4_multihop_port":24403,"obfs4_key":"gb5dp9i4QnFKT0GQPMEsDlqN+JORU3lyU65s9R1064aZ1jKfWfkc+SxbOlNEh23CvIAOeg"}}]},{"gateway":"us-va.gw.ivpn.net","country_code":"US","country":"United States","city":"Ashburn, VA","latitude":39.0437,"longitude":-77.4875,"isp":"Datapacket","hosts":[{"hostname":"us-va1.gw.ivpn.net","host":"37.19.206.105","load":22.97,"multihop_port":27701,"obfs":{"obfs3_multihop_port":27702,"obfs4_multihop_port":27703,"obfs4_key":"5Lk8BSID+M9QAGSglQTrYkom+V0mkIv0HgR80+9vKCcnZOu0f+aJhfOXqKnpHarJbIEHCw"}}]},{"gateway":"us-wa.gw.ivpn.net","country_code":"US","country":"United States","city":"Seattle, WA","latitude":47.6211,"longitude":-122.3244,"isp":"Tzulo","hosts":[{"hostname":"us-wa2.gw.ivpn.net","host":"198.44.131.3","load":14.58,"multihop_port":27801,"obfs":{"obfs3_multihop_port":27802,"obfs4_multihop_port":27803,"obfs4_key":"9h0W5BTzGSDpY2tGjdvViSJfEkT/BuwHS0cnFX07cEj3RRDtmxsC0f+kapO8+Kh+fz1XMQ"}}]},{"gateway":"za.gw.ivpn.net","country_code":"ZA","country":"South Africa","city":"Johannesburg","latitude":-26.195,"longitude":28.034,"isp":"Datapacket","hosts":[{"hostname":"za1.gw.ivpn.net","host":"169.150.238.103","load":8.1,"multihop_port":20840,"obfs":{"obfs3_multihop_port":20841,"obfs4_multihop_port":20842,"obfs4_key":"vM1zdiOMhoqMKZCOi/lMj7TfWJb5/UsM25p8FE/AUezwbYWhUkhpD5RbXBOBDNhZuYzPGA"}}]}],"config":{"antitracker":{"default":{"ip":"10.0.254.2","multihop-ip":"10.0.254.102"},"hardcore":{"ip":"10.0.254.3","multihop-ip":"10.0.254.103"}},"api":{"ips":["198.50.177.220","149.56.162.156","198.50.177.222","149.56.162.159","198.50.177.223"],"ipv6s":["2607:5300:203:1735::8888","2607:5300:203:1735::8","2607:5300:203:1735:6580:7300:0:aaaa"]},"ports":{"openvpn":[{"type":"UDP","port":53},{"type":"UDP","port":80},{"type":"UDP","range":{"min":5500,"max":19999}},{"type":"UDP","range":{"min":60000,"max":65000}},{"type":"UDP","port":123},{"type":"UDP","port":2049},{"type":"UDP","range":{"min":50000,"max":59999}},{"type":"UDP","port":2050},{"type":"UDP","range":{"min":40000,"max":49999}},{"type":"UDP","port":443},{"type":"UDP","port":1194},{"type":"UDP","range":{"min":30000,"max":39999}},{"type":"TCP","port":80},{"type":"TCP","port":443},{"type":"TCP","port":1194},{"type":"TCP","port":2049},{"type":"TCP","port":2050},{"type":"TCP","port":30587},{"type":"TCP","port":41893},{"type":"TCP","port":48574},{"type":"TCP","port":58237},{"type":"TCP","range":{"min":5500,"max":19999}},{"type":"TCP","range":{"min":30000,"max":65000}}],"wireguard":[{"type":"UDP","port":53},{"type":"UDP","port":80},{"type":"UDP","port":123},{"type":"UDP","port":443},{"type":"UDP","port":500},{"type":"UDP","port":1194},{"type":"UDP","port":2049},{"type":"UDP","port":2050},{"type":"UDP","port":4500},{"type":"UDP","port":30587},{"type":"UDP","port":41893},{"type":"UDP","port":48574},{"type":"UDP","port":58237},{"type":"UDP","range":{"min":5500,"max":19999}},{"type":"UDP","range":{"min":30000,"max":65000}}],"obfs3":{"port":5145},"obfs4":{"port":5146}}}} +{"wireguard":[{"gateway":"ca-qc.wg.ivpn.net","country_code":"CA","country":"Canada","city":"Montreal","latitude":45.5,"longitude":-73.5833,"isp":"M247","hosts":[{"hostname":"ca1.wg.ivpn.net","dns_name":"ca1.wg.ivpn.net","host":"37.120.130.58","public_key":"rg+GGDmjM4Vxo1hURvKmgm9yonb6qcoKbPCP/DNDBnI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":22.2,"multihop_port":23810},{"hostname":"ca-qc1.wg.ivpn.net","dns_name":"ca-qc1.gw.ivpn.net","host":"87.101.92.29","public_key":"98JU1mdCR8vD1aNZg017/NjBeTjuuCKUaLw0zfz/CUE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":45.55,"multihop_port":27001}]},{"gateway":"ch.wg.ivpn.net","country_code":"CH","country":"Switzerland","city":"Zurich","latitude":47.38,"longitude":8.55,"isp":"Privatelayer","hosts":[{"hostname":"ch1.wg.ivpn.net","dns_name":"ch1.wg.ivpn.net","host":"141.255.164.66","public_key":"jVZJ61i1xxkAfriDHpwvF/GDuTvZUqhwoWSjkOJvaUA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.54,"multihop_port":23610},{"hostname":"ch01.wg.ivpn.net","dns_name":"ch1.gw.ivpn.net","host":"185.212.170.141","public_key":"dU7gLfcupYd37LW0q6cxC6PHMba+eUFAUOoU/ryXZkY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.28,"multihop_port":23601},{"hostname":"ch3.wg.ivpn.net","dns_name":"ch3.gw.ivpn.net","host":"141.255.166.198","public_key":"JBpgBKtqIneRuEga7mbP2PAk/e4HPRaC11H0A0+R3lA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.47,"multihop_port":22901}]},{"gateway":"de.wg.ivpn.net","country_code":"DE","country":"Germany","city":"Frankfurt","latitude":50.1,"longitude":8.675,"isp":"Datapacket","hosts":[{"hostname":"de1.wg.ivpn.net","dns_name":"de1.wg.ivpn.net","host":"185.102.219.26","public_key":"mS3/WpXjnMAMmXjSpd4nFzx9HSE3ubv2WyjpyH2REgs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.08,"multihop_port":23010},{"hostname":"de01.wg.ivpn.net","dns_name":"de1.gw.ivpn.net","host":"178.162.212.24","public_key":"Sc5AUZieg0qX8kyCy9p0OHRES4n0CHtHHM+ZPyERFTc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.27,"multihop_port":23001},{"hostname":"de2.wg.ivpn.net","dns_name":"de2.gw.ivpn.net","host":"37.58.60.151","public_key":"QhY3OtBf4FFafKtLO33e6k8JnAl8e6ktFcRUyLjCDVY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.01,"multihop_port":22001},{"hostname":"de3.wg.ivpn.net","dns_name":"de3.gw.ivpn.net","host":"146.70.160.170","public_key":"CugQQtD8YJKRwS5IukNWkMcyqOzlOxfGRPhGeQRAb2Y=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":24.1,"multihop_port":21050}]},{"gateway":"gb.wg.ivpn.net","country_code":"GB","country":"United Kingdom","city":"London","latitude":51.5,"longitude":-0.1167,"isp":"M247","hosts":[{"hostname":"gb1.wg.ivpn.net","dns_name":"gb1.wg.ivpn.net","host":"81.92.202.114","public_key":"7+jos+Eg+hMEOQE4Std6OJ+WVnCcmbqS1/EbPwn9w3s=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.49,"multihop_port":20810},{"hostname":"gb01.wg.ivpn.net","dns_name":"gb1.gw.ivpn.net","host":"185.59.221.140","public_key":"yKK5x+D17Jr3Q12T/UBaDjNVmNdZBsqpvTqH6YfsGHg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":14.99,"multihop_port":20801},{"hostname":"gb2.wg.ivpn.net","dns_name":"gb2.gw.ivpn.net","host":"185.59.221.225","public_key":"x0BTRaxsdxAd58ZyU2YMX4bmuj+Eg+8/urT2F3Vs1n8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.89,"multihop_port":24201}]},{"gateway":"it.wg.ivpn.net","country_code":"IT","country":"Italy","city":"Milan","latitude":45.47,"longitude":9.205,"isp":"M247","hosts":[{"hostname":"it1.wg.ivpn.net","dns_name":"it1.wg.ivpn.net","host":"82.102.21.90","public_key":"Aj6b81yrDk7I913R+fuSW/NAmIl87N73vHgY5/WQY0Q=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.55,"multihop_port":24310},{"hostname":"it2.wg.ivpn.net","dns_name":"it2.gw.ivpn.net","host":"84.17.59.149","public_key":"IYi+s9DZusPErv0k2Ls/jgdubmeCrUcEJ1cNgmxPx0k=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.51,"multihop_port":21100}]},{"gateway":"nl.wg.ivpn.net","country_code":"NL","country":"Netherlands","city":"Amsterdam","latitude":52.35,"longitude":4.9166,"isp":"Datapacket","hosts":[{"hostname":"nl1.wg.ivpn.net","dns_name":"nl1.wg.ivpn.net","host":"185.102.218.104","public_key":"AsMT2FqpkZbjzWeDch6GwufF5odl259W/hIkGytVfWo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":22.6,"multihop_port":20301},{"hostname":"nl3.wg.ivpn.net","dns_name":"nl3.gw.ivpn.net","host":"95.211.95.9","public_key":"XDU6Syq1DY82IMatsHV0x/TAtbLiRwh/SdFCXlEn40c=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.08,"multihop_port":23101},{"hostname":"nl4.wg.ivpn.net","dns_name":"nl4.gw.ivpn.net","host":"95.211.95.19","public_key":"cVB66gPq5cZ9dfXY+e2pbsCyih5o1zk04l5c5VCsV1g=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.35,"multihop_port":23201},{"hostname":"nl5.wg.ivpn.net","dns_name":"nl5.gw.ivpn.net","host":"95.211.243.162","public_key":"NCagAawwRixI6Iw/NWiGD8lbjDNCl0aTICZKJtO/1HA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":25.48,"multihop_port":23901},{"hostname":"nl6.wg.ivpn.net","dns_name":"nl6.gw.ivpn.net","host":"95.211.243.182","public_key":"hMWpqb3FEATHIbImPVWB/5z2nWIXghwpnJjevPY+1H0=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":35.7,"multihop_port":24101},{"hostname":"nl7.wg.ivpn.net","dns_name":"nl7.gw.ivpn.net","host":"95.211.172.105","public_key":"hQNYqtfOOAEz0IGshLx/TI9hUrfR9gIIkjVm4VsCbBM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.84,"multihop_port":22501},{"hostname":"nl8.wg.ivpn.net","dns_name":"nl8.gw.ivpn.net","host":"95.211.198.167","public_key":"/nY1/OhVhdHtbnU/s31zYUuPBH0pizv4DemW5KDOUkg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":41.86,"multihop_port":22801}]},{"gateway":"se.wg.ivpn.net","country_code":"SE","country":"Sweden","city":"Stockholm","latitude":59.3508,"longitude":18.0973,"isp":"M247","hosts":[{"hostname":"se1.wg.ivpn.net","dns_name":"se1.wg.ivpn.net","host":"37.120.153.226","public_key":"2n0nFE1g/+vQr2AOQPm9Igyiy0zh9uTTultvOOSkMRo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.18,"multihop_port":24010},{"hostname":"se01.wg.ivpn.net","dns_name":"se1.gw.ivpn.net","host":"80.67.10.141","public_key":"u8VHnYEpoEjJWDAF9NAUkU6s810RnkMuhEfFD9U0cGo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":18.44,"multihop_port":24001}]},{"gateway":"sg.wg.ivpn.net","country_code":"SG","country":"Singapore","city":"Singapore","latitude":1.293,"longitude":103.8558,"isp":"M247","hosts":[{"hostname":"sg1.wg.ivpn.net","dns_name":"sg1.wg.ivpn.net","host":"37.120.151.122","public_key":"hSg0At4uwuIhmTy5UT4fRbi5AN6JO2ZWTuIvqd4nHCE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":31.71,"multihop_port":26110},{"hostname":"sg01.wg.ivpn.net","dns_name":"sg1.gw.ivpn.net","host":"185.128.24.189","public_key":"pWk0u1Xq8FHC+xpkN+C6yEKOTEanorR5zMCSfHlLzFw=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":18.02,"multihop_port":26101}]},{"gateway":"us-ca.wg.ivpn.net","country_code":"US","country":"United States","city":"Los Angeles, CA","latitude":34.1139,"longitude":-118.4068,"isp":"Datapacket","hosts":[{"hostname":"us-ca1.wg.ivpn.net","dns_name":"us-ca1.wg.ivpn.net","host":"185.180.13.41","public_key":"FGl78s9Ct6xNamQ2/CtAyXwGePrrU0kiZxfM27pm8XA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.89,"multihop_port":22210},{"hostname":"us-ca01.wg.ivpn.net","dns_name":"us-ca1.gw.ivpn.net","host":"216.144.236.44","public_key":"B+qXdkIuETpzI0bfhGUAHN4SU91Tjs6ItdFlu93S42I=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.36,"multihop_port":22201},{"hostname":"us-ca2.wg.ivpn.net","dns_name":"us-ca2.gw.ivpn.net","host":"216.144.236.68","public_key":"qv4Tupfon5NUSwzDpM8zPizSwJZn2h+9CqrufcyDOko=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.88,"multihop_port":22401},{"hostname":"us-ca3.wg.ivpn.net","dns_name":"us-ca3.gw.ivpn.net","host":"198.54.129.100","public_key":"J5+Bx84LxNPdWEhewOvBV/fGWiDluIBlAcr1QlJZil8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":12.21,"multihop_port":21301},{"hostname":"us-ca4.wg.ivpn.net","dns_name":"us-ca4.gw.ivpn.net","host":"216.144.237.83","public_key":"dYPXYr6HSRJPe3MhALwGWNtdEy1+EPE9Kqv7cTrUXk8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":34.8,"multihop_port":21901}]},{"gateway":"us-ga.wg.ivpn.net","country_code":"US","country":"United States","city":"Atlanta, GA","latitude":33.7627,"longitude":-84.4225,"isp":"Datapacket","hosts":[{"hostname":"us-ga1.wg.ivpn.net","dns_name":"us-ga1.wg.ivpn.net","host":"185.93.0.212","public_key":"jD8h+pL5/d6fmYcTzl0lR8AWzQVN5XkwRFSmM/3NcDM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":12.65,"multihop_port":24510},{"hostname":"us-ga01.wg.ivpn.net","dns_name":"us-ga1.gw.ivpn.net","host":"104.129.24.149","public_key":"EJFl28aYpZKfmJqb1jxxTEnGx6kaH2USVrigpHKKXhs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8.33,"multihop_port":24501},{"hostname":"us-ga2.wg.ivpn.net","dns_name":"us-ga2.gw.ivpn.net","host":"107.150.22.77","public_key":"hr2uQOEGCvGeDkoCQJ2dCI8dM8Iu5aKhb1PIvJ9q72E=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.77,"multihop_port":24810}]},{"gateway":"us-il.wg.ivpn.net","country_code":"US","country":"United States","city":"Chicago, IL","latitude":41.8373,"longitude":-87.6862,"isp":"Datapacket","hosts":[{"hostname":"us-il1.wg.ivpn.net","dns_name":"us-il1.wg.ivpn.net","host":"89.187.181.116","public_key":"hku9gjamhoii8OvxZgx+TdUDIkOAQYFu39qbav2AyUQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":15.99,"multihop_port":21410},{"hostname":"us-il01.wg.ivpn.net","dns_name":"us-il1.gw.ivpn.net","host":"72.11.137.158","public_key":"Uy5a8JOqneAUY1dC5s9jubLnotbyIfBsLP2nZuzRbHs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.09,"multihop_port":21401},{"hostname":"us-il2.wg.ivpn.net","dns_name":"us-il2.gw.ivpn.net","host":"72.11.137.148","public_key":"ANhVUMAQgStPVNRHW8mg0ZtN1YI1QHyXfNCO8+USNQQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":26.58,"multihop_port":24901}]},{"gateway":"us-ny.wg.ivpn.net","country_code":"US","country":"United States","city":"New York, NY","latitude":40.6943,"longitude":-73.9249,"isp":"M247","hosts":[{"hostname":"us-ny1.wg.ivpn.net","dns_name":"us-ny1.wg.ivpn.net","host":"91.132.137.170","public_key":"6/tjvgb7HFl7UuvBSegolxa1zKr3iSlDrlCexCmhAGE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.95,"multihop_port":21210},{"hostname":"us-ny2.wg.ivpn.net","dns_name":"us-ny2.gw.ivpn.net","host":"212.103.48.195","public_key":"c7DwY2uT+6ulWAJ5u8qJNWHroA0qyJLcdNzf/f2kkhs=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.35,"multihop_port":21801},{"hostname":"us-ny3.wg.ivpn.net","dns_name":"us-ny3.gw.ivpn.net","host":"89.187.178.145","public_key":"m5/Ssw9SN3WuE+yD/fAsH5G8iuI8TcDGEiZZnPgiMCc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.66,"multihop_port":27601}]},{"gateway":"us-tx.wg.ivpn.net","country_code":"US","country":"United States","city":"Dallas, TX","latitude":32.7936,"longitude":-96.7662,"isp":"Quadranet","hosts":[{"hostname":"us-tx1.wg.ivpn.net","dns_name":"us-tx1.wg.ivpn.net","host":"198.55.124.114","public_key":"JPT1veXLmasj2uQDstX24mpR7VWD+GmV8JDkidkz91Q=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.72,"multihop_port":21010},{"hostname":"us-tx01.wg.ivpn.net","dns_name":"us-tx1.gw.ivpn.net","host":"96.44.189.197","public_key":"LvWf548mFddi8PTrIGL6uD1/l85LU8z0Rc8tpvw2Vls=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.36,"multihop_port":21001},{"hostname":"us-tx2.wg.ivpn.net","dns_name":"us-tx2.gw.ivpn.net","host":"96.44.142.77","public_key":"om8hOGUcEvoOhHvJZoBHxNF4jxY/+Ml9Iy1WOSC/pFo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.49,"multihop_port":25001}]},{"gateway":"at.wg.ivpn.net","country_code":"AT","country":"Austria","city":"Vienna","latitude":48.2,"longitude":16.3666,"isp":"M247","hosts":[{"hostname":"at1.wg.ivpn.net","dns_name":"at1.gw.ivpn.net","host":"185.244.212.69","public_key":"83LUBnP97SFpnS0y1MpEAFcg8MIiQJgW1FRv/8Mc40g=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":97.98,"multihop_port":25601}]},{"gateway":"au-nsw.wg.ivpn.net","country_code":"AU","country":"Australia","city":"Sydney","latitude":-33.92,"longitude":151.1852,"isp":"M247","hosts":[{"hostname":"au-nsw1.wg.ivpn.net","dns_name":"au-nsw1.gw.ivpn.net","host":"46.102.153.246","public_key":"KmSrG48t5xw9CJCPlYLBG3JnmiY0CnUgyRM5TUEwZhM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":76.76,"multihop_port":26601},{"hostname":"au-nsw2.wg.ivpn.net","dns_name":"au-nsw2.gw.ivpn.net","host":"146.70.78.75","public_key":"q+wbp7GjiTszp5G16rNpGCqxkL0qSY3CH4pcgD6UsVQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":42.03,"multihop_port":27901}]},{"gateway":"be.wg.ivpn.net","country_code":"BE","country":"Belgium","city":"Brussels","latitude":50.8333,"longitude":4.3333,"isp":"M247","hosts":[{"hostname":"be1.wg.ivpn.net","dns_name":"be1.gw.ivpn.net","host":"194.187.251.13","public_key":"awriP5lpdxEMWKuG+A1DOg+vb1M5jd3WhynIMB61BhU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":99.49,"multihop_port":25701}]},{"gateway":"bg.wg.ivpn.net","country_code":"BG","country":"Bulgaria","city":"Sofia","latitude":42.6833,"longitude":23.3167,"isp":"M247","hosts":[{"hostname":"bg1.wg.ivpn.net","dns_name":"bg1.gw.ivpn.net","host":"82.102.23.21","public_key":"WDSsdJE6wvATIWfzQwayPtE/0DaXBQgW/hPm7sQSJmU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":47.1,"multihop_port":25901}]},{"gateway":"br.wg.ivpn.net","country_code":"BR","country":"Brazil","city":"Franca","latitude":-20.53,"longitude":-47.39,"isp":"Qnax","hosts":[{"hostname":"br1.wg.ivpn.net","dns_name":"br1.gw.ivpn.net","host":"45.162.229.133","public_key":"eN1f15S3YzRyYCALiPGRQcjkQO9xntcdqPhJJ6TOymc=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.39,"multihop_port":26701}]},{"gateway":"ca.wg.ivpn.net","country_code":"CA","country":"Canada","city":"Toronto","latitude":43.7,"longitude":-79.42,"isp":"Amanah","hosts":[{"hostname":"ca01.wg.ivpn.net","dns_name":"ca1.gw.ivpn.net","host":"104.254.90.181","public_key":"mdGnCZwinuOVGg46zsWnFhhenfFId6jht9GBTKB+xUA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":94.46,"multihop_port":23801},{"hostname":"ca2.wg.ivpn.net","dns_name":"ca2.gw.ivpn.net","host":"172.86.186.173","public_key":"5qHV10ZbFgEGnF6wg9QpKeh1l6Di2JUG/5PdNaaoNW8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":85.18,"multihop_port":22101}]},{"gateway":"cz.wg.ivpn.net","country_code":"CZ","country":"Czech Republic","city":"Prague","latitude":50.0833,"longitude":14.466,"isp":"Datapacket","hosts":[{"hostname":"cz1.wg.ivpn.net","dns_name":"cz1.gw.ivpn.net","host":"185.180.14.41","public_key":"gVbEq2cGRzwCSGPqT2oRSYYN+P6IK3uvvRffErASDSk=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":17.92,"multihop_port":25201}]},{"gateway":"dk.wg.ivpn.net","country_code":"DK","country":"Denmark","city":"Copenhagen","latitude":55.6786,"longitude":12.5635,"isp":"M247","hosts":[{"hostname":"dk1.wg.ivpn.net","dns_name":"dk1.gw.ivpn.net","host":"185.245.84.229","public_key":"jTsV5gOD7lT4egDj9rhKwO2OO2X7bKs2EQPcZEnUWDE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":40.34,"multihop_port":25501}]},{"gateway":"es.wg.ivpn.net","country_code":"ES","country":"Spain","city":"Madrid","latitude":40.4,"longitude":-3.6834,"isp":"Datapacket","hosts":[{"hostname":"es1.wg.ivpn.net","dns_name":"es1.gw.ivpn.net","host":"84.17.62.98","public_key":"w7umiArTtlJ4Pk6Ii9WX5VXK5vw/Qu+Z37/icKlIYWo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":9.23,"multihop_port":21501}]},{"gateway":"fi.wg.ivpn.net","country_code":"FI","country":"Finland","city":"Helsinki","latitude":60.1756,"longitude":24.9341,"isp":"Creanova","hosts":[{"hostname":"fi1.wg.ivpn.net","dns_name":"fi1.gw.ivpn.net","host":"194.34.134.63","public_key":"mIxEzfjZ2wV6jJVj30w38ECd2LSH4bw/HLMnM2ICHiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":100,"multihop_port":26001}]},{"gateway":"fr.wg.ivpn.net","country_code":"FR","country":"France","city":"Paris","latitude":48.8667,"longitude":2.3333,"isp":"Datapacket","hosts":[{"hostname":"fr1.wg.ivpn.net","dns_name":"fr1.gw.ivpn.net","host":"185.246.211.185","public_key":"g7BuMzj3r/noLiLR4qhQMcvU6GSIY8RGEnaYtdYsFX4=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":25.15,"multihop_port":23401}]},{"gateway":"gb-man.wg.ivpn.net","country_code":"GB","country":"United Kingdom","city":"Manchester","latitude":53.5004,"longitude":-2.248,"isp":"M247","hosts":[{"hostname":"gb-man1.wg.ivpn.net","dns_name":"gb-man1.gw.ivpn.net","host":"89.238.141.231","public_key":"+hf4DYilNEIjTdSOuCNcWdqVyaRoxGzXw7wvNl7f7Rg=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.87,"multihop_port":26901}]},{"gateway":"hk.wg.ivpn.net","country_code":"HK","country":"Hong Kong","city":"Hong Kong","latitude":22.305,"longitude":114.185,"isp":"Leaseweb","hosts":[{"hostname":"hk2.wg.ivpn.net","dns_name":"hk2.gw.ivpn.net","host":"64.120.120.239","public_key":"kyolyq4cJydI3vQB2ESTIUAy2Fq0bpOf+Qe7GIq6XEA=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":88.87,"multihop_port":27501},{"hostname":"hk3.wg.ivpn.net","dns_name":"hk3.gw.ivpn.net","host":"118.107.244.206","public_key":"qq1simsFNm2FpZM0J8u8Aa0rkk5HEasvLksPyLv+0Sk=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":8,"multihop_port":20800}]},{"gateway":"hu.wg.ivpn.net","country_code":"HU","country":"Hungary","city":"Budapest","latitude":47.5,"longitude":19.0833,"isp":"M247","hosts":[{"hostname":"hu1.wg.ivpn.net","dns_name":"hu1.gw.ivpn.net","host":"185.189.114.189","public_key":"G30fNdXrnlqtqqOLF23QXWzFdLIKDxLW60HoYPvqml8=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":98.65,"multihop_port":25401}]},{"gateway":"il.wg.ivpn.net","country_code":"IL","country":"Israel","city":"Holon, Tel Aviv","latitude":32.08,"longitude":34.77,"isp":"HQServ","hosts":[{"hostname":"il01.wg.ivpn.net","dns_name":"il1.gw.ivpn.net","host":"185.191.207.197","public_key":"HR9gAjpxXU3YVt6kehBw5n8yVYVE0iIgJdc4HTqOzEE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":36.94,"multihop_port":27301}]},{"gateway":"is.wg.ivpn.net","country_code":"IS","country":"Iceland","city":"Reykjavik","latitude":64.15,"longitude":-21.95,"isp":"Advania","hosts":[{"hostname":"is1.wg.ivpn.net","dns_name":"is1.gw.ivpn.net","host":"82.221.107.185","public_key":"nZZT6TlQ2dXlVe3P3B5ozEScHYMWH4JY4y3to8w5dz0=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":100,"multihop_port":23501}]},{"gateway":"jp.wg.ivpn.net","country_code":"JP","country":"Japan","city":"Tokyo","latitude":35.685,"longitude":139.7514,"isp":"M247","hosts":[{"hostname":"jp1.wg.ivpn.net","dns_name":"jp1.gw.ivpn.net","host":"91.207.174.237","public_key":"tb9WdC3LSho3d1rI5N7kfG9e42/d+u4LPVdEYERPsSQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":53.79,"multihop_port":26201},{"hostname":"jp2.wg.ivpn.net","dns_name":"jp2.gw.ivpn.net","host":"185.135.77.81","public_key":"YuhEd9+a90/+uucZC+qzsyMHkfe/GiwG1dq7g2HegXQ=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":22.31,"multihop_port":20830}]},{"gateway":"lu.wg.ivpn.net","country_code":"LU","country":"Luxembourg","city":"Luxembourg","latitude":49.6117,"longitude":6.13,"isp":"Evoluso","hosts":[{"hostname":"lu1.wg.ivpn.net","dns_name":"lu1.gw.ivpn.net","host":"92.223.89.57","public_key":"hUS1OAFLGwpba8+oc5mifYtohZt/RTro5dMyYBLYHjI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":93.03,"multihop_port":27201}]},{"gateway":"my.wg.ivpn.net","country_code":"MY","country":"Malaysia","city":"Kuala Lumpur","latitude":3.1494,"longitude":101.706,"isp":"TheGigabit","hosts":[{"hostname":"my1.wg.ivpn.net","dns_name":"my1.gw.ivpn.net","host":"61.4.97.153","public_key":"M9SsMCpUw7ad6YbqQr8r2saBK2zAf3tBj82DzsQjgkY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11,"multihop_port":20810}]},{"gateway":"no.wg.ivpn.net","country_code":"NO","country":"Norway","city":"Oslo","latitude":59.9167,"longitude":10.75,"isp":"Servetheworld","hosts":[{"hostname":"no1.wg.ivpn.net","dns_name":"no1.gw.ivpn.net","host":"91.189.177.156","public_key":"xFO6ksbO3Gr05rRgAW0O5Veoi4bpTgz2G9RvtBzK7Cg=","local_ip":"172.16.0.1/12","ipv6":{},"load":26.13,"multihop_port":25301}]},{"gateway":"pl.wg.ivpn.net","country_code":"PL","country":"Poland","city":"Warsaw","latitude":52.25,"longitude":21,"isp":"Datapacket","hosts":[{"hostname":"pl1.wg.ivpn.net","dns_name":"pl1.gw.ivpn.net","host":"185.246.208.109","public_key":"1JDmF79rWj5C+kHp71AbdHne/yGaizWCd2bLfSFvYjo=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.82,"multihop_port":25101}]},{"gateway":"pt.wg.ivpn.net","country_code":"PT","country":"Portugal","city":"Lisbon","latitude":38.7227,"longitude":-9.1449,"isp":"Hostwebis","hosts":[{"hostname":"pt1.wg.ivpn.net","dns_name":"pt1.gw.ivpn.net","host":"94.46.175.113","public_key":"nMnA82YVrvEK80GVoY/0Z9McWeqjcLzuMYSL+86j5nU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":20.75,"multihop_port":27101}]},{"gateway":"ro.wg.ivpn.net","country_code":"RO","country":"Romania","city":"Bucharest","latitude":44.4334,"longitude":26.0999,"isp":"M247","hosts":[{"hostname":"ro1.wg.ivpn.net","dns_name":"ro1.gw.ivpn.net","host":"37.120.206.53","public_key":"F2uQ57hysZTlw8WYELnyCw9Lga80wNYoYwkrrxyXKmw=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":96.95,"multihop_port":22301}]},{"gateway":"rs.wg.ivpn.net","country_code":"RS","country":"Serbia","city":"Belgrade","latitude":44.8186,"longitude":20.468,"isp":"M247","hosts":[{"hostname":"rs1.wg.ivpn.net","dns_name":"rs1.gw.ivpn.net","host":"141.98.103.253","public_key":"xLN/lpQThQ3z3tvYf7VqdAsRL/nton1Vhv2kCZlQtWE=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":100,"multihop_port":26801}]},{"gateway":"sk.wg.ivpn.net","country_code":"SK","country":"Slovakia","city":"Bratislava","latitude":48.15,"longitude":17.117,"isp":"M247","hosts":[{"hostname":"sk1.wg.ivpn.net","dns_name":"sk1.gw.ivpn.net","host":"185.245.85.253","public_key":"MOBWWpEgNsKbFj4BEyWSDFLlkBs5iUFiqdSdTFTDBko=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":62.68,"multihop_port":25801}]},{"gateway":"tw.wg.ivpn.net","country_code":"TW","country":"Taiwan","city":"Taipei","latitude":25.073,"longitude":121.578,"isp":"TheGigabit","hosts":[{"hostname":"tw1.wg.ivpn.net","dns_name":"tw1.gw.ivpn.net","host":"185.189.160.59","public_key":"fMTCCbbKqPp60fkqnaQvJ9mX2r6zBlt7xhUp8sGfJQY=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.45,"multihop_port":20820}]},{"gateway":"ua.wg.ivpn.net","country_code":"UA","country":"Ukraine","city":"Kharkiv","latitude":50,"longitude":36.25,"isp":"Xservers","hosts":[{"hostname":"ua1.wg.ivpn.net","dns_name":"ua1.gw.ivpn.net","host":"176.103.57.129","public_key":"mIxEzfjZ2wV6jJVj30w38ECd2LSH4bw/HLMnM2ICHiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.09,"multihop_port":26301}]},{"gateway":"us-az.wg.ivpn.net","country_code":"US","country":"United States","city":"Phoenix, AZ","latitude":33.5722,"longitude":-112.0891,"isp":"M247","hosts":[{"hostname":"us-az1.wg.ivpn.net","dns_name":"us-az1.gw.ivpn.net","host":"193.37.254.133","public_key":"Ts4MGazxpxL9rrYbERjgxa+kCEX85ou9gHoaJvDsRiI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":6.28,"multihop_port":26401}]},{"gateway":"us-fl.wg.ivpn.net","country_code":"US","country":"United States","city":"Miami, FL","latitude":25.7839,"longitude":-80.2102,"isp":"Quadranet","hosts":[{"hostname":"us-fl1.wg.ivpn.net","dns_name":"us-fl1.gw.ivpn.net","host":"173.44.49.93","public_key":"Rkzo9WgxJBiKyEbkZvqGWtOVh9Gk9Vd7wL49SHXdHig=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":10.47,"multihop_port":24601}]},{"gateway":"us-nj.wg.ivpn.net","country_code":"US","country":"United States","city":"New Jersey, NJ","latitude":40.737764,"longitude":-74.151747,"isp":"Quadranet","hosts":[{"hostname":"us-nj3.wg.ivpn.net","dns_name":"us-nj3.gw.ivpn.net","host":"23.226.128.21","public_key":"AX7C1LO0ECUcHRYgX4/tIDYdR8npvfB/+pf4AfI3OHU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":11.81,"multihop_port":21610},{"hostname":"us-nj4.wg.ivpn.net","dns_name":"us-nj4.gw.ivpn.net","host":"194.36.111.54","public_key":"1Te4AfL1yKo2k4jzPALnRPfKE3YSzXKo4XIRHPz5FxI=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.63,"multihop_port":27401}]},{"gateway":"us-nv.wg.ivpn.net","country_code":"US","country":"United States","city":"Las Vegas, NV","latitude":36.2333,"longitude":-115.2654,"isp":"M247","hosts":[{"hostname":"us-nv1.wg.ivpn.net","dns_name":"us-nv1.gw.ivpn.net","host":"185.242.5.37","public_key":"PRpvAZyoNWNm/KHlqafjtYoZtn1PkIPylUE4WbuYmgM=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":7.69,"multihop_port":26501}]},{"gateway":"us-ut.wg.ivpn.net","country_code":"US","country":"United States","city":"Salt Lake City, UT","latitude":40.7774,"longitude":-111.93,"isp":"100TB","hosts":[{"hostname":"us-ut1.wg.ivpn.net","dns_name":"us-ut1.gw.ivpn.net","host":"206.190.145.92","public_key":"KirI7bpxD186CuYiOqNHF+QUe6YmRYf6CN3pXWOJT2k=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":44.03,"multihop_port":24401}]},{"gateway":"us-va.wg.ivpn.net","country_code":"US","country":"United States","city":"Ashburn, VA","latitude":39.0437,"longitude":-77.4875,"isp":"Datapacket","hosts":[{"hostname":"us-va1.wg.ivpn.net","dns_name":"us-va1.gw.ivpn.net","host":"37.19.206.106","public_key":"ZCnZK6U+cRuP/WgzIDb/P6UG2rX/KyCRd5vJ1hAbr2E=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":46.82,"multihop_port":27701}]},{"gateway":"us-wa.wg.ivpn.net","country_code":"US","country":"United States","city":"Seattle, WA","latitude":47.6211,"longitude":-122.3244,"isp":"Tzulo","hosts":[{"hostname":"us-wa2.wg.ivpn.net","dns_name":"us-wa2.gw.ivpn.net","host":"198.44.131.4","public_key":"VcrOOozBUCIURU0AnqMAE7AkMmC7Qrp+j/PzPbgbalU=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":35.46,"multihop_port":27801}]},{"gateway":"za.wg.ivpn.net","country_code":"ZA","country":"South Africa","city":"Johannesburg","latitude":-26.195,"longitude":28.034,"isp":"Datapacket","hosts":[{"hostname":"za1.wg.ivpn.net","dns_name":"za1.gw.ivpn.net","host":"169.150.238.108","public_key":"tgrAA+uJZppS9esgOi0pe3rHajQQ7c/KF8WPOua6qy4=","local_ip":"172.16.0.1/12","ipv6":{"local_ip":"fd00:4956:504e:ffff::/96"},"load":5.62,"multihop_port":20840}]}],"openvpn":[{"gateway":"at.gw.ivpn.net","country_code":"AT","country":"Austria","city":"Vienna","latitude":48.2,"longitude":16.3666,"isp":"M247","hosts":[{"hostname":"at1.gw.ivpn.net","dns_name":"at1.gw.ivpn.net","host":"185.244.212.66","load":97.98,"multihop_port":25601,"obfs":{"obfs3_multihop_port":25602,"obfs4_multihop_port":25603,"obfs4_key":"75HhQC6n6ctp9Fa9wCvEnc6ip5FnEfuIGc+dVNLH4M15FjB/Ve6bI1b8lYFhk6T+4/HkDQ"}}]},{"gateway":"au-nsw.gw.ivpn.net","country_code":"AU","country":"Australia","city":"Sydney","latitude":-33.92,"longitude":151.1852,"isp":"M247","hosts":[{"hostname":"au-nsw1.gw.ivpn.net","dns_name":"au-nsw1.gw.ivpn.net","host":"46.102.153.242","load":76.76,"multihop_port":26601,"obfs":{"obfs3_multihop_port":26602,"obfs4_multihop_port":26603,"obfs4_key":"/rjoeDjduOFq1UvT332vhS398h1RP5hC3m7sDJKNSyJ6TO8mkcxWAYILw0i+bgS/3JD5YA"}},{"hostname":"au-nsw2.gw.ivpn.net","dns_name":"au-nsw2.gw.ivpn.net","host":"146.70.78.74","load":42.03,"multihop_port":27901,"obfs":{"obfs3_multihop_port":27902,"obfs4_multihop_port":27903,"obfs4_key":"qtdQ5krD9EQFR98xNo/v5cmGb10wqt0Om9pYMIHWQh4oz5xcAXj32rViEyN0bnkkhaZnBA"}}]},{"gateway":"be.gw.ivpn.net","country_code":"BE","country":"Belgium","city":"Brussels","latitude":50.8333,"longitude":4.3333,"isp":"M247","hosts":[{"hostname":"be1.gw.ivpn.net","dns_name":"be1.gw.ivpn.net","host":"194.187.251.10","load":99.49,"multihop_port":25701,"obfs":{"obfs3_multihop_port":25702,"obfs4_multihop_port":25703,"obfs4_key":"cN8i60FUVy2mmGpy+tkQAz8hu/N0EGPq8cZwIotEDwdhAYdLV+ATes/AEjzdub2K68TlYg"}}]},{"gateway":"bg.gw.ivpn.net","country_code":"BG","country":"Bulgaria","city":"Sofia","latitude":42.6833,"longitude":23.3167,"isp":"M247","hosts":[{"hostname":"bg1.gw.ivpn.net","dns_name":"bg1.gw.ivpn.net","host":"82.102.23.18","load":47.1,"multihop_port":25901,"obfs":{"obfs3_multihop_port":25902,"obfs4_multihop_port":25903,"obfs4_key":"K+mCw9+zy/8pBQt6IUKRlg2eJ3DCnJ1BvIccLq/6A2D6HoZddyDnZQYb2Sb2e464dVgBWw"}}]},{"gateway":"br.gw.ivpn.net","country_code":"BR","country":"Brazil","city":"Franca","latitude":-20.53,"longitude":-47.39,"isp":"Qnax","hosts":[{"hostname":"br1.gw.ivpn.net","dns_name":"br1.gw.ivpn.net","host":"45.162.229.130","load":10.39,"multihop_port":26701,"obfs":{"obfs3_multihop_port":26702,"obfs4_multihop_port":26703,"obfs4_key":"h4bBkocahWveuv/nWPRMYXBTw95ExTiXwmoydkNlV6hgfy8/ZjaKc34rqTuOyOH+CK7OZw"}}]},{"gateway":"ca-qc.gw.ivpn.net","country_code":"CA","country":"Canada","city":"Montreal","latitude":45.5,"longitude":-73.5833,"isp":"M247","hosts":[{"hostname":"ca-qc1.gw.ivpn.net","dns_name":"ca-qc1.gw.ivpn.net","host":"87.101.92.26","load":45.55,"multihop_port":27001,"obfs":{"obfs3_multihop_port":27002,"obfs4_multihop_port":27003,"obfs4_key":"E97qdaar8flBavysmvdIui7WQEFKkbmNi/ITTo8bPLvv39vnaBRzFj4vjMwpzXV2jXEGRQ"}}]},{"gateway":"ca.gw.ivpn.net","country_code":"CA","country":"Canada","city":"Toronto","latitude":43.7,"longitude":-79.42,"isp":"Amanah","hosts":[{"hostname":"ca1.gw.ivpn.net","dns_name":"ca1.gw.ivpn.net","host":"104.254.90.178","load":94.46,"multihop_port":23801,"obfs":{"obfs3_multihop_port":23802,"obfs4_multihop_port":23803,"obfs4_key":"49WDCCK1QGpOTSEVflRzIIaOdCT1BLB3jr/yNUJsbaUFrq7NuoB1E3wAdArNxQq9p5otTw"}},{"hostname":"ca2.gw.ivpn.net","dns_name":"ca2.gw.ivpn.net","host":"172.86.186.170","load":85.18,"multihop_port":22101,"obfs":{"obfs3_multihop_port":22102,"obfs4_multihop_port":22103,"obfs4_key":"xNkQbCkA0VCe2i4WvS2CPq2eBSMydIjsHH36E+Yg0C+gOPo3SwZyN51kpB+kwsYVS32fOQ"}}]},{"gateway":"ch.gw.ivpn.net","country_code":"CH","country":"Switzerland","city":"Zurich","latitude":47.38,"longitude":8.55,"isp":"M247","hosts":[{"hostname":"ch1.gw.ivpn.net","dns_name":"ch1.gw.ivpn.net","host":"185.212.170.138","load":17.28,"multihop_port":23601,"obfs":{"obfs3_multihop_port":23602,"obfs4_multihop_port":23603,"obfs4_key":"ELnV4JNKu0vUNd3J+QDn64yfZtqM0hNN6O5n6RkDLHbeSDBZmxP1N4dlwwChV/uySX+DEQ"}},{"hostname":"ch3.gw.ivpn.net","dns_name":"ch3.gw.ivpn.net","host":"141.255.166.194","load":10.47,"multihop_port":22901,"obfs":{"obfs3_multihop_port":22902,"obfs4_multihop_port":22903,"obfs4_key":"oNaH5sHCPGGk5m3/VMOrTDL+m1qsJrze+bqDs78vhOYBpjx5Jjq5TXu1dXNfDJCKNmKnUA"}}]},{"gateway":"cz.gw.ivpn.net","country_code":"CZ","country":"Czech Republic","city":"Prague","latitude":50.0833,"longitude":14.466,"isp":"Datapacket","hosts":[{"hostname":"cz1.gw.ivpn.net","dns_name":"cz1.gw.ivpn.net","host":"195.181.160.167","load":17.92,"multihop_port":25201,"obfs":{"obfs3_multihop_port":25202,"obfs4_multihop_port":25203,"obfs4_key":"JZ3PtIyflM3VwVow2vqi08OxddOWSx9j6B6yZSGoZLs9QE0hzSAj3ZBWEsCKFeQ2RcAoCQ"}}]},{"gateway":"de.gw.ivpn.net","country_code":"DE","country":"Germany","city":"Frankfurt","latitude":50.1,"longitude":8.675,"isp":"Leaseweb","hosts":[{"hostname":"de1.gw.ivpn.net","dns_name":"de1.gw.ivpn.net","host":"178.162.222.40","load":20.27,"multihop_port":23001,"obfs":{"obfs3_multihop_port":23002,"obfs4_multihop_port":23003,"obfs4_key":"PBhcWVcRNOCTMSWXbA2J+8eJBVzNd9H5HOr0YCF8QWwmKeSlEmqLSJQE8oDpKH5IbFH4Mw"}},{"hostname":"de2.gw.ivpn.net","dns_name":"de2.gw.ivpn.net","host":"178.162.211.114","load":7.01,"multihop_port":22001,"obfs":{"obfs3_multihop_port":22002,"obfs4_multihop_port":22003,"obfs4_key":"dEhLA4ZsvVP8+PRvlSHKwmW8JyzR1Bwy7+BFKF7Ux4L2B5YvdqqOrv/8eHliEj2mm2Z8Iw"}},{"hostname":"de3.gw.ivpn.net","dns_name":"de3.gw.ivpn.net","host":"146.70.160.162","load":24.1,"multihop_port":21050,"obfs":{"obfs3_multihop_port":21051,"obfs4_multihop_port":21052,"obfs4_key":"IFf+iLf7lgc0K81tQkZL5zndlWflvnLZyYSGGNLtSXLLivlIeBuXCPFDJ7fkL3TOd5uhOA"}}]},{"gateway":"dk.gw.ivpn.net","country_code":"DK","country":"Denmark","city":"Copenhagen","latitude":55.6786,"longitude":12.5635,"isp":"M247","hosts":[{"hostname":"dk1.gw.ivpn.net","dns_name":"dk1.gw.ivpn.net","host":"185.245.84.226","load":40.34,"multihop_port":25501,"obfs":{"obfs3_multihop_port":25502,"obfs4_multihop_port":25503,"obfs4_key":"ngjtv9UISX4tB5AkBnrEN2TrAnUqVwNZ688VqDlS4BDxQXJeJF3ynZtngRqeowhEahsccQ"}}]},{"gateway":"es.gw.ivpn.net","country_code":"ES","country":"Spain","city":"Madrid","latitude":40.4,"longitude":-3.6834,"isp":"Datapacket","hosts":[{"hostname":"es1.gw.ivpn.net","dns_name":"es1.gw.ivpn.net","host":"185.93.3.193","load":9.23,"multihop_port":21501,"obfs":{"obfs3_multihop_port":21502,"obfs4_multihop_port":21503,"obfs4_key":"x4A9SBY5yzPKH1QOkEsGYcIR2JA/Pu393jv/ZSg4YO2DsVhr3TQFxcMO3QhD9iSF48smJA"}}]},{"gateway":"fi.gw.ivpn.net","country_code":"FI","country":"Finland","city":"Helsinki","latitude":60.1756,"longitude":24.9341,"isp":"Creanova","hosts":[{"hostname":"fi1.gw.ivpn.net","dns_name":"fi1.gw.ivpn.net","host":"185.112.82.12","load":100,"multihop_port":26001,"obfs":{"obfs3_multihop_port":26002,"obfs4_multihop_port":26003,"obfs4_key":"SvvSpGiFctjs4n2wZGnZUf9fAL8wag70SrA3FX+9f3Sq+KgBn+/8P6fE3239ezemg9svLA"}}]},{"gateway":"fr.gw.ivpn.net","country_code":"FR","country":"France","city":"Paris","latitude":48.8667,"longitude":2.3333,"isp":"Datapacket","hosts":[{"hostname":"fr1.gw.ivpn.net","dns_name":"fr1.gw.ivpn.net","host":"185.246.211.179","load":25.15,"multihop_port":23401,"obfs":{"obfs3_multihop_port":23402,"obfs4_multihop_port":23403,"obfs4_key":"CMf0pNZ46nFdG0Tpa3hE0cK9wtUAReJL7HN66G9Jq3tlrTSWrU0DLf7sCQgXV+WFoc8iaw"}}]},{"gateway":"gb-man.gw.ivpn.net","country_code":"GB","country":"United Kingdom","city":"Manchester","latitude":53.5004,"longitude":-2.248,"isp":"M247","hosts":[{"hostname":"gb-man1.gw.ivpn.net","dns_name":"gb-man1.gw.ivpn.net","host":"89.238.141.228","load":20.87,"multihop_port":26901,"obfs":{"obfs3_multihop_port":26902,"obfs4_multihop_port":26903,"obfs4_key":"WuP3pMrsQA+uAC72sV+Y62E1uvOWcnbTNJCmRHXqtWbbYzECF5swu62dzD/JOKoa5t0tGQ"}}]},{"gateway":"gb.gw.ivpn.net","country_code":"GB","country":"United Kingdom","city":"London","latitude":51.5,"longitude":-0.1167,"isp":"Datapacket","hosts":[{"hostname":"gb1.gw.ivpn.net","dns_name":"gb1.gw.ivpn.net","host":"185.59.221.133","load":14.99,"multihop_port":20801,"obfs":{"obfs3_multihop_port":20802,"obfs4_multihop_port":20803,"obfs4_key":"5whTESvZxQE28wKqJWZ9fQFy09d8//GNaPDeYHVR+FJZTyI+DMS6qX4Mt2FKSf/zBToaDg"}},{"hostname":"gb2.gw.ivpn.net","dns_name":"gb2.gw.ivpn.net","host":"185.59.221.88","load":6.89,"multihop_port":24201,"obfs":{"obfs3_multihop_port":24202,"obfs4_multihop_port":24203,"obfs4_key":"4hrCOgPsRfmnQ6cLvV5mtM2XZCRS/DXG/izYSg2qZC+WJ0GsnhTlKByPM2iJ555MaM8vJA"}}]},{"gateway":"hk.gw.ivpn.net","country_code":"HK","country":"Hong Kong","city":"Hong Kong","latitude":22.305,"longitude":114.185,"isp":"Leaseweb","hosts":[{"hostname":"hk2.gw.ivpn.net","dns_name":"hk2.gw.ivpn.net","host":"209.58.188.13","load":88.87,"multihop_port":27501,"obfs":{"obfs3_multihop_port":27502,"obfs4_multihop_port":27503,"obfs4_key":"GIunWjiq00Piv3Xf4VeMkmUQ8NzD8sxRkSIbA3bxrU4LhPVth+3qM2zQwI4GesQDCDY5RA"}},{"hostname":"hk3.gw.ivpn.net","dns_name":"hk3.gw.ivpn.net","host":"118.107.244.184","load":8,"multihop_port":20800,"obfs":{"obfs3_multihop_port":20801,"obfs4_multihop_port":20802,"obfs4_key":"wnI0gz3hLM9VhkABSncBIsGERgn16UzTxkj7dEeYYo/y2Wu0/w24rfriA5KL7ugpTyvEFg"}}]},{"gateway":"hu.gw.ivpn.net","country_code":"HU","country":"Hungary","city":"Budapest","latitude":47.5,"longitude":19.0833,"isp":"M247","hosts":[{"hostname":"hu1.gw.ivpn.net","dns_name":"hu1.gw.ivpn.net","host":"185.189.114.186","load":98.65,"multihop_port":25401,"obfs":{"obfs3_multihop_port":25402,"obfs4_multihop_port":25403,"obfs4_key":"2TwZqxAakni0S4S3ulOIqMZimqqug0KCr6pNREN6KytrtIh486nkJyiFRqaYZlx+FlxEcg"}}]},{"gateway":"il.gw.ivpn.net","country_code":"IL","country":"Israel","city":"Holon, Tel Aviv","latitude":32.08,"longitude":34.77,"isp":"HQServ","hosts":[{"hostname":"il1.gw.ivpn.net","dns_name":"il1.gw.ivpn.net","host":"185.191.207.194","load":36.94,"multihop_port":27301,"obfs":{"obfs3_multihop_port":27302,"obfs4_multihop_port":27303,"obfs4_key":"DysuSM7UWjquj4BAVYf6mOUnRKfY1QXs17MXiV5aYapFfOkQPpx5nQPVQ2M+rLDxN9TSRg"}}]},{"gateway":"is.gw.ivpn.net","country_code":"IS","country":"Iceland","city":"Reykjavik","latitude":64.15,"longitude":-21.95,"isp":"Advania","hosts":[{"hostname":"is1.gw.ivpn.net","dns_name":"is1.gw.ivpn.net","host":"82.221.107.178","load":100,"multihop_port":23501,"obfs":{"obfs3_multihop_port":23502,"obfs4_multihop_port":23503,"obfs4_key":"xx/Lor3q60/pVh4PKWi0GZaw64pPXFTkALnGlvRaBMiPRkFilr7KhYmPInDnZxzr4c4AIw"}}]},{"gateway":"it.gw.ivpn.net","country_code":"IT","country":"Italy","city":"Milan","latitude":45.47,"longitude":9.205,"isp":"Datapacket","hosts":[{"hostname":"it2.gw.ivpn.net","dns_name":"it2.gw.ivpn.net","host":"84.17.59.137","load":10.51,"multihop_port":21100,"obfs":{"obfs3_multihop_port":21101,"obfs4_multihop_port":21102,"obfs4_key":"8msjDzd52ALBZF9Ej8i6BYXc4qSTiG8P739Px77EHp0uOVd5/VvDhrBfGcBQxDIgBlUeLw"}}]},{"gateway":"jp.gw.ivpn.net","country_code":"JP","country":"Japan","city":"Tokyo","latitude":35.685,"longitude":139.7514,"isp":"M247","hosts":[{"hostname":"jp1.gw.ivpn.net","dns_name":"jp1.gw.ivpn.net","host":"91.207.174.234","load":53.79,"multihop_port":26201,"obfs":{"obfs3_multihop_port":26202,"obfs4_multihop_port":26203,"obfs4_key":"CBqi0EpfoUzP/ijwYn9A9yEpItrhtX+BAKF0rvcUGv///UNzzXKNz+0RhBLdQayZx6y6TA"}},{"hostname":"jp2.gw.ivpn.net","dns_name":"jp2.gw.ivpn.net","host":"185.135.77.35","load":22.31,"multihop_port":20830,"obfs":{"obfs3_multihop_port":20831,"obfs4_multihop_port":20832,"obfs4_key":"giZJF4edg7wcjxbdgD2RjFcF9QAzExLHIJYjm2cLLtx7MrxP0p96mIFj9T8LSQotKB63fA"}}]},{"gateway":"lu.gw.ivpn.net","country_code":"LU","country":"Luxembourg","city":"Luxembourg","latitude":49.6117,"longitude":6.13,"isp":"Evoluso","hosts":[{"hostname":"lu1.gw.ivpn.net","dns_name":"lu1.gw.ivpn.net","host":"92.223.89.53","load":93.03,"multihop_port":27201,"obfs":{"obfs3_multihop_port":27202,"obfs4_multihop_port":27203,"obfs4_key":"auDmK8lVBI7fxq6UjXg7V0qoZJ3icACKm/9vruMGSr0lT6ViNsl28qMqYbjJRveHnx5eQw"}}]},{"gateway":"my.gw.ivpn.net","country_code":"MY","country":"Malaysia","city":"Kuala Lumpur","latitude":3.1494,"longitude":101.706,"isp":"TheGigabit","hosts":[{"hostname":"my1.gw.ivpn.net","dns_name":"my1.gw.ivpn.net","host":"61.4.97.148","load":11,"multihop_port":20810,"obfs":{"obfs3_multihop_port":20811,"obfs4_multihop_port":20812,"obfs4_key":"k2hwCe8gDb24K5n2jNXYO5YCl5XCIEhuRwpYSsEhKWorah8OUM1C1crawbfstj+W2IQdOA"}}]},{"gateway":"nl.gw.ivpn.net","country_code":"NL","country":"Netherlands","city":"Amsterdam","latitude":52.35,"longitude":4.9166,"isp":"Leaseweb","hosts":[{"hostname":"nl3.gw.ivpn.net","dns_name":"nl3.gw.ivpn.net","host":"95.211.172.68","load":15.08,"multihop_port":23101,"obfs":{"obfs3_multihop_port":23102,"obfs4_multihop_port":23103,"obfs4_key":"eUXsScIg0K0LKVgA8yq2Mc++pfnTQ9nr3gnV8n1NIw7wRqinhO6uuXiSS5J19agQaPK1ew"}},{"hostname":"nl4.gw.ivpn.net","dns_name":"nl4.gw.ivpn.net","host":"95.211.172.95","load":8.35,"multihop_port":23201,"obfs":{"obfs3_multihop_port":23202,"obfs4_multihop_port":23203,"obfs4_key":"KEw6WJF+NDOQv7yMvq+dAAAkPbcYJ8PX6pffRd8EM3uaOy2QcpMcdHI7s700Kq/ZvV3HBQ"}},{"hostname":"nl5.gw.ivpn.net","dns_name":"nl5.gw.ivpn.net","host":"95.211.187.222","load":25.48,"multihop_port":23901,"obfs":{"obfs3_multihop_port":23902,"obfs4_multihop_port":23903,"obfs4_key":"fcWCrzzatLbk1LNKsuQZKpQrC3ZXwQ85GO5xRS467KJBRDrmvnyMb6ARbLGu+gYkTnNELQ"}},{"hostname":"nl6.gw.ivpn.net","dns_name":"nl6.gw.ivpn.net","host":"95.211.187.228","load":35.7,"multihop_port":24101,"obfs":{"obfs3_multihop_port":24102,"obfs4_multihop_port":24103,"obfs4_key":"lT3OGPQS1CwwqtalMExN7qxEoDDBLLlcoh5a6YW3DPj8esEBEG6wY5OfYonxltBzoVu4PA"}},{"hostname":"nl7.gw.ivpn.net","dns_name":"nl7.gw.ivpn.net","host":"95.211.95.22","load":7.84,"multihop_port":22501,"obfs":{"obfs3_multihop_port":22502,"obfs4_multihop_port":22503,"obfs4_key":"ffMnq7Gc/D7KWoLckJ4t8nf3zZqVdlffe2lVfUCceOyOTdRApkeJGgEai0TI1z76Yey9Lw"}},{"hostname":"nl8.gw.ivpn.net","dns_name":"nl8.gw.ivpn.net","host":"95.211.172.18","load":41.86,"multihop_port":22801,"obfs":{"obfs3_multihop_port":22802,"obfs4_multihop_port":22803,"obfs4_key":"h+u/6VkPDJXySoJ6QEM1hOjWPD58OS4AZPP9ofP/yCWGBQpPoMc78l7C74eFvqKKkFAXDw"}}]},{"gateway":"no.gw.ivpn.net","country_code":"NO","country":"Norway","city":"Oslo","latitude":59.9167,"longitude":10.75,"isp":"Servetheworld","hosts":[{"hostname":"no1.gw.ivpn.net","dns_name":"no1.gw.ivpn.net","host":"194.242.10.150","load":26.13,"multihop_port":25301,"obfs":{"obfs3_multihop_port":25302,"obfs4_multihop_port":25303,"obfs4_key":"uhLy//KRu6DrYfgDJmwjC6Fxk5h+MRDNOwFe7qzGTjfOiHLWRSoRx6OdNvzjPPXq0ZJnZg"}}]},{"gateway":"pl.gw.ivpn.net","country_code":"PL","country":"Poland","city":"Warsaw","latitude":52.25,"longitude":21,"isp":"Datapacket","hosts":[{"hostname":"pl1.gw.ivpn.net","dns_name":"pl1.gw.ivpn.net","host":"185.246.208.86","load":20.82,"multihop_port":25101,"obfs":{"obfs3_multihop_port":25102,"obfs4_multihop_port":25103,"obfs4_key":"S9XZyigxYjF5jWcwYpMmV9HJq4Vni1yQvLKI03n0TJ7csrgsX7lPpFfECAGQruHh1wkMXg"}}]},{"gateway":"pt.gw.ivpn.net","country_code":"PT","country":"Portugal","city":"Lisbon","latitude":38.7227,"longitude":-9.1449,"isp":"Hostwebis","hosts":[{"hostname":"pt1.gw.ivpn.net","dns_name":"pt1.gw.ivpn.net","host":"94.46.175.112","load":20.75,"multihop_port":27101,"obfs":{"obfs3_multihop_port":27102,"obfs4_multihop_port":27103,"obfs4_key":"NqXqKMt8UF25hYDIwfh2K4Rr4a7F41HzZDGjX7SYwRaoOtrTL665yV6Z3h9wF+/R1YE8KQ"}}]},{"gateway":"ro.gw.ivpn.net","country_code":"RO","country":"Romania","city":"Bucharest","latitude":44.4334,"longitude":26.0999,"isp":"M247","hosts":[{"hostname":"ro1.gw.ivpn.net","dns_name":"ro1.gw.ivpn.net","host":"37.120.206.50","load":96.95,"multihop_port":22301,"obfs":{"obfs3_multihop_port":22302,"obfs4_multihop_port":22303,"obfs4_key":"lqfg/sP9uLakoQiA6YI5/kHQ4/FvQTp6jRgxSswjHwC8POOM23FijEWKyykngn1Eb3xfLA"}}]},{"gateway":"rs.gw.ivpn.net","country_code":"RS","country":"Serbia","city":"Belgrade","latitude":44.8186,"longitude":20.468,"isp":"M247","hosts":[{"hostname":"rs1.gw.ivpn.net","dns_name":"rs1.gw.ivpn.net","host":"141.98.103.250","load":100,"multihop_port":26801,"obfs":{"obfs3_multihop_port":26802,"obfs4_multihop_port":26803,"obfs4_key":"0MqgxLrLFQTlQWGAjY9es+Nv45d37/5lulWw0iEFoiUvtzOcbut8hK9AhCis17EXi+lUXw"}}]},{"gateway":"se.gw.ivpn.net","country_code":"SE","country":"Sweden","city":"Stockholm","latitude":59.3508,"longitude":18.0973,"isp":"GleSyS","hosts":[{"hostname":"se1.gw.ivpn.net","dns_name":"se1.gw.ivpn.net","host":"80.67.10.138","load":18.44,"multihop_port":24001,"obfs":{"obfs3_multihop_port":24002,"obfs4_multihop_port":24003,"obfs4_key":"/yhTV2SsTXlwsG2mCS90ZAYIZivsSyloaFw6VDj0pnpJOuUxXcZBOgdyQ/lfWxJtvHZmPg"}}]},{"gateway":"sg.gw.ivpn.net","country_code":"SG","country":"Singapore","city":"Singapore","latitude":1.293,"longitude":103.8558,"isp":"M247","hosts":[{"hostname":"sg1.gw.ivpn.net","dns_name":"sg1.gw.ivpn.net","host":"185.128.24.186","load":18.02,"multihop_port":26101,"obfs":{"obfs3_multihop_port":26102,"obfs4_multihop_port":26103,"obfs4_key":"0N1ZmZlnyhS/3Y1OhvB0Bk3BGU2LFy0zyuWPYwM/P+mfX57w8zI7/YcBfIXZVgDiStt4MQ"}}]},{"gateway":"sk.gw.ivpn.net","country_code":"SK","country":"Slovakia","city":"Bratislava","latitude":48.15,"longitude":17.117,"isp":"M247","hosts":[{"hostname":"sk1.gw.ivpn.net","dns_name":"sk1.gw.ivpn.net","host":"185.245.85.250","load":62.68,"multihop_port":25801,"obfs":{"obfs3_multihop_port":25802,"obfs4_multihop_port":25803,"obfs4_key":"8sl7oPfNHdCd2xYi98xWC6mBXyPvzio34UbfUbCPEU+8wo7DVbrR9mf8goR0Ievqzax4Hw"}}]},{"gateway":"tw.gw.ivpn.net","country_code":"TW","country":"Taiwan","city":"Taipei","latitude":25.073,"longitude":121.578,"isp":"TheGigabit","hosts":[{"hostname":"tw1.gw.ivpn.net","dns_name":"tw1.gw.ivpn.net","host":"185.189.160.6","load":5.45,"multihop_port":20820,"obfs":{"obfs3_multihop_port":20821,"obfs4_multihop_port":20822,"obfs4_key":"/ilRlB3BkUzUG2yd+++6KeYEF9PEB+3T3XcQhVjfoF8wJH1kgjGXvikjS1j/1SknFpGPaA"}}]},{"gateway":"ua.gw.ivpn.net","country_code":"UA","country":"Ukraine","city":"Kharkiv","latitude":50,"longitude":36.25,"isp":"Xservers","hosts":[{"hostname":"ua1.gw.ivpn.net","dns_name":"ua1.gw.ivpn.net","host":"176.103.58.123","load":7.09,"multihop_port":26301,"obfs":{"obfs3_multihop_port":26302,"obfs4_multihop_port":26303,"obfs4_key":"RsW3q+FmLATkKnKHOheUntwvslkrXEiCBx3ajDjhyHiZMtQI+Uy7TmhFK0YaHg/qKoljYw"}}]},{"gateway":"us-az.gw.ivpn.net","country_code":"US","country":"United States","city":"Phoenix, AZ","latitude":33.5722,"longitude":-112.0891,"isp":"M247","hosts":[{"hostname":"us-az1.gw.ivpn.net","dns_name":"us-az1.gw.ivpn.net","host":"193.37.254.130","load":6.28,"multihop_port":26401,"obfs":{"obfs3_multihop_port":26402,"obfs4_multihop_port":26403,"obfs4_key":"Y2klMvUi3NBIReXSALaKnNm8qI9IdWhFwgQrwl9ofUuVNuT6D93ohTTqbW//iKS5/lqndw"}}]},{"gateway":"us-ca.gw.ivpn.net","country_code":"US","country":"United States","city":"Los Angeles, CA","latitude":34.1139,"longitude":-118.4068,"isp":"Quadranet","hosts":[{"hostname":"us-ca1.gw.ivpn.net","dns_name":"us-ca1.gw.ivpn.net","host":"173.254.196.58","load":6.36,"multihop_port":22201,"obfs":{"obfs3_multihop_port":22202,"obfs4_multihop_port":22203,"obfs4_key":"C/Ct5AG8tkV0Yi7MnXv+bNvExY8Dgii4OeJ7DA7lIq3HptUa+WbG+IAR/UIDaMn8VeXDIg"}},{"hostname":"us-ca2.gw.ivpn.net","dns_name":"us-ca2.gw.ivpn.net","host":"69.12.80.146","load":9.88,"multihop_port":22401,"obfs":{"obfs3_multihop_port":22402,"obfs4_multihop_port":22403,"obfs4_key":"nvizO9jj1D3xMqCMTnP6XDIzTLy6KcYNsDSxvJjm5QwZ9Y+5gommAk9LIcCeX9o4FjlkVA"}},{"hostname":"us-ca3.gw.ivpn.net","dns_name":"us-ca3.gw.ivpn.net","host":"198.54.129.99","load":12.21,"multihop_port":21301,"obfs":{"obfs3_multihop_port":21302,"obfs4_multihop_port":21303,"obfs4_key":"rharPyhkUzYwmCP8ZzeaCwnJAmwOqwDTLOlJqzi/kAxMn4OVXtbzCk9Ww8XR31D2rmk3MA"}},{"hostname":"us-ca4.gw.ivpn.net","dns_name":"us-ca4.gw.ivpn.net","host":"173.254.204.202","load":34.8,"multihop_port":21901,"obfs":{"obfs3_multihop_port":21902,"obfs4_multihop_port":21903,"obfs4_key":"2Sdam2VI658TdQRvj5bxwKPFljrsKgwBDv/mqhXNYgDQGs+WVhAz508b2oWVgHed3Ki8dQ"}}]},{"gateway":"us-fl.gw.ivpn.net","country_code":"US","country":"United States","city":"Miami, FL","latitude":25.7839,"longitude":-80.2102,"isp":"Quadranet","hosts":[{"hostname":"us-fl1.gw.ivpn.net","dns_name":"us-fl1.gw.ivpn.net","host":"173.44.49.90","load":10.47,"multihop_port":24601,"obfs":{"obfs3_multihop_port":24602,"obfs4_multihop_port":24603,"obfs4_key":"vS7u4rijvWECRS/Mo2KOpl8kx0NOozp3kF/FMxGmCZILE46etitrheYI2hCpNsYUg3YTBQ"}}]},{"gateway":"us-ga.gw.ivpn.net","country_code":"US","country":"United States","city":"Atlanta, GA","latitude":33.7627,"longitude":-84.4225,"isp":"Quadranet","hosts":[{"hostname":"us-ga1.gw.ivpn.net","dns_name":"us-ga1.gw.ivpn.net","host":"104.129.24.146","load":8.33,"multihop_port":24501,"obfs":{"obfs3_multihop_port":24502,"obfs4_multihop_port":24503,"obfs4_key":"+No53UtdyPN4uT89vMlvRTjFnxtMKol+oOld9I9WMnlK7BU+y10oXWofzcI4eRgkm195FQ"}},{"hostname":"us-ga2.gw.ivpn.net","dns_name":"us-ga2.gw.ivpn.net","host":"107.150.22.74","load":6.77,"multihop_port":24810,"obfs":{"obfs3_multihop_port":24811,"obfs4_multihop_port":24812,"obfs4_key":"3viWXkxZx1KZF9uzd5tRxb5lNMMnRZ90PqwLUaZdkZuaouj+Vb20t5uk3BVz/YyZkrSoGw"}}]},{"gateway":"us-il.gw.ivpn.net","country_code":"US","country":"United States","city":"Chicago, IL","latitude":41.8373,"longitude":-87.6862,"isp":"Quadranet","hosts":[{"hostname":"us-il1.gw.ivpn.net","dns_name":"us-il1.gw.ivpn.net","host":"107.150.28.82","load":10.09,"multihop_port":21401,"obfs":{"obfs3_multihop_port":21402,"obfs4_multihop_port":21403,"obfs4_key":"6PpxOt8CwINAjun8o/wsf/cAidNbJZM/Pg4im1Cx9kCBV/lau3XFq3bMwBW0SzptZ/5WdA"}},{"hostname":"us-il2.gw.ivpn.net","dns_name":"us-il2.gw.ivpn.net","host":"72.11.137.146","load":26.58,"multihop_port":24901,"obfs":{"obfs3_multihop_port":24902,"obfs4_multihop_port":24903,"obfs4_key":"cfvJR/gplqAbFx8myJSW/cPC3hN1782PPma2v5YKJR5LyekWX+AHTJjzdz8xSr2mM6IGQw"}}]},{"gateway":"us-nj.gw.ivpn.net","country_code":"US","country":"United States","city":"New Jersey, NJ","latitude":40.737764,"longitude":-74.151747,"isp":"Quadranet","hosts":[{"hostname":"us-nj3.gw.ivpn.net","dns_name":"us-nj3.gw.ivpn.net","host":"23.226.128.18","load":11.81,"multihop_port":21610,"obfs":{"obfs3_multihop_port":21611,"obfs4_multihop_port":21612,"obfs4_key":"JtB/8Lv8MOq9+bpYC751voS2CwoEwf9ku2CziwJScn3Gc1F/BTul6ehnrGiedmpkQXAtJw"}},{"hostname":"us-nj4.gw.ivpn.net","dns_name":"us-nj4.gw.ivpn.net","host":"194.36.111.50","load":7.63,"multihop_port":27401,"obfs":{"obfs3_multihop_port":27402,"obfs4_multihop_port":27403,"obfs4_key":"lHDLT6cTgt0bh3ysogDdiXL4eWGRtJZ0cZGJmvpeK0YLUAsBfsOzKv46V0iv5ykwRPm6Mg"}}]},{"gateway":"us-nv.gw.ivpn.net","country_code":"US","country":"United States","city":"Las Vegas, NV","latitude":36.2333,"longitude":-115.2654,"isp":"M247","hosts":[{"hostname":"us-nv1.gw.ivpn.net","dns_name":"us-nv1.gw.ivpn.net","host":"185.242.5.34","load":7.69,"multihop_port":26501,"obfs":{"obfs3_multihop_port":26502,"obfs4_multihop_port":26503,"obfs4_key":"Kux7OTSrUOkklATpG67hJPz7xCWpW6eD9Qdw2GNKAmaaPA5zvPC3SXQRvyrYdyAAqMXMfg"}}]},{"gateway":"us-ny.gw.ivpn.net","country_code":"US","country":"United States","city":"New York, NY","latitude":40.6943,"longitude":-73.9249,"isp":"M247","hosts":[{"hostname":"us-ny2.gw.ivpn.net","dns_name":"us-ny2.gw.ivpn.net","host":"212.103.48.194","load":17.35,"multihop_port":21801,"obfs":{"obfs3_multihop_port":21802,"obfs4_multihop_port":21803,"obfs4_key":"GtK9yCXTtrLOrf0MTWdWqjzQ1vd1eKsVjiOuR5CiVaDf4dCSalyJ+kmik4nfU9Gj6UwcCg"}},{"hostname":"us-ny3.gw.ivpn.net","dns_name":"us-ny3.gw.ivpn.net","host":"89.187.178.144","load":20.66,"multihop_port":27601,"obfs":{"obfs3_multihop_port":27602,"obfs4_multihop_port":27603,"obfs4_key":"eL/9iKx6f5bHowNJBsT2E/Aag5w8Cvtb3DduySudJmuK2GtIOUwNzS33lFZwSUEnJIYwLg"}}]},{"gateway":"us-tx.gw.ivpn.net","country_code":"US","country":"United States","city":"Dallas, TX","latitude":32.7936,"longitude":-96.7662,"isp":"Quadranet","hosts":[{"hostname":"us-tx1.gw.ivpn.net","dns_name":"us-tx1.gw.ivpn.net","host":"96.44.189.194","load":6.36,"multihop_port":21001,"obfs":{"obfs3_multihop_port":21002,"obfs4_multihop_port":21003,"obfs4_key":"GBDWrGN71fGa7a7S8b2tHzjYQMhnA2vJW5yq3iID+VoSzA1xIAgHiOxISEU93v+CBTCXWg"}},{"hostname":"us-tx2.gw.ivpn.net","dns_name":"us-tx2.gw.ivpn.net","host":"96.44.142.74","load":9.49,"multihop_port":25001,"obfs":{"obfs3_multihop_port":25002,"obfs4_multihop_port":25003,"obfs4_key":"VYfEVELWNqOm7kyO19usXm3GSK9wawRObopQLOLDbLodKnmX/jPah+IlGkL2xYiNxEzUKw"}}]},{"gateway":"us-ut.gw.ivpn.net","country_code":"US","country":"United States","city":"Salt Lake City, UT","latitude":40.7774,"longitude":-111.93,"isp":"100TB","hosts":[{"hostname":"us-ut1.gw.ivpn.net","dns_name":"us-ut1.gw.ivpn.net","host":"198.105.216.28","load":44.03,"multihop_port":24401,"obfs":{"obfs3_multihop_port":24402,"obfs4_multihop_port":24403,"obfs4_key":"gb5dp9i4QnFKT0GQPMEsDlqN+JORU3lyU65s9R1064aZ1jKfWfkc+SxbOlNEh23CvIAOeg"}}]},{"gateway":"us-va.gw.ivpn.net","country_code":"US","country":"United States","city":"Ashburn, VA","latitude":39.0437,"longitude":-77.4875,"isp":"Datapacket","hosts":[{"hostname":"us-va1.gw.ivpn.net","dns_name":"us-va1.gw.ivpn.net","host":"37.19.206.105","load":46.82,"multihop_port":27701,"obfs":{"obfs3_multihop_port":27702,"obfs4_multihop_port":27703,"obfs4_key":"5Lk8BSID+M9QAGSglQTrYkom+V0mkIv0HgR80+9vKCcnZOu0f+aJhfOXqKnpHarJbIEHCw"}}]},{"gateway":"us-wa.gw.ivpn.net","country_code":"US","country":"United States","city":"Seattle, WA","latitude":47.6211,"longitude":-122.3244,"isp":"Tzulo","hosts":[{"hostname":"us-wa2.gw.ivpn.net","dns_name":"us-wa2.gw.ivpn.net","host":"198.44.131.3","load":35.46,"multihop_port":27801,"obfs":{"obfs3_multihop_port":27802,"obfs4_multihop_port":27803,"obfs4_key":"9h0W5BTzGSDpY2tGjdvViSJfEkT/BuwHS0cnFX07cEj3RRDtmxsC0f+kapO8+Kh+fz1XMQ"}}]},{"gateway":"za.gw.ivpn.net","country_code":"ZA","country":"South Africa","city":"Johannesburg","latitude":-26.195,"longitude":28.034,"isp":"Datapacket","hosts":[{"hostname":"za1.gw.ivpn.net","dns_name":"za1.gw.ivpn.net","host":"169.150.238.103","load":5.62,"multihop_port":20840,"obfs":{"obfs3_multihop_port":20841,"obfs4_multihop_port":20842,"obfs4_key":"vM1zdiOMhoqMKZCOi/lMj7TfWJb5/UsM25p8FE/AUezwbYWhUkhpD5RbXBOBDNhZuYzPGA"}}]}],"config":{"antitracker":{"default":{"ip":"10.0.254.2","multihop-ip":"10.0.254.102"},"hardcore":{"ip":"10.0.254.3","multihop-ip":"10.0.254.103"}},"api":{"ips":["198.50.177.220","149.56.162.156","198.50.177.222","149.56.162.159","198.50.177.223"],"ipv6s":["2607:5300:203:1735::8888","2607:5300:203:1735::8","2607:5300:203:1735:6580:7300:0:aaaa"]},"ports":{"openvpn":[{"type":"UDP","port":53},{"type":"UDP","port":80},{"type":"UDP","range":{"min":5500,"max":19999}},{"type":"UDP","range":{"min":60000,"max":65000}},{"type":"UDP","port":123},{"type":"UDP","port":2049},{"type":"UDP","range":{"min":50000,"max":59999}},{"type":"UDP","port":2050},{"type":"UDP","range":{"min":40000,"max":49999}},{"type":"UDP","port":443},{"type":"UDP","port":1194},{"type":"UDP","range":{"min":30000,"max":39999}},{"type":"TCP","port":80},{"type":"TCP","port":443},{"type":"TCP","port":1194},{"type":"TCP","port":2049},{"type":"TCP","port":2050},{"type":"TCP","port":30587},{"type":"TCP","port":41893},{"type":"TCP","port":48574},{"type":"TCP","port":58237},{"type":"TCP","range":{"min":5500,"max":19999}},{"type":"TCP","range":{"min":30000,"max":65000}}],"wireguard":[{"type":"UDP","port":53},{"type":"UDP","port":80},{"type":"UDP","port":123},{"type":"UDP","port":443},{"type":"UDP","port":500},{"type":"UDP","port":1194},{"type":"UDP","port":2049},{"type":"UDP","port":2050},{"type":"UDP","port":4500},{"type":"UDP","port":30587},{"type":"UDP","port":41893},{"type":"UDP","port":48574},{"type":"UDP","port":58237},{"type":"UDP","range":{"min":5500,"max":19999}},{"type":"UDP","range":{"min":30000,"max":65000}}],"obfs3":{"port":5145},"obfs4":{"port":5146}}}} From 5bc122d002e1892d5790fc8de9455cfae90968f4 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Mon, 20 Feb 2023 14:28:22 +0100 Subject: [PATCH 168/581] feat: update getRandomServer method --- IVPNClient/Models/VPNServer.swift | 8 ++++---- IVPNClient/Models/VPNServerList.swift | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/IVPNClient/Models/VPNServer.swift b/IVPNClient/Models/VPNServer.swift index 87f4bee65..217c87294 100644 --- a/IVPNClient/Models/VPNServer.swift +++ b/IVPNClient/Models/VPNServer.swift @@ -157,11 +157,11 @@ class VPNServer { return true } - static func validMultiHopCountry(_ first: VPNServer, _ second: VPNServer) -> Bool { + static func validMultiHopCountry(_ first: VPNServer, _ second: VPNServer, ignoreSettings: Bool = false) -> Bool { guard UserDefaults.shared.isMultiHop else { return true } - guard UserDefaults.standard.preventSameCountryMultiHop else { + guard UserDefaults.standard.preventSameCountryMultiHop || ignoreSettings else { return true } guard first.country != second.country else { @@ -171,11 +171,11 @@ class VPNServer { return true } - static func validMultiHopISP(_ first: VPNServer, _ second: VPNServer) -> Bool { + static func validMultiHopISP(_ first: VPNServer, _ second: VPNServer, ignoreSettings: Bool = false) -> Bool { guard UserDefaults.shared.isMultiHop else { return true } - guard UserDefaults.standard.preventSameISPMultiHop else { + guard UserDefaults.standard.preventSameISPMultiHop || ignoreSettings else { return true } guard first.isp != second.isp else { diff --git a/IVPNClient/Models/VPNServerList.swift b/IVPNClient/Models/VPNServerList.swift index 2cef1a71a..9a349b98e 100644 --- a/IVPNClient/Models/VPNServerList.swift +++ b/IVPNClient/Models/VPNServerList.swift @@ -306,7 +306,11 @@ class VPNServerList { var list = [VPNServer]() let serverToValidate = isExitServer ? Application.shared.settings.selectedServer : Application.shared.settings.selectedExitServer - list = servers.filter { VPNServer.validMultiHop($0, serverToValidate) } + list = servers.filter { + VPNServer.validMultiHop($0, serverToValidate) && + VPNServer.validMultiHopCountry($0, serverToValidate, ignoreSettings: true) && + VPNServer.validMultiHopISP($0, serverToValidate, ignoreSettings: true) + } if let randomServer = list.randomElement() { randomServer.fastest = false From 412485b1daaf408f4d9c54cee3d21064d39b3a70 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Thu, 23 Feb 2023 10:51:21 +0100 Subject: [PATCH 169/581] feat: update validMultiHop method in ServerViewController --- IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift | 8 ++++---- .../Scenes/ViewControllers/ServerViewController.swift | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift b/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift index a6e7a751a..72d7f148f 100644 --- a/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift +++ b/IVPNClient/Scenes/MainScreen/Map/MapScrollView.swift @@ -335,15 +335,15 @@ class MapScrollView: UIScrollView { let secondServer = Application.shared.settings.selectedServer - guard VPNServer.validMultiHopISP(server, secondServer) else { - viewController.showActionAlert(title: VPNServer.validMultiHopISPTitle, message: VPNServer.validMultiHopISPMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in + guard VPNServer.validMultiHopCountry(server, secondServer) else { + viewController.showActionAlert(title: VPNServer.validMultiHopCountryTitle, message: VPNServer.validMultiHopCountryMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in selectServer(city: server.city, force: true) }) return false } - guard VPNServer.validMultiHopCountry(server, secondServer) else { - viewController.showActionAlert(title: VPNServer.validMultiHopCountryTitle, message: VPNServer.validMultiHopCountryMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in + guard VPNServer.validMultiHopISP(server, secondServer) else { + viewController.showActionAlert(title: VPNServer.validMultiHopISPTitle, message: VPNServer.validMultiHopISPMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in selectServer(city: server.city, force: true) }) return false diff --git a/IVPNClient/Scenes/ViewControllers/ServerViewController.swift b/IVPNClient/Scenes/ViewControllers/ServerViewController.swift index 0a57a06ef..ee742e3e0 100644 --- a/IVPNClient/Scenes/ViewControllers/ServerViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/ServerViewController.swift @@ -286,16 +286,16 @@ class ServerViewController: UITableViewController { return false } - guard VPNServer.validMultiHopISP(server, secondServer) else { - showActionAlert(title: VPNServer.validMultiHopISPTitle, message: VPNServer.validMultiHopISPMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in + guard VPNServer.validMultiHopCountry(server, secondServer) else { + showActionAlert(title: VPNServer.validMultiHopCountryTitle, message: VPNServer.validMultiHopCountryMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in selected(indexPath: indexPath, force: true) }) tableView.deselectRow(at: indexPath, animated: true) return false } - guard VPNServer.validMultiHopCountry(server, secondServer) else { - showActionAlert(title: VPNServer.validMultiHopCountryTitle, message: VPNServer.validMultiHopCountryMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in + guard VPNServer.validMultiHopISP(server, secondServer) else { + showActionAlert(title: VPNServer.validMultiHopISPTitle, message: VPNServer.validMultiHopISPMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in selected(indexPath: indexPath, force: true) }) tableView.deselectRow(at: indexPath, animated: true) From 4f61aa5575fef5bf7cf121cff0c8ad27db7951e3 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 14 Mar 2023 21:08:58 +0100 Subject: [PATCH 170/581] feat(settings): update sendLogs method in SettingsViewController --- .../SettingsViewController.swift | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift index 5e347fd5b..58243738a 100644 --- a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift @@ -354,15 +354,12 @@ class SettingsViewController: UITableViewController { return } - let composer = MFMailComposeViewController() - composer.mailComposeDelegate = self - composer.setToRecipients([Config.contactSupportMail]) - + var logFiles = [URL]() var openvpnLogAttached = false var presentMailComposer = true // App logs - var appLog: String? + var appLog = "" if let file = NSData(contentsOfFile: appLogPath) { appLog = String(data: file as Data, encoding: .utf8) ?? "" } @@ -371,11 +368,12 @@ class SettingsViewController: UITableViewController { let logFile = FileSystemManager.sharedFilePath(name: Config.appLogFile).path if let fileData = NSData(contentsOfFile: logFile) { - composer.addAttachmentData(fileData as Data, mimeType: "text/txt", fileName: "\(Date.logFileName(prefix: "app-")).txt") + appLog = String(data: fileData as Data, encoding: .utf8) ?? "" + logFiles.append(writeTempFile(text: appLog, fileName: "\(Date.logFileName(prefix: "app-"))")) } // WireGuard tunnel logs - var wireguardLog: String? + var wireguardLog = "" if let file = NSData(contentsOfFile: wireguardLogPath) { wireguardLog = String(data: file as Data, encoding: .utf8) ?? "" } @@ -384,7 +382,8 @@ class SettingsViewController: UITableViewController { let wireguardLogFile = FileSystemManager.sharedFilePath(name: Config.wireGuardLogFile).path if let fileData = NSData(contentsOfFile: wireguardLogFile) { - composer.addAttachmentData(fileData as Data, mimeType: "text/txt", fileName: "\(Date.logFileName(prefix: "wireguard-")).txt") + wireguardLog = String(data: fileData as Data, encoding: .utf8) ?? "" + logFiles.append(writeTempFile(text: wireguardLog, fileName: "\(Date.logFileName(prefix: "wireguard-"))")) } // OpenVPN tunnel logs @@ -393,19 +392,32 @@ class SettingsViewController: UITableViewController { FileSystemManager.updateLogFile(newestLog: openVPNLog, name: Config.openVPNLogFile, isLoggedIn: Application.shared.authentication.isLoggedIn) let logFile = FileSystemManager.sharedFilePath(name: Config.openVPNLogFile).path - if let fileData = NSData(contentsOfFile: logFile), !openvpnLogAttached { - composer.addAttachmentData(fileData as Data, mimeType: "text/txt", fileName: "\(Date.logFileName(prefix: "openvpn-")).txt") + var openvpnLog = "" + if let file = NSData(contentsOfFile: logFile), !openvpnLogAttached { + openvpnLog = String(data: file as Data, encoding: .utf8) ?? "" + logFiles.append(self.writeTempFile(text: openvpnLog, fileName: "\(Date.logFileName(prefix: "openvpn-"))")) openvpnLogAttached = true } } if presentMailComposer { - self.present(composer, animated: true, completion: nil) + let activityView = UIActivityViewController(activityItems: logFiles, applicationActivities: nil) + activityView.popoverPresentationController?.sourceView = self.view + activityView.excludedActivityTypes = [.postToFacebook] + self.present(activityView, animated: true, completion: nil) presentMailComposer = false } } } + private func writeTempFile(text: String, fileName: String) -> URL { + let url = FileManager.default.temporaryDirectory + .appendingPathComponent(fileName) + .appendingPathExtension("txt") + try? text.write(to: url, atomically: false, encoding: .utf8) + return url + } + private func contactSupport() { guard evaluateMailCompose() else { return From 63b5dd5aeb669d603a23f1544580f577836c8c69 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Tue, 14 Mar 2023 21:12:50 +0100 Subject: [PATCH 171/581] feat(settings): add tempFile method in FileSystemManager --- IVPNClient/Managers/FileSystemManager.swift | 9 +++++++++ .../ViewControllers/SettingsViewController.swift | 14 +++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/IVPNClient/Managers/FileSystemManager.swift b/IVPNClient/Managers/FileSystemManager.swift index bbc42c779..2a3060175 100644 --- a/IVPNClient/Managers/FileSystemManager.swift +++ b/IVPNClient/Managers/FileSystemManager.swift @@ -158,4 +158,13 @@ class FileSystemManager { return directory.appendingPathComponent(name) } + static func tempFile(text: String, fileName: String) -> URL { + let url = FileManager.default.temporaryDirectory + .appendingPathComponent(fileName) + .appendingPathExtension("txt") + try? text.write(to: url, atomically: false, encoding: .utf8) + + return url + } + } diff --git a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift index 58243738a..c462e6900 100644 --- a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift @@ -369,7 +369,7 @@ class SettingsViewController: UITableViewController { let logFile = FileSystemManager.sharedFilePath(name: Config.appLogFile).path if let fileData = NSData(contentsOfFile: logFile) { appLog = String(data: fileData as Data, encoding: .utf8) ?? "" - logFiles.append(writeTempFile(text: appLog, fileName: "\(Date.logFileName(prefix: "app-"))")) + logFiles.append(FileSystemManager.tempFile(text: appLog, fileName: "\(Date.logFileName(prefix: "app-"))")) } // WireGuard tunnel logs @@ -383,7 +383,7 @@ class SettingsViewController: UITableViewController { let wireguardLogFile = FileSystemManager.sharedFilePath(name: Config.wireGuardLogFile).path if let fileData = NSData(contentsOfFile: wireguardLogFile) { wireguardLog = String(data: fileData as Data, encoding: .utf8) ?? "" - logFiles.append(writeTempFile(text: wireguardLog, fileName: "\(Date.logFileName(prefix: "wireguard-"))")) + logFiles.append(FileSystemManager.tempFile(text: wireguardLog, fileName: "\(Date.logFileName(prefix: "wireguard-"))")) } // OpenVPN tunnel logs @@ -395,7 +395,7 @@ class SettingsViewController: UITableViewController { var openvpnLog = "" if let file = NSData(contentsOfFile: logFile), !openvpnLogAttached { openvpnLog = String(data: file as Data, encoding: .utf8) ?? "" - logFiles.append(self.writeTempFile(text: openvpnLog, fileName: "\(Date.logFileName(prefix: "openvpn-"))")) + logFiles.append(FileSystemManager.tempFile(text: openvpnLog, fileName: "\(Date.logFileName(prefix: "openvpn-"))")) openvpnLogAttached = true } } @@ -410,14 +410,6 @@ class SettingsViewController: UITableViewController { } } - private func writeTempFile(text: String, fileName: String) -> URL { - let url = FileManager.default.temporaryDirectory - .appendingPathComponent(fileName) - .appendingPathExtension("txt") - try? text.write(to: url, atomically: false, encoding: .utf8) - return url - } - private func contactSupport() { guard evaluateMailCompose() else { return From 5caa14bfc3b0660850d2a2fa5c55925bf8477c95 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 10:40:21 +0100 Subject: [PATCH 172/581] refactor: update logFileName method in Date+Ext.swift --- .../Scenes/ViewControllers/SettingsViewController.swift | 7 +++---- IVPNClient/Utilities/Extensions/Date+Ext.swift | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift index c462e6900..01997190a 100644 --- a/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/SettingsViewController.swift @@ -369,7 +369,7 @@ class SettingsViewController: UITableViewController { let logFile = FileSystemManager.sharedFilePath(name: Config.appLogFile).path if let fileData = NSData(contentsOfFile: logFile) { appLog = String(data: fileData as Data, encoding: .utf8) ?? "" - logFiles.append(FileSystemManager.tempFile(text: appLog, fileName: "\(Date.logFileName(prefix: "app-"))")) + logFiles.append(FileSystemManager.tempFile(text: appLog, fileName: "app-\(Date.logFileName())")) } // WireGuard tunnel logs @@ -383,7 +383,7 @@ class SettingsViewController: UITableViewController { let wireguardLogFile = FileSystemManager.sharedFilePath(name: Config.wireGuardLogFile).path if let fileData = NSData(contentsOfFile: wireguardLogFile) { wireguardLog = String(data: fileData as Data, encoding: .utf8) ?? "" - logFiles.append(FileSystemManager.tempFile(text: wireguardLog, fileName: "\(Date.logFileName(prefix: "wireguard-"))")) + logFiles.append(FileSystemManager.tempFile(text: wireguardLog, fileName: "wireguard-\(Date.logFileName())")) } // OpenVPN tunnel logs @@ -395,7 +395,7 @@ class SettingsViewController: UITableViewController { var openvpnLog = "" if let file = NSData(contentsOfFile: logFile), !openvpnLogAttached { openvpnLog = String(data: file as Data, encoding: .utf8) ?? "" - logFiles.append(FileSystemManager.tempFile(text: openvpnLog, fileName: "\(Date.logFileName(prefix: "openvpn-"))")) + logFiles.append(FileSystemManager.tempFile(text: openvpnLog, fileName: "openvpn-\(Date.logFileName())")) openvpnLogAttached = true } } @@ -403,7 +403,6 @@ class SettingsViewController: UITableViewController { if presentMailComposer { let activityView = UIActivityViewController(activityItems: logFiles, applicationActivities: nil) activityView.popoverPresentationController?.sourceView = self.view - activityView.excludedActivityTypes = [.postToFacebook] self.present(activityView, animated: true, completion: nil) presentMailComposer = false } diff --git a/IVPNClient/Utilities/Extensions/Date+Ext.swift b/IVPNClient/Utilities/Extensions/Date+Ext.swift index a9e1faaf6..0e9a4f54f 100644 --- a/IVPNClient/Utilities/Extensions/Date+Ext.swift +++ b/IVPNClient/Utilities/Extensions/Date+Ext.swift @@ -34,8 +34,8 @@ extension Date { return formatted(format: logFormat) } - static func logFileName(prefix: String = "") -> String { - return "\(prefix)\(formatted(format: fileNameFormat))" + static func logFileName() -> String { + return "\(formatted(format: fileNameFormat))" } static func changeDays(by days: Int) -> Date { From 39950b796a0ac0c2c7ceb17d0ab3f2641b5c0926 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 11:35:09 +0100 Subject: [PATCH 173/581] feat(settings): add wgMTU in /UserDefaults+Ext.swift --- IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift index 5c9989e98..229b2df89 100644 --- a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift @@ -47,6 +47,7 @@ extension UserDefaults { static let antiTrackerHardcoreDNS = "antiTrackerHardcoreDNS" static let wgKeyTimestamp = "wgKeyTimestamp" static let wgRegenerationRate = "wgRegenerationRate" + static let wgMTU = "wgMTU" static let hostNames = "hostNames" static let ipv6HostNames = "ipv6HostNames" static let apiHostName = "apiHostName" @@ -156,6 +157,10 @@ extension UserDefaults { return integer(forKey: Key.wgRegenerationRate) } + @objc dynamic var wgMTU: Int { + return integer(forKey: Key.wgMTU) + } + @objc dynamic var hostNames: [String] { return stringArray(forKey: Key.hostNames) ?? [] } @@ -251,6 +256,7 @@ extension UserDefaults { standard.removeObject(forKey: Key.fastestServerConfigured) standard.removeObject(forKey: Key.showIPv4Servers) standard.removeObject(forKey: Key.selectedProtocol) + standard.removeObject(forKey: Key.wgMTU) standard.synchronize() } From 33cf46432bea9076ebbed5e373abcb62d16ccf23 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 11:51:05 +0100 Subject: [PATCH 174/581] feat(settings): create MTUViewController.swift --- IVPNClient.xcodeproj/project.pbxproj | 4 + .../ViewControllers/MTUViewController.swift | 81 +++++++++++++++++++ .../Extensions/UserDefaults+Ext.swift | 8 +- 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 IVPNClient/Scenes/ViewControllers/MTUViewController.swift diff --git a/IVPNClient.xcodeproj/project.pbxproj b/IVPNClient.xcodeproj/project.pbxproj index f5d1b5617..bfad1113c 100644 --- a/IVPNClient.xcodeproj/project.pbxproj +++ b/IVPNClient.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 8201A5022354A32F008C83DB /* ErrorResultSessionNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8201A5012354A32F008C83DB /* ErrorResultSessionNew.swift */; }; 8201A5042356536B008C83DB /* UpgradePlanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8201A5032356536B008C83DB /* UpgradePlanViewController.swift */; }; 820203932186EE0E00D756AA /* WireGuardSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820203922186EE0E00D756AA /* WireGuardSettingsViewController.swift */; }; + 82052E5629C1D83700227CF9 /* MTUViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82052E5529C1D83700227CF9 /* MTUViewController.swift */; }; 820535282302B9D7007BDD58 /* APIAccessManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820535272302B9D7007BDD58 /* APIAccessManager.swift */; }; 820535292302BE8F007BDD58 /* APIAccessManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820535272302B9D7007BDD58 /* APIAccessManager.swift */; }; 8205352A2302BEA3007BDD58 /* Array+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823DA732215E3CCB00DAFE37 /* Array+Ext.swift */; }; @@ -413,6 +414,7 @@ 8201A5012354A32F008C83DB /* ErrorResultSessionNew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorResultSessionNew.swift; sourceTree = ""; }; 8201A5032356536B008C83DB /* UpgradePlanViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpgradePlanViewController.swift; sourceTree = ""; }; 820203922186EE0E00D756AA /* WireGuardSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireGuardSettingsViewController.swift; sourceTree = ""; }; + 82052E5529C1D83700227CF9 /* MTUViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTUViewController.swift; sourceTree = ""; }; 820535272302B9D7007BDD58 /* APIAccessManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIAccessManager.swift; sourceTree = ""; }; 8205963C2245264300011091 /* UITableViewController+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewController+Ext.swift"; sourceTree = ""; }; 82061F60238D2730009DDF4D /* PingResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PingResult.swift; sourceTree = ""; }; @@ -1154,6 +1156,7 @@ 8201A5032356536B008C83DB /* UpgradePlanViewController.swift */, 821CA2D6287C5AB20067F70D /* PortViewController.swift */, 82AB0874291A6B5F0084625A /* AddCustomPortViewController.swift */, + 82052E5529C1D83700227CF9 /* MTUViewController.swift */, ); path = ViewControllers; sourceTree = ""; @@ -2115,6 +2118,7 @@ 824777EA21A6BC3A001EEFAF /* Network+CoreDataProperties.swift in Sources */, 82C34D6E26FB02F900F06016 /* WireGuardEndpoint.swift in Sources */, 8232FBF42240DE19006B81D2 /* ErrorResult.swift in Sources */, + 82052E5629C1D83700227CF9 /* MTUViewController.swift in Sources */, 82351FCE2420CE6800E6E0FD /* MapMarkerView.swift in Sources */, 9C6942371DD218A900F9A801 /* AccessDetails.swift in Sources */, 82D598B421A5A7A3000FABDE /* NetworkTrust.swift in Sources */, diff --git a/IVPNClient/Scenes/ViewControllers/MTUViewController.swift b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift new file mode 100644 index 000000000..0579f24ef --- /dev/null +++ b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift @@ -0,0 +1,81 @@ +// +// MTUViewController.swift +// IVPN iOS app +// https://github.com/ivpn/ios-app +// +// Created by Juraj Hilje on 2023-03-15. +// Copyright (c) 2023 Privatus Limited. +// +// This file is part of the IVPN iOS app. +// +// The IVPN iOS app is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any later version. +// +// The IVPN iOS app is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License +// along with the IVPN iOS app. If not, see . +// + +import UIKit + +protocol MTUViewControllerDelegate: AnyObject { + func mtuSaved() +} + +class MTUViewController: UITableViewController { + + // MARK: - @IBOutlets - + + @IBOutlet weak var mtuTextField: UITextField! + + // MARK: - Properties - + + weak var delegate: MTUViewControllerDelegate? + + var mtu: Int { + return Int(mtuTextField.text ?? "") ?? 0 + } + + // MARK: - @IBActions - + + @IBAction func saveMtu() { + UserDefaults.standard.setValue(mtu, forKey: UserDefaults.Key.wgMtu) + navigationController?.dismiss(animated: true) { [self] in + delegate?.mtuSaved() + } + } + + // MARK: - View Lifecycle - + + override func viewDidLoad() { + super.viewDidLoad() + } + +} + +// MARK: - UITextFieldDelegate - + +extension MTUViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + if textField == mtuTextField { + textField.resignFirstResponder() + saveMtu() + } + + return true + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + let allowedCharacters = CharacterSet.decimalDigits + let characterSet = CharacterSet(charactersIn: string) + return allowedCharacters.isSuperset(of: characterSet) + } + +} + diff --git a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift index 229b2df89..e6f3a201a 100644 --- a/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift +++ b/IVPNClient/Utilities/Extensions/UserDefaults+Ext.swift @@ -47,7 +47,7 @@ extension UserDefaults { static let antiTrackerHardcoreDNS = "antiTrackerHardcoreDNS" static let wgKeyTimestamp = "wgKeyTimestamp" static let wgRegenerationRate = "wgRegenerationRate" - static let wgMTU = "wgMTU" + static let wgMtu = "wgMtu" static let hostNames = "hostNames" static let ipv6HostNames = "ipv6HostNames" static let apiHostName = "apiHostName" @@ -157,8 +157,8 @@ extension UserDefaults { return integer(forKey: Key.wgRegenerationRate) } - @objc dynamic var wgMTU: Int { - return integer(forKey: Key.wgMTU) + @objc dynamic var wgMtu: Int { + return integer(forKey: Key.wgMtu) } @objc dynamic var hostNames: [String] { @@ -256,7 +256,7 @@ extension UserDefaults { standard.removeObject(forKey: Key.fastestServerConfigured) standard.removeObject(forKey: Key.showIPv4Servers) standard.removeObject(forKey: Key.selectedProtocol) - standard.removeObject(forKey: Key.wgMTU) + standard.removeObject(forKey: Key.wgMtu) standard.synchronize() } From 07bf17ce8d03884beeb91d6c874b604c2ab35f4c Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 12:10:28 +0100 Subject: [PATCH 175/581] feat(settings): update saveMtu method in MTUViewController --- .../ViewControllers/MTUViewController.swift | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/IVPNClient/Scenes/ViewControllers/MTUViewController.swift b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift index 0579f24ef..82dafbc15 100644 --- a/IVPNClient/Scenes/ViewControllers/MTUViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift @@ -37,14 +37,19 @@ class MTUViewController: UITableViewController { weak var delegate: MTUViewControllerDelegate? - var mtu: Int { + var getMtu: Int { return Int(mtuTextField.text ?? "") ?? 0 } // MARK: - @IBActions - @IBAction func saveMtu() { - UserDefaults.standard.setValue(mtu, forKey: UserDefaults.Key.wgMtu) + guard isValid(mtu: getMtu) else { + showErrorAlert(title: "Error", message: "Expected value: [576 - 65535]") + return + } + + UserDefaults.standard.setValue(getMtu, forKey: UserDefaults.Key.wgMtu) navigationController?.dismiss(animated: true) { [self] in delegate?.mtuSaved() } @@ -54,6 +59,21 @@ class MTUViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() + setupView() + } + + // MARK: - Methods - + + private func setupView() { + mtuTextField.placeholder = "576 - 65535" + let mtu = UserDefaults.standard.wgMtu + if mtu > 0 { + mtuTextField.text = String(mtu) + } + } + + private func isValid(mtu: Int) -> Bool { + return mtu >= 576 && mtu <= 65535 } } From fc7528b25df83a209701f7e8d964fe6961b7134b Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 12:26:38 +0100 Subject: [PATCH 176/581] feat(settings): add getMTUViewController method in NavigationManager --- IVPNClient/Managers/NavigationManager.swift | 12 ++++++++++++ .../WireGuardSettingsViewController.swift | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/IVPNClient/Managers/NavigationManager.swift b/IVPNClient/Managers/NavigationManager.swift index d51d6b16b..6986e66b9 100644 --- a/IVPNClient/Managers/NavigationManager.swift +++ b/IVPNClient/Managers/NavigationManager.swift @@ -193,4 +193,16 @@ class NavigationManager { return navController! } + static func getMTUViewController(delegate: MTUViewControllerDelegate? = nil) -> UIViewController { + let storyBoard = UIStoryboard(name: "Main", bundle: nil) + let navController = storyBoard.instantiateViewController(withIdentifier: "configureMtu") as? UINavigationController + navController?.modalPresentationStyle = .formSheet + + if let viewController = navController?.topViewController as? MTUViewController { + viewController.delegate = delegate + } + + return navController! + } + } diff --git a/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift b/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift index bf66d3834..97259ccf5 100644 --- a/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift @@ -78,6 +78,11 @@ class WireGuardSettingsViewController: UITableViewController { } } + @IBAction func configureMtu(_ sender: Any) { + let viewController = NavigationManager.getMTUViewController(delegate: self) + present(viewController, animated: true) + } + // MARK: - View Lifecycle - override func viewDidLoad() { @@ -191,3 +196,13 @@ extension WireGuardSettingsViewController { } } + +// MARK: - MTUViewControllerDelegate - + +extension WireGuardSettingsViewController: MTUViewControllerDelegate { + + func mtuSaved() { + + } + +} From eece21c8d38903fa1de3c83efa69ee5f597e8db2 Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 13:52:23 +0100 Subject: [PATCH 177/581] feat(settings): update setupView method in WireGuardSettingsViewController --- IVPNClient/Scenes/ViewControllers/MTUViewController.swift | 8 +++----- .../ViewControllers/WireGuardSettingsViewController.swift | 5 ++++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/IVPNClient/Scenes/ViewControllers/MTUViewController.swift b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift index 82dafbc15..c4d214763 100644 --- a/IVPNClient/Scenes/ViewControllers/MTUViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/MTUViewController.swift @@ -65,15 +65,13 @@ class MTUViewController: UITableViewController { // MARK: - Methods - private func setupView() { - mtuTextField.placeholder = "576 - 65535" let mtu = UserDefaults.standard.wgMtu - if mtu > 0 { - mtuTextField.text = String(mtu) - } + mtuTextField.text = mtu > 0 ? String(mtu) : nil + mtuTextField.placeholder = "576 - 65535" } private func isValid(mtu: Int) -> Bool { - return mtu >= 576 && mtu <= 65535 + return (mtu >= 576 && mtu <= 65535) || mtu == 0 } } diff --git a/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift b/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift index 97259ccf5..e6fb11110 100644 --- a/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift +++ b/IVPNClient/Scenes/ViewControllers/WireGuardSettingsViewController.swift @@ -34,6 +34,7 @@ class WireGuardSettingsViewController: UITableViewController { @IBOutlet weak var keyTimestampLabel: UILabel! @IBOutlet weak var keyExpirationTimestampLabel: UILabel! @IBOutlet weak var keyRegenerationTimestampLabel: UILabel! + @IBOutlet weak var mtuLabel: UILabel! // MARK: - Properties - @@ -101,6 +102,8 @@ class WireGuardSettingsViewController: UITableViewController { keyTimestampLabel.text = AppKeyManager.keyTimestamp.formatDate() keyExpirationTimestampLabel.text = AppKeyManager.keyExpirationTimestamp.formatDate() keyRegenerationTimestampLabel.text = AppKeyManager.keyRegenerationTimestamp.formatDate() + let mtu = UserDefaults.standard.wgMtu + mtuLabel.text = mtu > 0 ? String(mtu) : "Leave blank to use default value" } private func addObservers() { @@ -202,7 +205,7 @@ extension WireGuardSettingsViewController { extension WireGuardSettingsViewController: MTUViewControllerDelegate { func mtuSaved() { - + setupView() } } From 126b883602a997da10756b129fd86393c07169bc Mon Sep 17 00:00:00 2001 From: Juraj Hilje Date: Wed, 15 Mar 2023 19:39:55 +0100 Subject: [PATCH 178/581] feat(settings): update WireGuardSettings view --- IVPNClient/Scenes/Base.lproj/Main.storyboard | 145 ++++++++++++++----- 1 file changed, 105 insertions(+), 40 deletions(-) diff --git a/IVPNClient/Scenes/Base.lproj/Main.storyboard b/IVPNClient/Scenes/Base.lproj/Main.storyboard index ac649b522..f191b016d 100644 --- a/IVPNClient/Scenes/Base.lproj/Main.storyboard +++ b/IVPNClient/Scenes/Base.lproj/Main.storyboard @@ -21,7 +21,7 @@ - + - - - - Using the same internal IP address and keys for extended period of time may not be ideal for various reasons when connected with WireGuard protocol. - - + @@ -2084,7 +2080,7 @@ - + @@ -2101,6 +2097,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2113,6 +2177,7 @@ + @@ -2387,13 +2452,13 @@ -