fix ip packet
This commit is contained in:
parent
702eb1e608
commit
4cccd411e0
@ -566,22 +566,23 @@ actor SDLContextActor {
|
|||||||
// 检查权限逻辑
|
// 检查权限逻辑
|
||||||
let identitySnapshot = self.snapshotPublisher.current()
|
let identitySnapshot = self.snapshotPublisher.current()
|
||||||
if let ruleMap = identitySnapshot.lookup(data.identityID) {
|
if let ruleMap = identitySnapshot.lookup(data.identityID) {
|
||||||
SDLLogger.shared.log("[SDLContext] identity: \(data.identityID), ruleMap: \(ruleMap)", level: .debug)
|
|
||||||
|
|
||||||
let proto = ipPacket.header.proto
|
let proto = ipPacket.header.proto
|
||||||
switch TransportProtocol(rawValue: proto) {
|
switch ipPacket.transportPacket() {
|
||||||
case .udp, .tcp:
|
case .tcp(let tcpPacket):
|
||||||
if let dstPort = ipPacket.getDstPort(), ruleMap.isAllow(proto: proto, port: dstPort) {
|
let dstPort = tcpPacket.header.dstPort
|
||||||
|
if ruleMap.isAllow(proto: proto, port: dstPort) {
|
||||||
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
|
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
|
||||||
self.provider.packetFlow.writePacketObjects([packet])
|
self.provider.packetFlow.writePacketObjects([packet])
|
||||||
} else {
|
SDLLogger.shared.log("[SDLContext] identity: \(data.identityID), ruleMap: \(ruleMap), dstPort: \(dstPort) allow", level: .debug)
|
||||||
if let dstPort = ipPacket.getDstPort() {
|
|
||||||
SDLLogger.shared.log("[SDLContext] identity: \(data.identityID), dst port: \(dstPort) not allow", level: .debug)
|
|
||||||
} else {
|
|
||||||
SDLLogger.shared.log("[SDLContext] identity: \(data.identityID), invalid ip packet, not allow", level: .debug)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case .icmp:
|
case .udp(let udpPacket):
|
||||||
|
let dstPort = udpPacket.dstPort
|
||||||
|
if ruleMap.isAllow(proto: proto, port: dstPort) {
|
||||||
|
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
|
||||||
|
self.provider.packetFlow.writePacketObjects([packet])
|
||||||
|
SDLLogger.shared.log("[SDLContext] identity: \(data.identityID), ruleMap: \(ruleMap), dstPort: \(dstPort) allow", level: .debug)
|
||||||
|
}
|
||||||
|
case .icmp(_):
|
||||||
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
|
let packet = NEPacket(data: ipPacket.data, protocolFamily: 2)
|
||||||
self.provider.packetFlow.writePacketObjects([packet])
|
self.provider.packetFlow.writePacketObjects([packet])
|
||||||
default:
|
default:
|
||||||
@ -638,8 +639,6 @@ actor SDLContextActor {
|
|||||||
let networkAddr = self.config.networkAddress
|
let networkAddr = self.config.networkAddress
|
||||||
|
|
||||||
if SDLDNSClient.Helper.isDnsRequestPacket(ipPacket: packet) {
|
if SDLDNSClient.Helper.isDnsRequestPacket(ipPacket: packet) {
|
||||||
let destIp = packet.header.destination_ip
|
|
||||||
SDLLogger.shared.log("[DNSQuery] destIp: \(destIp), int: \(packet.header.destination.asIpAddress())", level: .debug)
|
|
||||||
self.dnsClient?.forward(ipPacket: packet)
|
self.dnsClient?.forward(ipPacket: packet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,35 +7,6 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct IPHeader {
|
|
||||||
let version: UInt8
|
|
||||||
let headerLength: UInt8
|
|
||||||
let typeOfService: UInt8
|
|
||||||
let totalLength: UInt16
|
|
||||||
let id: UInt16
|
|
||||||
let offset: UInt16
|
|
||||||
let timeToLive: UInt8
|
|
||||||
let proto: UInt8
|
|
||||||
let checksum: UInt16
|
|
||||||
let source: UInt32
|
|
||||||
let destination: UInt32
|
|
||||||
|
|
||||||
var source_ip: String {
|
|
||||||
return SDLUtil.int32ToIp(source)
|
|
||||||
}
|
|
||||||
|
|
||||||
var destination_ip: String {
|
|
||||||
return SDLUtil.int32ToIp(destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
public var description: String {
|
|
||||||
"""
|
|
||||||
IPHeader version: \(version), header length: \(headerLength), type of service: \(typeOfService), total length: \(totalLength),
|
|
||||||
id: \(id), offset: \(offset), time ot live: \(timeToLive), proto: \(proto), checksum: \(checksum), source ip: \(source_ip), destination ip:\(destination_ip)
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum IPVersion: UInt8 {
|
enum IPVersion: UInt8 {
|
||||||
case ipv4 = 4
|
case ipv4 = 4
|
||||||
case ipv6 = 6
|
case ipv6 = 6
|
||||||
@ -43,46 +14,236 @@ enum IPVersion: UInt8 {
|
|||||||
|
|
||||||
enum TransportProtocol: UInt8 {
|
enum TransportProtocol: UInt8 {
|
||||||
case icmp = 1
|
case icmp = 1
|
||||||
case tcp = 6
|
case tcp = 6
|
||||||
case udp = 17
|
case udp = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - IP Header
|
||||||
|
|
||||||
|
struct IPHeader {
|
||||||
|
let version: UInt8
|
||||||
|
let headerLength: UInt8
|
||||||
|
let typeOfService: UInt8
|
||||||
|
let totalLength: UInt16
|
||||||
|
let id: UInt16
|
||||||
|
let offset: UInt16
|
||||||
|
let ttl: UInt8
|
||||||
|
let proto: UInt8
|
||||||
|
let checksum: UInt16
|
||||||
|
let source: UInt32
|
||||||
|
let destination: UInt32
|
||||||
|
|
||||||
|
var headerBytes: Int {
|
||||||
|
Int(headerLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - IP Packet
|
||||||
|
|
||||||
struct IPPacket {
|
struct IPPacket {
|
||||||
let header: IPHeader
|
let header: IPHeader
|
||||||
let data: Data
|
let data: Data
|
||||||
|
|
||||||
|
var payload: Data.SubSequence {
|
||||||
|
let offset = Int(header.headerLength)
|
||||||
|
|
||||||
|
return data[offset..<data.count]
|
||||||
|
}
|
||||||
|
|
||||||
init?(_ data: Data) {
|
init?(_ data: Data) {
|
||||||
guard data.count >= 20 else {
|
guard data.count >= 20 else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.header = IPHeader(version: data[0] >> 4,
|
let version = data[0] >> 4
|
||||||
headerLength: (data[0] & 0b1111) * 4,
|
let headerLen = (data[0] & 0x0F) * 4
|
||||||
typeOfService: data[1],
|
|
||||||
totalLength: UInt16(bytes: (data[2], data[3])),
|
|
||||||
id: UInt16(bytes: (data[4], data[5])),
|
|
||||||
offset: 1,
|
|
||||||
timeToLive: data[8],
|
|
||||||
proto: data[9],
|
|
||||||
checksum: UInt16(bytes: (data[10], data[11])),
|
|
||||||
source: UInt32(bytes: (data[12], data[13], data[14], data[15])),
|
|
||||||
destination: UInt32(bytes: (data[16], data[17], data[18], data[19])))
|
|
||||||
self.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取负载部分
|
guard data.count >= headerLen else {
|
||||||
func getPayload() -> Data {
|
|
||||||
return data.subdata(in: 20..<data.count)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取ip数据包里面目标端口
|
|
||||||
func getDstPort() -> UInt16? {
|
|
||||||
guard case .ipv4 = IPVersion(rawValue: self.header.version), self.data.count >= 24 else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 系统只会读取到ipv4的数据包,(srcPort:16, dstPort:16, ...)
|
self.header = IPHeader(
|
||||||
return UInt16(bytes: (self.data[22], self.data[23]))
|
version: version,
|
||||||
|
headerLength: headerLen,
|
||||||
|
typeOfService: data[1],
|
||||||
|
totalLength: UInt16(bytes: (data[2], data[3])),
|
||||||
|
id: UInt16(bytes: (data[4], data[5])),
|
||||||
|
offset: UInt16(bytes: (data[6], data[7])),
|
||||||
|
ttl: data[8],
|
||||||
|
proto: data[9],
|
||||||
|
checksum: UInt16(bytes: (data[10], data[11])),
|
||||||
|
source: UInt32(bytes: (data[12], data[13], data[14], data[15])),
|
||||||
|
destination: UInt32(bytes: (data[16], data[17], data[18], data[19]))
|
||||||
|
)
|
||||||
|
|
||||||
|
self.data = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - TCP Flags
|
||||||
|
|
||||||
|
struct TCPFlags: OptionSet {
|
||||||
|
let rawValue: UInt16
|
||||||
|
|
||||||
|
static let fin = TCPFlags(rawValue: 1 << 0)
|
||||||
|
static let syn = TCPFlags(rawValue: 1 << 1)
|
||||||
|
static let rst = TCPFlags(rawValue: 1 << 2)
|
||||||
|
static let psh = TCPFlags(rawValue: 1 << 3)
|
||||||
|
static let ack = TCPFlags(rawValue: 1 << 4)
|
||||||
|
static let urg = TCPFlags(rawValue: 1 << 5)
|
||||||
|
static let ece = TCPFlags(rawValue: 1 << 6)
|
||||||
|
static let cwr = TCPFlags(rawValue: 1 << 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - TCP Header
|
||||||
|
|
||||||
|
struct TCPHeader {
|
||||||
|
let srcPort: UInt16
|
||||||
|
let dstPort: UInt16
|
||||||
|
|
||||||
|
let seq: UInt32
|
||||||
|
let ack: UInt32
|
||||||
|
|
||||||
|
let dataOffset: UInt8
|
||||||
|
let flags: TCPFlags
|
||||||
|
|
||||||
|
let window: UInt16
|
||||||
|
let checksum: UInt16
|
||||||
|
let urgentPointer: UInt16
|
||||||
|
|
||||||
|
var headerLength: Int {
|
||||||
|
Int(dataOffset) * 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - TCP Packet
|
||||||
|
|
||||||
|
struct TCPPacket {
|
||||||
|
let header: TCPHeader
|
||||||
|
let payload: Data
|
||||||
|
|
||||||
|
init?(_ data: Data) {
|
||||||
|
guard data.count >= 20 else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let srcPort = UInt16(bytes: (data[0], data[1]))
|
||||||
|
let dstPort = UInt16(bytes: (data[2], data[3]))
|
||||||
|
|
||||||
|
let seq = UInt32(bytes: (data[4], data[5], data[6], data[7]))
|
||||||
|
let ack = UInt32(bytes: (data[8], data[9], data[10], data[11]))
|
||||||
|
|
||||||
|
let offsetAndFlags = UInt16(bytes: (data[12], data[13]))
|
||||||
|
|
||||||
|
let dataOffset = UInt8(offsetAndFlags >> 12)
|
||||||
|
let flags = TCPFlags(rawValue: offsetAndFlags & 0x01FF)
|
||||||
|
|
||||||
|
let window = UInt16(bytes: (data[14], data[15]))
|
||||||
|
let checksum = UInt16(bytes: (data[16], data[17]))
|
||||||
|
let urgent = UInt16(bytes: (data[18], data[19]))
|
||||||
|
|
||||||
|
let header = TCPHeader(
|
||||||
|
srcPort: srcPort,
|
||||||
|
dstPort: dstPort,
|
||||||
|
seq: seq,
|
||||||
|
ack: ack,
|
||||||
|
dataOffset: dataOffset,
|
||||||
|
flags: flags,
|
||||||
|
window: window,
|
||||||
|
checksum: checksum,
|
||||||
|
urgentPointer: urgent
|
||||||
|
)
|
||||||
|
|
||||||
|
let headerLen = header.headerLength
|
||||||
|
|
||||||
|
guard data.count >= headerLen else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.header = header
|
||||||
|
self.payload = data.subdata(in: headerLen..<data.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - UDP Packet
|
||||||
|
|
||||||
|
struct UDPPacket {
|
||||||
|
let srcPort: UInt16
|
||||||
|
let dstPort: UInt16
|
||||||
|
let length: UInt16
|
||||||
|
let checksum: UInt16
|
||||||
|
let payload: Data
|
||||||
|
|
||||||
|
init?(_ data: Data) {
|
||||||
|
|
||||||
|
guard data.count >= 8 else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.srcPort = UInt16(bytes: (data[0], data[1]))
|
||||||
|
self.dstPort = UInt16(bytes: (data[2], data[3]))
|
||||||
|
self.length = UInt16(bytes: (data[4], data[5]))
|
||||||
|
self.checksum = UInt16(bytes: (data[6], data[7]))
|
||||||
|
|
||||||
|
self.payload = data.subdata(in: 8..<data.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - ICMP Packet
|
||||||
|
|
||||||
|
struct ICMPPacket {
|
||||||
|
let type: UInt8
|
||||||
|
let code: UInt8
|
||||||
|
let checksum: UInt16
|
||||||
|
let payload: Data
|
||||||
|
|
||||||
|
init?(_ data: Data) {
|
||||||
|
guard data.count >= 4 else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.type = data[0]
|
||||||
|
self.code = data[1]
|
||||||
|
self.checksum = UInt16(bytes: (data[2], data[3]))
|
||||||
|
self.payload = data.subdata(in: 4..<data.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - IPPacket Transport Parsing
|
||||||
|
|
||||||
|
extension IPPacket {
|
||||||
|
enum TransportPacket {
|
||||||
|
case tcp(TCPPacket)
|
||||||
|
case udp(UDPPacket)
|
||||||
|
case icmp(ICMPPacket)
|
||||||
|
case unsupported(UInt8)
|
||||||
|
case malformed
|
||||||
|
}
|
||||||
|
|
||||||
|
func transportPacket() -> TransportPacket {
|
||||||
|
guard let proto = TransportProtocol(rawValue: header.proto) else {
|
||||||
|
return .unsupported(header.proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch proto {
|
||||||
|
case .tcp:
|
||||||
|
guard let tcp = TCPPacket(payload) else {
|
||||||
|
return .malformed
|
||||||
|
}
|
||||||
|
return .tcp(tcp)
|
||||||
|
|
||||||
|
case .udp:
|
||||||
|
guard let udp = UDPPacket(payload) else {
|
||||||
|
return .malformed
|
||||||
|
}
|
||||||
|
return .udp(udp)
|
||||||
|
|
||||||
|
case .icmp:
|
||||||
|
guard let icmp = ICMPPacket(payload) else {
|
||||||
|
return .malformed
|
||||||
|
}
|
||||||
|
return .icmp(icmp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
//
|
|
||||||
// UDPPacket.swift
|
|
||||||
// Tun
|
|
||||||
//
|
|
||||||
// Created by 安礼成 on 2025/12/13.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct UDPHeader {
|
|
||||||
let sourcePort: UInt16
|
|
||||||
let destinationPort: UInt16
|
|
||||||
let length: UInt16
|
|
||||||
let checksum: UInt16
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UDPPacket {
|
|
||||||
let header: UDPHeader
|
|
||||||
let payload: Data
|
|
||||||
|
|
||||||
init?(_ data: Data) {
|
|
||||||
// UDP header 至少 8 字节
|
|
||||||
guard data.count >= 8 else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let header = UDPHeader(sourcePort: UInt16(bytes: (data[0], data[1])),
|
|
||||||
destinationPort: UInt16(bytes: (data[2], data[3])),
|
|
||||||
length: UInt16(bytes: (data[4], data[5])),
|
|
||||||
checksum: UInt16(bytes: (data[6], data[7]))
|
|
||||||
)
|
|
||||||
// UDP payload = length - 8
|
|
||||||
let payloadLength = Int(header.length) - 8
|
|
||||||
|
|
||||||
self.header = header
|
|
||||||
self.payload = data.subdata(in: 8..<(8 + payloadLength))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -50,22 +50,22 @@ struct punchnetApp: App {
|
|||||||
RootView()
|
RootView()
|
||||||
.frame(width: 800, height: 500)
|
.frame(width: 800, height: 500)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// 获取主屏幕的尺寸
|
// // 获取主屏幕的尺寸
|
||||||
guard let screenFrame = NSScreen.main?.frame else {
|
// guard let screenFrame = NSScreen.main?.frame else {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 获取当前应用的窗口(假设只有一个窗口)
|
// // 获取当前应用的窗口(假设只有一个窗口)
|
||||||
NSApplication.shared.windows.forEach { window in
|
// NSApplication.shared.windows.forEach { window in
|
||||||
// 计算窗口的中心位置
|
// // 计算窗口的中心位置
|
||||||
let windowWidth = window.frame.width
|
// let windowWidth = window.frame.width
|
||||||
let windowHeight = window.frame.height
|
// let windowHeight = window.frame.height
|
||||||
let centerX = (screenFrame.width - windowWidth) / 2
|
// let centerX = (screenFrame.width - windowWidth) / 2
|
||||||
let centerY = (screenFrame.height - windowHeight) / 2
|
// let centerY = (screenFrame.height - windowHeight) / 2
|
||||||
|
//
|
||||||
// 设置窗口位置
|
// // 设置窗口位置
|
||||||
window.setFrameOrigin(NSPoint(x: centerX, y: centerY))
|
// window.setFrameOrigin(NSPoint(x: centerX, y: centerY))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
//.toolbar(.hidden)
|
//.toolbar(.hidden)
|
||||||
.navigationTitle("")
|
.navigationTitle("")
|
||||||
@ -83,24 +83,28 @@ struct punchnetApp: App {
|
|||||||
}
|
}
|
||||||
.windowResizability(.contentSize)
|
.windowResizability(.contentSize)
|
||||||
.windowToolbarStyle(.unified)
|
.windowToolbarStyle(.unified)
|
||||||
|
.defaultPosition(.center)
|
||||||
|
|
||||||
Window("设置", id: "settings") {
|
Window("设置", id: "settings") {
|
||||||
SettingsView()
|
SettingsView()
|
||||||
.environment(self.userContext)
|
.environment(self.userContext)
|
||||||
}
|
}
|
||||||
.defaultSize(width: 800, height: 500)
|
.defaultSize(width: 800, height: 500)
|
||||||
|
.defaultPosition(.center)
|
||||||
|
|
||||||
Window("重置密码", id: "resetPassword") {
|
Window("重置密码", id: "resetPassword") {
|
||||||
ResetPasswordRootView()
|
ResetPasswordRootView()
|
||||||
.environment(self.userContext)
|
.environment(self.userContext)
|
||||||
}
|
}
|
||||||
.defaultSize(width: 800, height: 500)
|
.defaultSize(width: 800, height: 500)
|
||||||
|
.defaultPosition(.center)
|
||||||
|
|
||||||
Window("注册", id: "register") {
|
Window("注册", id: "register") {
|
||||||
ResetPasswordRootView()
|
ResetPasswordRootView()
|
||||||
.environment(self.userContext)
|
.environment(self.userContext)
|
||||||
}
|
}
|
||||||
.defaultSize(width: 800, height: 500)
|
.defaultSize(width: 800, height: 500)
|
||||||
|
.defaultPosition(.center)
|
||||||
|
|
||||||
MenuBarExtra("punchnet", image: "logo_32") {
|
MenuBarExtra("punchnet", image: "logo_32") {
|
||||||
VStack {
|
VStack {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user