in Sources/NIOExtras/WritePCAPHandler.swift [512:589]
mutating func writePCAPRecord(_ record: PCAPRecordHeader) throws {
let rawDataLength = record.payloadLength
let tcpLength = rawDataLength + 20 /* TCP header length */
// record
// guint32 ts_sec; /* timestamp seconds */
self.writeInteger(.init(record.time.tv_sec), endianness: .host, as: UInt32.self)
// guint32 ts_usec; /* timestamp microseconds */
self.writeInteger(.init(record.time.tv_usec), endianness: .host, as: UInt32.self)
// continued below ...
switch record.addresses {
case .v4(let la, let ra):
let ipv4WholeLength = tcpLength + 20 /* IPv4 header length, included in IPv4 */
let recordLength = ipv4WholeLength + 4 /* 32 bits for protocol id */
// record, continued
// guint32 incl_len; /* number of octets of packet saved in file */
self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self)
// guint32 orig_len; /* actual length of packet */
self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self)
self.writeInteger(2, endianness: .host, as: UInt32.self) // IPv4
// IPv4 packet
self.writeInteger(0x45, as: UInt8.self) // IP version (4) & IHL (5)
self.writeInteger(0, as: UInt8.self) // DSCP
self.writeInteger(.init(ipv4WholeLength), as: UInt16.self)
self.writeInteger(0, as: UInt16.self) // identification
self.writeInteger(0x4000 /* this set's "don't fragment" */, as: UInt16.self) // flags & fragment offset
self.writeInteger(.max /* we don't care about TTL */, as: UInt8.self) // TTL
self.writeInteger(6, as: UInt8.self) // TCP
self.writeInteger(0, as: UInt16.self) // checksum
self.writeInteger(la.address.sin_addr.s_addr, endianness: .host, as: UInt32.self)
self.writeInteger(ra.address.sin_addr.s_addr, endianness: .host, as: UInt32.self)
case .v6(let la, let ra):
let ipv6PayloadLength = tcpLength
let recordLength = ipv6PayloadLength + 4 /* 32 bits for protocol id */ + 40 /* IPv6 header length */
// record, continued
// guint32 incl_len; /* number of octets of packet saved in file */
self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self)
// guint32 orig_len; /* actual length of packet */
self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self)
self.writeInteger(24, endianness: .host, as: UInt32.self) // IPv6
// IPv6 packet
self.writeInteger(/* version */ (6 << 28), as: UInt32.self) // IP version (6) & fancy stuff
self.writeInteger(.init(ipv6PayloadLength), as: UInt16.self)
self.writeInteger(6, as: UInt8.self) // TCP
self.writeInteger(.max /* we don't care about TTL */, as: UInt8.self) // hop limit (like TTL)
var laAddress = la.address
withUnsafeBytes(of: &laAddress.sin6_addr) { ptr in
assert(ptr.count == 16)
self.writeBytes(ptr)
}
var raAddress = ra.address
withUnsafeBytes(of: &raAddress.sin6_addr) { ptr in
assert(ptr.count == 16)
self.writeBytes(ptr)
}
}
// TCP
self.writeInteger(record.tcp.srcPort, as: UInt16.self)
self.writeInteger(record.tcp.dstPort, as: UInt16.self)
self.writeInteger(record.tcp.sequenceNumber, as: UInt32.self) // seq no
self.writeInteger(record.tcp.ackNumber ?? 0, as: UInt32.self) // ack no
self.writeInteger(5 << 12 | UInt16(record.tcp.flags.rawValue), as: UInt16.self) // data offset + reserved bits + fancy stuff
self.writeInteger(.max /* we don't do actual window sizes */, as: UInt16.self) // window size
self.writeInteger(0xbad /* fake */, as: UInt16.self) // checksum
self.writeInteger(0, as: UInt16.self) // urgent pointer
}