mutating func writePCAPRecord()

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
    }