Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions IVPNClient/Models/Host.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct Host: Codable {
var publicKey: String
var localIP: String
var ipv6: IPv6?
var isp: String
var multihopPort: Int
var load: Double
var v2ray: String
Expand Down
67 changes: 57 additions & 10 deletions IVPNClient/Models/VPNServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,16 @@ class VPNServer {
return gateway.components(separatedBy: CharacterSet.decimalDigits).joined()
}

private (set) var gateway: String
private (set) var countryCode: String
private (set) var country: String
private (set) var city: String
private (set) var latitude: Double
private (set) var longitude: Double
private (set) var isp: String
private (set) var hosts: [Host]
private (set) var load: Double?
private (set) var ipv6: IPv6?
private(set) var gateway: String
private(set) var countryCode: String
private(set) var country: String
private(set) var city: String
private(set) var latitude: Double
private(set) var longitude: Double
private(set) var isp: String
private(set) var hosts: [Host]
private(set) var load: Double?
private(set) var ipv6: IPv6?
var dnsName: String?

// MARK: - Initialize -
Expand Down Expand Up @@ -182,5 +182,52 @@ class VPNServer {

return true
}

static func validHostMultiHopISP(_ first: VPNServer, _ second: VPNServer, _ firstHost: Host?, _ secondHost: Host?) -> Bool {
guard UserDefaults.shared.isMultiHop else {
return true
}
guard UserDefaults.standard.preventSameISPMultiHop else {
return true
}

if let firstHost = firstHost, let secondHost = secondHost {
guard firstHost.isp != secondHost.isp else {
return false
}
} else {
guard first.isp != second.isp else {
return false
}
}

return true
}

static func validHostsMultiHopISP(_ first: VPNServer, _ second: VPNServer, _ hosts: [Host]) -> Bool {
guard UserDefaults.shared.isMultiHop else {
return true
}
guard UserDefaults.standard.preventSameISPMultiHop else {
return true
}
guard hasHostWithDifferentISP(second, hosts) else {
return false
}

return true
}

private static func hasHostWithDifferentISP(_ server: VPNServer, _ hosts: [Host]) -> Bool {
for host in hosts {
guard host.isp != server.isp else {
continue
}

return true
}

return false
}

}
1 change: 1 addition & 0 deletions IVPNClient/Models/VPNServerList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ class VPNServerList {
dnsName: host["dns_name"] as? String ?? "",
publicKey: host["public_key"] as? String ?? "",
localIP: host["local_ip"] as? String ?? "",
isp: host["isp"] as? String ?? "",
multihopPort: host["multihop_port"] as? Int ?? 0,
load: host["load"] as? Double ?? 0,
v2ray: host["v2ray"] as? String ?? ""
Expand Down
11 changes: 9 additions & 2 deletions IVPNClient/Scenes/TableCells/ServerTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ class ServerTableViewCell: UITableViewCell {

var serverToValidate: VPNServer! {
didSet {
guard VPNServer.validMultiHopCountry(viewModel.server, serverToValidate) else {
if !VPNServer.validMultiHopCountry(viewModel.server, serverToValidate) {
contentView.alpha = 0.55
return
}
guard VPNServer.validMultiHopISP(viewModel.server, serverToValidate) else {
if !viewModel.server.isHost, !VPNServer.validHostsMultiHopISP(viewModel.server, serverToValidate, viewModel.server.hosts) {
contentView.alpha = 0.55
return
}
if viewModel.server.isHost, !VPNServer.validHostMultiHopISP(viewModel.server, serverToValidate, host, hostToValidate) {
contentView.alpha = 0.55
return
}
Expand All @@ -70,6 +74,9 @@ class ServerTableViewCell: UITableViewCell {
}
}

var host: Host?
var hostToValidate: Host?

var indexPath: IndexPath! {
didSet {
if indexPath.row == 0 || !isMultiHop && indexPath.row == 1 {
Expand Down
28 changes: 24 additions & 4 deletions IVPNClient/Scenes/ViewControllers/ServerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,12 +274,13 @@ class ServerViewController: UITableViewController {
return false
}

private func validMultiHop(server: VPNServer, indexPath: IndexPath, force: Bool) -> Bool {
private func validMultiHop(server: VPNServer, host: Host?, indexPath: IndexPath, force: Bool) -> Bool {
guard !force else {
return true
}

let secondServer = isExitServer ? Application.shared.settings.selectedServer : Application.shared.settings.selectedExitServer
let secondHost = isExitServer ? Application.shared.settings.selectedHost : Application.shared.settings.selectedExitHost

guard VPNServer.validMultiHop(server, secondServer) else {
showAlert(title: "Entry and exit servers are the same", message: "Please select a different entry or exit server.")
Expand All @@ -295,7 +296,15 @@ class ServerViewController: UITableViewController {
return false
}

guard VPNServer.validMultiHopISP(server, secondServer) else {
if host == nil, !VPNServer.validHostsMultiHopISP(server, secondServer, server.hosts) {
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)
return false
}

if host != nil, !VPNServer.validHostMultiHopISP(server, secondServer, host, secondHost) {
showActionAlert(title: VPNServer.validMultiHopISPTitle, message: VPNServer.validMultiHopISPMessage, action: "Continue", cancel: "Cancel", actionHandler: { [self] _ in
selected(indexPath: indexPath, force: true)
})
Expand Down Expand Up @@ -371,7 +380,7 @@ class ServerViewController: UITableViewController {
}
}

guard validMultiHop(server: selectedServer, indexPath: indexPath, force: force) else {
guard validMultiHop(server: selectedServer, host: selectedHost, indexPath: indexPath, force: force) else {
return
}

Expand Down Expand Up @@ -408,9 +417,20 @@ extension ServerViewController {
cell.isFavorite = isFavorite
cell.indexPath = indexPath
cell.viewModel = VPNServerViewModel(server: server)
cell.serverToValidate = isExitServer ? Application.shared.settings.selectedServer : Application.shared.settings.selectedExitServer
cell.expandedGateways = expandedGateways

if server.isHost {
if let serverByCity = Application.shared.serverList.getServer(byCity: server.city) {
cell.host = serverByCity.getHost(hostName: server.gateway)
cell.hostToValidate = isExitServer ? Application.shared.settings.selectedHost : Application.shared.settings.selectedExitHost
}
} else {
cell.host = nil
cell.hostToValidate = nil
}

cell.serverToValidate = isExitServer ? Application.shared.settings.selectedServer : Application.shared.settings.selectedExitServer

return cell
}

Expand Down
32 changes: 32 additions & 0 deletions IVPNClient/Utilities/Extensions/NETunnelProviderProtocol+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,22 @@ extension NETunnelProviderProtocol {
return selectedHost
}

if UserDefaults.shared.isMultiHop, UserDefaults.standard.preventSameISPMultiHop {
let hosts = Application.shared.settings.selectedServer.hosts
let secondServer = Application.shared.settings.selectedExitServer
var filteredHosts: [Host] = []

for host in hosts {
if host.isp != secondServer.isp {
filteredHosts.append(host)
}
}

if let firstHost = filteredHosts.first {
return firstHost
}
}

if let firstHost = Application.shared.settings.selectedServer.hosts.first {
return firstHost
}
Expand All @@ -194,6 +210,22 @@ extension NETunnelProviderProtocol {
return selectedHost
}

if UserDefaults.shared.isMultiHop, UserDefaults.standard.preventSameISPMultiHop {
let hosts = Application.shared.settings.selectedExitServer.hosts
let secondServer = Application.shared.settings.selectedServer
var filteredHosts: [Host] = []

for host in hosts {
if host.isp != secondServer.isp {
filteredHosts.append(host)
}
}

if let firstHost = filteredHosts.first {
return firstHost
}
}

if let firstHost = Application.shared.settings.selectedExitServer.hosts.first {
return firstHost
}
Expand Down
Loading