fix arpServer

This commit is contained in:
anlicheng 2026-03-12 17:00:07 +08:00
parent 48bb011e54
commit cb33d81428
3 changed files with 47 additions and 36 deletions

View File

@ -56,7 +56,7 @@ actor SDLContextActor {
private var readTask: Task<(), Never>?
nonisolated private let sessionManager = SessionManager()
nonisolated private let arpServer = ArpServer()
nonisolated private let arpServer: ArpServer
//
private var monitor: SDLNetworkMonitor?
@ -93,6 +93,8 @@ actor SDLContextActor {
self.puncherActor = SDLPuncherActor()
self.proberActor = SDLNATProberActor(addressArray: config.stunProbeSocketAddressArray)
self.arpServer = ArpServer()
//
let snapshotPublisher = SnapshotPublisher(initial: IdentitySnapshot.empty())
self.identifyStore = IdentityStore(publisher: snapshotPublisher)
@ -102,6 +104,9 @@ actor SDLContextActor {
public func start() async {
self.startMonitor()
// arp
await self.arpServer.start()
// puncher
await self.puncherActor.start()
@ -172,7 +177,7 @@ actor SDLContextActor {
await self.identifyStore.applyPolicyResponse(policyResponse)
case .arpResponse(let arpResponse):
SDLLogger.shared.log("[SDLContext] get arp response: \(arpResponse)")
self.arpServer.handleArpResponse(arpResponse: arpResponse)
await self.arpServer.handleArpResponse(arpResponse: arpResponse)
}
}
}
@ -536,7 +541,7 @@ actor SDLContextActor {
await self.routeLayerPacket(dstMac: arpPacket.senderMAC, type: .arp, data: response.marshal())
case .response:
SDLLogger.shared.log("[SDLContext] get arp response packet", level: .debug)
self.arpServer.append(ip: arpPacket.senderIP, mac: arpPacket.senderMAC)
await self.arpServer.append(ip: arpPacket.senderIP, mac: arpPacket.senderMAC)
}
} else {
SDLLogger.shared.log("[SDLContext] get invalid arp packet: \(arpPacket), target_ip: \(SDLUtil.int32ToIp(arpPacket.targetIP)), net ip: \(SDLUtil.int32ToIp(networkAddr.ip))", level: .debug)
@ -660,7 +665,7 @@ actor SDLContextActor {
}
// arpmac
if let dstMac = self.arpServer.query(ip: dstIp) {
if let dstMac = await self.arpServer.query(ip: dstIp) {
SDLLogger.shared.log("[SDLContext] dstIp: \(dstIp.asIpAddress()), dst_mac is: \(SDLUtil.formatMacAddress(mac: dstMac))", level: .debug)
await self.routeLayerPacket(dstMac: dstMac, type: .ipv4, data: packet.data)
}
@ -670,7 +675,7 @@ actor SDLContextActor {
// let arpReqeust = ARPPacket.arpRequest(senderIP: networkAddr.ip, senderMAC: networkAddr.mac, targetIP: dstIp)
// await self.routeLayerPacket(dstMac: ARPPacket.broadcastMac , type: .arp, data: arpReqeust.marshal())
try? self.arpServer.arpRequest(targetIp: dstIp, use: self.quicClient)
try? await self.arpServer.arpRequest(targetIp: dstIp, use: self.quicClient)
}
}

View File

@ -1,35 +1,46 @@
//
// ArpServer.swift
// sdlan
//
// 1. ipmac
// 2. ip
// Created by on 2025/7/14.
//
import Foundation
import Darwin
final class ArpServer {
actor ArpServer {
//
struct ArpEntry {
var mac: Data
var expireTime: TimeInterval
}
private let locker = NSLock()
private var coolingDown: [UInt32: Date] = [:]
private var packetId: UInt32 = 1
private var known_macs: [UInt32: ArpEntry] = [:]
private let arpTTL: TimeInterval
private var cleanupTask: Task<Void, Never>?
init(arpTTL: TimeInterval = 300) {
self.arpTTL = arpTTL
}
func query(ip: UInt32) -> Data? {
locker.lock()
defer {
locker.unlock()
func start() {
guard self.cleanupTask == nil else {
return
}
self.cleanupTask = Task {
while !Task.isCancelled {
try? await Task.sleep(for: .seconds(1))
self.cleanup()
}
}
}
func query(ip: UInt32) -> Data? {
guard let entry = known_macs[ip] else {
return nil
}
@ -43,47 +54,32 @@ final class ArpServer {
}
func append(ip: UInt32, mac: Data) {
locker.lock()
defer {
locker.unlock()
}
let expireAt = Date().timeIntervalSince1970 + arpTTL
self.known_macs[ip] = ArpEntry(mac: mac, expireTime: expireAt)
}
func remove(ip: UInt32) {
locker.lock()
defer {
locker.unlock()
}
self.known_macs.removeValue(forKey: ip)
}
func dropMacs(macs: [Data]) {
locker.lock()
defer {
locker.unlock()
}
self.known_macs = self.known_macs.filter { !macs.contains($0.value.mac) }
}
func clear() {
locker.lock()
self.known_macs = [:]
locker.unlock()
}
func arpRequest(targetIp: UInt32, use quicClient: SDLQUICClient?) throws {
guard let quicClient else {
guard let quicClient, self.coolingDown[targetIp] == nil else {
return
}
locker.lock()
let pktID = self.packetId
self.packetId += 1
locker.unlock()
self.packetId &+= 1
//
self.coolingDown[targetIp] = Date().addingTimeInterval(3)
// arp
var arpRequest = SDLArpRequest()
@ -98,10 +94,17 @@ final class ArpServer {
let targetMac = arpResponse.targetMac
if !targetMac.isEmpty {
let expireAt = Date().timeIntervalSince1970 + arpTTL
locker.lock()
self.known_macs[targetIp] = ArpEntry(mac: targetMac, expireTime: expireAt)
locker.unlock()
}
}
private func cleanup() {
let now = Date()
self.coolingDown = self.coolingDown.filter { $0.value > now }
}
deinit {
self.cleanupTask?.cancel()
}
}

View File

@ -87,9 +87,12 @@ enum SDLNAKErrorCode: UInt8 {
}
extension SDLV4Info {
func socketAddress() async throws -> SocketAddress {
let address = "\(v4[0]).\(v4[1]).\(v4[2]).\(v4[3])"
func socketAddress() async throws -> SocketAddress? {
guard self.v4.count == 4 else {
return nil
}
let address = "\(v4[0]).\(v4[1]).\(v4[2]).\(v4[3])"
return try await SDLAddressResolver.shared.resolve(host: address, port: Int(port))
}
}