108 lines
2.5 KiB
Swift
108 lines
2.5 KiB
Swift
//
|
|
// ArpServer.swift
|
|
// sdlan
|
|
//
|
|
// Created by 安礼成 on 2025/7/14.
|
|
//
|
|
import Foundation
|
|
import Darwin
|
|
|
|
final class ArpServer {
|
|
// 增加缓存时间逻辑
|
|
struct ArpEntry {
|
|
var mac: Data
|
|
var expireTime: TimeInterval
|
|
}
|
|
|
|
private let locker = NSLock()
|
|
|
|
private var packetId: UInt32 = 1
|
|
private var known_macs: [UInt32: ArpEntry] = [:]
|
|
private let arpTTL: TimeInterval
|
|
|
|
init(arpTTL: TimeInterval = 300) {
|
|
self.arpTTL = arpTTL
|
|
}
|
|
|
|
func query(ip: UInt32) -> Data? {
|
|
locker.lock()
|
|
defer {
|
|
locker.unlock()
|
|
}
|
|
|
|
guard let entry = known_macs[ip] else {
|
|
return nil
|
|
}
|
|
|
|
if entry.expireTime < Date().timeIntervalSince1970 {
|
|
known_macs.removeValue(forKey: ip)
|
|
return nil
|
|
}
|
|
|
|
return entry.mac
|
|
}
|
|
|
|
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 {
|
|
return
|
|
}
|
|
|
|
locker.lock()
|
|
let pktID = self.packetId
|
|
self.packetId += 1
|
|
locker.unlock()
|
|
|
|
// 进行arp查询
|
|
var arpRequest = SDLArpRequest()
|
|
arpRequest.targetIp = targetIp
|
|
arpRequest.pktID = pktID
|
|
|
|
quicClient.send(type: .arpRequest, data: try arpRequest.serializedData())
|
|
}
|
|
|
|
func handleArpResponse(arpResponse: SDLArpResponse) {
|
|
let targetIp = arpResponse.targetIp
|
|
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()
|
|
}
|
|
}
|
|
|
|
}
|