From 9037b90747ccd153b57dfb223a6400456dcddcf5 Mon Sep 17 00:00:00 2001 From: Jeroen Leenarts Date: Wed, 15 Aug 2018 20:35:21 +0200 Subject: [PATCH] Add Validator for Endpoints. Signed-off-by: Jason A. Donenfeld --- Shared/Validators.swift | 71 ++++++++++++++++++++++++++++ WireGuard.xcodeproj/project.pbxproj | 10 ++++ WireGuardTests/ValidatorsTests.swift | 56 ++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 Shared/Validators.swift create mode 100644 WireGuardTests/ValidatorsTests.swift diff --git a/Shared/Validators.swift b/Shared/Validators.swift new file mode 100644 index 0000000..b215343 --- /dev/null +++ b/Shared/Validators.swift @@ -0,0 +1,71 @@ +// +// IPValidator.swift +// WireGuard +// +// Created by Jeroen Leenarts on 15-08-18. +// Copyright © 2018 WireGuard. All rights reserved. +// + +import Foundation + +enum AddressType { + case IPv6, IPv4, other +} + +public enum EndpointValidationError: Error { + case noIpAndPort(String) + case invalidIP(String) + case invalidPort(String) + + var localizedDescription: String { + switch self { + case .noIpAndPort: + return NSLocalizedString("EndpointValidationError.noIpAndPort", comment: "Error message for malformed endpoint.") + case .invalidIP: + return NSLocalizedString("EndpointValidationError.invalidIP", comment: "Error message for invalid endpoint ip.") + case .invalidPort: + return NSLocalizedString("EndpointValidationError.invalidPort", comment: "Error message invalid endpoint port.") + } + } +} +struct Endpoint { + var ipAddress: String + var port: Int32 + var addressType: AddressType + + init?(endpointString: String) throws { + let parts = endpointString.split(separator: ":") + guard parts.count == 2 else { + throw EndpointValidationError.noIpAndPort(endpointString) + } + guard let port = Int32(parts[1]), port > 0 else { + throw EndpointValidationError.invalidPort(String(parts[1])) + } + + ipAddress = String(parts[0]) + let addressType = validateIpAddress(ipToValidate: ipAddress) + guard addressType == .IPv4 || addressType == .IPv6 else { + throw EndpointValidationError.invalidIP(ipAddress) + } + self.addressType = addressType + + self.port = port + } +} + +func validateIpAddress(ipToValidate: String) -> AddressType { + + var sin = sockaddr_in() + if ipToValidate.withCString({ cstring in inet_pton(AF_INET, cstring, &sin.sin_addr) }) == 1 { + // IPv4 peer. + return .IPv4 + } + + var sin6 = sockaddr_in6() + if ipToValidate.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 { + // IPv6 peer. + return .IPv6 + } + + return .other +} diff --git a/WireGuard.xcodeproj/project.pbxproj b/WireGuard.xcodeproj/project.pbxproj index 784d6de..06a1e06 100644 --- a/WireGuard.xcodeproj/project.pbxproj +++ b/WireGuard.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 48CF751B34E9703133F1B1AF /* Pods_WireGuard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 861983CAE8FDC13BC83E7E04 /* Pods_WireGuard.framework */; }; + 4A4351592124956200261999 /* Validators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4351582124956200261999 /* Validators.swift */; }; + 4A43515A2124956200261999 /* Validators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4351582124956200261999 /* Validators.swift */; }; + 4A43515C21249E5700261999 /* ValidatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A43515B21249E5700261999 /* ValidatorsTests.swift */; }; 4A4BA6D820B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4BA6D720B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift */; }; 4A4BACE620B5F1BF00F12B28 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4BACE520B5F1BF00F12B28 /* AppDelegate.swift */; }; 4A4BACE820B5F1BF00F12B28 /* TunnelsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A4BACE720B5F1BF00F12B28 /* TunnelsTableViewController.swift */; }; @@ -75,6 +78,8 @@ /* Begin PBXFileReference section */ 0CE52E030FAA93F3BF5747B2 /* Pods-WireGuard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WireGuard.release.xcconfig"; path = "Pods/Target Support Files/Pods-WireGuard/Pods-WireGuard.release.xcconfig"; sourceTree = ""; }; 25E2BE31A33C8CCE6E79B6EF /* Pods-WireGuard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WireGuard.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WireGuard/Pods-WireGuard.debug.xcconfig"; sourceTree = ""; }; + 4A4351582124956200261999 /* Validators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Validators.swift; sourceTree = ""; }; + 4A43515B21249E5700261999 /* ValidatorsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsTests.swift; sourceTree = ""; }; 4A4BA6D720B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelConfigurationTableViewController.swift; sourceTree = ""; }; 4A4BACE220B5F1BF00F12B28 /* WireGuard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WireGuard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4A4BACE520B5F1BF00F12B28 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -193,6 +198,7 @@ children = ( 4A4BACFA20B5F1C100F12B28 /* WireGuardTests.swift */, 4A4BACFC20B5F1C100F12B28 /* Info.plist */, + 4A43515B21249E5700261999 /* ValidatorsTests.swift */, ); path = WireGuardTests; sourceTree = ""; @@ -259,6 +265,7 @@ isa = PBXGroup; children = ( 4AC086822120B9F900CEE5ED /* ProviderConfigurationKeys.swift */, + 4A4351582124956200261999 /* Validators.swift */, ); path = Shared; sourceTree = ""; @@ -528,6 +535,7 @@ 4A4BAD1A20B5F8FF00F12B28 /* Tunnel+CoreDataClass.swift in Sources */, 4A4BACE820B5F1BF00F12B28 /* TunnelsTableViewController.swift in Sources */, 4A4BAD1020B5F6EC00F12B28 /* RootCoordinator.swift in Sources */, + 4A4351592124956200261999 /* Validators.swift in Sources */, 4AC5462E2116306F00749D21 /* Tunnel+Extension.swift in Sources */, 4A4BAD0E20B5F6C300F12B28 /* Coordinator.swift in Sources */, 4A4BA6D820B73CBA00223AB8 /* TunnelConfigurationTableViewController.swift in Sources */, @@ -545,6 +553,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4A43515C21249E5700261999 /* ValidatorsTests.swift in Sources */, 4A4BACFB20B5F1C100F12B28 /* WireGuardTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -556,6 +565,7 @@ 4AD095CC20DC42CD000E9CF5 /* WireGuardGoWrapper.m in Sources */, 4AC086852120BCB500CEE5ED /* ProviderConfigurationKeys.swift in Sources */, 4AC086862120BD5800CEE5ED /* PacketTunnelProvider.swift in Sources */, + 4A43515A2124956200261999 /* Validators.swift in Sources */, 4AEAC32920F14B3B007B67AB /* Log.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/WireGuardTests/ValidatorsTests.swift b/WireGuardTests/ValidatorsTests.swift new file mode 100644 index 0000000..1efae8d --- /dev/null +++ b/WireGuardTests/ValidatorsTests.swift @@ -0,0 +1,56 @@ +// +// ValidatorsTests.swift +// WireGuardTests +// +// Created by Jeroen Leenarts on 15-08-18. +// Copyright © 2018 WireGuard. All rights reserved. +// + +import XCTest +@testable import WireGuard + +class ValidatorsTests: XCTestCase { + func testIPv6Endpoint() throws { + XCTFail("Still needs implementation") + } + + func testIPv4Endpoint() throws { + _ = try Endpoint(endpointString: "192.168.0.1:12345") + } + + func testIPv4Endpoint_invalidIP() throws { + XCTAssertThrowsError(try Endpoint(endpointString: "12345:12345")) { (error) in + guard case EndpointValidationError.invalidIP(let value) = error else { + return XCTFail("Unexpected error") + } + XCTAssertEqual(value, "12345") + } + } + + func testIPv4Endpoint_invalidPort() throws { + XCTAssertThrowsError(try Endpoint(endpointString: "192.168.0.1:-12345")) { (error) in + guard case EndpointValidationError.invalidPort(let value) = error else { + return XCTFail("Unexpected error") + } + XCTAssertEqual(value, "-12345") + } + } + + func testIPv4Endpoint_noIpAndPort() throws { + + func executeTest(endpointString: String) { + XCTAssertThrowsError(try Endpoint(endpointString: endpointString)) { (error) in + guard case EndpointValidationError.noIpAndPort(let value) = error else { + return XCTFail("Unexpected error") + } + XCTAssertEqual(value, endpointString, file: #file, line: #line) + } + } + + executeTest(endpointString: ":") + executeTest(endpointString: "192.168.0.1") + executeTest(endpointString: "192.168.0.1:") + executeTest(endpointString: ":12345") + executeTest(endpointString: "12345") + } +}