2026-03-10 21:41:00 +08:00

245 lines
6.2 KiB
Swift

//
// IPPacket.swift
// Tun
//
// Created by on 2024/1/18.
//
import Foundation
enum IPVersion: UInt8 {
case ipv4 = 4
case ipv6 = 6
}
enum TransportProtocol: UInt8 {
case icmp = 1
case tcp = 6
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 {
let header: IPHeader
let data: Data
let transportPacket: TransportPacket?
enum TransportPacket {
case tcp(TCPPacket)
case udp(UDPPacket)
case icmp(ICMPPacket)
case unsupported(UInt8)
case malformed
}
init?(_ data: Data) {
guard data.count >= 20 else {
return nil
}
let version = data[0] >> 4
let headerLen = (data[0] & 0x0F) * 4
guard data.count >= headerLen else {
return nil
}
self.header = IPHeader(
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
let offset = Int(headerLen)
self.transportPacket = Self.parseTransportPacket(proto: data[9], offset: offset, data: data)
SDLLogger.shared.log("[SDLContext] ipPacket proto \(data[9]), offset: \(offset), ip_data: \(data), data: \(self.transportPacket)", level: .debug)
}
private static func parseTransportPacket(proto: UInt8, offset: Int, data: Data) -> TransportPacket? {
guard let proto = TransportProtocol(rawValue: proto) else {
return .unsupported(proto)
}
switch proto {
case .tcp:
guard let tcp = TCPPacket(data, offset: offset) else {
return .malformed
}
return .tcp(tcp)
case .udp:
guard let udp = UDPPacket(data, offset: offset) else {
return .malformed
}
return .udp(udp)
case .icmp:
guard let icmp = ICMPPacket(data, offset: offset) else {
return .malformed
}
return .icmp(icmp)
}
}
}
// 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, offset: Int) {
guard data.count >= offset + 20 else {
return nil
}
let srcPort = UInt16(bytes: (data[offset], data[offset + 1]))
let dstPort = UInt16(bytes: (data[offset + 2], data[offset + 3]))
let seq = UInt32(bytes: (data[offset + 4], data[offset + 5], data[offset + 6], data[offset + 7]))
let ack = UInt32(bytes: (data[offset + 8], data[offset + 9], data[offset + 10], data[offset + 11]))
let offsetAndFlags = UInt16(bytes: (data[offset + 12], data[offset + 13]))
let dataOffset = UInt8(offsetAndFlags >> 12)
let flags = TCPFlags(rawValue: offsetAndFlags & 0x01FF)
let window = UInt16(bytes: (data[offset + 14], data[offset + 15]))
let checksum = UInt16(bytes: (data[offset + 16], data[offset + 17]))
let urgent = UInt16(bytes: (data[offset + 18], data[offset + 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 >= offset + headerLen else {
return nil
}
self.header = header
self.payload = data[offset + 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, offset: Int) {
guard data.count >= offset + 8 else {
return nil
}
self.srcPort = UInt16(bytes: (data[offset], data[offset + 1]))
self.dstPort = UInt16(bytes: (data[offset + 2], data[offset + 3]))
self.length = UInt16(bytes: (data[offset + 4], data[offset + 5]))
self.checksum = UInt16(bytes: (data[offset + 6], data[offset + 7]))
self.payload = data[offset + 8..<data.count]
}
}
// MARK: - ICMP Packet
struct ICMPPacket {
let type: UInt8
let code: UInt8
let checksum: UInt16
let payload: Data
init?(_ data: Data, offset: Int) {
guard data.count >= offset + 4 else {
return nil
}
self.type = data[offset]
self.code = data[offset + 1]
self.checksum = UInt16(bytes: (data[offset + 2], data[offset + 3]))
self.payload = data[offset + 4..<data.count]
}
}