redhound 0.2.0 → 1.0.1
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 +16 -3
- data/Dockerfile +1 -1
- data/README.md +2 -2
- data/Rakefile +12 -1
- data/Steepfile +4 -0
- data/lib/redhound/analyzer.rb +19 -15
- data/lib/redhound/builder/packet_mreq.rb +56 -0
- data/lib/redhound/builder/socket.rb +35 -0
- data/lib/redhound/builder.rb +4 -0
- data/lib/redhound/command.rb +6 -1
- data/lib/redhound/l2/ether.rb +68 -0
- data/lib/redhound/l2/protocol.rb +33 -0
- data/lib/redhound/l2.rb +4 -0
- data/lib/redhound/l3/arp.rb +114 -0
- data/lib/redhound/l3/base.rb +49 -0
- data/lib/redhound/{header → l3}/ipv4.rb +27 -44
- data/lib/redhound/l3/ipv6.rb +69 -0
- data/lib/redhound/l3/protocol.rb +173 -0
- data/lib/redhound/l3/resolver.rb +30 -0
- data/lib/redhound/l3.rb +9 -0
- data/lib/redhound/l4/base.rb +31 -0
- data/lib/redhound/{header → l4}/icmp.rb +20 -26
- data/lib/redhound/l4/resolver.rb +28 -0
- data/lib/redhound/{header → l4}/udp.rb +19 -19
- data/lib/redhound/l4.rb +6 -0
- data/lib/redhound/receiver.rb +17 -5
- data/lib/redhound/resolver.rb +22 -0
- data/lib/redhound/source/socket.rb +18 -0
- data/lib/redhound/source.rb +3 -0
- data/lib/redhound/version.rb +2 -1
- data/lib/redhound/writer.rb +9 -2
- data/lib/redhound.rb +6 -3
- data/rbs_collection.lock.yaml +20 -0
- data/rbs_collection.yaml +17 -0
- data/sig/generated/redhound/analyzer.rbs +14 -0
- data/sig/generated/redhound/builder/packet_mreq.rbs +39 -0
- data/sig/generated/redhound/builder/socket.rbs +24 -0
- data/sig/generated/redhound/command.rbs +19 -0
- data/sig/generated/redhound/l2/ether.rbs +41 -0
- data/sig/generated/redhound/l2/protocol.rbs +15 -0
- data/sig/generated/redhound/l3/arp.rbs +57 -0
- data/sig/generated/redhound/l3/base.rbs +28 -0
- data/sig/generated/redhound/l3/ipv4.rbs +53 -0
- data/sig/generated/redhound/l3/ipv6.rbs +38 -0
- data/sig/generated/redhound/l3/protocol.rbs +16 -0
- data/sig/generated/redhound/l3/resolver.rbs +16 -0
- data/sig/generated/redhound/l4/base.rbs +19 -0
- data/sig/generated/redhound/l4/icmp.rbs +33 -0
- data/sig/generated/redhound/l4/resolver.rbs +16 -0
- data/sig/generated/redhound/l4/udp.rbs +36 -0
- data/sig/generated/redhound/receiver.rbs +19 -0
- data/sig/generated/redhound/resolver.rbs +11 -0
- data/sig/generated/redhound/source/socket.rbs +13 -0
- data/sig/generated/redhound/version.rbs +5 -0
- data/sig/generated/redhound/writer.rbs +25 -0
- metadata +48 -11
- data/lib/redhound/header/ether.rb +0 -67
- data/lib/redhound/header.rb +0 -6
- data/lib/redhound/packet_mreq.rb +0 -46
- data/lib/redhound/socket_builder.rb +0 -30
- data/sig/redhound.rbs +0 -4
@@ -0,0 +1,69 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class L3
|
6
|
+
class Ipv6 < Base
|
7
|
+
class << self
|
8
|
+
# @rbs (bytes: Array[Integer]) -> Redhound::L3::Ipv6
|
9
|
+
def generate(bytes:)
|
10
|
+
new(bytes:).generate
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :protocol #: Protocol
|
15
|
+
|
16
|
+
# @rbs (bytes: Array[Integer]) -> void
|
17
|
+
def initialize(bytes:)
|
18
|
+
raise ArgumentError, "bytes must be bigger than #{size} bytes" unless bytes.size >= size
|
19
|
+
|
20
|
+
@bytes = bytes
|
21
|
+
end
|
22
|
+
|
23
|
+
# @rbs () -> Integer
|
24
|
+
def size = 40
|
25
|
+
|
26
|
+
# @rbs () -> Redhound::L3::Ipv6
|
27
|
+
def generate
|
28
|
+
version_traffic_flow = @bytes[0..3].join.to_i(16)
|
29
|
+
@version = (version_traffic_flow >> 28) & 0xF
|
30
|
+
@traffic_class = (version_traffic_flow >> 20) & 0xFF
|
31
|
+
@flow_label = version_traffic_flow & 0xFFFFF
|
32
|
+
@payload_length = @bytes[4..5]
|
33
|
+
@next_header = @bytes[6]
|
34
|
+
@hop_limit = @bytes[7]
|
35
|
+
@saddr = @bytes[8..23]
|
36
|
+
@daddr = @bytes[24..39]
|
37
|
+
@protocol = Protocol.new(protocol: @next_header)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# @rbs () -> String
|
42
|
+
def to_s
|
43
|
+
" └─ IPv6 Ver: #{@version} Traffic Class: #{@traffic_class} Flow Label: #{@flow_label} Payload Length: #{payload_length} Next Header: #{@protocol} Hop Limit: #{@hop_limit} Src: #{saddr} Dst: #{daddr}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# @rbs () -> bool
|
47
|
+
def supported_protocol?
|
48
|
+
@protocol.udp? # steep:ignore
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @rbs () -> Integer
|
54
|
+
def payload_length
|
55
|
+
@payload_length.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @rbs () -> Integer
|
59
|
+
def saddr
|
60
|
+
@saddr.map { |b| b.to_s(16).rjust(2, '0') }.join(':')
|
61
|
+
end
|
62
|
+
|
63
|
+
# @rbs () -> Integer
|
64
|
+
def daddr
|
65
|
+
@daddr.map { |b| b.to_s(16).rjust(2, '0') }.join(':')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class L3
|
6
|
+
class Protocol
|
7
|
+
# refs: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml#protocol-numbers-1
|
8
|
+
PROTO_TABLE = {
|
9
|
+
0 => 'HOPOPT',
|
10
|
+
1 => 'ICMP',
|
11
|
+
2 => 'IGMP',
|
12
|
+
3 => 'GGP',
|
13
|
+
4 => 'IP-in-IP',
|
14
|
+
5 => 'ST',
|
15
|
+
6 => 'TCP',
|
16
|
+
7 => 'CBT',
|
17
|
+
8 => 'EGP',
|
18
|
+
9 => 'IGP',
|
19
|
+
10 => 'BBN-RCC-MON',
|
20
|
+
11 => 'NVP-II',
|
21
|
+
12 => 'PUP',
|
22
|
+
13 => 'ARGUS',
|
23
|
+
14 => 'EMCON',
|
24
|
+
15 => 'XNET',
|
25
|
+
16 => 'CHAOS',
|
26
|
+
17 => 'UDP',
|
27
|
+
18 => 'MUX',
|
28
|
+
19 => 'DCN-MEAS',
|
29
|
+
20 => 'HMP',
|
30
|
+
21 => 'PRM',
|
31
|
+
22 => 'XNS-IDP',
|
32
|
+
23 => 'TRUNK-1',
|
33
|
+
24 => 'TRUNK-2',
|
34
|
+
25 => 'LEAF-1',
|
35
|
+
26 => 'LEAF-2',
|
36
|
+
27 => 'RDP',
|
37
|
+
28 => 'IRTP',
|
38
|
+
29 => 'ISO-TP4',
|
39
|
+
30 => 'NETBLT',
|
40
|
+
31 => 'MFE-NSP',
|
41
|
+
32 => 'MERIT-INP',
|
42
|
+
33 => 'DCCP',
|
43
|
+
34 => '3PC',
|
44
|
+
35 => 'IDPR',
|
45
|
+
36 => 'XTP',
|
46
|
+
37 => 'DDP',
|
47
|
+
38 => 'IDPR-CMTP',
|
48
|
+
39 => 'TP++',
|
49
|
+
40 => 'IL',
|
50
|
+
41 => 'IPv6',
|
51
|
+
42 => 'SDRP',
|
52
|
+
43 => 'IPv6-Route',
|
53
|
+
44 => 'IPv6-Frag',
|
54
|
+
45 => 'IDRP',
|
55
|
+
46 => 'RSVP',
|
56
|
+
47 => 'GRE',
|
57
|
+
48 => 'DSR',
|
58
|
+
49 => 'BNA',
|
59
|
+
50 => 'ESP',
|
60
|
+
51 => 'AH',
|
61
|
+
52 => 'I-NLSP',
|
62
|
+
53 => 'SWIPE',
|
63
|
+
54 => 'NARP',
|
64
|
+
55 => 'MOBILE',
|
65
|
+
56 => 'TLSP',
|
66
|
+
57 => 'SKIP',
|
67
|
+
58 => 'IPv6-ICMP',
|
68
|
+
59 => 'IPv6-NoNxt',
|
69
|
+
60 => 'IPv6-Opts',
|
70
|
+
61 => 'Any host internal protocol',
|
71
|
+
62 => 'CFTP',
|
72
|
+
63 => 'Any local network',
|
73
|
+
64 => 'SAT-EXPAK',
|
74
|
+
65 => 'KRYPTOLAN',
|
75
|
+
66 => 'RVD',
|
76
|
+
67 => 'IPPC',
|
77
|
+
68 => 'Any distributed file system',
|
78
|
+
69 => 'SAT-MON',
|
79
|
+
70 => 'VISA',
|
80
|
+
71 => 'IPCV',
|
81
|
+
72 => 'CPNX',
|
82
|
+
73 => 'CPHB',
|
83
|
+
74 => 'WSN',
|
84
|
+
75 => 'PVP',
|
85
|
+
76 => 'BR-SAT-MON',
|
86
|
+
77 => 'SUN-ND',
|
87
|
+
78 => 'WB-MON',
|
88
|
+
79 => 'WB-EXPAK',
|
89
|
+
80 => 'ISO-IP',
|
90
|
+
81 => 'VMTP',
|
91
|
+
82 => 'SECURE-VMTP',
|
92
|
+
83 => 'VINES',
|
93
|
+
84 => 'TTP',
|
94
|
+
85 => 'NSFNET-IGP',
|
95
|
+
86 => 'DGP',
|
96
|
+
87 => 'TCF',
|
97
|
+
88 => 'EIGRP',
|
98
|
+
89 => 'OSPFIGP',
|
99
|
+
90 => 'Sprite-RPC',
|
100
|
+
91 => 'LARP',
|
101
|
+
92 => 'MTP',
|
102
|
+
93 => 'AX.25',
|
103
|
+
94 => 'IPIP',
|
104
|
+
95 => 'MICP',
|
105
|
+
96 => 'SCC-SP',
|
106
|
+
97 => 'ETHERIP',
|
107
|
+
98 => 'ENCAP',
|
108
|
+
99 => 'Any private encryption scheme',
|
109
|
+
100 => 'GMTP',
|
110
|
+
101 => 'IFMP',
|
111
|
+
102 => 'PNNI',
|
112
|
+
103 => 'PIM',
|
113
|
+
104 => 'ARIS',
|
114
|
+
105 => 'SCPS',
|
115
|
+
106 => 'QNX',
|
116
|
+
107 => 'A/N',
|
117
|
+
108 => 'IPComp',
|
118
|
+
109 => 'SNP',
|
119
|
+
110 => 'Compaq-Peer',
|
120
|
+
111 => 'IPX-in-IP',
|
121
|
+
112 => 'VRRP',
|
122
|
+
113 => 'PGM',
|
123
|
+
114 => 'Any 0-hop protocol',
|
124
|
+
115 => 'L2TP',
|
125
|
+
116 => 'DDX',
|
126
|
+
117 => 'IATP',
|
127
|
+
118 => 'STP',
|
128
|
+
119 => 'SRP',
|
129
|
+
120 => 'UTI',
|
130
|
+
121 => 'SMP',
|
131
|
+
122 => 'SM',
|
132
|
+
123 => 'PTP',
|
133
|
+
124 => 'IS-IS over IPv4',
|
134
|
+
125 => 'FIRE',
|
135
|
+
126 => 'CRTP',
|
136
|
+
127 => 'CRUDP',
|
137
|
+
128 => 'SSCOPMCE',
|
138
|
+
129 => 'IPLT',
|
139
|
+
130 => 'SPS',
|
140
|
+
131 => 'PIPE',
|
141
|
+
132 => 'SCTP',
|
142
|
+
133 => 'FC',
|
143
|
+
134 => 'RSVP-E2E-IGNORE',
|
144
|
+
135 => 'Mobility Header',
|
145
|
+
136 => 'UDPLite',
|
146
|
+
137 => 'MPLS-in-IP',
|
147
|
+
138 => 'manet',
|
148
|
+
139 => 'HIP',
|
149
|
+
140 => 'Shim6',
|
150
|
+
141 => 'WESP',
|
151
|
+
142 => 'ROHC',
|
152
|
+
255 => 'Reserved'
|
153
|
+
}.freeze
|
154
|
+
|
155
|
+
# @rbs (protocol: Integer) -> void
|
156
|
+
def initialize(protocol:)
|
157
|
+
@protocol = protocol
|
158
|
+
end
|
159
|
+
|
160
|
+
# @rbs () -> String
|
161
|
+
def to_s
|
162
|
+
PROTO_TABLE[@protocol] || 'Unknown'
|
163
|
+
end
|
164
|
+
|
165
|
+
PROTO_TABLE.each do |code, name|
|
166
|
+
method_name = name.downcase.gsub(/[ \-]/, '_') + '?'
|
167
|
+
define_method(method_name) do
|
168
|
+
@protocol == code
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class L3
|
6
|
+
class Resolver
|
7
|
+
# @rbs (bytes: Array[Integer], l2: Redhound::L2::Ether) -> Redhound::L3::Base?
|
8
|
+
def self.resolve(bytes:, l2:)
|
9
|
+
new(bytes:, l2:).resolve
|
10
|
+
end
|
11
|
+
|
12
|
+
# @rbs (bytes: Array[Integer], l2: Redhound::L2::Ether) -> void
|
13
|
+
def initialize(bytes:, l2:)
|
14
|
+
@bytes = bytes
|
15
|
+
@l2 = l2
|
16
|
+
end
|
17
|
+
|
18
|
+
# @rbs () -> Redhound::L3::Base?
|
19
|
+
def resolve
|
20
|
+
if @l2.type.ipv4?
|
21
|
+
Ipv4.generate(bytes: @bytes)
|
22
|
+
elsif @l2.type.ipv6?
|
23
|
+
Ipv6.generate(bytes: @bytes)
|
24
|
+
elsif @l2.type.arp?
|
25
|
+
Arp.generate(bytes: @bytes)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/redhound/l3.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class L4
|
6
|
+
class Base
|
7
|
+
class << self
|
8
|
+
# @rbs (bytes: Array[Integer]) -> Redhound::L4::Base
|
9
|
+
def generate(bytes:)
|
10
|
+
new(bytes:).generate
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @rbs (bytes: Array[Integer]) -> void
|
15
|
+
def initialize(bytes:)
|
16
|
+
warn 'initialize method must be implemented'
|
17
|
+
end
|
18
|
+
|
19
|
+
# @rbs () -> Redhound::L4::Base
|
20
|
+
def generate
|
21
|
+
warn 'generate method must be implemented'
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
# @rbs () -> void
|
26
|
+
def dump
|
27
|
+
puts self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,20 +1,17 @@
|
|
1
|
+
# rbs_inline: enabled
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Redhound
|
4
|
-
class
|
5
|
-
class Icmp
|
6
|
-
|
7
|
-
def generate(bytes:)
|
8
|
-
new(bytes:).generate
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
5
|
+
class L4
|
6
|
+
class Icmp < Base
|
7
|
+
# @rbs (bytes: Array[Integer]) -> void
|
12
8
|
def initialize(bytes:)
|
13
|
-
raise ArgumentError,
|
9
|
+
raise ArgumentError, "bytes must be bigger than #{size} bytes" unless bytes.size >= size
|
14
10
|
|
15
11
|
@bytes = bytes
|
16
12
|
end
|
17
13
|
|
14
|
+
# @rbs () -> Redhound::L4::Icmp
|
18
15
|
def generate
|
19
16
|
@type = @bytes[0]
|
20
17
|
@code = @bytes[1]
|
@@ -30,47 +27,44 @@ module Redhound
|
|
30
27
|
self
|
31
28
|
end
|
32
29
|
|
33
|
-
|
34
|
-
|
35
|
-
puts self
|
36
|
-
end
|
30
|
+
# @rbs () -> Integer
|
31
|
+
def size = 8
|
37
32
|
|
33
|
+
# @rbs () -> String
|
38
34
|
def to_s
|
39
35
|
if @type.zero? || @type == 8
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
Checksum: #{check}
|
44
|
-
ID: #{id}
|
45
|
-
Sequence: #{seq}
|
46
|
-
Data: #{data}
|
36
|
+
<<-ICMP.chomp
|
37
|
+
└─ ICMP Type: #{@type} Code: #{@code} Checksum: #{check} ID: #{id} Sequence: #{seq}
|
38
|
+
└─ Payload: #{data}
|
47
39
|
ICMP
|
48
40
|
else
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
Checksum: #{check}
|
53
|
-
Data: #{data}
|
41
|
+
<<-ICMP.chomp
|
42
|
+
└─ ICMP Type: #{@type} Code: #{@code} Checksum: #{check}
|
43
|
+
└─ Payload: #{data}
|
54
44
|
ICMP
|
55
45
|
end
|
56
46
|
end
|
57
47
|
|
58
48
|
private
|
59
49
|
|
50
|
+
# @rbs () -> Integer
|
60
51
|
def check
|
61
52
|
@check.map { |b| b.to_s(16).rjust(2, '0') }.join
|
62
53
|
end
|
63
54
|
|
55
|
+
# @rbs () -> Integer
|
64
56
|
def id
|
65
57
|
@id.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
66
58
|
end
|
67
59
|
|
60
|
+
# @rbs () -> Integer
|
68
61
|
def seq
|
69
62
|
@seq.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
70
63
|
end
|
71
64
|
|
65
|
+
# @rbs () -> String
|
72
66
|
def data
|
73
|
-
@data.map(&:chr).join
|
67
|
+
@data.map(&:chr).join.force_encoding("UTF-8")
|
74
68
|
end
|
75
69
|
end
|
76
70
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class L4
|
6
|
+
class Resolver
|
7
|
+
# @rbs (bytes: Array[Integer], l3: Redhound::L3::Base) -> Redhound::L4::Base?
|
8
|
+
def self.resolve(bytes:, l3:)
|
9
|
+
new(bytes:, l3:).resolve
|
10
|
+
end
|
11
|
+
|
12
|
+
# @rbs (bytes: Array[Integer], l3: Redhound::L3::Base) -> void
|
13
|
+
def initialize(bytes:, l3:)
|
14
|
+
@bytes = bytes
|
15
|
+
@l3 = l3
|
16
|
+
end
|
17
|
+
|
18
|
+
# @rbs () -> Redhound::L4::Base?
|
19
|
+
def resolve
|
20
|
+
if @l3.protocol.udp?
|
21
|
+
Udp.generate(bytes: @bytes)
|
22
|
+
elsif @l3.protocol.icmp?
|
23
|
+
Icmp.generate(bytes: @bytes)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,20 +1,17 @@
|
|
1
|
+
# rbs_inline: enabled
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Redhound
|
4
|
-
class
|
5
|
-
class Udp
|
6
|
-
|
7
|
-
def generate(bytes:)
|
8
|
-
new(bytes:).generate
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
5
|
+
class L4
|
6
|
+
class Udp < Base
|
7
|
+
# @rbs (bytes: Array[Integer]) -> void
|
12
8
|
def initialize(bytes:)
|
13
|
-
raise ArgumentError,
|
9
|
+
raise ArgumentError, "bytes must be bigger than #{size} bytes" unless bytes.size >= size
|
14
10
|
|
15
11
|
@bytes = bytes
|
16
12
|
end
|
17
13
|
|
14
|
+
# @rbs () -> Redhound::L4::Udp
|
18
15
|
def generate
|
19
16
|
@sport = @bytes[0..1]
|
20
17
|
@dport = @bytes[2..3]
|
@@ -24,37 +21,40 @@ module Redhound
|
|
24
21
|
self
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
puts self
|
30
|
-
end
|
24
|
+
# @rbs () -> Integer
|
25
|
+
def size = 8
|
31
26
|
|
27
|
+
# @rbs () -> String
|
32
28
|
def to_s
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
Length: #{len}
|
37
|
-
Checksum: #{check}
|
38
|
-
Data: #{data}
|
29
|
+
<<-UDP
|
30
|
+
└─ UDP Src: #{sport} Dst: #{dport} Len: #{len} Checksum: #{check}
|
31
|
+
└─ Payload: #{data}
|
39
32
|
UDP
|
40
33
|
end
|
41
34
|
|
35
|
+
private
|
36
|
+
|
37
|
+
# @rbs () -> Integer
|
42
38
|
def sport
|
43
39
|
@sport.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
44
40
|
end
|
45
41
|
|
42
|
+
# @rbs () -> Integer
|
46
43
|
def dport
|
47
44
|
@dport.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
48
45
|
end
|
49
46
|
|
47
|
+
# @rbs () -> Integer
|
50
48
|
def len
|
51
49
|
@len.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
52
50
|
end
|
53
51
|
|
52
|
+
# @rbs () -> Integer
|
54
53
|
def check
|
55
54
|
@check.map { |b| b.to_s(16).rjust(2, '0') }.join.to_i(16)
|
56
55
|
end
|
57
56
|
|
57
|
+
# @rbs () -> String
|
58
58
|
def data
|
59
59
|
@data.map(&:chr).join
|
60
60
|
end
|
data/lib/redhound/l4.rb
ADDED
data/lib/redhound/receiver.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# rbs_inline: enabled
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'socket'
|
@@ -5,29 +6,40 @@ require 'socket'
|
|
5
6
|
module Redhound
|
6
7
|
class Receiver
|
7
8
|
class << self
|
9
|
+
# @rbs (ifname: String, filename: String) -> void
|
8
10
|
def run(ifname:, filename:)
|
9
11
|
new(ifname:, filename:).run
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
15
|
+
# @rbs (ifname: String, filename: String) -> void
|
13
16
|
def initialize(ifname:, filename:)
|
14
17
|
@ifname = ifname
|
15
|
-
@
|
18
|
+
@source = Resolver.resolve(ifname:)
|
16
19
|
if filename
|
17
20
|
@writer = Writer.new(filename:)
|
18
21
|
@writer.start
|
19
22
|
end
|
23
|
+
@count = 0
|
20
24
|
end
|
21
25
|
|
26
|
+
# @rbs () -> void
|
22
27
|
def run
|
23
28
|
loop do
|
24
|
-
msg, = @
|
25
|
-
Analyzer.analyze(msg:)
|
26
|
-
@writer
|
29
|
+
msg, = @source.next_packet
|
30
|
+
Analyzer.analyze(msg:, count: increment)
|
31
|
+
@writer&.write(msg:)
|
27
32
|
rescue Interrupt
|
28
|
-
@writer
|
33
|
+
@writer&.stop
|
29
34
|
break
|
30
35
|
end
|
31
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @rbs () -> Integer
|
41
|
+
def increment
|
42
|
+
@count.tap { @count += 1 }
|
43
|
+
end
|
32
44
|
end
|
33
45
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
class Resolver
|
6
|
+
class << self
|
7
|
+
# @rbs (ifname: String) -> void
|
8
|
+
def resolve(ifname:)
|
9
|
+
new.resolve(ifname:)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @rbs (ifname: String) -> Redhound::Source::Socket
|
14
|
+
def resolve(ifname:)
|
15
|
+
if RUBY_PLATFORM =~ /darwin/
|
16
|
+
raise 'Not implemented yet'
|
17
|
+
else
|
18
|
+
Redhound::Builder::Socket.build(ifname:)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Redhound
|
5
|
+
module Source
|
6
|
+
class Socket
|
7
|
+
# @rbs (socket: ::Socket) -> void
|
8
|
+
def initialize(socket:)
|
9
|
+
@socket = socket
|
10
|
+
end
|
11
|
+
|
12
|
+
# @rbs (Integer size) -> [String, Addrinfo]
|
13
|
+
def next_packet(size = 2048)
|
14
|
+
@socket.recvfrom(size)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/redhound/version.rb
CHANGED
data/lib/redhound/writer.rb
CHANGED
@@ -1,27 +1,33 @@
|
|
1
|
+
# rbs_inline: enabled
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Redhound
|
4
5
|
class Writer
|
6
|
+
# @rbs (filename: String) -> void
|
5
7
|
def initialize(filename:)
|
6
8
|
@filename = filename
|
7
9
|
end
|
8
10
|
|
11
|
+
# @rbs () -> void
|
9
12
|
def start
|
10
13
|
@file = File.open(@filename, 'wb')
|
11
14
|
@file.write(file_header)
|
12
15
|
end
|
13
16
|
|
14
|
-
|
17
|
+
# @rbs (msg: String) -> void
|
18
|
+
def write(msg:)
|
15
19
|
@file.write(packet_record(Time.now, msg.bytesize, msg.bytesize))
|
16
20
|
@file.write(msg)
|
17
21
|
end
|
18
22
|
|
23
|
+
# @rbs () -> void
|
19
24
|
def stop
|
20
25
|
@file.close
|
21
26
|
end
|
22
27
|
|
23
28
|
private
|
24
29
|
|
30
|
+
# @rbs () -> String
|
25
31
|
def file_header
|
26
32
|
[
|
27
33
|
0xa1b2c3d4, # Magic Number (little-endian)
|
@@ -34,10 +40,11 @@ module Redhound
|
|
34
40
|
].pack('VvvVVVV')
|
35
41
|
end
|
36
42
|
|
43
|
+
# @rbs (Time timestamp, Integer captured_length, Integer original_length) -> String
|
37
44
|
def packet_record(timestamp, captured_length, original_length)
|
38
45
|
[
|
39
46
|
timestamp.to_i, # Timestamp seconds
|
40
|
-
|
47
|
+
timestamp.usec || 0, # Timestamp microseconds
|
41
48
|
captured_length, # Captured packet length
|
42
49
|
original_length # Original packet length
|
43
50
|
].pack('VVVV')
|
data/lib/redhound.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'redhound/analyzer'
|
4
|
+
require_relative 'redhound/builder'
|
4
5
|
require_relative 'redhound/command'
|
5
|
-
require_relative 'redhound/
|
6
|
-
require_relative 'redhound/
|
6
|
+
require_relative 'redhound/l2'
|
7
|
+
require_relative 'redhound/l3'
|
8
|
+
require_relative 'redhound/l4'
|
7
9
|
require_relative 'redhound/receiver'
|
8
|
-
require_relative 'redhound/
|
10
|
+
require_relative 'redhound/resolver'
|
11
|
+
require_relative 'redhound/source'
|
9
12
|
require_relative 'redhound/version'
|
10
13
|
require_relative 'redhound/writer'
|