|
12 | 12 | //
|
13 | 13 | //===----------------------------------------------------------------------===//
|
14 | 14 |
|
15 |
| -#if os(macOS) || os(tvOS) || os(iOS) || os(watchOS) |
16 |
| -import Darwin |
17 |
| -#else |
18 |
| -import Glibc |
19 |
| -#endif |
| 15 | +//#if os(macOS) || os(tvOS) || os(iOS) || os(watchOS) |
| 16 | +//import Darwin |
| 17 | +//#else |
| 18 | +//import Glibc |
| 19 | +//#endif |
20 | 20 | import Dispatch
|
21 | 21 |
|
22 | 22 | import NIOCore
|
| 23 | +import NIOPCAP |
23 | 24 |
|
24 | 25 | let sysWrite = write
|
25 | 26 |
|
26 |
| -struct TCPHeader { |
27 |
| - struct Flags: OptionSet { |
28 |
| - var rawValue: UInt8 |
29 |
| - |
30 |
| - init(rawValue: UInt8) { |
31 |
| - self.rawValue = rawValue |
32 |
| - } |
33 |
| - |
34 |
| - static let fin = Flags(rawValue: 1 << 0) |
35 |
| - static let syn = Flags(rawValue: 1 << 1) |
36 |
| - static let rst = Flags(rawValue: 1 << 2) |
37 |
| - static let psh = Flags(rawValue: 1 << 3) |
38 |
| - static let ack = Flags(rawValue: 1 << 4) |
39 |
| - static let urg = Flags(rawValue: 1 << 5) |
40 |
| - static let ece = Flags(rawValue: 1 << 6) |
41 |
| - static let cwr = Flags(rawValue: 1 << 7) |
42 |
| - } |
43 |
| - |
44 |
| - var flags: Flags |
45 |
| - var ackNumber: UInt32? |
46 |
| - var sequenceNumber: UInt32 |
47 |
| - var srcPort: UInt16 |
48 |
| - var dstPort: UInt16 |
49 |
| -} |
50 |
| - |
51 |
| -struct PCAPRecordHeader { |
52 |
| - enum Error: Swift.Error { |
53 |
| - case incompatibleAddressPair(SocketAddress, SocketAddress) |
54 |
| - } |
55 |
| - enum AddressTuple { |
56 |
| - case v4(src: SocketAddress.IPv4Address, dst: SocketAddress.IPv4Address) |
57 |
| - case v6(src: SocketAddress.IPv6Address, dst: SocketAddress.IPv6Address) |
58 |
| - |
59 |
| - var srcPort: UInt16 { |
60 |
| - switch self { |
61 |
| - case .v4(src: let src, dst: _): |
62 |
| - return UInt16(bigEndian: src.address.sin_port) |
63 |
| - case .v6(src: let src, dst: _): |
64 |
| - return UInt16(bigEndian: src.address.sin6_port) |
65 |
| - } |
66 |
| - } |
67 |
| - |
68 |
| - var dstPort: UInt16 { |
69 |
| - switch self { |
70 |
| - case .v4(src: _, dst: let dst): |
71 |
| - return UInt16(bigEndian: dst.address.sin_port) |
72 |
| - case .v6(src: _, dst: let dst): |
73 |
| - return UInt16(bigEndian: dst.address.sin6_port) |
74 |
| - } |
75 |
| - } |
76 |
| - } |
77 |
| - |
78 |
| - var payloadLength: Int |
79 |
| - var addresses: AddressTuple |
80 |
| - var time: timeval |
81 |
| - var tcp: TCPHeader |
82 |
| - |
83 |
| - init(payloadLength: Int, addresses: AddressTuple, time: timeval, tcp: TCPHeader) { |
84 |
| - self.payloadLength = payloadLength |
85 |
| - self.addresses = addresses |
86 |
| - self.time = time |
87 |
| - self.tcp = tcp |
88 |
| - |
89 |
| - assert(addresses.srcPort == Int(tcp.srcPort)) |
90 |
| - assert(addresses.dstPort == Int(tcp.dstPort)) |
91 |
| - assert(tcp.ackNumber == nil ? !tcp.flags.contains([.ack]) : tcp.flags.contains([.ack])) |
92 |
| - } |
93 |
| - |
94 |
| - init(payloadLength: Int, src: SocketAddress, dst: SocketAddress, tcp: TCPHeader) throws { |
95 |
| - let addressTuple: AddressTuple |
96 |
| - switch (src, dst) { |
97 |
| - case (.v4(let src), .v4(let dst)): |
98 |
| - addressTuple = .v4(src: src, dst: dst) |
99 |
| - case (.v6(let src), .v6(let dst)): |
100 |
| - addressTuple = .v6(src: src, dst: dst) |
101 |
| - default: |
102 |
| - throw Error.incompatibleAddressPair(src, dst) |
103 |
| - } |
104 |
| - self = .init(payloadLength: payloadLength, addresses: addressTuple, tcp: tcp) |
105 |
| - } |
106 |
| - |
107 |
| - init(payloadLength: Int, addresses: AddressTuple, tcp: TCPHeader) { |
108 |
| - var tv = timeval() |
109 |
| - gettimeofday(&tv, nil) |
110 |
| - self = .init(payloadLength: payloadLength, addresses: addresses, time: tv, tcp: tcp) |
111 |
| - } |
112 |
| -} |
113 |
| - |
114 | 27 | /// A `ChannelHandler` that can write a [`.pcap` file](https://en.wikipedia.org/wiki/Pcap) containing the send/received
|
115 | 28 | /// data as synthesized TCP packet captures.
|
116 | 29 | ///
|
@@ -186,7 +99,7 @@ public class NIOWritePCAPHandler: RemovableChannelHandler {
|
186 | 99 |
|
187 | 100 | public static var pcapFileHeader: ByteBuffer {
|
188 | 101 | var buffer = ByteBufferAllocator().buffer(capacity: 24)
|
189 |
| - buffer.writePCAPHeader() |
| 102 | + buffer.writePCAPHeader(.default) |
190 | 103 | return buffer
|
191 | 104 | }
|
192 | 105 |
|
@@ -491,104 +404,6 @@ extension NIOWritePCAPHandler: ChannelDuplexHandler {
|
491 | 404 | }
|
492 | 405 | }
|
493 | 406 |
|
494 |
| -extension ByteBuffer { |
495 |
| - mutating func writePCAPHeader() { |
496 |
| - // guint32 magic_number; /* magic number */ |
497 |
| - self.writeInteger(0xa1b2c3d4, endianness: .host, as: UInt32.self) |
498 |
| - // guint16 version_major; /* major version number */ |
499 |
| - self.writeInteger(2, endianness: .host, as: UInt16.self) |
500 |
| - // guint16 version_minor; /* minor version number * |
501 |
| - self.writeInteger(4, endianness: .host, as: UInt16.self) |
502 |
| - // gint32 thiszone; /* GMT to local correction */ |
503 |
| - self.writeInteger(0, endianness: .host, as: UInt32.self) |
504 |
| - // guint32 sigfigs; /* accuracy of timestamps */ |
505 |
| - self.writeInteger(0, endianness: .host, as: UInt32.self) |
506 |
| - // guint32 snaplen; /* max length of captured packets, in octets */ |
507 |
| - self.writeInteger(.max, endianness: .host, as: UInt32.self) |
508 |
| - // guint32 network; /* data link type */ |
509 |
| - self.writeInteger(0, endianness: .host, as: UInt32.self) |
510 |
| - } |
511 |
| - |
512 |
| - mutating func writePCAPRecord(_ record: PCAPRecordHeader) throws { |
513 |
| - let rawDataLength = record.payloadLength |
514 |
| - let tcpLength = rawDataLength + 20 /* TCP header length */ |
515 |
| - |
516 |
| - // record |
517 |
| - // guint32 ts_sec; /* timestamp seconds */ |
518 |
| - self.writeInteger(.init(record.time.tv_sec), endianness: .host, as: UInt32.self) |
519 |
| - // guint32 ts_usec; /* timestamp microseconds */ |
520 |
| - self.writeInteger(.init(record.time.tv_usec), endianness: .host, as: UInt32.self) |
521 |
| - // continued below ... |
522 |
| - |
523 |
| - switch record.addresses { |
524 |
| - case .v4(let la, let ra): |
525 |
| - let ipv4WholeLength = tcpLength + 20 /* IPv4 header length, included in IPv4 */ |
526 |
| - let recordLength = ipv4WholeLength + 4 /* 32 bits for protocol id */ |
527 |
| - |
528 |
| - // record, continued |
529 |
| - // guint32 incl_len; /* number of octets of packet saved in file */ |
530 |
| - self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self) |
531 |
| - // guint32 orig_len; /* actual length of packet */ |
532 |
| - self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self) |
533 |
| - |
534 |
| - self.writeInteger(2, endianness: .host, as: UInt32.self) // IPv4 |
535 |
| - |
536 |
| - // IPv4 packet |
537 |
| - self.writeInteger(0x45, as: UInt8.self) // IP version (4) & IHL (5) |
538 |
| - self.writeInteger(0, as: UInt8.self) // DSCP |
539 |
| - self.writeInteger(.init(ipv4WholeLength), as: UInt16.self) |
540 |
| - |
541 |
| - self.writeInteger(0, as: UInt16.self) // identification |
542 |
| - self.writeInteger(0x4000 /* this set's "don't fragment" */, as: UInt16.self) // flags & fragment offset |
543 |
| - self.writeInteger(.max /* we don't care about TTL */, as: UInt8.self) // TTL |
544 |
| - self.writeInteger(6, as: UInt8.self) // TCP |
545 |
| - self.writeInteger(0, as: UInt16.self) // checksum |
546 |
| - self.writeInteger(la.address.sin_addr.s_addr, endianness: .host, as: UInt32.self) |
547 |
| - self.writeInteger(ra.address.sin_addr.s_addr, endianness: .host, as: UInt32.self) |
548 |
| - case .v6(let la, let ra): |
549 |
| - let ipv6PayloadLength = tcpLength |
550 |
| - let recordLength = ipv6PayloadLength + 4 /* 32 bits for protocol id */ + 40 /* IPv6 header length */ |
551 |
| - |
552 |
| - // record, continued |
553 |
| - // guint32 incl_len; /* number of octets of packet saved in file */ |
554 |
| - self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self) |
555 |
| - // guint32 orig_len; /* actual length of packet */ |
556 |
| - self.writeInteger(.init(recordLength), endianness: .host, as: UInt32.self) |
557 |
| - |
558 |
| - self.writeInteger(24, endianness: .host, as: UInt32.self) // IPv6 |
559 |
| - |
560 |
| - // IPv6 packet |
561 |
| - self.writeInteger(/* version */ (6 << 28), as: UInt32.self) // IP version (6) & fancy stuff |
562 |
| - self.writeInteger(.init(ipv6PayloadLength), as: UInt16.self) |
563 |
| - self.writeInteger(6, as: UInt8.self) // TCP |
564 |
| - self.writeInteger(.max /* we don't care about TTL */, as: UInt8.self) // hop limit (like TTL) |
565 |
| - |
566 |
| - var laAddress = la.address |
567 |
| - withUnsafeBytes(of: &laAddress.sin6_addr) { ptr in |
568 |
| - assert(ptr.count == 16) |
569 |
| - self.writeBytes(ptr) |
570 |
| - } |
571 |
| - var raAddress = ra.address |
572 |
| - withUnsafeBytes(of: &raAddress.sin6_addr) { ptr in |
573 |
| - assert(ptr.count == 16) |
574 |
| - self.writeBytes(ptr) |
575 |
| - } |
576 |
| - } |
577 |
| - |
578 |
| - // TCP |
579 |
| - self.writeInteger(record.tcp.srcPort, as: UInt16.self) |
580 |
| - self.writeInteger(record.tcp.dstPort, as: UInt16.self) |
581 |
| - |
582 |
| - self.writeInteger(record.tcp.sequenceNumber, as: UInt32.self) // seq no |
583 |
| - self.writeInteger(record.tcp.ackNumber ?? 0, as: UInt32.self) // ack no |
584 |
| - |
585 |
| - self.writeInteger(5 << 12 | UInt16(record.tcp.flags.rawValue), as: UInt16.self) // data offset + reserved bits + fancy stuff |
586 |
| - self.writeInteger(.max /* we don't do actual window sizes */, as: UInt16.self) // window size |
587 |
| - self.writeInteger(0xbad /* fake */, as: UInt16.self) // checksum |
588 |
| - self.writeInteger(0, as: UInt16.self) // urgent pointer |
589 |
| - } |
590 |
| -} |
591 |
| - |
592 | 407 | extension NIOWritePCAPHandler {
|
593 | 408 | /// A synchronised file sink that uses a `DispatchQueue` to do all the necessary write synchronously.
|
594 | 409 | ///
|
|
0 commit comments