redhound 0.2.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -3
  3. data/Dockerfile +1 -1
  4. data/README.md +2 -2
  5. data/Rakefile +12 -1
  6. data/Steepfile +4 -0
  7. data/lib/redhound/analyzer.rb +19 -15
  8. data/lib/redhound/builder/packet_mreq.rb +56 -0
  9. data/lib/redhound/builder/socket.rb +35 -0
  10. data/lib/redhound/builder.rb +4 -0
  11. data/lib/redhound/command.rb +6 -1
  12. data/lib/redhound/l2/ether.rb +68 -0
  13. data/lib/redhound/l2/protocol.rb +33 -0
  14. data/lib/redhound/l2.rb +4 -0
  15. data/lib/redhound/l3/arp.rb +114 -0
  16. data/lib/redhound/l3/base.rb +49 -0
  17. data/lib/redhound/{header → l3}/ipv4.rb +27 -44
  18. data/lib/redhound/l3/ipv6.rb +69 -0
  19. data/lib/redhound/l3/protocol.rb +173 -0
  20. data/lib/redhound/l3/resolver.rb +30 -0
  21. data/lib/redhound/l3.rb +9 -0
  22. data/lib/redhound/l4/base.rb +31 -0
  23. data/lib/redhound/{header → l4}/icmp.rb +20 -26
  24. data/lib/redhound/l4/resolver.rb +28 -0
  25. data/lib/redhound/{header → l4}/udp.rb +19 -19
  26. data/lib/redhound/l4.rb +6 -0
  27. data/lib/redhound/receiver.rb +17 -5
  28. data/lib/redhound/resolver.rb +22 -0
  29. data/lib/redhound/source/socket.rb +18 -0
  30. data/lib/redhound/source.rb +3 -0
  31. data/lib/redhound/version.rb +2 -1
  32. data/lib/redhound/writer.rb +9 -2
  33. data/lib/redhound.rb +6 -3
  34. data/rbs_collection.lock.yaml +20 -0
  35. data/rbs_collection.yaml +17 -0
  36. data/sig/generated/redhound/analyzer.rbs +14 -0
  37. data/sig/generated/redhound/builder/packet_mreq.rbs +39 -0
  38. data/sig/generated/redhound/builder/socket.rbs +24 -0
  39. data/sig/generated/redhound/command.rbs +19 -0
  40. data/sig/generated/redhound/l2/ether.rbs +41 -0
  41. data/sig/generated/redhound/l2/protocol.rbs +15 -0
  42. data/sig/generated/redhound/l3/arp.rbs +57 -0
  43. data/sig/generated/redhound/l3/base.rbs +28 -0
  44. data/sig/generated/redhound/l3/ipv4.rbs +53 -0
  45. data/sig/generated/redhound/l3/ipv6.rbs +38 -0
  46. data/sig/generated/redhound/l3/protocol.rbs +16 -0
  47. data/sig/generated/redhound/l3/resolver.rbs +16 -0
  48. data/sig/generated/redhound/l4/base.rbs +19 -0
  49. data/sig/generated/redhound/l4/icmp.rbs +33 -0
  50. data/sig/generated/redhound/l4/resolver.rbs +16 -0
  51. data/sig/generated/redhound/l4/udp.rbs +36 -0
  52. data/sig/generated/redhound/receiver.rbs +19 -0
  53. data/sig/generated/redhound/resolver.rbs +11 -0
  54. data/sig/generated/redhound/source/socket.rbs +13 -0
  55. data/sig/generated/redhound/version.rbs +5 -0
  56. data/sig/generated/redhound/writer.rbs +25 -0
  57. metadata +48 -11
  58. data/lib/redhound/header/ether.rb +0 -67
  59. data/lib/redhound/header.rb +0 -6
  60. data/lib/redhound/packet_mreq.rb +0 -46
  61. data/lib/redhound/socket_builder.rb +0 -30
  62. 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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'l3/base'
4
+
5
+ require_relative 'l3/arp'
6
+ require_relative 'l3/ipv4'
7
+ require_relative 'l3/ipv6'
8
+ require_relative 'l3/protocol'
9
+ require_relative 'l3/resolver'
@@ -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 Header
5
- class Icmp
6
- class << self
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, 'bytes must be bigger than 8 bytes' unless bytes.size >= 8
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
- def dump
34
- puts 'ICMP HEADER----------------'
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
- <<~ICMP
41
- Type: #{@type}
42
- Code: #{@code}
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
- <<~ICMP
50
- Type: #{@type}
51
- Code: #{@code}
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 Header
5
- class Udp
6
- class << self
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, 'bytes must be bigger than 8 bytes' unless bytes.size >= 8
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
- def dump
28
- puts 'UDP HEADER----------------'
29
- puts self
30
- end
24
+ # @rbs () -> Integer
25
+ def size = 8
31
26
 
27
+ # @rbs () -> String
32
28
  def to_s
33
- <<~UDP
34
- Source Port: #{sport}
35
- Destination Port: #{dport}
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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'l4/base'
4
+ require_relative 'l4/icmp'
5
+ require_relative 'l4/resolver'
6
+ require_relative 'l4/udp'
@@ -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
- @socket = SocketBuilder.build(ifname:)
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, = @socket.recvfrom(2048)
25
- Analyzer.analyze(msg:)
26
- @writer.write(msg) if @writer
29
+ msg, = @source.next_packet
30
+ Analyzer.analyze(msg:, count: increment)
31
+ @writer&.write(msg:)
27
32
  rescue Interrupt
28
- @writer.stop if @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
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'source/socket'
@@ -1,5 +1,6 @@
1
+ # rbs_inline: enabled
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Redhound
4
- VERSION = '0.2.0'
5
+ VERSION = '1.0.1'
5
6
  end
@@ -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
- def write(msg)
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
- (timestamp.usec || 0), # Timestamp microseconds
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/header'
6
- require_relative 'redhound/packet_mreq'
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/socket_builder'
10
+ require_relative 'redhound/resolver'
11
+ require_relative 'redhound/source'
9
12
  require_relative 'redhound/version'
10
13
  require_relative 'redhound/writer'