summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2020-09-08 19:04:13 +0200
committerAndrej Mihajlov <and@mullvad.net>2020-09-08 19:04:13 +0200
commitfacc4ae770b6ad3c18d9d41e91c292cbae1588a9 (patch)
treec911edaa9ffd66feb70b0aeb8dd36c144b002f7d
parentfefd87f82d5d0cae01a6e21d6ce1d309e1ac4973 (diff)
parent3c54a89fd45bed2601d21e3e2964675bb65b83b8 (diff)
downloadmullvadvpn-facc4ae770b6ad3c18d9d41e91c292cbae1588a9.tar.xz
mullvadvpn-facc4ae770b6ad3c18d9d41e91c292cbae1588a9.zip
Merge branch 'improve-ipaddress-range'
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj20
-rw-r--r--ios/MullvadVPN/IPAddress+Codable.swift (renamed from ios/MullvadVPN/IpAddress+Codable.swift)2
-rw-r--r--ios/MullvadVPN/IPAddressRange.swift114
-rw-r--r--ios/MullvadVPNTests/IPAddressRangeTests.swift54
4 files changed, 146 insertions, 44 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index acb84d969c..177e5d20dc 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -58,11 +58,12 @@
582BB1B1229569620055B6EF /* CustomNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582BB1B0229569620055B6EF /* CustomNavigationBar.swift */; };
582BB1B3229574F40055B6EF /* SettingsAccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582BB1B2229574F40055B6EF /* SettingsAccountCell.swift */; };
582BB1B52295780F0055B6EF /* AccountExpiry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582BB1B42295780F0055B6EF /* AccountExpiry.swift */; };
+ 58341D9D2507826300D2BB19 /* IPAddressRangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58341D9C2507826300D2BB19 /* IPAddressRangeTests.swift */; };
5835B7CC233B76CB0096D79F /* TunnelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5835B7CB233B76CB0096D79F /* TunnelManager.swift */; };
583BC70724FE4DC500C9DE04 /* Optional+DispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583BC70624FE4DC400C9DE04 /* Optional+DispatchQueue.swift */; };
583BC70824FE4DC500C9DE04 /* Optional+DispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583BC70624FE4DC400C9DE04 /* Optional+DispatchQueue.swift */; };
- 5840250122B1124600E4CFEC /* IpAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */; };
- 5840250222B1124600E4CFEC /* IpAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */; };
+ 5840250122B1124600E4CFEC /* IPAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */; };
+ 5840250222B1124600E4CFEC /* IPAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */; };
5840250422B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
5840250522B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
5845F842236CBACD00B2D93C /* PacketTunnelIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */; };
@@ -138,7 +139,7 @@
58B0A2A8238EE68200BC001D /* RelaySelectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 584B26F3237434D00073B10E /* RelaySelectorTests.swift */; };
58B0A2A9238EE6A100BC001D /* RelayConstraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CC822AE7CA8009B9D8E /* RelayConstraints.swift */; };
58B0A2AA238EE6A900BC001D /* RelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58781CD422AFBA39009B9D8E /* RelaySelector.swift */; };
- 58B0A2AC238EE6D500BC001D /* IpAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */; };
+ 58B0A2AC238EE6D500BC001D /* IPAddress+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */; };
58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */; };
58B8743222B25A7600015324 /* WireguardAssociatedAddresses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743122B25A7600015324 /* WireguardAssociatedAddresses.swift */; };
58B8743B22B788D200015324 /* PacketTunnelSettingsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58B8743722B25EAB00015324 /* PacketTunnelSettingsGenerator.swift */; };
@@ -288,9 +289,10 @@
582BB1B0229569620055B6EF /* CustomNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavigationBar.swift; sourceTree = "<group>"; };
582BB1B2229574F40055B6EF /* SettingsAccountCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAccountCell.swift; sourceTree = "<group>"; };
582BB1B42295780F0055B6EF /* AccountExpiry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountExpiry.swift; sourceTree = "<group>"; };
+ 58341D9C2507826300D2BB19 /* IPAddressRangeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPAddressRangeTests.swift; sourceTree = "<group>"; };
5835B7CB233B76CB0096D79F /* TunnelManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelManager.swift; sourceTree = "<group>"; };
583BC70624FE4DC400C9DE04 /* Optional+DispatchQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+DispatchQueue.swift"; sourceTree = "<group>"; };
- 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IpAddress+Codable.swift"; sourceTree = "<group>"; };
+ 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IPAddress+Codable.swift"; sourceTree = "<group>"; };
5840250322B11AB700E4CFEC /* MullvadEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MullvadEndpoint.swift; sourceTree = "<group>"; };
5845F841236CBACD00B2D93C /* PacketTunnelIpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelIpc.swift; sourceTree = "<group>"; };
584B26F3237434D00073B10E /* RelaySelectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelaySelectorTests.swift; sourceTree = "<group>"; };
@@ -489,6 +491,7 @@
58B0A2A1238EE67E00BC001D /* MullvadVPNTests */ = {
isa = PBXGroup;
children = (
+ 58341D9C2507826300D2BB19 /* IPAddressRangeTests.swift */,
582AE3112440CA0D00E6733A /* AccountTokenInputTests.swift */,
58B0A2A4238EE67E00BC001D /* Info.plist */,
584B26F3237434D00073B10E /* RelaySelectorTests.swift */,
@@ -558,7 +561,7 @@
58F3C0A3249CB069003E76BE /* HeaderBarView.swift */,
58FD5BF32428C67600112C88 /* InAppPurchaseButton.swift */,
58CE5E6F224146210008646E /* Info.plist */,
- 5840250022B1124600E4CFEC /* IpAddress+Codable.swift */,
+ 5840250022B1124600E4CFEC /* IPAddress+Codable.swift */,
58C6B34E22BB7AC0003C19AD /* IPAddressRange.swift */,
58561C98239A5D1500BD6B5E /* IPEndpoint.swift */,
58FAEDF6245088E100CB0F5B /* Keychain.swift */,
@@ -929,6 +932,7 @@
5857F23B24C8448600CF6F47 /* OperationProtocol.swift in Sources */,
5857F22F24C8404C00CF6F47 /* MullvadRest.swift in Sources */,
58B0A2AA238EE6A900BC001D /* RelaySelector.swift in Sources */,
+ 58341D9D2507826300D2BB19 /* IPAddressRangeTests.swift in Sources */,
5857F23924C8446A00CF6F47 /* AnyOperationObserver.swift in Sources */,
5896AE86246D6AD8005B36CB /* CustomDateComponentsFormattingTests.swift in Sources */,
5807E2C3243203E700F5FF30 /* String+Split.swift in Sources */,
@@ -939,7 +943,7 @@
5857F23F24C844AD00CF6F47 /* Locking.swift in Sources */,
5857F23424C8443700CF6F47 /* AsyncOperation.swift in Sources */,
5857F23624C8445300CF6F47 /* OutputOperation.swift in Sources */,
- 58B0A2AC238EE6D500BC001D /* IpAddress+Codable.swift in Sources */,
+ 58B0A2AC238EE6D500BC001D /* IPAddress+Codable.swift in Sources */,
58B0A2AD238EE6EC00BC001D /* MullvadEndpoint.swift in Sources */,
58FAEDF4245088B300CB0F5B /* KeychainError.swift in Sources */,
5896AE88246D7FAF005B36CB /* CustomDateComponentsFormatting.swift in Sources */,
@@ -965,7 +969,7 @@
58BFA5CC22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */,
58BA692E23E99EFF009DC256 /* Locking.swift in Sources */,
580EE21E24B3237F00F9D8A1 /* OutputOperation.swift in Sources */,
- 5840250122B1124600E4CFEC /* IpAddress+Codable.swift in Sources */,
+ 5840250122B1124600E4CFEC /* IPAddress+Codable.swift in Sources */,
5857F24724C882D700CF6F47 /* SelectLocationNavigationController.swift in Sources */,
580EE21224B322FC00F9D8A1 /* ResultOperation.swift in Sources */,
58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */,
@@ -1083,7 +1087,7 @@
58F3C0962492617E003E76BE /* AsyncOperation.swift in Sources */,
580EE22924B3289300F9D8A1 /* AssociatedValue.swift in Sources */,
58AEEF662344A37400C9BBD5 /* KeychainError.swift in Sources */,
- 5840250222B1124600E4CFEC /* IpAddress+Codable.swift in Sources */,
+ 5840250222B1124600E4CFEC /* IPAddress+Codable.swift in Sources */,
58BA693223EAE1AE009DC256 /* SimulatorTunnelProvider.swift in Sources */,
580EE21924B3235100F9D8A1 /* AnyOperationObserver.swift in Sources */,
580EE21324B322FC00F9D8A1 /* ResultOperation.swift in Sources */,
diff --git a/ios/MullvadVPN/IpAddress+Codable.swift b/ios/MullvadVPN/IPAddress+Codable.swift
index 73fb34f642..d8802e85ca 100644
--- a/ios/MullvadVPN/IpAddress+Codable.swift
+++ b/ios/MullvadVPN/IPAddress+Codable.swift
@@ -1,5 +1,5 @@
//
-// IpAddress+Codable.swift
+// IPAddress+Codable.swift
// MullvadVPN
//
// Created by pronebird on 12/06/2019.
diff --git a/ios/MullvadVPN/IPAddressRange.swift b/ios/MullvadVPN/IPAddressRange.swift
index d887020fef..712dc4d39e 100644
--- a/ios/MullvadVPN/IPAddressRange.swift
+++ b/ios/MullvadVPN/IPAddressRange.swift
@@ -4,14 +4,51 @@
//
// Created by pronebird on 20/06/2019.
// Copyright © 2019 Mullvad VPN AB. All rights reserved.
+// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
//
import Foundation
import Network
+/// A struct describing an IP address range
struct IPAddressRange {
let address: IPAddress
- var networkPrefixLength: UInt8
+ let networkPrefixLength: UInt8
+
+ init(address: IPAddress, networkPrefixLength: UInt8) {
+ self.address = address
+ self.networkPrefixLength = min(networkPrefixLength, address.maxNetworkPrefixLength)
+ }
+
+ init(string: String) throws {
+ let separatorIndex = string.lastIndex(of: "/") ?? string.endIndex
+ let prefixStartIndex = string.index(separatorIndex, offsetBy: 1, limitedBy: string.endIndex)
+
+ let prefixSubstring = prefixStartIndex.flatMap { string[$0...] }
+ var prefix: UInt8?
+ if let prefixSubstring = prefixSubstring {
+ if let parsedPrefix = UInt8(prefixSubstring) {
+ prefix = parsedPrefix
+ } else {
+ throw IPAddressRangeParseError.parsePrefix(String(prefixSubstring))
+ }
+ }
+
+ let addressString = String(string[..<separatorIndex])
+ if let ipv4Address = IPv4Address(addressString) {
+ self = IPAddressRange(
+ address: ipv4Address,
+ networkPrefixLength: prefix ?? ipv4Address.maxNetworkPrefixLength
+ )
+ } else if let ipv6Address = IPv6Address(addressString) {
+ self = IPAddressRange(
+ address: ipv6Address,
+ networkPrefixLength: prefix ?? ipv6Address.maxNetworkPrefixLength
+ )
+ } else {
+ throw IPAddressRangeParseError.parseAddress(addressString)
+ }
+ }
}
extension IPAddressRange: Equatable {
@@ -34,44 +71,31 @@ extension IPAddressRange: CustomStringConvertible {
}
}
-extension IPAddressRange {
-
- init?(from string: String) {
- guard let parsed = IPAddressRange.parseAddressString(string) else { return nil }
- address = parsed.0
- networkPrefixLength = parsed.1
+private extension IPv4Address {
+ var maxNetworkPrefixLength: UInt8 {
+ return 32
}
+}
- private static func parseAddressString(_ string: String) -> (IPAddress, UInt8)? {
- let endOfIPAddress = string.lastIndex(of: "/") ?? string.endIndex
- let addressString = String(string[string.startIndex ..< endOfIPAddress])
- let address: IPAddress
- if let addr = IPv4Address(addressString) {
- address = addr
- } else if let addr = IPv6Address(addressString) {
- address = addr
- } else {
- return nil
- }
+private extension IPv6Address {
+ var maxNetworkPrefixLength: UInt8 {
+ return 128
+ }
+}
- let maxNetworkPrefixLength: UInt8 = address is IPv4Address ? 32 : 128
- var networkPrefixLength: UInt8
- if endOfIPAddress < string.endIndex { // "/" was located
- let indexOfNetworkPrefixLength = string.index(after: endOfIPAddress)
- guard indexOfNetworkPrefixLength < string.endIndex else { return nil }
- let networkPrefixLengthSubstring = string[indexOfNetworkPrefixLength ..< string.endIndex]
- guard let npl = UInt8(networkPrefixLengthSubstring) else { return nil }
- networkPrefixLength = min(npl, maxNetworkPrefixLength)
+private extension IPAddress {
+ var maxNetworkPrefixLength: UInt8 {
+ if let ipv4Address = self as? IPv4Address {
+ return ipv4Address.maxNetworkPrefixLength
+ } else if let ipv6Address = self as? IPv6Address {
+ return ipv6Address.maxNetworkPrefixLength
} else {
- networkPrefixLength = maxNetworkPrefixLength
+ fatalError()
}
-
- return (address, networkPrefixLength)
}
}
extension IPAddressRange: Codable {
-
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
@@ -82,11 +106,31 @@ extension IPAddressRange: Codable {
let container = try decoder.singleValueContainer()
let value = try container.decode(String.self)
- if let addressRange = IPAddressRange(from: value) {
- self = addressRange
- } else {
- throw DecodingError.dataCorruptedError(
- in: container, debugDescription: "Invalid IPAddressRange representation")
+ do {
+ self = try IPAddressRange(string: value)
+ } catch {
+ let context = DecodingError.Context(
+ codingPath: container.codingPath,
+ debugDescription: "Invalid IPAddressRange representation",
+ underlyingError: error)
+ throw DecodingError.dataCorrupted(context)
+ }
+ }
+}
+
+enum IPAddressRangeParseError: LocalizedError, Equatable {
+ /// A failure to parse the IP address
+ case parseAddress(String)
+
+ /// A failure to parse the network prefix
+ case parsePrefix(String)
+
+ var errorDescription: String? {
+ switch self {
+ case .parseAddress(let addressString):
+ return "Failure to parse the IP address: \(addressString)"
+ case .parsePrefix(let prefixString):
+ return "Failure to parse the network prefix: \(prefixString)"
}
}
}
diff --git a/ios/MullvadVPNTests/IPAddressRangeTests.swift b/ios/MullvadVPNTests/IPAddressRangeTests.swift
new file mode 100644
index 0000000000..37dc3415a2
--- /dev/null
+++ b/ios/MullvadVPNTests/IPAddressRangeTests.swift
@@ -0,0 +1,54 @@
+//
+// IPAddressRangeTests.swift
+// MullvadVPNTests
+//
+// Created by pronebird on 08/09/2020.
+// Copyright © 2020 Mullvad VPN AB. All rights reserved.
+//
+
+import XCTest
+
+class IPAddressRangeTests: XCTestCase {
+
+ func testParsingValidIPv4AddressRange() throws {
+ let addr = try IPAddressRange(string: "127.0.0.1/32")
+ XCTAssertEqual("\(addr)", "127.0.0.1/32")
+ }
+
+ func testParsingValidIPv6AddressRange() throws {
+ let addr = try IPAddressRange(string: "::1/128")
+ XCTAssertEqual("\(addr)", "::1/128")
+ }
+
+ func testParsingIPv4AddressWithoutNetworkPrefix() throws {
+ let addr = try IPAddressRange(string: "127.0.0.1")
+ XCTAssertEqual("\(addr)", "127.0.0.1/32")
+ }
+
+ func testParsingIPv6AddressWithoutNetworkPrefix() throws {
+ let addr = try IPAddressRange(string: "::1")
+ XCTAssertEqual("\(addr)", "::1/128")
+ }
+
+ func testParsingInvalidIPv4AddressNetworkPrefix() throws {
+ let addr = try IPAddressRange(string: "127.0.0.1/33")
+ XCTAssertEqual("\(addr)", "127.0.0.1/32")
+ }
+
+ func testParsingInvalidIPv6AddressNetworkPrefix() throws {
+ let addr = try IPAddressRange(string: "::1/129")
+ XCTAssertEqual("\(addr)", "::1/128")
+ }
+
+ func testParsingInvalidIPAddress() throws {
+ XCTAssertThrowsError(try IPAddressRange(string: "1.2.3.4.5/32")) { (error) in
+ XCTAssertEqual(error as? IPAddressRangeParseError, IPAddressRangeParseError.parseAddress("1.2.3.4.5"))
+ }
+ }
+
+ func testParsingEmptyNetworkPrefix() throws {
+ XCTAssertThrowsError(try IPAddressRange(string: "::1/")) { (error) in
+ XCTAssertEqual(error as? IPAddressRangeParseError, IPAddressRangeParseError.parsePrefix(""))
+ }
+ }
+}