punchnet-macos/Tun/Punchnet/SDLFlowSessionManager.swift
2026-03-10 15:01:32 +08:00

127 lines
3.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// FiveTuple.swift
// punchnet
// tcp/udp Flow
// Created by on 2026/3/10.
//
import Foundation
// MARK: - key
struct FlowSession: Hashable {
let srcIP: UInt32
let dstIP: UInt32
let srcPort: UInt16
let dstPort: UInt16
let proto: UInt8
func hash(into hasher: inout Hasher) {
// hash
hasher.combine(srcIP)
hasher.combine(dstIP)
hasher.combine(UInt32(srcPort) << 16 | UInt32(dstPort))
hasher.combine(proto)
}
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.srcIP == rhs.srcIP &&
lhs.dstIP == rhs.dstIP &&
lhs.srcPort == rhs.srcPort &&
lhs.dstPort == rhs.dstPort &&
lhs.proto == rhs.proto
}
func reverse() -> FlowSession {
return FlowSession(
srcIP: dstIP,
dstIP: srcIP,
srcPort: dstPort,
dstPort: srcPort,
proto: proto
)
}
}
// MARK: -
final class SDLFlowSessionManager {
private var sessions: [FlowSession: TimeInterval] = [:]
private let lock = NSLock()
private let sessionTimeout: TimeInterval
/// - Parameter sessionTimeout:
init(sessionTimeout: TimeInterval = 300) {
self.sessionTimeout = sessionTimeout
}
//
func updateSession(_ key: FlowSession) {
lock.lock()
defer {
lock.unlock()
}
sessions[key] = Date().timeIntervalSince1970 + sessionTimeout
}
//
func hasSession(_ key: FlowSession) -> Bool {
lock.lock()
defer {
lock.unlock()
}
if let expireTs = sessions[key] {
if expireTs >= Date().timeIntervalSince1970 {
return true
}
self.sessions.removeValue(forKey: key)
}
return false
}
//
func removeSession(_ key: FlowSession) {
lock.lock()
defer {
lock.unlock()
}
sessions.removeValue(forKey: key)
}
//
func cleanupExpiredSessions() {
lock.lock()
defer {
lock.unlock()
}
let now = Date().timeIntervalSince1970
self.sessions = self.sessions.filter { $0.value >= now }
}
// /
var count: Int {
lock.lock()
defer {
lock.unlock()
}
return sessions.count
}
}
extension IPPacket {
func flowSession() -> FlowSession? {
switch self.transportPacket {
case .tcp(let tcpPacket):
return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: tcpPacket.header.srcPort, dstPort: tcpPacket.header.dstPort, proto: header.proto)
case .udp(let udpPacket):
return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: udpPacket.srcPort, dstPort: udpPacket.dstPort, proto: header.proto)
default:
return nil
}
}
}