Skip to content

Commit

Permalink
getTunnelNetworkSettings in Swift
Browse files Browse the repository at this point in the history
  • Loading branch information
fortuna committed Jul 6, 2023
1 parent fa8af37 commit 14ce1ff
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

import Foundation
import NetworkExtension

// Serializable class to wrap a tunnel's configuration.
// Properties must be kept in sync with ServerConfig in www/types/outlinePlugin.d.ts
Expand Down Expand Up @@ -64,8 +65,21 @@ public class OutlineTunnel: NSObject, Codable {
}

Check warning on line 65 in src/cordova/apple/OutlineAppleLib/Sources/OutlineTunnelSources/OutlineTunnel.swift

View check run for this annotation

Codecov / codecov/patch

src/cordova/apple/OutlineAppleLib/Sources/OutlineTunnelSources/OutlineTunnel.swift#L63-L65

Added lines #L63 - L65 were not covered by tests

// Helper function that we can call from Objective-C.
@objc public static func getAddressForVpn() -> String {
return selectVpnAddress(interfaceAddresses: getNetworkInterfaceAddresses())
@objc public static func getTunnelNetworkSettings(tunnelRemoteAddress: String) -> NEPacketTunnelNetworkSettings {
// The remote address is not used for routing, but for display in Settings > VPN > Outline.
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress)

// Configure VPN address and routing.
let vpnAddress = selectVpnAddress(interfaceAddresses: getNetworkInterfaceAddresses())
let ipv4Settings = NEIPv4Settings(addresses: [vpnAddress], subnetMasks: ["255.255.255.0"])
ipv4Settings.includedRoutes = [NEIPv4Route.default()]
ipv4Settings.excludedRoutes = getExcludedIpv4Routes()
settings.ipv4Settings = ipv4Settings

// Configure with Cloudflare, Quad9, and OpenDNS resolver addresses.
settings.dnsSettings = NEDNSSettings(servers: ["1.1.1.1", "9.9.9.9", "208.67.222.222", "208.67.220.220"])

return settings
}
}

Expand Down Expand Up @@ -123,3 +137,32 @@ func selectVpnAddress(interfaceAddresses: [String]) -> String {
// Select a random subnet from the remaining candidates.
return candidates.randomElement()?.value ?? ""
}

let kExcludedSubnets = [
"10.0.0.0/8",
"100.64.0.0/10",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.31.196.0/24",
"192.52.193.0/24",
"192.88.99.0/24",
"192.168.0.0/16",
"192.175.48.0/24",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"240.0.0.0/4"
]

func getExcludedIpv4Routes() -> [NEIPv4Route] {
var excludedIpv4Routes = [NEIPv4Route]()
for cidrSubnet in kExcludedSubnets {
if let subnet = Subnet.parse(cidrSubnet) {
let route = NEIPv4Route(destinationAddress: subnet.address, subnetMask: subnet.mask)
excludedIpv4Routes.append(route)
}
}
return excludedIpv4Routes
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,6 @@ import Foundation
// target of the OutlineAppleLib Swift Package.
@objcMembers
public class Subnet: NSObject {
public static let kReservedSubnets = [
"10.0.0.0/8",
"100.64.0.0/10",
"169.254.0.0/16",
"172.16.0.0/12",
"192.0.0.0/24",
"192.0.2.0/24",
"192.31.196.0/24",
"192.52.193.0/24",
"192.88.99.0/24",
"192.168.0.0/16",
"192.175.48.0/24",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"240.0.0.0/4"
]

// Parses a CIDR subnet into a Subnet object. Returns nil on failure.
public static func parse(_ cidrSubnet: String) -> Subnet? {
let components = cidrSubnet.components(separatedBy: "/")
Expand All @@ -51,17 +33,6 @@ public class Subnet: NSObject {
return Subnet(address: components[0], prefix: prefix)
}

// Returns a list of reserved Subnets.
public static func getReservedSubnets() -> [Subnet] {
var subnets: [Subnet] = []
for cidrSubnet in kReservedSubnets {
if let subnet = self.parse(cidrSubnet) {
subnets.append(subnet)
}
}
return subnets
}

public var address: String
public var prefix: UInt16
public var mask: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ - (void)startTunnelWithOptions:(NSDictionary *)options
userInfo:nil]);
}

[self connectTunnel:[self getTunnelNetworkSettings]
[self connectTunnel:[OutlineTunnel getTunnelNetworkSettingsWithTunnelRemoteAddress:self.hostNetworkAddress]

Check warning on line 143 in src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m

View check run for this annotation

Codecov / codecov/patch

src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m#L143

Added line #L143 was not covered by tests
completion:^(NSError *_Nullable error) {
if (error != nil) {
[self execAppCallbackForAction:kActionStart errorCode:vpnPermissionNotGranted];
Expand Down Expand Up @@ -197,7 +197,7 @@ - (void)handleAppMessage:(NSData *)messageData completionHandler:(void (^)(NSDat
}
DDLogInfo(@"Received app message: %@", action);
void (^callbackWrapper)(NSNumber *) = ^void(NSNumber *errorCode) {
NSString *tunnelId;
NSString *tunnelId = @"";

Check warning on line 200 in src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m

View check run for this annotation

Codecov / codecov/patch

src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m#L200

Added line #L200 was not covered by tests
if (self.tunnelConfig != nil) {
tunnelId = self.tunnelConfig.id;
}
Expand Down Expand Up @@ -293,33 +293,6 @@ - (void)connectTunnel:(NEPacketTunnelNetworkSettings *)settings
}];
}

- (NEPacketTunnelNetworkSettings *) getTunnelNetworkSettings {
NSString *vpnAddress = [OutlineTunnel getAddressForVpn];
NEIPv4Settings *ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:@[ vpnAddress ]
subnetMasks:@[ @"255.255.255.0" ]];
ipv4Settings.includedRoutes = @[[NEIPv4Route defaultRoute]];
ipv4Settings.excludedRoutes = [self getExcludedIpv4Routes];

// The remote address is not used for routing, but for display in Settings > VPN > Outline.
NEPacketTunnelNetworkSettings *settings =
[[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.hostNetworkAddress];
settings.IPv4Settings = ipv4Settings;
// Configure with Cloudflare, Quad9, and OpenDNS resolver addresses.
settings.DNSSettings = [[NEDNSSettings alloc]
initWithServers:@[ @"1.1.1.1", @"9.9.9.9", @"208.67.222.222", @"208.67.220.220" ]];
return settings;
}

- (NSArray *)getExcludedIpv4Routes {
NSMutableArray *excludedIpv4Routes = [[NSMutableArray alloc] init];
for (Subnet *subnet in [Subnet getReservedSubnets]) {
NEIPv4Route *route = [[NEIPv4Route alloc] initWithDestinationAddress:subnet.address
subnetMask:subnet.mask];
[excludedIpv4Routes addObject:route];
}
return excludedIpv4Routes;
}

// Registers KVO for the `defaultPath` property to receive network connectivity changes.
- (void)listenForNetworkChanges {
[self stopListeningForNetworkChanges];
Expand Down Expand Up @@ -446,7 +419,7 @@ - (void)reconnectTunnel:(bool)configChanged {
}
if (!configChanged && [activeHostNetworkAddress isEqualToString:self.hostNetworkAddress]) {
// Nothing changed. Connect the tunnel with the current settings.
[self connectTunnel:[self getTunnelNetworkSettings]
[self connectTunnel:[OutlineTunnel getTunnelNetworkSettingsWithTunnelRemoteAddress:self.hostNetworkAddress]

Check warning on line 422 in src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m

View check run for this annotation

Codecov / codecov/patch

src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m#L422

Added line #L422 was not covered by tests
completion:^(NSError *_Nullable error) {
if (error != nil) {
[self cancelTunnelWithError:error];
Expand Down Expand Up @@ -484,7 +457,7 @@ - (void)reconnectTunnel:(bool)configChanged {
userInfo:nil]];
return;
}
[self connectTunnel:[self getTunnelNetworkSettings]
[self connectTunnel:[OutlineTunnel getTunnelNetworkSettingsWithTunnelRemoteAddress:self.hostNetworkAddress]

Check warning on line 460 in src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m

View check run for this annotation

Codecov / codecov/patch

src/cordova/apple/OutlineAppleLib/Sources/PacketTunnelProviderSources/PacketTunnelProvider.m#L460

Added line #L460 was not covered by tests
completion:^(NSError *_Nullable error) {
if (error != nil) {
[self execAppCallbackForAction:kActionStart errorCode:vpnStartFailure];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,21 @@ final class OutlineTunnelTest: XCTestCase {
XCTAssertEqual("172.16.9.1", selectVpnAddress(interfaceAddresses:["10.111.222.1", "192.168.20.2", "169.254.19.1"]))
XCTAssertEqual("192.168.20.1", selectVpnAddress(interfaceAddresses:["10.111.222.1", "172.16.9.2", "169.254.19.1"]))
XCTAssertEqual("169.254.19.0", selectVpnAddress(interfaceAddresses:["10.111.222.1", "172.16.9.2", "192.168.20.2"]))
XCTAssertTrue(kVpnSubnetCandidates.values.contains(selectVpnAddress(interfaceAddresses: getNetworkInterfaceAddresses())))
}

func testGetAddressForVpn() {
XCTAssertTrue(kVpnSubnetCandidates.values.contains(OutlineTunnel.getAddressForVpn()))
func testGetTunnelNetworkSettings() {
let settings = OutlineTunnel.getTunnelNetworkSettings(tunnelRemoteAddress: "1.2.3.4")

XCTAssertEqual("1.2.3.4", settings.tunnelRemoteAddress)

XCTAssertEqual(1, settings.ipv4Settings?.addresses.count)
XCTAssertTrue(kVpnSubnetCandidates.values.contains(settings.ipv4Settings?.addresses[0] ?? ""))
XCTAssertEqual(["255.255.255.0"], settings.ipv4Settings?.subnetMasks)

XCTAssertEqual([NEIPv4Route.default()], settings.ipv4Settings?.includedRoutes)
XCTAssertEqual(15, settings.ipv4Settings?.excludedRoutes?.count ?? 0)

XCTAssertEqual(["1.1.1.1", "9.9.9.9", "208.67.222.222", "208.67.220.220"], settings.dnsSettings?.servers)
}
}

0 comments on commit 14ce1ff

Please sign in to comment.