redhound 1.0.1 → 2.0.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +97 -31
- data/docs/API.md +76 -0
- data/docs/FILTERS.md +37 -0
- data/docs/MIGRATION.md +23 -0
- data/docs/PROTOCOLS.md +45 -0
- data/docs/USAGE.md +82 -0
- data/docs/VALIDATION.md +59 -0
- data/docs/json-schema.json +64 -0
- data/exe/redhound +2 -1
- data/lib/redhound/analysis/flow_key.rb +53 -0
- data/lib/redhound/analysis/flow_table.rb +117 -0
- data/lib/redhound/analysis/ip_reassembler.rb +176 -0
- data/lib/redhound/analysis/stats.rb +138 -0
- data/lib/redhound/analysis/tcp_analysis.rb +43 -0
- data/lib/redhound/analysis/tcp_reassembler.rb +124 -0
- data/lib/redhound/analysis/tcp_stream.rb +151 -0
- data/lib/redhound/analysis.rb +129 -0
- data/lib/redhound/capture/bsd/bpf_device.rb +152 -0
- data/lib/redhound/capture/bsd/constants.rb +29 -0
- data/lib/redhound/capture/file_source.rb +83 -0
- data/lib/redhound/capture/interface.rb +66 -0
- data/lib/redhound/capture/linktype.rb +30 -0
- data/lib/redhound/capture/linux/constants.rb +37 -0
- data/lib/redhound/capture/linux/cooked.rb +18 -0
- data/lib/redhound/capture/linux/ifreq.rb +42 -0
- data/lib/redhound/capture/linux/packet_socket.rb +180 -0
- data/lib/redhound/capture/linux/sockaddr_ll.rb +33 -0
- data/lib/redhound/capture/linux/tpacket_v3.rb +132 -0
- data/lib/redhound/capture/source.rb +79 -0
- data/lib/redhound/capture/stats.rb +22 -0
- data/lib/redhound/capture.rb +69 -0
- data/lib/redhound/cli/command.rb +42 -0
- data/lib/redhound/cli/options.rb +133 -0
- data/lib/redhound/cli/privileges.rb +29 -0
- data/lib/redhound/cli/runner.rb +129 -0
- data/lib/redhound/context.rb +20 -0
- data/lib/redhound/cursor.rb +69 -0
- data/lib/redhound/diagnostic.rb +7 -0
- data/lib/redhound/dissector.rb +138 -0
- data/lib/redhound/engine.rb +66 -0
- data/lib/redhound/errors.rb +38 -0
- data/lib/redhound/field.rb +62 -0
- data/lib/redhound/file/format.rb +56 -0
- data/lib/redhound/file/pcap_reader.rb +43 -0
- data/lib/redhound/file/pcap_writer.rb +72 -0
- data/lib/redhound/file/pcapng_reader.rb +209 -0
- data/lib/redhound/file/pcapng_writer.rb +143 -0
- data/lib/redhound/file/rotating_writer.rb +98 -0
- data/lib/redhound/filter/analyzer.rb +197 -0
- data/lib/redhound/filter/bpf/assembler.rb +121 -0
- data/lib/redhound/filter/bpf/disassembler.rb +58 -0
- data/lib/redhound/filter/bpf/validator.rb +77 -0
- data/lib/redhound/filter/bpf/vm.rb +108 -0
- data/lib/redhound/filter/codegen.rb +413 -0
- data/lib/redhound/filter/lexer.rb +46 -0
- data/lib/redhound/filter/parser.rb +206 -0
- data/lib/redhound/filter/program.rb +55 -0
- data/lib/redhound/filter.rb +30 -0
- data/lib/redhound/layer.rb +75 -0
- data/lib/redhound/output/fields.rb +20 -0
- data/lib/redhound/output/follow.rb +59 -0
- data/lib/redhound/output/hexdump.rb +29 -0
- data/lib/redhound/output/json.rb +32 -0
- data/lib/redhound/output/summary.rb +59 -0
- data/lib/redhound/output/timestamp.rb +34 -0
- data/lib/redhound/output/tree.rb +24 -0
- data/lib/redhound/packet.rb +63 -0
- data/lib/redhound/protocols/arp.rb +39 -0
- data/lib/redhound/protocols/checksum.rb +38 -0
- data/lib/redhound/protocols/data.rb +21 -0
- data/lib/redhound/protocols/dhcp.rb +124 -0
- data/lib/redhound/protocols/dns.rb +268 -0
- data/lib/redhound/protocols/ethernet.rb +24 -0
- data/lib/redhound/protocols/http.rb +183 -0
- data/lib/redhound/protocols/icmp.rb +191 -0
- data/lib/redhound/protocols/ipv4.rb +56 -0
- data/lib/redhound/protocols/ipv6.rb +65 -0
- data/lib/redhound/protocols/link.rb +70 -0
- data/lib/redhound/protocols/llc.rb +37 -0
- data/lib/redhound/protocols/ntp.rb +47 -0
- data/lib/redhound/protocols/tcp.rb +80 -0
- data/lib/redhound/protocols/tls.rb +218 -0
- data/lib/redhound/protocols/tunnel.rb +48 -0
- data/lib/redhound/protocols/udp.rb +32 -0
- data/lib/redhound/protocols/vlan.rb +23 -0
- data/lib/redhound/reader.rb +8 -0
- data/lib/redhound/registry.rb +64 -0
- data/lib/redhound/stream_dissector.rb +168 -0
- data/lib/redhound/util/seq.rb +21 -0
- data/lib/redhound/version.rb +2 -1
- data/lib/redhound/writer.rb +25 -43
- data/lib/redhound.rb +81 -9
- data/sig/generated/redhound/analysis/flow_key.rbs +15 -0
- data/sig/generated/redhound/analysis/flow_table.rbs +98 -0
- data/sig/generated/redhound/analysis/ip_reassembler.rbs +40 -0
- data/sig/generated/redhound/analysis/stats.rbs +77 -0
- data/sig/generated/redhound/analysis/tcp_analysis.rbs +15 -0
- data/sig/generated/redhound/analysis/tcp_reassembler.rbs +27 -0
- data/sig/generated/redhound/analysis/tcp_stream.rbs +60 -0
- data/sig/generated/redhound/analysis.rbs +38 -0
- data/sig/generated/redhound/capture/bsd/bpf_device.rbs +39 -0
- data/sig/generated/redhound/capture/bsd/constants.rbs +40 -0
- data/sig/generated/redhound/capture/file_source.rbs +34 -0
- data/sig/generated/redhound/capture/interface.rbs +53 -0
- data/sig/generated/redhound/capture/linktype.rbs +20 -0
- data/sig/generated/redhound/capture/linux/constants.rbs +58 -0
- data/sig/generated/redhound/capture/linux/cooked.rbs +15 -0
- data/sig/generated/redhound/capture/linux/ifreq.rbs +18 -0
- data/sig/generated/redhound/capture/linux/packet_socket.rbs +57 -0
- data/sig/generated/redhound/capture/linux/sockaddr_ll.rbs +31 -0
- data/sig/generated/redhound/capture/linux/tpacket_v3.rbs +35 -0
- data/sig/generated/redhound/capture/source.rbs +44 -0
- data/sig/generated/redhound/capture/stats.rbs +25 -0
- data/sig/generated/redhound/capture.rbs +14 -0
- data/sig/generated/redhound/cli/command.rbs +12 -0
- data/sig/generated/redhound/cli/options.rbs +25 -0
- data/sig/generated/redhound/cli/privileges.rbs +12 -0
- data/sig/generated/redhound/cli/runner.rbs +27 -0
- data/sig/generated/redhound/context.rbs +27 -0
- data/sig/generated/redhound/cursor.rbs +59 -0
- data/sig/generated/redhound/diagnostic.rbs +21 -0
- data/sig/generated/redhound/dissector.rbs +113 -0
- data/sig/generated/redhound/engine.rbs +23 -0
- data/sig/generated/redhound/errors.rbs +56 -0
- data/sig/generated/redhound/field.rbs +74 -0
- data/sig/generated/redhound/file/format.rbs +33 -0
- data/sig/generated/redhound/file/pcap_reader.rbs +19 -0
- data/sig/generated/redhound/file/pcap_writer.rbs +38 -0
- data/sig/generated/redhound/file/pcapng_reader.rbs +54 -0
- data/sig/generated/redhound/file/pcapng_writer.rbs +50 -0
- data/sig/generated/redhound/file/rotating_writer.rbs +42 -0
- data/sig/generated/redhound/filter/analyzer.rbs +42 -0
- data/sig/generated/redhound/filter/bpf/assembler.rbs +39 -0
- data/sig/generated/redhound/filter/bpf/disassembler.rbs +18 -0
- data/sig/generated/redhound/filter/bpf/validator.rbs +30 -0
- data/sig/generated/redhound/filter/bpf/vm.rbs +26 -0
- data/sig/generated/redhound/filter/codegen.rbs +101 -0
- data/sig/generated/redhound/filter/lexer.rbs +15 -0
- data/sig/generated/redhound/filter/parser.rbs +65 -0
- data/sig/generated/redhound/filter/program.rbs +48 -0
- data/sig/generated/redhound/filter.rbs +10 -0
- data/sig/generated/redhound/layer.rbs +81 -0
- data/sig/generated/redhound/output/fields.rbs +15 -0
- data/sig/generated/redhound/output/follow.rbs +21 -0
- data/sig/generated/redhound/output/hexdump.rbs +15 -0
- data/sig/generated/redhound/output/json.rbs +18 -0
- data/sig/generated/redhound/output/summary.rbs +21 -0
- data/sig/generated/redhound/output/timestamp.rbs +21 -0
- data/sig/generated/redhound/output/tree.rbs +15 -0
- data/sig/generated/redhound/packet.rbs +77 -0
- data/sig/generated/redhound/protocols/arp.rbs +15 -0
- data/sig/generated/redhound/protocols/checksum.rbs +15 -0
- data/sig/generated/redhound/protocols/data.rbs +15 -0
- data/sig/generated/redhound/protocols/dhcp.rbs +28 -0
- data/sig/generated/redhound/protocols/dns.rbs +42 -0
- data/sig/generated/redhound/protocols/ethernet.rbs +15 -0
- data/sig/generated/redhound/protocols/http.rbs +36 -0
- data/sig/generated/redhound/protocols/icmp.rbs +41 -0
- data/sig/generated/redhound/protocols/ipv4.rbs +15 -0
- data/sig/generated/redhound/protocols/ipv6.rbs +24 -0
- data/sig/generated/redhound/protocols/link.rbs +33 -0
- data/sig/generated/redhound/protocols/llc.rbs +15 -0
- data/sig/generated/redhound/protocols/ntp.rbs +17 -0
- data/sig/generated/redhound/protocols/tcp.rbs +25 -0
- data/sig/generated/redhound/protocols/tls.rbs +51 -0
- data/sig/generated/redhound/protocols/tunnel.rbs +24 -0
- data/sig/generated/redhound/protocols/udp.rbs +18 -0
- data/sig/generated/redhound/protocols/vlan.rbs +12 -0
- data/sig/generated/redhound/reader.rbs +7 -0
- data/sig/generated/redhound/registry.rbs +45 -0
- data/sig/generated/redhound/stream_dissector.rbs +44 -0
- data/sig/generated/redhound/util/seq.rbs +20 -0
- data/sig/generated/redhound/version.rbs +1 -0
- data/sig/generated/redhound/writer.rbs +6 -19
- data/sig/generated/redhound.rbs +18 -0
- data/sig/shims/io.rbs +7 -0
- data/sig/shims/process.rbs +3 -0
- metadata +175 -55
- data/CODE_OF_CONDUCT.md +0 -132
- data/Dockerfile +0 -7
- data/Rakefile +0 -15
- data/Steepfile +0 -4
- data/docker-compose.yml +0 -9
- data/lib/redhound/analyzer.rb +0 -34
- data/lib/redhound/builder/packet_mreq.rb +0 -56
- data/lib/redhound/builder/socket.rb +0 -35
- data/lib/redhound/builder.rb +0 -4
- data/lib/redhound/command.rb +0 -67
- data/lib/redhound/l2/ether.rb +0 -68
- data/lib/redhound/l2/protocol.rb +0 -33
- data/lib/redhound/l2.rb +0 -4
- data/lib/redhound/l3/arp.rb +0 -114
- data/lib/redhound/l3/base.rb +0 -49
- data/lib/redhound/l3/ipv4.rb +0 -95
- data/lib/redhound/l3/ipv6.rb +0 -69
- data/lib/redhound/l3/protocol.rb +0 -173
- data/lib/redhound/l3/resolver.rb +0 -30
- data/lib/redhound/l3.rb +0 -9
- data/lib/redhound/l4/base.rb +0 -31
- data/lib/redhound/l4/icmp.rb +0 -71
- data/lib/redhound/l4/resolver.rb +0 -28
- data/lib/redhound/l4/udp.rb +0 -63
- data/lib/redhound/l4.rb +0 -6
- data/lib/redhound/receiver.rb +0 -45
- data/lib/redhound/resolver.rb +0 -22
- data/lib/redhound/source/socket.rb +0 -18
- data/lib/redhound/source.rb +0 -3
- data/rbs_collection.lock.yaml +0 -20
- data/rbs_collection.yaml +0 -17
- data/sig/generated/redhound/analyzer.rbs +0 -14
- data/sig/generated/redhound/builder/packet_mreq.rbs +0 -39
- data/sig/generated/redhound/builder/socket.rbs +0 -24
- data/sig/generated/redhound/command.rbs +0 -19
- data/sig/generated/redhound/l2/ether.rbs +0 -41
- data/sig/generated/redhound/l2/protocol.rbs +0 -15
- data/sig/generated/redhound/l3/arp.rbs +0 -57
- data/sig/generated/redhound/l3/base.rbs +0 -28
- data/sig/generated/redhound/l3/ipv4.rbs +0 -53
- data/sig/generated/redhound/l3/ipv6.rbs +0 -38
- data/sig/generated/redhound/l3/protocol.rbs +0 -16
- data/sig/generated/redhound/l3/resolver.rbs +0 -16
- data/sig/generated/redhound/l4/base.rbs +0 -19
- data/sig/generated/redhound/l4/icmp.rbs +0 -33
- data/sig/generated/redhound/l4/resolver.rbs +0 -16
- data/sig/generated/redhound/l4/udp.rbs +0 -36
- data/sig/generated/redhound/receiver.rbs +0 -19
- data/sig/generated/redhound/resolver.rbs +0 -11
- data/sig/generated/redhound/source/socket.rbs +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd9c749a43481a575813ed4bacad00dbc54dfecc7701e63a0baeb6789a1d8680
|
|
4
|
+
data.tar.gz: 791efd1f3e810c7e67bcf5abfbbc3e02aa0db460bd8dca51b83beecd94797bae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99e69fb1319c95448572dcfc2151da08987523b95301c1b50f1f1345b269752cd98e4ddcd3c24f711866bc6b7754793061b51f1d208f92428dfd337a007ac444
|
|
7
|
+
data.tar.gz: 1081108559a19f9f17b0c482dc91285f4950b1f7dda81c4f1221e2eac76206831839d265d50139182060c203e12dfd7752e434ecfae2fa5479310260b039fa7f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 2.0.0.rc1 - 2026-10-01
|
|
6
|
+
|
|
7
|
+
### Breaking changes
|
|
8
|
+
|
|
9
|
+
- 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.
|
|
10
|
+
- Use a one-line summary by default. Select `-V` or `-T tree` for detailed output; `-v` controls verbosity and `--version` prints the version.
|
|
11
|
+
- Make `-w` save packets without dissection or display unless an output format is also selected.
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- Read and write pcap and pcapng, including stdin/stdout, interface metadata and size/time rotation.
|
|
16
|
+
- Capture on macOS BPF devices and Linux socket/TPACKET_V3 backends, including Linux `any`, directions, snaplen and drop statistics.
|
|
17
|
+
- Compile tcpdump-style capture filters to validated cBPF for kernel capture and file filtering; support filter files and instruction dumps.
|
|
18
|
+
- 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.
|
|
19
|
+
- Track flows, reassemble IP fragments and TCP application messages, report TCP analysis flags/RTT, and follow TCP streams as ASCII, hex or exact bytes.
|
|
20
|
+
- Add tree, hex, JSON/NDJSON and selected-field output, conversation/endpoint/interval/protocol statistics, decode-as overrides and custom Ruby dissectors.
|
|
21
|
+
- Support privilege dropping after capture setup and write capture files with private permissions.
|
|
22
|
+
|
|
23
|
+
### Bug fixes
|
|
24
|
+
|
|
25
|
+
- Fix crashes on padded ARP, short frames and malformed packet headers.
|
|
26
|
+
- Correct IPv4 and IPv6 fields, IP options and transport payload boundaries; label ICMP types/codes and avoid false checksum failures on incomplete IPv6 fragments.
|
|
27
|
+
- Display TCP ports, sequence numbers, flags and payload lengths.
|
|
28
|
+
- Escape terminal control characters in captured payloads.
|
|
29
|
+
- Save packets before analysis and close captures reliably on termination or errors.
|
|
30
|
+
- Capture larger frames with kernel timestamps and remove loopback duplicates.
|
|
31
|
+
- List interfaces without duplicates and accept interface indexes.
|
|
32
|
+
- Protect read inputs and their aliases from rotated-output overwrites, validate filters on empty captures, and stop stdin reads cleanly on termination.
|
|
33
|
+
- Decode foreign-endian loopback capture headers correctly and preserve original wire lengths for truncated VLAN packets.
|
|
34
|
+
- Handle HEAD responses and pipelined HTTP correctly, reassemble HTTP on nonstandard ports, and report missing or incomplete TCP data at FIN and EOF.
|
|
35
|
+
|
|
5
36
|
## 1.0.1 - 2025-01-17
|
|
6
37
|
|
|
7
38
|
- Fix an NameError in Redhound::L3::Arp
|
data/README.md
CHANGED
|
@@ -1,51 +1,117 @@
|
|
|
1
1
|
# Redhound [](https://badge.fury.io/rb/redhound) [](https://github.com/ydah/redhound/actions/workflows/main.yml)
|
|
2
2
|
|
|
3
|
-
Pure Ruby
|
|
4
|
-
|
|
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
|
-
|
|
8
|
+
Version 2 is currently a release candidate. See [validation status](docs/VALIDATION.md)
|
|
9
|
+
for remaining GA evaluation gates.
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
## Installation
|
|
9
12
|
|
|
10
|
-
```
|
|
11
|
-
|
|
13
|
+
```sh
|
|
14
|
+
gem install redhound --pre
|
|
12
15
|
```
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
Or add `gem 'redhound', '~> 2.0.0.rc1'` to your Gemfile.
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
29
|
-
Dump and analyze network packets.
|
|
82
|
+
## Library
|
|
30
83
|
|
|
31
|
-
|
|
84
|
+
```ruby
|
|
85
|
+
require 'redhound'
|
|
32
86
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
91
|
+
packet = Redhound.dissect(frame_bytes, linktype: :ethernet)
|
|
92
|
+
p packet['ip.src']
|
|
93
|
+
p packet.to_h
|
|
94
|
+
```
|
|
42
95
|
|
|
43
|
-
|
|
96
|
+
## Development
|
|
44
97
|
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
113
|
+
## Contributing and license
|
|
50
114
|
|
|
51
|
-
|
|
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,76 @@
|
|
|
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
|
+
|
|
30
|
+
`Redhound.dissect` creates an immutable-byte Packet and decodes its layers lazily.
|
|
31
|
+
Packet metadata includes `timestamp_ns`, `original_length`, `linktype`,
|
|
32
|
+
`interface`, `direction`, and `number`. `caplen`, `truncated?`, and `time` expose
|
|
33
|
+
capture properties. A symbol index selects the first Layer; a dotted string
|
|
34
|
+
selects a decoded field value. `layers_of`, `innermost`, and `field_values` expose
|
|
35
|
+
repeated or tunneled layers. Layer has `values`, `fields`, and `diagnostics`.
|
|
36
|
+
`to_h` follows [json-schema.json](json-schema.json); bytes use hexadecimal strings,
|
|
37
|
+
addresses use text, booleans remain booleans, repeated fields become arrays.
|
|
38
|
+
|
|
39
|
+
Writer accepts `format: :pcap|:pcapng`, `linktype`, `snaplen`, `precision`,
|
|
40
|
+
`packet_buffered`, `max_bytes`, `interval`, `file_count`, and
|
|
41
|
+
`post_rotate_command`. `write`/`<<`, `flush`, `write_stats`, and `close` are
|
|
42
|
+
available. Use a block for deterministic closure.
|
|
43
|
+
|
|
44
|
+
## Custom dissectors
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
class Example < Redhound::Dissector
|
|
48
|
+
protocol :example, name: 'Example protocol', short: 'EXAMPLE'
|
|
49
|
+
dissects_on 'udp.port', 9999
|
|
50
|
+
header do
|
|
51
|
+
uint16 :message_id, 'example.id'
|
|
52
|
+
uint8 :kind, 'example.kind'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def summary(layer)
|
|
56
|
+
"Example id #{layer[:message_id]}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Header fields support unsigned integers, MAC/IPv4/IPv6 addresses and bit fields.
|
|
62
|
+
Use `dissect(ctx, layer)` for bounded variable-length parsing through
|
|
63
|
+
`ctx.cursor`; append fields with `layer.add`. `next_dissector(ctx, layer)` returns
|
|
64
|
+
a registered dissector class, or nil. Child cursors cannot escape their packet
|
|
65
|
+
bounds. Truncated input creates a diagnostic. `REDHOUND_STRICT=1` re-raises
|
|
66
|
+
unexpected implementation errors for tests. Ordinary malformed input remains
|
|
67
|
+
safe. Registry copies allow per-session decode-as rules without changing global
|
|
68
|
+
registrations.
|
|
69
|
+
|
|
70
|
+
`Analysis::Session#update(packet)` adds flow/stream analysis and completed
|
|
71
|
+
application PDUs. It provides bounded flow/reassembly state and `snapshot`,
|
|
72
|
+
`finish`; library users opt into it explicitly. Reassembly does not modify the
|
|
73
|
+
packet's captured bytes. `Filter.compile(expression, linktype:)` returns a
|
|
74
|
+
validated cBPF Program with `match?`, `evaluate`, `serialize`, and `disassemble`.
|
|
75
|
+
|
|
76
|
+
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.0.0.rc1 is 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,45 @@
|
|
|
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 icmp.ident icmp.seq
|
|
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
|
+
|
|
41
|
+
Dissectors use checked cursors and parent payload boundaries. Truncation,
|
|
42
|
+
malformed lengths, checksum failures and reassembly gaps are available as
|
|
43
|
+
structured diagnostics. Checksum verification is enabled by `-v` or
|
|
44
|
+
`Engine.new(verify_checksums: true)`; outgoing/offloaded packets are marked
|
|
45
|
+
unverified.
|
data/docs/USAGE.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
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 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
|
+
|
|
80
|
+
Windows, Wi-Fi monitor mode, packet transmission, TLS decryption, complete
|
|
81
|
+
HTTP/2/QUIC dissection, display-filter syntax and a TUI are outside v2's scope.
|
|
82
|
+
See [release validation status](VALIDATION.md) before promoting a prerelease.
|
data/docs/VALIDATION.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Release validation
|
|
2
|
+
|
|
3
|
+
## 2.0.0.rc1
|
|
4
|
+
|
|
5
|
+
The implementation covers the v2 roadmap: the packet/dissector API, network and
|
|
6
|
+
application protocols, Ruby cBPF compiler/VM, Linux socket/ring and macOS BPF
|
|
7
|
+
backends, capture files/rotation/privilege drop, bounded stateful analysis,
|
|
8
|
+
statistics, follow output and documentation. This is a release candidate,
|
|
9
|
+
not a claim that time-dependent GA acceptance checks have completed.
|
|
10
|
+
|
|
11
|
+
Reproducible checks:
|
|
12
|
+
|
|
13
|
+
- `bundle exec rake`: RSpec, generated RBS and Steep.
|
|
14
|
+
- `REDHOUND_COVERAGE_GATE=1 bundle exec rake`: at least 90% total line coverage
|
|
15
|
+
and 95% protocol line coverage.
|
|
16
|
+
- `bundle exec rspec spec/differential`: tcpdump filter match/bytecode parity
|
|
17
|
+
(163 expressions across five link types), tshark protocol and stateful analysis
|
|
18
|
+
field/statistics/follow comparisons.
|
|
19
|
+
- `FUZZ_ITERATIONS=1000000 bundle exec rspec spec/fuzz`: strict parser fuzzing.
|
|
20
|
+
- `sudo -E env "PATH=$PATH" REDHOUND_LIVE=1 bundle exec rspec --tag live`:
|
|
21
|
+
native capture, attached filters, kernel time, snaplen, stop and loopback.
|
|
22
|
+
- `sudo -E env "PATH=$PATH" REDHOUND_LIVE=1 REDHOUND_NETNS=1 bundle exec rspec spec/integration/netns_capture_spec.rb --tag live`:
|
|
23
|
+
Linux veth socket/ring parity and offloaded VLAN restoration/filtering.
|
|
24
|
+
- `bundle exec yard stats --list-undoc`: documented public API.
|
|
25
|
+
- `actionlint`: test and release workflow validation.
|
|
26
|
+
|
|
27
|
+
Fixtures are generated without runtime dependencies. Golden output freezes
|
|
28
|
+
addresses and timestamps, and validates all JSON snapshots against the schema.
|
|
29
|
+
The CI matrix checks Ruby 3.3/3.4/4.0/head, Linux/macOS live capture and tool
|
|
30
|
+
comparisons. Scheduled runs execute one million fuzz cases. Benchmark jobs warn
|
|
31
|
+
on a summary throughput regression over 15% compared with the previous commit.
|
|
32
|
+
|
|
33
|
+
Local validation on 2026-10-01: Linux aarch64 Ruby 3.4 passed all 171 non-live
|
|
34
|
+
examples, including tcpdump/tshark differential checks, and five live capture
|
|
35
|
+
examples using socket and ring backends. Native macOS Ruby 4.0 passed unit,
|
|
36
|
+
golden and filter checks; BPF ioctl constants match the installed SDK. Native
|
|
37
|
+
BPF loopback and en0 Ethernet capture, attached filters, timestamps, truncation,
|
|
38
|
+
termination, privilege dropping and pcapng metadata passed the macOS CI job.
|
|
39
|
+
The Linux namespace test passed socket/ring parity and offloaded VLAN checks.
|
|
40
|
+
Ruby 3.3/3.4/4.0/head all passed the CI type, signature and coverage gates.
|
|
41
|
+
Whole-library line coverage measured 90.92%; isolated protocol line coverage
|
|
42
|
+
measured 99.90%. See [benchmarks](../bench/RESULTS.md)
|
|
43
|
+
for throughput figures and measurement limits.
|
|
44
|
+
|
|
45
|
+
## Remaining GA acceptance gates
|
|
46
|
+
|
|
47
|
+
- Run a 24-hour continuous capture stability check.
|
|
48
|
+
- Run a 72-hour rotation soak and record RSS, descriptor counts and drop rates.
|
|
49
|
+
- Run an hour of high-load aarch64 socket/ring comparison before changing its
|
|
50
|
+
automatic backend default.
|
|
51
|
+
- Confirm x86_64 single-core throughput and live drop targets on the specified
|
|
52
|
+
workload; file benchmarks alone cannot establish loss-free live throughput.
|
|
53
|
+
- Keep rc1 available for two weeks, classify reports, and fix critical/high
|
|
54
|
+
failures before GA.
|
|
55
|
+
|
|
56
|
+
These elapsed-time/hardware gates are not marked complete by unit tests.
|
|
57
|
+
Promote to 2.0.0 only after their evidence is recorded. A 1.x maintenance
|
|
58
|
+
end date is set at GA plus six months; no maintenance branch is created by this
|
|
59
|
+
main-only implementation.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/ydah/redhound/blob/main/docs/json-schema.json",
|
|
4
|
+
"title": "Redhound packet",
|
|
5
|
+
"description": "One packet object emitted by Packet#to_h, NDJSON, or an element of the JSON output array. Nanosecond timestamps and lengths are integers; byte fields use hexadecimal strings; repeated fields use arrays.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["frame", "layers", "diagnostics"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"frame": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"required": ["number", "time_epoch_ns", "time", "caplen", "len", "interface", "direction", "linktype"],
|
|
13
|
+
"additionalProperties": false,
|
|
14
|
+
"properties": {
|
|
15
|
+
"number": { "type": "integer", "minimum": 1 },
|
|
16
|
+
"time_epoch_ns": { "type": "integer" },
|
|
17
|
+
"time": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{9}Z$" },
|
|
18
|
+
"caplen": { "type": "integer", "minimum": 0 },
|
|
19
|
+
"len": { "type": "integer", "minimum": 0 },
|
|
20
|
+
"interface": { "type": ["string", "null"] },
|
|
21
|
+
"direction": { "enum": ["in", "out", null] },
|
|
22
|
+
"linktype": { "type": "integer", "minimum": 0 }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"layers": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["protocol", "offset", "length", "embedded", "fields"],
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"properties": {
|
|
32
|
+
"protocol": { "type": "string" },
|
|
33
|
+
"offset": { "type": "integer", "minimum": 0 },
|
|
34
|
+
"length": { "type": "integer", "minimum": 0 },
|
|
35
|
+
"embedded": { "type": "boolean" },
|
|
36
|
+
"fields": { "type": "object", "additionalProperties": { "$ref": "#/$defs/fieldValue" } }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"diagnostics": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"required": ["layer", "severity", "code", "message", "field"],
|
|
45
|
+
"additionalProperties": false,
|
|
46
|
+
"properties": {
|
|
47
|
+
"layer": { "type": "string" },
|
|
48
|
+
"severity": { "enum": ["note", "warn", "warning", "error"] },
|
|
49
|
+
"code": { "type": "string" },
|
|
50
|
+
"message": { "type": "string" },
|
|
51
|
+
"field": { "type": ["string", "null"] }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"$defs": {
|
|
57
|
+
"fieldValue": {
|
|
58
|
+
"anyOf": [
|
|
59
|
+
{ "type": ["string", "number", "boolean", "null"] },
|
|
60
|
+
{ "type": "array", "items": { "$ref": "#/$defs/fieldValue" } }
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
data/exe/redhound
CHANGED