mirror of
https://github.com/jkcoxson/LocalDevVPN.git
synced 2026-03-02 14:36:16 +01:00
110 lines
3.7 KiB
Swift
110 lines
3.7 KiB
Swift
//
|
|
// PacketTunnelProvider.swift
|
|
// TunnelProv
|
|
//
|
|
// Created by Stossy11 on 28/03/2025.
|
|
//
|
|
|
|
import NetworkExtension
|
|
|
|
class PacketTunnelProvider: NEPacketTunnelProvider {
|
|
var tunnelDeviceIp: String = "10.7.0.0"
|
|
var tunnelFakeIp: String = "10.7.0.1"
|
|
var tunnelSubnetMask: String = "255.255.255.0"
|
|
|
|
private var deviceIpValue: UInt32 = 0
|
|
private var fakeIpValue: UInt32 = 0
|
|
|
|
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
|
if let deviceIp = options?["TunnelDeviceIP"] as? String {
|
|
tunnelDeviceIp = deviceIp
|
|
}
|
|
if let fakeIp = options?["TunnelFakeIP"] as? String {
|
|
tunnelFakeIp = fakeIp
|
|
}
|
|
|
|
deviceIpValue = ipToUInt32(tunnelDeviceIp)
|
|
fakeIpValue = ipToUInt32(tunnelFakeIp)
|
|
|
|
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelDeviceIp)
|
|
let ipv4 = NEIPv4Settings(addresses: [tunnelDeviceIp], subnetMasks: [tunnelSubnetMask])
|
|
ipv4.includedRoutes = [NEIPv4Route(destinationAddress: tunnelDeviceIp, subnetMask: tunnelSubnetMask)]
|
|
ipv4.excludedRoutes = [.default()]
|
|
settings.ipv4Settings = ipv4
|
|
|
|
setTunnelNetworkSettings(settings) { error in
|
|
if error == nil {
|
|
self.readPackets()
|
|
}
|
|
completionHandler(error)
|
|
}
|
|
}
|
|
|
|
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
|
completionHandler()
|
|
}
|
|
|
|
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
|
completionHandler?(messageData)
|
|
}
|
|
|
|
override func sleep(completionHandler: @escaping () -> Void) {
|
|
completionHandler()
|
|
}
|
|
|
|
override func wake() {}
|
|
|
|
private func readPackets() {
|
|
packetFlow.readPackets { packets, protocols in
|
|
var output = [Data](repeating: Data(), count: packets.count)
|
|
|
|
for (i, packet) in packets.enumerated() {
|
|
guard protocols[i].int32Value == AF_INET, packet.count >= 20 else {
|
|
output[i] = packet
|
|
continue
|
|
}
|
|
|
|
output[i] = self.processPacket(packet)
|
|
}
|
|
|
|
self.packetFlow.writePackets(output, withProtocols: protocols)
|
|
self.readPackets()
|
|
}
|
|
}
|
|
|
|
private func processPacket(_ packet: Data) -> Data {
|
|
var bytes = [UInt8](packet)
|
|
|
|
let srcIP = UInt32(bigEndian: bytes.withUnsafeBytes { $0.load(fromByteOffset: 12, as: UInt32.self) })
|
|
let dstIP = UInt32(bigEndian: bytes.withUnsafeBytes { $0.load(fromByteOffset: 16, as: UInt32.self) })
|
|
|
|
if srcIP == deviceIpValue {
|
|
let replacement = fakeIpValue.bigEndian
|
|
withUnsafeBytes(of: replacement) { bytes.replaceSubrange(12..<16, with: $0) }
|
|
}
|
|
if dstIP == fakeIpValue {
|
|
let replacement = deviceIpValue.bigEndian
|
|
withUnsafeBytes(of: replacement) { bytes.replaceSubrange(16..<20, with: $0) }
|
|
}
|
|
|
|
bytes.swapAt(12, 16)
|
|
bytes.swapAt(13, 17)
|
|
bytes.swapAt(14, 18)
|
|
bytes.swapAt(15, 19)
|
|
|
|
return Data(bytes)
|
|
}
|
|
|
|
private func ipToUInt32(_ ipString: String) -> UInt32 {
|
|
let components = ipString.split(separator: ".")
|
|
guard components.count == 4,
|
|
let b1 = UInt32(components[0]),
|
|
let b2 = UInt32(components[1]),
|
|
let b3 = UInt32(components[2]),
|
|
let b4 = UInt32(components[3]) else {
|
|
return 0
|
|
}
|
|
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4
|
|
}
|
|
}
|