diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2020-09-08 19:04:13 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2020-09-08 19:04:13 +0200 |
| commit | facc4ae770b6ad3c18d9d41e91c292cbae1588a9 (patch) | |
| tree | c911edaa9ffd66feb70b0aeb8dd36c144b002f7d | |
| parent | fefd87f82d5d0cae01a6e21d6ce1d309e1ac4973 (diff) | |
| parent | 3c54a89fd45bed2601d21e3e2964675bb65b83b8 (diff) | |
| download | mullvadvpn-facc4ae770b6ad3c18d9d41e91c292cbae1588a9.tar.xz mullvadvpn-facc4ae770b6ad3c18d9d41e91c292cbae1588a9.zip | |
Merge branch 'improve-ipaddress-range'
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 20 | ||||
| -rw-r--r-- | ios/MullvadVPN/IPAddress+Codable.swift (renamed from ios/MullvadVPN/IpAddress+Codable.swift) | 2 | ||||
| -rw-r--r-- | ios/MullvadVPN/IPAddressRange.swift | 114 | ||||
| -rw-r--r-- | ios/MullvadVPNTests/IPAddressRangeTests.swift | 54 |
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("")) + } + } +} |
