redhound 1.0.1 → 2.0.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/README.md +97 -31
  4. data/docs/API.md +104 -0
  5. data/docs/FILTERS.md +37 -0
  6. data/docs/MIGRATION.md +23 -0
  7. data/docs/PROTOCOLS.md +54 -0
  8. data/docs/USAGE.md +86 -0
  9. data/docs/VALIDATION.md +175 -0
  10. data/docs/json-schema.json +64 -0
  11. data/exe/redhound +2 -1
  12. data/lib/redhound/analysis/flow_key.rb +59 -0
  13. data/lib/redhound/analysis/flow_table.rb +124 -0
  14. data/lib/redhound/analysis/ip_reassembler.rb +209 -0
  15. data/lib/redhound/analysis/stats.rb +150 -0
  16. data/lib/redhound/analysis/tcp_analysis.rb +43 -0
  17. data/lib/redhound/analysis/tcp_reassembler.rb +176 -0
  18. data/lib/redhound/analysis/tcp_stream.rb +156 -0
  19. data/lib/redhound/analysis.rb +157 -0
  20. data/lib/redhound/capture/bsd/bpf_device.rb +155 -0
  21. data/lib/redhound/capture/bsd/constants.rb +29 -0
  22. data/lib/redhound/capture/bsd/ifreq.rb +41 -0
  23. data/lib/redhound/capture/file_source.rb +214 -0
  24. data/lib/redhound/capture/interface.rb +70 -0
  25. data/lib/redhound/capture/linktype.rb +30 -0
  26. data/lib/redhound/capture/linux/constants.rb +37 -0
  27. data/lib/redhound/capture/linux/cooked.rb +18 -0
  28. data/lib/redhound/capture/linux/ifreq.rb +42 -0
  29. data/lib/redhound/capture/linux/packet_socket.rb +224 -0
  30. data/lib/redhound/capture/linux/sockaddr_ll.rb +33 -0
  31. data/lib/redhound/capture/linux/tpacket_v3.rb +137 -0
  32. data/lib/redhound/capture/source.rb +79 -0
  33. data/lib/redhound/capture/stats.rb +22 -0
  34. data/lib/redhound/capture.rb +70 -0
  35. data/lib/redhound/cli/command.rb +42 -0
  36. data/lib/redhound/cli/options.rb +133 -0
  37. data/lib/redhound/cli/privileges.rb +29 -0
  38. data/lib/redhound/cli/runner.rb +129 -0
  39. data/lib/redhound/context.rb +20 -0
  40. data/lib/redhound/cursor.rb +69 -0
  41. data/lib/redhound/diagnostic.rb +7 -0
  42. data/lib/redhound/dissector.rb +152 -0
  43. data/lib/redhound/engine.rb +69 -0
  44. data/lib/redhound/errors.rb +38 -0
  45. data/lib/redhound/field.rb +62 -0
  46. data/lib/redhound/file/format.rb +63 -0
  47. data/lib/redhound/file/pcap_reader.rb +43 -0
  48. data/lib/redhound/file/pcap_writer.rb +79 -0
  49. data/lib/redhound/file/pcapng_reader.rb +221 -0
  50. data/lib/redhound/file/pcapng_writer.rb +151 -0
  51. data/lib/redhound/file/rotating_writer.rb +98 -0
  52. data/lib/redhound/filter/analyzer.rb +197 -0
  53. data/lib/redhound/filter/bpf/assembler.rb +121 -0
  54. data/lib/redhound/filter/bpf/disassembler.rb +58 -0
  55. data/lib/redhound/filter/bpf/validator.rb +77 -0
  56. data/lib/redhound/filter/bpf/vm.rb +109 -0
  57. data/lib/redhound/filter/codegen.rb +413 -0
  58. data/lib/redhound/filter/lexer.rb +46 -0
  59. data/lib/redhound/filter/parser.rb +206 -0
  60. data/lib/redhound/filter/program.rb +55 -0
  61. data/lib/redhound/filter.rb +30 -0
  62. data/lib/redhound/layer.rb +75 -0
  63. data/lib/redhound/output/fields.rb +20 -0
  64. data/lib/redhound/output/follow.rb +64 -0
  65. data/lib/redhound/output/hexdump.rb +29 -0
  66. data/lib/redhound/output/json.rb +32 -0
  67. data/lib/redhound/output/summary.rb +84 -0
  68. data/lib/redhound/output/timestamp.rb +34 -0
  69. data/lib/redhound/output/tree.rb +25 -0
  70. data/lib/redhound/packet.rb +77 -0
  71. data/lib/redhound/protocols/arp.rb +39 -0
  72. data/lib/redhound/protocols/checksum.rb +38 -0
  73. data/lib/redhound/protocols/data.rb +23 -0
  74. data/lib/redhound/protocols/dhcp.rb +140 -0
  75. data/lib/redhound/protocols/dns.rb +268 -0
  76. data/lib/redhound/protocols/ethernet.rb +24 -0
  77. data/lib/redhound/protocols/http.rb +185 -0
  78. data/lib/redhound/protocols/icmp.rb +205 -0
  79. data/lib/redhound/protocols/ipv4.rb +56 -0
  80. data/lib/redhound/protocols/ipv6.rb +68 -0
  81. data/lib/redhound/protocols/link.rb +70 -0
  82. data/lib/redhound/protocols/llc.rb +37 -0
  83. data/lib/redhound/protocols/ntp.rb +45 -0
  84. data/lib/redhound/protocols/tcp.rb +88 -0
  85. data/lib/redhound/protocols/tls.rb +218 -0
  86. data/lib/redhound/protocols/tunnel.rb +48 -0
  87. data/lib/redhound/protocols/udp.rb +32 -0
  88. data/lib/redhound/protocols/vlan.rb +23 -0
  89. data/lib/redhound/reader.rb +8 -0
  90. data/lib/redhound/registry.rb +64 -0
  91. data/lib/redhound/stream_dissector.rb +168 -0
  92. data/lib/redhound/util/seq.rb +21 -0
  93. data/lib/redhound/version.rb +2 -1
  94. data/lib/redhound/writer.rb +25 -43
  95. data/lib/redhound.rb +81 -9
  96. data/sig/generated/redhound/analysis/flow_key.rbs +15 -0
  97. data/sig/generated/redhound/analysis/flow_table.rbs +102 -0
  98. data/sig/generated/redhound/analysis/ip_reassembler.rbs +52 -0
  99. data/sig/generated/redhound/analysis/stats.rbs +80 -0
  100. data/sig/generated/redhound/analysis/tcp_analysis.rbs +15 -0
  101. data/sig/generated/redhound/analysis/tcp_reassembler.rbs +39 -0
  102. data/sig/generated/redhound/analysis/tcp_stream.rbs +60 -0
  103. data/sig/generated/redhound/analysis.rbs +38 -0
  104. data/sig/generated/redhound/capture/bsd/bpf_device.rbs +39 -0
  105. data/sig/generated/redhound/capture/bsd/constants.rbs +40 -0
  106. data/sig/generated/redhound/capture/bsd/ifreq.rbs +15 -0
  107. data/sig/generated/redhound/capture/file_source.rbs +67 -0
  108. data/sig/generated/redhound/capture/interface.rbs +53 -0
  109. data/sig/generated/redhound/capture/linktype.rbs +20 -0
  110. data/sig/generated/redhound/capture/linux/constants.rbs +58 -0
  111. data/sig/generated/redhound/capture/linux/cooked.rbs +15 -0
  112. data/sig/generated/redhound/capture/linux/ifreq.rbs +18 -0
  113. data/sig/generated/redhound/capture/linux/packet_socket.rbs +64 -0
  114. data/sig/generated/redhound/capture/linux/sockaddr_ll.rbs +31 -0
  115. data/sig/generated/redhound/capture/linux/tpacket_v3.rbs +35 -0
  116. data/sig/generated/redhound/capture/source.rbs +44 -0
  117. data/sig/generated/redhound/capture/stats.rbs +25 -0
  118. data/sig/generated/redhound/capture.rbs +14 -0
  119. data/sig/generated/redhound/cli/command.rbs +12 -0
  120. data/sig/generated/redhound/cli/options.rbs +25 -0
  121. data/sig/generated/redhound/cli/privileges.rbs +12 -0
  122. data/sig/generated/redhound/cli/runner.rbs +27 -0
  123. data/sig/generated/redhound/context.rbs +27 -0
  124. data/sig/generated/redhound/cursor.rbs +59 -0
  125. data/sig/generated/redhound/diagnostic.rbs +21 -0
  126. data/sig/generated/redhound/dissector.rbs +117 -0
  127. data/sig/generated/redhound/engine.rbs +23 -0
  128. data/sig/generated/redhound/errors.rbs +56 -0
  129. data/sig/generated/redhound/field.rbs +74 -0
  130. data/sig/generated/redhound/file/format.rbs +39 -0
  131. data/sig/generated/redhound/file/pcap_reader.rbs +19 -0
  132. data/sig/generated/redhound/file/pcap_writer.rbs +38 -0
  133. data/sig/generated/redhound/file/pcapng_reader.rbs +54 -0
  134. data/sig/generated/redhound/file/pcapng_writer.rbs +50 -0
  135. data/sig/generated/redhound/file/rotating_writer.rbs +42 -0
  136. data/sig/generated/redhound/filter/analyzer.rbs +42 -0
  137. data/sig/generated/redhound/filter/bpf/assembler.rbs +39 -0
  138. data/sig/generated/redhound/filter/bpf/disassembler.rbs +18 -0
  139. data/sig/generated/redhound/filter/bpf/validator.rbs +30 -0
  140. data/sig/generated/redhound/filter/bpf/vm.rbs +28 -0
  141. data/sig/generated/redhound/filter/codegen.rbs +101 -0
  142. data/sig/generated/redhound/filter/lexer.rbs +15 -0
  143. data/sig/generated/redhound/filter/parser.rbs +65 -0
  144. data/sig/generated/redhound/filter/program.rbs +48 -0
  145. data/sig/generated/redhound/filter.rbs +10 -0
  146. data/sig/generated/redhound/layer.rbs +81 -0
  147. data/sig/generated/redhound/output/fields.rbs +15 -0
  148. data/sig/generated/redhound/output/follow.rbs +21 -0
  149. data/sig/generated/redhound/output/hexdump.rbs +15 -0
  150. data/sig/generated/redhound/output/json.rbs +18 -0
  151. data/sig/generated/redhound/output/summary.rbs +21 -0
  152. data/sig/generated/redhound/output/timestamp.rbs +21 -0
  153. data/sig/generated/redhound/output/tree.rbs +15 -0
  154. data/sig/generated/redhound/packet.rbs +82 -0
  155. data/sig/generated/redhound/protocols/arp.rbs +15 -0
  156. data/sig/generated/redhound/protocols/checksum.rbs +15 -0
  157. data/sig/generated/redhound/protocols/data.rbs +17 -0
  158. data/sig/generated/redhound/protocols/dhcp.rbs +31 -0
  159. data/sig/generated/redhound/protocols/dns.rbs +42 -0
  160. data/sig/generated/redhound/protocols/ethernet.rbs +15 -0
  161. data/sig/generated/redhound/protocols/http.rbs +36 -0
  162. data/sig/generated/redhound/protocols/icmp.rbs +41 -0
  163. data/sig/generated/redhound/protocols/ipv4.rbs +15 -0
  164. data/sig/generated/redhound/protocols/ipv6.rbs +24 -0
  165. data/sig/generated/redhound/protocols/link.rbs +33 -0
  166. data/sig/generated/redhound/protocols/llc.rbs +15 -0
  167. data/sig/generated/redhound/protocols/ntp.rbs +17 -0
  168. data/sig/generated/redhound/protocols/tcp.rbs +25 -0
  169. data/sig/generated/redhound/protocols/tls.rbs +51 -0
  170. data/sig/generated/redhound/protocols/tunnel.rbs +24 -0
  171. data/sig/generated/redhound/protocols/udp.rbs +18 -0
  172. data/sig/generated/redhound/protocols/vlan.rbs +12 -0
  173. data/sig/generated/redhound/reader.rbs +7 -0
  174. data/sig/generated/redhound/registry.rbs +45 -0
  175. data/sig/generated/redhound/stream_dissector.rbs +44 -0
  176. data/sig/generated/redhound/util/seq.rbs +20 -0
  177. data/sig/generated/redhound/version.rbs +1 -0
  178. data/sig/generated/redhound/writer.rbs +6 -19
  179. data/sig/generated/redhound.rbs +18 -0
  180. data/sig/shims/io.rbs +7 -0
  181. data/sig/shims/process.rbs +3 -0
  182. metadata +177 -55
  183. data/CODE_OF_CONDUCT.md +0 -132
  184. data/Dockerfile +0 -7
  185. data/Rakefile +0 -15
  186. data/Steepfile +0 -4
  187. data/docker-compose.yml +0 -9
  188. data/lib/redhound/analyzer.rb +0 -34
  189. data/lib/redhound/builder/packet_mreq.rb +0 -56
  190. data/lib/redhound/builder/socket.rb +0 -35
  191. data/lib/redhound/builder.rb +0 -4
  192. data/lib/redhound/command.rb +0 -67
  193. data/lib/redhound/l2/ether.rb +0 -68
  194. data/lib/redhound/l2/protocol.rb +0 -33
  195. data/lib/redhound/l2.rb +0 -4
  196. data/lib/redhound/l3/arp.rb +0 -114
  197. data/lib/redhound/l3/base.rb +0 -49
  198. data/lib/redhound/l3/ipv4.rb +0 -95
  199. data/lib/redhound/l3/ipv6.rb +0 -69
  200. data/lib/redhound/l3/protocol.rb +0 -173
  201. data/lib/redhound/l3/resolver.rb +0 -30
  202. data/lib/redhound/l3.rb +0 -9
  203. data/lib/redhound/l4/base.rb +0 -31
  204. data/lib/redhound/l4/icmp.rb +0 -71
  205. data/lib/redhound/l4/resolver.rb +0 -28
  206. data/lib/redhound/l4/udp.rb +0 -63
  207. data/lib/redhound/l4.rb +0 -6
  208. data/lib/redhound/receiver.rb +0 -45
  209. data/lib/redhound/resolver.rb +0 -22
  210. data/lib/redhound/source/socket.rb +0 -18
  211. data/lib/redhound/source.rb +0 -3
  212. data/rbs_collection.lock.yaml +0 -20
  213. data/rbs_collection.yaml +0 -17
  214. data/sig/generated/redhound/analyzer.rbs +0 -14
  215. data/sig/generated/redhound/builder/packet_mreq.rbs +0 -39
  216. data/sig/generated/redhound/builder/socket.rbs +0 -24
  217. data/sig/generated/redhound/command.rbs +0 -19
  218. data/sig/generated/redhound/l2/ether.rbs +0 -41
  219. data/sig/generated/redhound/l2/protocol.rbs +0 -15
  220. data/sig/generated/redhound/l3/arp.rbs +0 -57
  221. data/sig/generated/redhound/l3/base.rbs +0 -28
  222. data/sig/generated/redhound/l3/ipv4.rbs +0 -53
  223. data/sig/generated/redhound/l3/ipv6.rbs +0 -38
  224. data/sig/generated/redhound/l3/protocol.rbs +0 -16
  225. data/sig/generated/redhound/l3/resolver.rbs +0 -16
  226. data/sig/generated/redhound/l4/base.rbs +0 -19
  227. data/sig/generated/redhound/l4/icmp.rbs +0 -33
  228. data/sig/generated/redhound/l4/resolver.rbs +0 -16
  229. data/sig/generated/redhound/l4/udp.rbs +0 -36
  230. data/sig/generated/redhound/receiver.rbs +0 -19
  231. data/sig/generated/redhound/resolver.rbs +0 -11
  232. data/sig/generated/redhound/source/socket.rbs +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fc9146df6d249b2bdd3ca7c529c6d72eaad8c78970e6cc21d4be41f9e233a25
4
- data.tar.gz: 9f66932249c4235042d3934579fdf7f9be92ad531f30e1e5c05ed1a55ae436e4
3
+ metadata.gz: 33f3a971291b9d5c6be138098ab5d6072717b8ffc79f418830f3538d8b9c4500
4
+ data.tar.gz: 191cf625ab53877b304432e4cd0b9caa6725afd1e4929bebaba31ef2382c0108
5
5
  SHA512:
6
- metadata.gz: 4ee95bd38fa1717c5286ae994db3b4d2c024c07119489d65f7b48a2cd9f5337b1a0cf0ebf36659f37d113052aaee178cd8ee29d50c2d995bee06d97443335fc6
7
- data.tar.gz: 895d8f8b92858aaf63ac5bfc9b7ee2dc4a4fb594313e20052a96bdf893380aaae4853988c8e2966657ea3f2788eabf604a3ef44ebb16cf9954f0df5c4aeef444
6
+ metadata.gz: 73fc49a4129a62cfdad32ee818adb4d1915f115f3bbe3f0a47b36d5d8a23c625d275d28a39e8307d4b8d1cc068b0d6be12409e2f99400f0135aa89383d58b0f9
7
+ data.tar.gz: 817303ae395d6f1b288bbab65105736d97f019cfb27dc6ba8edea787d7eab82fed9817d4a3fd0ee36e7e1407af17b48c50adab04412410b36f29044d778f0215
data/CHANGELOG.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.0.0.rc2 - 2026-10-02
6
+
7
+ ### Features
8
+
9
+ - Use the ring backend automatically on aarch64 Linux when mapping is available.
10
+
11
+ ### Bug fixes
12
+
13
+ - Improve file reading and packet summary throughput while keeping stdin responsive.
14
+ - Preserve readable fields in truncated headers and correct ICMP errors, IGMP reports, signed NTP precision, IPv6 extension boundaries and variable field locations.
15
+ - Reject malformed TCP options and empty or conflicting HTTP Content-Length values; recognize HTTP when its first line spans segments on nonstandard ports.
16
+ - Report incomplete IP/TCP data at EOF and flow eviction, distinguish retransmitted SYN/FIN packets, and handle IPv6 atomic fragments independently.
17
+ - Account for retained buffer capacity when enforcing reassembly limits, bound pcapng interface metadata, and release analysis buffers even when output fails.
18
+ - Keep capture timeouts and stopping responsive under rejected traffic and idle stdin, preserve partial input records across timeouts, and support replacing file-source filters.
19
+ - Preserve wire lengths with attached filters, close capture files after write failures, and prevent metadata errors from corrupting pcapng interface numbering.
20
+ - Correct macOS interface MAC/MTU and loopback link types; include interface and direction in packet output and show checksum/TCP options with verbose summaries.
21
+ - Preserve negative and expanded-year timestamps and emit valid JSON for invalid UTF-8 diagnostics and interface names; reject invalid packet metadata before file serialization.
22
+ - Include empty intervals in IO statistics and keep unknown IP protocol conversations separate.
23
+ - Fall back to socket capture when Ruby 4.0 cannot map a packet ring, and explain unavailable explicit ring capture and receive-buffer/VLAN limitations.
24
+
25
+ ## 2.0.0.rc1 - 2026-10-01
26
+
27
+ ### Breaking changes
28
+
29
+ - Replace the Analyzer/Builder/L2/L3/L4 API with Packet, Layer, Field and the Dissector DSL; use `Redhound.open`, `Redhound.capture` and `Redhound.dissect` for library integrations.
30
+ - Use a one-line summary by default. Select `-V` or `-T tree` for detailed output; `-v` controls verbosity and `--version` prints the version.
31
+ - Make `-w` save packets without dissection or display unless an output format is also selected.
32
+
33
+ ### Features
34
+
35
+ - Read and write pcap and pcapng, including stdin/stdout, interface metadata and size/time rotation.
36
+ - Capture on macOS BPF devices and Linux socket/TPACKET_V3 backends, including Linux `any`, directions, snaplen and drop statistics.
37
+ - Compile tcpdump-style capture filters to validated cBPF for kernel capture and file filtering; support filter files and instruction dumps.
38
+ - Decode VLAN/QinQ, LLC/SNAP, cooked/null/raw links, IPv6 extensions, ICMPv6/NDP, IGMPv3, DNS/mDNS/LLMNR, DHCP, NTP, HTTP/1.x, TLS hellos, GRE and VXLAN.
39
+ - Track flows, reassemble IP fragments and TCP application messages, report TCP analysis flags/RTT, and follow TCP streams as ASCII, hex or exact bytes.
40
+ - Add tree, hex, JSON/NDJSON and selected-field output, conversation/endpoint/interval/protocol statistics, decode-as overrides and custom Ruby dissectors.
41
+ - Support privilege dropping after capture setup and write capture files with private permissions.
42
+
43
+ ### Bug fixes
44
+
45
+ - Fix crashes on padded ARP, short frames and malformed packet headers.
46
+ - Correct IPv4 and IPv6 fields, IP options and transport payload boundaries; label ICMP types/codes and avoid false checksum failures on incomplete IPv6 fragments.
47
+ - Display TCP ports, sequence numbers, flags and payload lengths.
48
+ - Escape terminal control characters in captured payloads.
49
+ - Save packets before analysis and close captures reliably on termination or errors.
50
+ - Capture larger frames with kernel timestamps and remove loopback duplicates.
51
+ - List interfaces without duplicates and accept interface indexes.
52
+ - Protect read inputs and their aliases from rotated-output overwrites, validate filters on empty captures, and stop stdin reads cleanly on termination.
53
+ - Decode foreign-endian loopback capture headers correctly and preserve original wire lengths for truncated VLAN packets.
54
+ - Handle HEAD responses and pipelined HTTP correctly, reassemble HTTP on nonstandard ports, and report missing or incomplete TCP data at FIN and EOF.
55
+
5
56
  ## 1.0.1 - 2025-01-17
6
57
 
7
58
  - Fix an NameError in Redhound::L3::Arp
data/README.md CHANGED
@@ -1,51 +1,117 @@
1
1
  # Redhound [![Gem Version](https://badge.fury.io/rb/redhound.svg)](https://badge.fury.io/rb/redhound) [![Test](https://github.com/ydah/redhound/actions/workflows/main.yml/badge.svg)](https://github.com/ydah/redhound/actions/workflows/main.yml)
2
2
 
3
- Pure Ruby packet analyzer.
4
- At this time, it is only guaranteed to work on Linux.
3
+ Capture and analyze network packets in Pure Ruby. Redhound runs on Linux and
4
+ macOS, reads and writes pcap/pcapng, compiles capture filters to cBPF, and
5
+ provides summary, tree, hex and JSON output. No libpcap, Fiddle or runtime gem
6
+ dependency is required. Ruby 3.3 or later is required.
5
7
 
6
- ## Installation
8
+ Version 2 is currently a release candidate. See [validation status](docs/VALIDATION.md)
9
+ for remaining GA evaluation gates.
7
10
 
8
- Install the gem and add to the application's Gemfile by executing:
11
+ ## Installation
9
12
 
10
- ```bash
11
- bundle add redhound
13
+ ```sh
14
+ gem install redhound --pre
12
15
  ```
13
16
 
14
- If bundler is not being used to manage dependencies, install the gem by executing:
17
+ Or add `gem 'redhound', '~> 2.0.0.rc2'` to your Gemfile.
15
18
 
16
- ```bash
17
- gem install redhound
19
+ ## Usage
20
+
21
+ ```sh
22
+ redhound -D
23
+ sudo redhound -i any 'tcp port 443'
24
+ sudo redhound -i en0 -c 100 -w trace.pcapng
25
+ redhound -r trace.pcapng -T tree
26
+ redhound -r trace.pcap --stats conv,tcp
27
+ redhound -r trace.pcap --follow tcp,ascii,0
18
28
  ```
19
29
 
20
- ## Usage
30
+ Live capture normally requires root or capture permissions. File analysis does
31
+ not. `-i any` is Linux only; use `lo0`/`en0` on macOS. `-w` alone saves packets
32
+ without dissection; add `-T summary` to also print them. Addresses are numeric
33
+ by default. Use `-N` to resolve names.
34
+
35
+ ```text
36
+ Usage: redhound [options] [filter expression]
37
+ -i, --interface IF interface name, index or any
38
+ -D, --list-interfaces list interfaces and exit
39
+ -r, --read FILE read pcap or pcapng (- for stdin)
40
+ -c, --count N stop after N packets
41
+ -s, --snaplen N capture length (default 262144)
42
+ -p, --no-promiscuous disable promiscuous capture
43
+ -B, --buffer-size KiB kernel buffer size
44
+ -Q, --direction DIR capture direction
45
+ -F, --filter-file FILE read a capture filter
46
+ --capture-backend BACKEND capture backend
47
+ -w, --write FILE write capture (- for stdout)
48
+ --format FORMAT capture file format
49
+ -C MB rotate after MB (decimal)
50
+ -G SECONDS rotate at this interval
51
+ -W N maximum rotation file count
52
+ --post-rotate-command CMD command to run after closing each file
53
+ -U, --packet-buffered flush each packet
54
+ -T, --output-format FORMAT packet output format
55
+ -V show packet details
56
+ -q quick output and no capture statistics
57
+ --time-stamp-precision PRECISION
58
+ timestamp digits
59
+ -N, --resolve-names resolve addresses
60
+ -n disable address resolution (default)
61
+ --stats SPEC io,N / conv,TYPE / endpoints,TYPE / phs
62
+ --follow SPEC tcp,ascii|hex|raw,N
63
+ --decode-as RULE e.g. udp.port==8443,dns
64
+ -I, --require FILE load a custom dissector
65
+ -d dump cBPF instructions
66
+ -Z, --relinquish-privileges USER drop capture privileges
67
+ --list-protocols list protocols and fields
68
+ --debug print error backtraces
69
+ --no-yjit disable automatic YJIT activation
70
+ -h, --help print help
71
+ --version print version
72
+ -e [-T fields: FIELD] link header or selected field (repeatable)
73
+ -v / -vv / -vvv verbosity and checksum verification
74
+ -t / -tt / -ttt / -tttt / -ttttt timestamp style
75
+ -x / -xx / -X / -XX hex dump, with link header / ASCII
76
+ ```
21
77
 
22
- ```command
23
- ___ ____ __
24
- / _ \___ ___/ / / ___ __ _____ ___/ /
25
- / , _/ -_) _ / _ \/ _ \/ // / _ \/ _ /
26
- /_/|_|\__/\_,_/_//_/\___/\_,_/_//_/\_,_/
78
+ See [usage and tcpdump option mapping](docs/USAGE.md),
79
+ [supported protocols](docs/PROTOCOLS.md), [capture filters](docs/FILTERS.md),
80
+ [Ruby API and plugins](docs/API.md), and [migration from 1.x](docs/MIGRATION.md).
27
81
 
28
- Version: 1.0.1
29
- Dump and analyze network packets.
82
+ ## Library
30
83
 
31
- Usage: redhound [options] ...
84
+ ```ruby
85
+ require 'redhound'
32
86
 
33
- Options:
34
- -i, --interface INTERFACE name or idx of interface
35
- -D, --list-interfaces print list of interfaces and exit
36
- -w FILE write packets to a pcap capture file format to file
37
- -h, --help display this help and exit
38
- -v, --version display version information and exit
39
- ```
87
+ Redhound.open('trace.pcapng', filter: 'udp port 53') do |reader|
88
+ reader.each { |packet| puts packet.summary }
89
+ end
40
90
 
41
- ## Contributing
91
+ packet = Redhound.dissect(frame_bytes, linktype: :ethernet)
92
+ p packet['ip.src']
93
+ p packet.to_h
94
+ ```
42
95
 
43
- Bug reports and pull requests are welcome on GitHub at https://github.com/ydah/redhound. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/ydah/redhound/blob/main/CODE_OF_CONDUCT.md).
96
+ ## Development
44
97
 
45
- ## License
98
+ ```sh
99
+ bundle install
100
+ bundle exec rbs collection install --frozen
101
+ bundle exec rake
102
+ bundle exec yard stats --list-undoc
103
+ FUZZ_ITERATIONS=1000000 bundle exec rspec spec/fuzz
104
+ sudo -E env "PATH=$PATH" REDHOUND_LIVE=1 bundle exec rspec --tag live
105
+ ```
46
106
 
47
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
107
+ Differential tests use tcpdump/tshark as development tools. Fixtures are
108
+ regenerated with `ruby -Ilib spec/fixtures/generators/applications.rb` and
109
+ `ruby -Ilib spec/fixtures/generators/network.rb`. Update output snapshots with
110
+ `UPDATE_GOLDEN=1 bundle exec rspec spec/golden`, then review the changes.
111
+ See [benchmark results](bench/RESULTS.md) for reproducible performance checks.
48
112
 
49
- ## Code of Conduct
113
+ ## Contributing and license
50
114
 
51
- Everyone interacting in the Redhound project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ydah/redhound/blob/main/CODE_OF_CONDUCT.md).
115
+ Bug reports and pull requests are welcome at [GitHub](https://github.com/ydah/redhound).
116
+ Contributors must follow the [code of conduct](CODE_OF_CONDUCT.md).
117
+ Redhound is available under the [MIT License](LICENSE.txt).
data/docs/API.md ADDED
@@ -0,0 +1,104 @@
1
+ # Ruby API
2
+
3
+ ```ruby
4
+ require 'redhound'
5
+
6
+ Redhound.open('trace.pcapng', filter: 'tcp port 443') do |reader|
7
+ reader.each do |packet|
8
+ puts packet.summary
9
+ puts packet['ip.src']
10
+ p packet[:tcp]&.values
11
+ p packet.to_h
12
+ end
13
+ end
14
+
15
+ Redhound.capture(interface: 'lo', count: 10, filter: 'udp') do |packet|
16
+ puts packet.summary
17
+ end
18
+
19
+ packet = Redhound.dissect(frame_bytes, linktype: :ethernet,
20
+ timestamp_ns: 1_700_000_000_123_456_789)
21
+ Redhound::Writer.open('copy.pcapng') { |writer| writer << packet }
22
+ ```
23
+
24
+ `Redhound.open` accepts a path, `-`, or a binary IO. Reader is Enumerable,
25
+ provides `next_packet`, `stats`, `interfaces`, `stop`, and `close`; a block always
26
+ closes it. `Redhound.capture` yields packets and closes the live source even if
27
+ the block fails. Capture options include `snaplen`, `promiscuous`, `buffer_size`
28
+ (bytes), `direction` (`:in`, `:out`, `:inout`), `backend`, and `filter`.
29
+ On Linux Ruby 4.0, `backend: :auto` uses sockets because `IO::Buffer.map` cannot
30
+ map packet sockets; explicit `:ring` raises `UnsupportedPlatform`. Ruby 3.3/3.4
31
+ retain ring support.
32
+
33
+ `next_packet(timeout:)` returns nil at its deadline without discarding a partial
34
+ stdin/pipe record. `stop` interrupts a waiting read. `attach_filter(program)`
35
+ replaces a source's capture filter; filtering preserves the original wire length.
36
+ For pcapng input, retained interface metadata is limited to 4,096 interfaces and
37
+ 16 MiB across sections, with at most 4,096 options in a block. Excess input raises
38
+ `FileFormatError` rather than growing memory without a bound.
39
+
40
+ `Redhound.dissect` creates an immutable-byte Packet and decodes its layers lazily.
41
+ Packet metadata includes `timestamp_ns`, `original_length`, `linktype`,
42
+ `interface`, `direction`, and `number`. `caplen`, `truncated?`, and `time` expose
43
+ capture properties. A symbol index selects the first Layer; a dotted string
44
+ selects a decoded field value. `layers_of`, `innermost`, and `field_values` expose
45
+ repeated or tunneled layers. Layer has `values`, `fields`, and `diagnostics`.
46
+ `to_h` follows [json-schema.json](json-schema.json); bytes use hexadecimal strings,
47
+ addresses use text, booleans remain booleans, repeated fields become arrays.
48
+ `timestamp_ns` must be an Integer; calendar output preserves expanded years
49
+ outside 0000..9999. `number` is positive, `direction` is `:in`, `:out`, or nil,
50
+ and integer link types are restricted to 0..65535. Invalid UTF-8 field text,
51
+ interface names, and diagnostic text use hexadecimal strings without discarding
52
+ their original bytes.
53
+
54
+ Each Field exposes its `name`, `type`, `value`, `raw_value`, `offset`, and
55
+ `length`. For packet dissection, offsets are absolute captured byte positions;
56
+ lengths describe the encoded source span. Complete fixed fields remain available
57
+ when the rest of a header or its options are truncated. Derived values such as
58
+ `tcp.len`, `data.len`, and `igmp.version` have zero source length. DNS compressed
59
+ names refer to their encoded name/pointer span. Concatenated DHCP values and TLS
60
+ handshakes crossing records span the first through last source byte, including
61
+ intervening TLV/record headers; decoded values need not equal a direct byte slice.
62
+ Likewise, chunked HTTP body spans include chunk framing. Stream-reassembled
63
+ application fields use offsets in the logical PDU rather than the completing
64
+ packet's `data`; `tcp.reassembled_from` identifies the contributing frames.
65
+
66
+ Writer accepts `format: :pcap|:pcapng`, `linktype`, `snaplen`, `precision`,
67
+ `packet_buffered`, `max_bytes`, `interval`, `file_count`, and
68
+ `post_rotate_command`. `write`/`<<`, `flush`, `write_stats`, and `close` are
69
+ available. Use a block for deterministic closure.
70
+
71
+ ## Custom dissectors
72
+
73
+ ```ruby
74
+ class Example < Redhound::Dissector
75
+ protocol :example, name: 'Example protocol', short: 'EXAMPLE'
76
+ dissects_on 'udp.port', 9999
77
+ header do
78
+ uint16 :message_id, 'example.id'
79
+ uint8 :kind, 'example.kind'
80
+ end
81
+
82
+ def summary(layer)
83
+ "Example id #{layer[:message_id]}"
84
+ end
85
+ end
86
+ ```
87
+
88
+ Header fields support unsigned integers, signed `int8`, MAC/IPv4/IPv6 addresses
89
+ and bit fields.
90
+ Use `dissect(ctx, layer)` for bounded variable-length parsing through
91
+ `ctx.cursor`; append fields with `layer.add`. `next_dissector(ctx, layer)` returns
92
+ a registered dissector class, or nil. Child cursors cannot escape their packet
93
+ bounds. Truncated input creates a diagnostic. `REDHOUND_STRICT=1` re-raises
94
+ unexpected implementation errors for tests. Ordinary malformed input remains
95
+ safe. Registry copies allow per-session decode-as rules without changing global
96
+ registrations.
97
+
98
+ `Analysis::Session#update(packet)` adds flow/stream analysis and completed
99
+ application PDUs. It provides bounded flow/reassembly state and `snapshot`,
100
+ `finish`; library users opt into it explicitly. Reassembly does not modify the
101
+ packet's captured bytes. `Filter.compile(expression, linktype:)` returns a
102
+ validated cBPF Program with `match?`, `evaluate`, `serialize`, and `disassemble`.
103
+
104
+ Generate reference documentation with `bundle exec yard doc lib/**/*.rb`.
data/docs/FILTERS.md ADDED
@@ -0,0 +1,37 @@
1
+ # Capture filters
2
+
3
+ Redhound compiles filters to classic BPF in Ruby. Live capture attaches the verified program to the kernel; file capture executes the same instructions in the Ruby VM. No libpcap or external command is needed at runtime.
4
+
5
+ ```ruby
6
+ program = Redhound::Filter.compile('ip and udp dst port 53', linktype: :ethernet)
7
+ program.match?(packet)
8
+ program.instructions # [code, jt, jf, k] tuples
9
+ program.packed # native struct sock_filter bytes
10
+ program.disassemble(format: :text) # :ruby and :decimal are also available
11
+ ```
12
+
13
+ Supported primitives include `ip`, `ip6`, `arp`, `rarp`, `tcp`, `udp`, `sctp`, `icmp`, `icmp6`, and `igmp`; `host`, `net`, `port`, `portrange`, `proto`; `src`, `dst`, `src or dst`, `src and dst`; Ethernet addresses and EtherTypes; `vlan [id]`; `greater`, `less`, `broadcast`, and `multicast`. Numeric IPv4 and IPv6 addresses, CIDR networks, IPv4 netmasks, host names, protocol names, and service names are resolved when compiling. For reserved protocol names after `proto`, tcpdump spells them with an escape, e.g. `ip proto \tcp`; Redhound also accepts the unescaped spelling.
14
+
15
+ Identical qualifiers carry forward: `tcp dst port 80 or 443` means `tcp dst port 80 or tcp dst port 443`. Parenthesized operand lists work as well: `tcp dst port (80 or 443)`.
16
+
17
+ As specified by [pcap-filter](https://github.com/the-tcpdump-group/libpcap/blob/master/pcap-filter.manmisc.in), `and` and `or` have **equal precedence** and associate from left to right; `not` binds more tightly. Thus `udp or tcp and port 443` means `(udp or tcp) and port 443`. Use parentheses to express a different grouping. This corrects the separate AND/OR precedence in the original design's EBNF and is checked against tcpdump.
18
+
19
+ Arithmetic supports `len`, packet accesses of width 1, 2, or 4, `+ - * / % & | ^ << >>`, unary minus, and comparisons `= == != < <= > >=` with unsigned 32-bit values:
20
+
21
+ ```text
22
+ ip[2:2] > 576
23
+ tcp[tcpflags] & (tcp-syn | tcp-fin) != 0
24
+ (ip[0] & 15) * 4 = 20
25
+ icmp6[0] = 128
26
+ len >= 100
27
+ ```
28
+
29
+ Transport accesses and ports check IPv4 fragment offsets and honor IPv4 options. IPv6 ports require a directly following TCP/UDP/SCTP header; extension-header traversal (`protochain`) is outside the v2 subset. Plain protocol predicates additionally recognize an IPv6 fragment header's next-header field. `tcp[]`, `udp[]`, `icmp[]`, and `igmp[]` access IPv4 transport headers, matching libpcap; `icmp6[]` accesses a directly following ICMPv6 header.
30
+
31
+ `vlan` changes the offsets for all following primitives, including those in subsequent `or` branches, matching tcpdump. Repeated `vlan` predicates support nested tags. Linux live Ethernet filters also recognize hardware-stripped tags through VLAN ancillary loads; the VM reads these from `packet.meta[:vlan_tci]` (including tag ID zero). Linux `any` filters compile for kernel network-layer bytes and protocol metadata, while file filters use the synthetic SLL2 header.
32
+
33
+ Linktypes are Ethernet (1), RAW (101), Linux SLL (113), Linux SLL2 (276), NULL (0), LOOP (108), IPv4 (228), and IPv6 (229). Their corresponding symbol names are `:ethernet`, `:raw`, `:linux_sll`, `:linux_sll2`, `:null`, `:loop`, `:ipv4`, and `:ipv6`. Ethernet address and VLAN predicates require Ethernet. IPv4 `broadcast` without an interface netmask recognizes zero and all-one destinations; link broadcast compares the Ethernet destination.
34
+
35
+ `FilterSyntaxError` supplies the original expression and error position. Programs are limited to 4096 instructions and 16 scratch words; oversized programs raise `FilterTooLarge`. The verifier rejects invalid opcodes, jumps, memory accesses, uninitialized scratch reads, and constant zero divisors. Truncated packet loads and dynamic zero divisors reject the packet. Conditional branches beyond 255 instructions use forward jump trampolines.
36
+
37
+ The differential suite contains more than 160 expressions and compares selected packets and tcpdump-generated bytecode on Ethernet, RAW, SLL, SLL2, and NULL. tcpdump is a test dependency only. Historical protocols, `gateway`, and `protochain` are unsupported; network operands use numeric addresses rather than `/etc/networks` aliases.
data/docs/MIGRATION.md ADDED
@@ -0,0 +1,23 @@
1
+ # Migrating from 1.x
2
+
3
+ Redhound 2 replaces the former Analyzer/Builder/L2/L3/L4 classes with Packet,
4
+ Layer, Field and Dissector. Those internal classes have been removed. Migrate
5
+ library integrations to the APIs in [API.md](API.md). Ruby 3.3 remains the
6
+ minimum version.
7
+
8
+ The default CLI output is now a one-line summary. Use `-V` or `-T tree` for
9
+ packet details. `-v` now increases verbosity; use `--version` to print the
10
+ version. Numeric addresses remain the default.
11
+
12
+ `-w` alone records packets without printing or parsing them. Use `-w capture.pcap
13
+ -T summary` to save and display. Unknown protocols remain accessible as Data
14
+ layers, and malformed headers produce diagnostics instead of terminating the
15
+ capture. Payload text escapes terminal control bytes.
16
+
17
+ Interface indexes and Linux `any` are supported. Linux loopback duplicates are
18
+ removed. Capture timestamps come from the kernel; captured and original packet
19
+ lengths are recorded separately. pcapng supports multiple interfaces and metadata.
20
+
21
+ Version 2 is currently a prerelease. The two-week RC evaluation and long capture
22
+ soak gates remain prerequisites for GA; a 1.x maintenance deadline will be
23
+ announced when GA is published.
data/docs/PROTOCOLS.md ADDED
@@ -0,0 +1,54 @@
1
+ # Supported protocols
2
+
3
+ Built-in protocol registry (regenerate with `redhound --list-protocols`):
4
+
5
+ ```text
6
+ data: Data
7
+ eth: Ethernet eth.dst eth.src eth.type
8
+ vlan: 802.1Q VLAN vlan.priority vlan.dei vlan.id vlan.etype
9
+ llc: Logical Link Control llc.dsap llc.ssap llc.control
10
+ sll: Linux cooked capture sll.pkttype sll.hatype sll.halen sll.src sll.etype
11
+ sll2: Linux cooked capture v2 sll.etype sll.reserved sll.ifindex sll.hatype sll.pkttype sll.halen sll.src
12
+ null: BSD loopback
13
+ raw: Raw IP
14
+ arp: Address Resolution Protocol arp.hw.type arp.proto.type arp.hw.size arp.proto.size arp.opcode
15
+ ipv4: Internet Protocol v4 ip.version ip.hdr_len ip.dsfield.dscp ip.dsfield.ecn ip.len ip.id ip.flags.rb ip.flags.df ip.flags.mf ip.frag_offset ip.ttl ip.proto ip.checksum ip.src ip.dst
16
+ ipv6: Internet Protocol v6 ipv6.version ipv6.tclass ipv6.flow ipv6.plen ipv6.nxt ipv6.hlim ipv6.src ipv6.dst
17
+ ipv6_ext: IPv6 extension
18
+ udp: User Datagram Protocol udp.srcport udp.dstport udp.length udp.checksum
19
+ tcp: Transmission Control Protocol tcp.srcport tcp.dstport tcp.seq tcp.ack tcp.hdr_len tcp.reserved tcp.flags tcp.window_size_value tcp.checksum tcp.urgent_pointer
20
+ icmp: Internet Control Message Protocol icmp.type icmp.code icmp.checksum
21
+ icmpv6: ICMPv6 / Neighbor Discovery icmpv6.type icmpv6.code icmpv6.checksum
22
+ igmp: Internet Group Management Protocol igmp.type igmp.max_resp igmp.checksum
23
+ gre: Generic Routing Encapsulation gre.flags gre.proto
24
+ vxlan: Virtual eXtensible LAN vxlan.flags vxlan.vni_word
25
+ dns: Domain Name System
26
+ dhcp: Dynamic Host Configuration Protocol dhcp.type dhcp.hw.type dhcp.hw.len dhcp.hops dhcp.id dhcp.secs dhcp.flags dhcp.ip.client dhcp.ip.your dhcp.ip.server dhcp.ip.relay
27
+ ntp: Network Time Protocol ntp.flags.li ntp.flags.vn ntp.flags.mode ntp.stratum ntp.ppoll ntp.precision ntp.rootdelay ntp.rootdispersion ntp.refid ntp.reftime ntp.org ntp.rec ntp.xmt
28
+ http: Hypertext Transfer Protocol
29
+ tls: Transport Layer Security
30
+ ```
31
+
32
+ Variable-length fields, including options, resource records, application headers
33
+ and stream analysis, are added while parsing and appear in tree/JSON output.
34
+ Unknown protocols produce a Data layer; unsupported encrypted TLS content stays
35
+ opaque. HTTP is limited to HTTP/1.x. TLS parsing covers record framing and
36
+ ClientHello/ServerHello metadata including SNI, ALPN and supported versions.
37
+ DNS includes mDNS/LLMNR and TCP framing. IPv6 supports Hop-by-Hop, Routing,
38
+ Fragment, Destination and AH headers; ESP stops dissection. GRE and VXLAN
39
+ encapsulations decode inner packet layers.
40
+ ICMP identifiers/sequences are emitted for echo, timestamp, and address-mask
41
+ messages; fragmentation-needed errors expose `icmp.mtu` instead. IGMP reserved
42
+ report bytes are not labeled as maximum-response times. NTP timestamps such as
43
+ `ntp.xmt` preserve the unsigned 32.32 wire integer; their era-dependent calendar
44
+ interpretation is left to the caller.
45
+
46
+ Dissectors use checked cursors and parent payload boundaries. Truncation,
47
+ malformed lengths, checksum failures and reassembly gaps are available as
48
+ structured diagnostics. Checksum verification is enabled by `-v` or
49
+ `Engine.new(verify_checksums: true)`; outgoing/offloaded packets are marked
50
+ unverified.
51
+ IPv6 No Next Header terminates the chain, and the 16-extension limit applies
52
+ independently to each encapsulated IPv6 header. Variable wire fields carry source
53
+ ranges; [API.md](API.md) describes compression, concatenation, and reassembly
54
+ span semantics.
data/docs/USAGE.md ADDED
@@ -0,0 +1,86 @@
1
+ # Using Redhound
2
+
3
+ Ruby 3.3 or later is required. File analysis needs no capture privileges.
4
+ Live capture uses Linux AF_PACKET or macOS BPF devices and normally requires
5
+ root or an appropriate device/capability grant. Runtime dependencies are Ruby's
6
+ standard libraries; neither libpcap nor a native extension is required.
7
+
8
+ ```sh
9
+ redhound -D
10
+ sudo redhound -i any 'tcp port 443'
11
+ sudo redhound -i en0 -c 100 -w trace.pcapng
12
+ redhound -r trace.pcapng -T tree
13
+ redhound -r trace.pcap -T ndjson 'udp port 53'
14
+ redhound -r trace.pcap -T fields -e ip.src -e tcp.dstport
15
+ redhound -r trace.pcap --stats conv,tcp --stats io,1
16
+ redhound -r trace.pcap --follow tcp,ascii,0
17
+ ```
18
+
19
+ Options must precede the filter expression. Quote filters containing shell
20
+ operators. Addresses are numeric by default; `-N` enables name resolution.
21
+ `--help` lists every option. `--list-protocols` lists registered protocols and
22
+ their declared fields. Dynamic fields also appear in detailed and JSON output.
23
+
24
+ ## Options for tcpdump users
25
+
26
+ | tcpdump | Redhound |
27
+ | --- | --- |
28
+ | `-i`, `-D`, `-c`, `-s`, `-p`, `-B`, `-Q` | Same purpose; `-i any` is Linux only |
29
+ | `-r`, `-w`, `-U` | Read/write pcap or pcapng; `-` selects stdin/stdout |
30
+ | `-C`, `-G`, `-W` | Size/time rotation and file count |
31
+ | `-e`, `-q`, `-v`, `-vv`, `-vvv` | Link header, short output, increasing detail/checksums |
32
+ | `-t` through `-ttttt` | No time, epoch, delta, date/time, elapsed time |
33
+ | `-x`, `-xx`, `-X`, `-XX` | Hex/ASCII, optionally including the link header |
34
+ | `-F`, `-d`, `-dd`, `-ddd` | Filter file and cBPF listing |
35
+ | `-Z USER` | Drop user/group privileges after opening capture and output |
36
+
37
+ See [supported capture filters](FILTERS.md). Capture filters select packets;
38
+ Wireshark display filters are not supported. `--decode-as udp.port==8443,dns`
39
+ overrides port dispatch. `-I plugin.rb` loads a Ruby dissector before capture.
40
+
41
+ ## Saving and rotation
42
+
43
+ `-w` alone saves raw packets without dissection. Add `-T summary` or `-V` to
44
+ also display them. Binary output to stdout cannot be combined with text output.
45
+ `--format pcapng` overrides the extension. pcapng preserves interface identities,
46
+ nanosecond timestamps, packet directions and available drop statistics.
47
+
48
+ `-C` uses decimal megabytes; `-G` uses seconds. Rotated files receive a five-digit
49
+ sequence before the extension. With `-C -W`, names form an overwrite ring.
50
+ With `-G -W` alone, capture stops after the requested number of files. `-G`
51
+ expands strftime directives in the base name. Rotation happens when the next
52
+ packet arrives. `--post-rotate-command 'gzip -f'` invokes an argument vector,
53
+ appending the closed filename; it does not invoke a shell. Input files and their
54
+ aliases are protected from output truncation, including rotated destinations.
55
+
56
+ ## Analysis and termination
57
+
58
+ Displayed TCP packets receive stream IDs and analysis flags. IP fragments and
59
+ TCP application messages are reassembled within bounded state. Conflicting
60
+ IPv6 overlaps discard the datagram; IPv4/TCP retain first-seen bytes and report
61
+ conflicts. Incomplete, expired or evicted state is diagnosed, not retained
62
+ indefinitely. `--follow tcp,raw,N` emits the selected stream bytes without headers;
63
+ ASCII and hex modes label the endpoints and directions.
64
+
65
+ Statistics accept `io,SECONDS`, `conv,eth|ip|ipv6|tcp|udp`,
66
+ `endpoints,eth|ip|ipv6|tcp|udp`, or `phs`; options can be repeated. Packet counts
67
+ and byte totals use captured packets and original frame lengths. SIGUSR1 (and
68
+ SIGINFO on macOS) prints a statistics snapshot; SIGINT/SIGTERM close output and
69
+ capture sources cleanly. Capture statistics go to stderr. Exit status is 0 on
70
+ success, 1 on capture/file failures and 2 on invalid arguments.
71
+
72
+ ## Platforms and limits
73
+
74
+ Linux `auto` uses TPACKET_V3 on x86_64 and aarch64 and falls back to the socket backend when
75
+ mapping is unavailable. Other Linux architectures default to sockets; `ring`
76
+ can be selected explicitly. macOS uses BPF, with native timestamp precision
77
+ reported by the device. Linux socket capture cannot recover NIC-stripped VLAN
78
+ tags; choose the ring backend for that metadata.
79
+ Ruby 4.0's `IO::Buffer.map` rejects packet sockets, so `auto` uses socket capture
80
+ and explicit `ring` reports the mapping limitation. Use Ruby 3.3/3.4 for ring
81
+ capture. If using sockets, disable receive VLAN offload on the receiving
82
+ interface when VLAN tags are required (`ethtool -K IF rxvlan off`).
83
+
84
+ Windows, Wi-Fi monitor mode, packet transmission, TLS decryption, complete
85
+ HTTP/2/QUIC dissection, display-filter syntax and a TUI are outside v2's scope.
86
+ See [release validation status](VALIDATION.md) before promoting a prerelease.