Files
proxypin/ios/ProxyPin/vpn/transport/protocol/IP4Header.swift
2024-10-09 02:30:02 +08:00

162 lines
7.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.
//
// IP4Header.swift
// ProxyPin
//
// Created by wanghongen on 2024/9/16.
//
import Foundation
import os.log
// IPv4 header data structure
class IP4Header {
var ipVersion: UInt8 // IPv44IPv4 4bit
var internetHeaderLength: UInt8 // 4bit
var diffTypeOfService: UInt8 // =>6
var ecn: UInt8 // ECN
var totalLength: UInt16 // IP 16bit
var identification: UInt16 // IP 16bit
var mayFragment: Bool // 1bit
var lastFragment: Bool // 1bit
var fragmentOffset: UInt16 // IP 13bit
var timeToLive: UInt8 // 8bit
var protocolNumber: UInt8 // IP使 8bit
var headerChecksum: UInt16 // 16 16bit
var sourceIP: UInt32 // IPv4 32bit
var destinationIP: UInt32 // IPv4 32bit
//3
//bit 0:
//bit 1: Don't Fragment (DF)
//bit 2: More Fragments (MF)
private var flag: UInt8
init(
ipVersion: UInt8, internetHeaderLength: UInt8, diffTypeOfService: UInt8, ecn: UInt8, totalLength: UInt16, identification: UInt16,
mayFragment: Bool, lastFragment: Bool, fragmentOffset: UInt16, timeToLive: UInt8, protocolNumber: UInt8, headerChecksum: UInt16,
sourceIP: UInt32, destinationIP: UInt32
) {
self.ipVersion = ipVersion
self.internetHeaderLength = internetHeaderLength
self.diffTypeOfService = diffTypeOfService
self.ecn = ecn
self.totalLength = totalLength
self.identification = identification
self.mayFragment = mayFragment
self.lastFragment = lastFragment
self.fragmentOffset = fragmentOffset
self.timeToLive = timeToLive
self.protocolNumber = protocolNumber
self.headerChecksum = headerChecksum
self.sourceIP = sourceIP
self.destinationIP = destinationIP
self.flag = IP4Header.initFlag(mayFragment: mayFragment, lastFragment: lastFragment)
}
private static func initFlag(mayFragment: Bool, lastFragment: Bool) -> UInt8 {
var initFlag: UInt8 = 0
if mayFragment {
initFlag = 0x40
}
if lastFragment {
initFlag |= 0x20
}
return initFlag
}
func setMayFragment(_ mayFragment: Bool) {
self.mayFragment = mayFragment
flag = mayFragment ? (flag | 0x40) : (flag & 0xBF)
}
func getIPHeaderLength() -> Int {
return Int(internetHeaderLength * 4)
}
func copy() -> IP4Header {
return IP4Header(
ipVersion: ipVersion, internetHeaderLength: internetHeaderLength, diffTypeOfService: diffTypeOfService, ecn: ecn, totalLength: totalLength, identification: identification,
mayFragment: mayFragment, lastFragment: lastFragment, fragmentOffset: fragmentOffset, timeToLive: timeToLive, protocolNumber: protocolNumber, headerChecksum: headerChecksum,
sourceIP: sourceIP, destinationIP: destinationIP
)
}
func toBytes() -> Data {
var buffer = Data()
buffer.append(UInt8((ipVersion << 4) + internetHeaderLength))
buffer.append(UInt8((diffTypeOfService << 2) + ecn))
buffer.append(contentsOf: totalLength.bytes)
buffer.append(contentsOf: identification.bytes)
//
buffer.append(UInt8((fragmentOffset >> 8) & 0x1F) | flag)
buffer.append(UInt8(fragmentOffset & 0xFF))
buffer.append(timeToLive)
buffer.append(protocolNumber)
buffer.append(contentsOf: headerChecksum.bytes)
buffer.append(contentsOf: sourceIP.bytes)
buffer.append(contentsOf: destinationIP.bytes)
return buffer
}
}
class IPPacketFactory {
static let IP4_HEADER_SIZE = 20
static let IP4_VERSION: UInt8 = 0x04
//ByteBufferIPv4
static func createIP4Header(data: Data) -> IP4Header? {
guard data.count >= IP4_HEADER_SIZE else {
return nil
}
let buffer = [UInt8](data)
let versionAndHeaderLength = buffer[0]
let ipVersion = versionAndHeaderLength >> 4
guard ipVersion == IP4_VERSION else {
return nil
}
let internetHeaderLength = versionAndHeaderLength & 0x0F
let typeOfService = buffer[1]
let diffTypeOfService = typeOfService >> 2
let ecn = typeOfService & 0x03
let totalLength = UInt16(buffer[2]) << 8 | UInt16(buffer[3])
let identification = UInt16(buffer[4]) << 8 | UInt16(buffer[5])
let flagsAndFragmentOffset = UInt16(buffer[6]) << 8 | UInt16(buffer[7])
let mayFragment = (flagsAndFragmentOffset & 0x4000) != 0
let lastFragment = (flagsAndFragmentOffset & 0x2000) != 0
let fragmentOffset = flagsAndFragmentOffset & 0x1FFF
let timeToLive = buffer[8]
let protocolNumber = buffer[9]
let checksum = UInt16(buffer[10]) << 8 | UInt16(buffer[11])
let sourceIp = UInt32(buffer[12]) << 24 | UInt32(buffer[13]) << 16 | UInt32(buffer[14]) << 8 | UInt32(buffer[15])
let desIp = UInt32(buffer[16]) << 24 | UInt32(buffer[17]) << 16 | UInt32(buffer[18]) << 8 | UInt32(buffer[19])
if internetHeaderLength > 5 {
// drop the IP option
for _ in 0..<(internetHeaderLength - 5) {
// Skip the IP options
}
}
return IP4Header(
ipVersion: ipVersion, internetHeaderLength: internetHeaderLength, diffTypeOfService: diffTypeOfService, ecn: ecn, totalLength: totalLength, identification: identification,
mayFragment: mayFragment, lastFragment: lastFragment, fragmentOffset: fragmentOffset, timeToLive: timeToLive, protocolNumber: protocolNumber, headerChecksum: checksum,
sourceIP: sourceIp, destinationIP: desIp
)
}
public static func printPacket(data: Data) {
guard let ipHeader = createIP4Header(data: data) else {
return
}
os_log("IP Header: version: %{public}d, internetHeaderLength: %{public}d, diffTypeOfService: %{public}d, ecn: %{public}d, totalLength: %{public}d, identification: %{public}d, mayFragment: %{public}d, lastFragment: %{public}d, fragmentOffset: %{public}d, timeToLive: %{public}d, protocolNumber: %{public}d, headerChecksum: %{public}d, sourceIP: %{public}@, destinationIP: %{public}@", log: OSLog.default, type: .default, ipHeader.ipVersion, ipHeader.internetHeaderLength, ipHeader.diffTypeOfService, ipHeader.ecn, ipHeader.totalLength, ipHeader.identification, ipHeader.mayFragment, ipHeader.lastFragment, ipHeader.fragmentOffset, ipHeader.timeToLive, ipHeader.protocolNumber, ipHeader.headerChecksum, PacketUtil.intToIPAddress(ipHeader.sourceIP), PacketUtil.intToIPAddress(ipHeader.destinationIP))
}
}