packetgen 3.1.4 → 3.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/packetgen.rb +8 -1
- data/lib/packetgen/capture.rb +16 -8
- data/lib/packetgen/config.rb +15 -9
- data/lib/packetgen/deprecation.rb +1 -1
- data/lib/packetgen/header/dhcpv6/option.rb +1 -11
- data/lib/packetgen/header/dns/qdsection.rb +1 -1
- data/lib/packetgen/header/dot11.rb +2 -32
- data/lib/packetgen/header/dot1x.rb +1 -14
- data/lib/packetgen/header/eap.rb +11 -15
- data/lib/packetgen/header/eth.rb +3 -0
- data/lib/packetgen/header/http/headers.rb +3 -0
- data/lib/packetgen/header/ip/addr.rb +3 -0
- data/lib/packetgen/header/ipv6/addr.rb +3 -0
- data/lib/packetgen/header/tcp.rb +1 -20
- data/lib/packetgen/inspect.rb +1 -17
- data/lib/packetgen/inspectable.rb +20 -0
- data/lib/packetgen/pcaprub_wrapper.rb +18 -4
- data/lib/packetgen/types/abstract_tlv.rb +4 -1
- data/lib/packetgen/types/array.rb +4 -3
- data/lib/packetgen/types/cstring.rb +3 -0
- data/lib/packetgen/types/enum.rb +4 -0
- data/lib/packetgen/types/fields.rb +121 -89
- data/lib/packetgen/types/int.rb +14 -0
- data/lib/packetgen/types/int_string.rb +3 -0
- data/lib/packetgen/types/oui.rb +3 -0
- data/lib/packetgen/types/string.rb +1 -0
- data/lib/packetgen/types/tlv.rb +3 -0
- data/lib/packetgen/utils.rb +1 -1
- data/lib/packetgen/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 476cbc2bd2b9fb254ea40fe0a07a4d703a0fc36e4accc823de7e83b640d95a2d
|
4
|
+
data.tar.gz: 375f31ea90589b2b0c0b257b8a3efaa66715e8b369c542124fe3dcac283d9221
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c518ff72cf70227c8f9ef38cce97ba5036eb3229051d38172ba947898b9051f508670d1e0106bac0f5edf577fe1450d5f71db557aa6968b7e3998945a87177d7
|
7
|
+
data.tar.gz: 9382d6f8a7542c8988dec0aaf92940f1518885133bf9e7c835478e787546309410c7e7bcfb4525c13fb7479a9cad9a7ece3e30a3d3c6bbb4f081c1cc48b7f02e
|
data/lib/packetgen.rb
CHANGED
@@ -97,6 +97,12 @@ module PacketGen
|
|
97
97
|
Interfacez.default
|
98
98
|
end
|
99
99
|
|
100
|
+
# Get loopback network interface
|
101
|
+
# @return [String]
|
102
|
+
def self.loopback_iface
|
103
|
+
Interfacez.loopback
|
104
|
+
end
|
105
|
+
|
100
106
|
# Shortcut to get a header class
|
101
107
|
# @example builtin class
|
102
108
|
# # same as PacketGen::Header::Dot11:Data.new(id: 0xfedc)
|
@@ -114,8 +120,9 @@ module PacketGen
|
|
114
120
|
end
|
115
121
|
|
116
122
|
require 'packetgen/deprecation'
|
117
|
-
require 'packetgen/types'
|
118
123
|
require 'packetgen/inspect'
|
124
|
+
require 'packetgen/inspectable'
|
125
|
+
require 'packetgen/types'
|
119
126
|
require 'packetgen/pcapng'
|
120
127
|
require 'packetgen/pcap'
|
121
128
|
require 'packetgen/packet'
|
data/lib/packetgen/capture.rb
CHANGED
@@ -13,7 +13,7 @@ module PacketGen
|
|
13
13
|
class Capture
|
14
14
|
private
|
15
15
|
|
16
|
-
attr_reader :filter, :cap_thread, :snaplen, :promisc
|
16
|
+
attr_reader :filter, :cap_thread, :snaplen, :promisc, :monitor
|
17
17
|
|
18
18
|
public
|
19
19
|
|
@@ -41,14 +41,18 @@ module PacketGen
|
|
41
41
|
# yielding. Default: +true+
|
42
42
|
# @param [Integer] snaplen maximum number of bytes to capture for
|
43
43
|
# each packet.
|
44
|
+
# @param [Boolean] monitor enable or disable monitor mode on interface (if supported by +iface+).
|
44
45
|
# @since 2.0.0 remove old 1.x API
|
45
46
|
# @since 3.0.0 arguments are kwargs and no more a hash
|
46
|
-
|
47
|
-
|
47
|
+
# @since 3.1.5 add monitor argument
|
48
|
+
# @author Sylvain Daubert
|
49
|
+
# @author optix2000 - add monitor argument
|
50
|
+
def initialize(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: nil, monitor: nil)
|
51
|
+
@iface = iface || PacketGen.default_iface || PacketGen.loopback_iface
|
48
52
|
|
49
53
|
@packets = []
|
50
54
|
@raw_packets = []
|
51
|
-
set_options iface, max, timeout, filter, promisc, parse, snaplen
|
55
|
+
set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor
|
52
56
|
end
|
53
57
|
|
54
58
|
# Start capture
|
@@ -56,8 +60,11 @@ module PacketGen
|
|
56
60
|
# @yieldparam [Packet,String] packet if a block is given, yield each
|
57
61
|
# captured packet (Packet or raw data String, depending on +:parse+ option)
|
58
62
|
# @since 3.0.0 arguments are kwargs and no more a hash
|
59
|
-
|
60
|
-
|
63
|
+
# @since 3.1.5 add monitor argument
|
64
|
+
# @author Sylvain Daubert
|
65
|
+
# @author optix2000 - add monitor argument
|
66
|
+
def start(iface: nil, max: nil, timeout: nil, filter: nil, promisc: false, parse: true, snaplen: nil, monitor: nil, &block)
|
67
|
+
set_options iface, max, timeout, filter, promisc, parse, snaplen, monitor
|
61
68
|
|
62
69
|
@cap_thread = Thread.new do
|
63
70
|
PCAPRUBWrapper.capture(**capture_args) do |packet_data|
|
@@ -79,7 +86,7 @@ module PacketGen
|
|
79
86
|
|
80
87
|
private
|
81
88
|
|
82
|
-
def set_options(iface, max, timeout, filter, promisc, parse, snaplen)
|
89
|
+
def set_options(iface, max, timeout, filter, promisc, parse, snaplen, monitor)
|
83
90
|
@max = max if max
|
84
91
|
@filter = filter unless filter.nil?
|
85
92
|
@timeout = timeout unless timeout.nil?
|
@@ -87,10 +94,11 @@ module PacketGen
|
|
87
94
|
@snaplen = snaplen unless snaplen.nil?
|
88
95
|
@parse = parse unless parse.nil?
|
89
96
|
@iface = iface unless iface.nil?
|
97
|
+
@monitor = monitor unless monitor.nil?
|
90
98
|
end
|
91
99
|
|
92
100
|
def capture_args
|
93
|
-
h = { iface: iface, filter: filter }
|
101
|
+
h = { iface: iface, filter: filter, monitor: monitor }
|
94
102
|
h[:snaplen] = snaplen unless snaplen.nil?
|
95
103
|
h[:promisc] = promisc unless promisc.nil?
|
96
104
|
h
|
data/lib/packetgen/config.rb
CHANGED
@@ -22,37 +22,43 @@ module PacketGen
|
|
22
22
|
attr_reader :default_iface
|
23
23
|
|
24
24
|
def initialize
|
25
|
-
@default_iface =
|
25
|
+
@default_iface = PacketGen.default_iface || PacketGen.loopback_iface
|
26
26
|
@hwaddr = {}
|
27
27
|
@ipaddr = {}
|
28
28
|
@ip6addr = {}
|
29
29
|
|
30
|
-
|
31
|
-
@hwaddr[iface_name] = Interfacez.mac_address_of(iface_name)
|
32
|
-
@ipaddr[iface_name] = Interfacez.ipv4_address_of(iface_name)
|
33
|
-
@ip6addr[iface_name] = Interfacez.ipv6_addresses_of(iface_name)
|
34
|
-
end
|
30
|
+
initialize_local_addresses
|
35
31
|
end
|
36
32
|
|
37
33
|
# Get MAC address for given network interface
|
38
34
|
# @param [String,nil] iface network interface. If +nil+, use default one.
|
39
35
|
# @return [String]
|
40
36
|
def hwaddr(iface=nil)
|
41
|
-
@hwaddr[iface ||
|
37
|
+
@hwaddr[iface || default_iface]
|
42
38
|
end
|
43
39
|
|
44
40
|
# Get IP address for given network interface
|
45
41
|
# @param [String,nil] iface network interface. If +nil+, use default one.
|
46
42
|
# @return [String]
|
47
43
|
def ipaddr(iface=nil)
|
48
|
-
@ipaddr[iface ||
|
44
|
+
@ipaddr[iface || default_iface]
|
49
45
|
end
|
50
46
|
|
51
47
|
# Get IPv6 addresses for given network interface
|
52
48
|
# @param [String,nil] iface network interface. If +nil+, use default one.
|
53
49
|
# @return [Array<String>]
|
54
50
|
def ip6addr(iface=nil)
|
55
|
-
@ip6addr[iface ||
|
51
|
+
@ip6addr[iface || default_iface]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def initialize_local_addresses
|
57
|
+
Interfacez.all do |iface_name|
|
58
|
+
@hwaddr[iface_name] = Interfacez.mac_address_of(iface_name)
|
59
|
+
@ipaddr[iface_name] = Interfacez.ipv4_address_of(iface_name)
|
60
|
+
@ip6addr[iface_name] = Interfacez.ipv6_addresses_of(iface_name)
|
61
|
+
end
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|
@@ -31,7 +31,7 @@ module PacketGen
|
|
31
31
|
complete_deprecated_method_name = "#{base_name}#{deprecated_method}"
|
32
32
|
complete_new_method_name = "#{base_name}#{new_method}" unless new_method.nil?
|
33
33
|
|
34
|
-
file, line = caller(2..2).split(':')[0, 2]
|
34
|
+
file, line = caller(2..2).first.split(':')[0, 2]
|
35
35
|
message = +"#{file}:#{line}: #{complete_deprecated_method_name} is deprecated"
|
36
36
|
message << " in favor of #{complete_new_method_name}" unless new_method.nil?
|
37
37
|
message << '. ' << self.removed(remove_version)
|
@@ -230,17 +230,7 @@ module PacketGen
|
|
230
230
|
|
231
231
|
# @!attribute options
|
232
232
|
# @return [RequestedOptions]
|
233
|
-
define_field :options, RequestedOptions
|
234
|
-
|
235
|
-
# Populate object from +str+
|
236
|
-
# @param [String] str
|
237
|
-
# @return [self]
|
238
|
-
def read(str)
|
239
|
-
self[:type].read str[0, 2]
|
240
|
-
self[:length].read str[2, 2]
|
241
|
-
self[:options].read str[4, self.length]
|
242
|
-
self
|
243
|
-
end
|
233
|
+
define_field :options, RequestedOptions, builder: ->(h, t) { t.new(length_from: h[:length]) }
|
244
234
|
|
245
235
|
# Get human-readable data
|
246
236
|
# @return [String]
|
@@ -28,7 +28,7 @@ module PacketGen
|
|
28
28
|
define_field :dlt, Types::Int32le
|
29
29
|
# @!attribute ppi_fields
|
30
30
|
# @return [Type::String] concatenation of PPI fields
|
31
|
-
define_field :ppi_fields, Types::String
|
31
|
+
define_field :ppi_fields, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) }
|
32
32
|
# @!attribute body
|
33
33
|
# @return [Type::String]
|
34
34
|
define_field :body, Types::String
|
@@ -36,21 +36,6 @@ module PacketGen
|
|
36
36
|
# @return [Boolean] align flag from {#flags} attribute
|
37
37
|
define_bit_fields_on :flags, :reserved, 7, :align
|
38
38
|
|
39
|
-
# @param [String] str
|
40
|
-
# @return [PPI] self
|
41
|
-
def read(str)
|
42
|
-
return self if str.nil?
|
43
|
-
|
44
|
-
force_binary str
|
45
|
-
self[:version].read str[0, 1]
|
46
|
-
self[:flags].read str[1, 1]
|
47
|
-
self[:length].read str[2, 2]
|
48
|
-
self[:dlt].read str[4, 4]
|
49
|
-
self[:ppi_fields].read str[8, length - 8]
|
50
|
-
self[:body].read str[length, str.size]
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
39
|
# Check version field
|
55
40
|
# @see [Base#parse?]
|
56
41
|
def parse?
|
@@ -91,26 +76,11 @@ module PacketGen
|
|
91
76
|
define_field :present_flags, Types::Int32le
|
92
77
|
# @!attribute radio_fields
|
93
78
|
# @return [Type::String] concatenation of RadioTap fields
|
94
|
-
define_field :radio_fields, Types::String
|
79
|
+
define_field :radio_fields, Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - 8 }) }
|
95
80
|
# @!attribute body
|
96
81
|
# @return [Type::String]
|
97
82
|
define_field :body, Types::String
|
98
83
|
|
99
|
-
# @param [String] str
|
100
|
-
# @return [RadioTap] self
|
101
|
-
def read(str)
|
102
|
-
return self if str.nil?
|
103
|
-
|
104
|
-
force_binary str
|
105
|
-
self[:version].read str[0, 1]
|
106
|
-
self[:pad].read str[1, 1]
|
107
|
-
self[:length].read str[2, 2]
|
108
|
-
self[:present_flags].read str[4, 4]
|
109
|
-
self[:radio_fields].read str[8, length - 8]
|
110
|
-
self[:body].read str[length, str.size]
|
111
|
-
self
|
112
|
-
end
|
113
|
-
|
114
84
|
# Check version field
|
115
85
|
# @see [Base#parse?]
|
116
86
|
def parse?
|
@@ -45,20 +45,7 @@ module PacketGen
|
|
45
45
|
define_field :length, Types::Int16
|
46
46
|
# @!attribute body
|
47
47
|
# @return [Types::String,Header::Base]
|
48
|
-
define_field :body, Types::String
|
49
|
-
|
50
|
-
# Populate object from string
|
51
|
-
# @param [String] str
|
52
|
-
# @return [self]
|
53
|
-
def read(str)
|
54
|
-
return self if str.nil?
|
55
|
-
|
56
|
-
self[:version].read(str[0, 1])
|
57
|
-
self[:type].read(str[1, 1])
|
58
|
-
self[:length].read(str[2, 2])
|
59
|
-
self[:body].read(str[4, self.length])
|
60
|
-
self
|
61
|
-
end
|
48
|
+
define_field :body, Types::String, builder: ->(h, t) { t.new(length_from: h[:length]) }
|
62
49
|
|
63
50
|
# Get human readable type
|
64
51
|
# @return [String]
|
data/lib/packetgen/header/eap.rb
CHANGED
@@ -132,21 +132,17 @@ module PacketGen
|
|
132
132
|
def read(str)
|
133
133
|
super str
|
134
134
|
return self unless self.class == EAP
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
else
|
147
|
-
self
|
148
|
-
end
|
149
|
-
obj
|
135
|
+
return self unless type?
|
136
|
+
|
137
|
+
case self.type
|
138
|
+
when 4
|
139
|
+
EAP::MD5.new.read(str)
|
140
|
+
when 13
|
141
|
+
EAP::TLS.new.read(str)
|
142
|
+
when 21
|
143
|
+
EAP::TTLS.new.read(str)
|
144
|
+
when 43
|
145
|
+
EAP::FAST.new.read(str)
|
150
146
|
else
|
151
147
|
self
|
152
148
|
end
|
data/lib/packetgen/header/eth.rb
CHANGED
@@ -33,6 +33,8 @@ module PacketGen
|
|
33
33
|
# Ethernet MAC address, as a group of 6 bytes
|
34
34
|
# @author Sylvain Daubert
|
35
35
|
class MacAddr < Types::Fields
|
36
|
+
include Inspectable
|
37
|
+
|
36
38
|
# @!attribute a0
|
37
39
|
# @return [Integer] first byte from MacAddr
|
38
40
|
define_field :a0, Types::Int8
|
@@ -75,6 +77,7 @@ module PacketGen
|
|
75
77
|
def to_human
|
76
78
|
fields.map { |m| '%02x' % self[m] }.join(':')
|
77
79
|
end
|
80
|
+
alias format_inspect to_human
|
78
81
|
|
79
82
|
def ==(other)
|
80
83
|
other.is_a?(self.class) &&
|
@@ -12,6 +12,8 @@ module PacketGen
|
|
12
12
|
# @abstract Base class for HTTP headers.
|
13
13
|
# @author Kent 'picat' Gruber
|
14
14
|
class Headers
|
15
|
+
include Inspectable
|
16
|
+
|
15
17
|
# Underlying Headers data (or nil).
|
16
18
|
# @return [Hash, nil]
|
17
19
|
attr_reader :data
|
@@ -56,6 +58,7 @@ module PacketGen
|
|
56
58
|
def to_human
|
57
59
|
@data
|
58
60
|
end
|
61
|
+
alias format_inspect to_human
|
59
62
|
|
60
63
|
# Read human-readable data to populate header data.
|
61
64
|
# @param [String, Hash] data
|
@@ -11,6 +11,8 @@ module PacketGen
|
|
11
11
|
# IP address, as a group of 4 bytes
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Addr < Types::Fields
|
14
|
+
include Inspectable
|
15
|
+
|
14
16
|
# @!attribute a1
|
15
17
|
# @return [Integer] IP address first byte
|
16
18
|
define_field :a1, Types::Int8
|
@@ -47,6 +49,7 @@ module PacketGen
|
|
47
49
|
def to_human
|
48
50
|
fields.map { |f| self[f].to_i.to_s }.join('.')
|
49
51
|
end
|
52
|
+
alias format_inspect to_human
|
50
53
|
|
51
54
|
# Addr as an integer
|
52
55
|
# @return [Integer]
|
@@ -14,6 +14,8 @@ module PacketGen
|
|
14
14
|
# IPv6 address, as a group of 8 2-byte words
|
15
15
|
# @author Sylvain Daubert
|
16
16
|
class Addr < Types::Fields
|
17
|
+
include Inspectable
|
18
|
+
|
17
19
|
# @!attribute a1
|
18
20
|
# 1st 2-byte word of IPv6 address
|
19
21
|
# @return [Integer]
|
@@ -73,6 +75,7 @@ module PacketGen
|
|
73
75
|
def to_human
|
74
76
|
IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
|
75
77
|
end
|
78
|
+
alias format_inspect to_human
|
76
79
|
|
77
80
|
# Return an array of address 16-bit words
|
78
81
|
# @return [Array<Integer>]
|
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -121,7 +121,7 @@ module PacketGen
|
|
121
121
|
# @!attribute options
|
122
122
|
# TCP options
|
123
123
|
# @return [Options]
|
124
|
-
define_field :options, TCP::Options
|
124
|
+
define_field :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
|
125
125
|
# @!attribute body
|
126
126
|
# @return [Types::String,Header::Base]
|
127
127
|
define_field :body, Types::String
|
@@ -189,25 +189,6 @@ module PacketGen
|
|
189
189
|
# @return [Boolean] 1-bit FIN flag
|
190
190
|
define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg,
|
191
191
|
:flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin
|
192
|
-
# Read a TCP header from a string
|
193
|
-
# @param [String] str binary string
|
194
|
-
# @return [self]
|
195
|
-
def read(str)
|
196
|
-
return self if str.nil?
|
197
|
-
|
198
|
-
force_binary str
|
199
|
-
self[:sport].read str[0, 2]
|
200
|
-
self[:dport].read str[2, 2]
|
201
|
-
self[:seqnum].read str[4, 4]
|
202
|
-
self[:acknum].read str[8, 4]
|
203
|
-
self[:u16].read str[12, 2]
|
204
|
-
self[:window].read str[14, 2]
|
205
|
-
self[:checksum].read str[16, 2]
|
206
|
-
self[:urg_pointer].read str[18, 2]
|
207
|
-
self[:options].read str[20, (self.data_offset - 5) * 4] if self.data_offset > 5
|
208
|
-
self[:body].read str[self.data_offset * 4..-1]
|
209
|
-
self
|
210
|
-
end
|
211
192
|
|
212
193
|
# Compute checksum and set +checksum+ field
|
213
194
|
# @return [Integer]
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -68,23 +68,7 @@ module PacketGen
|
|
68
68
|
# @return [String]
|
69
69
|
def self.inspect_attribute(attr, value, level=1)
|
70
70
|
type = value.class.to_s.sub(/.*::/, '')
|
71
|
-
|
72
|
-
when Types::Enum
|
73
|
-
enum_human_hex(value.to_human, value.to_i, value.sz * 2)
|
74
|
-
when Types::Int
|
75
|
-
int_dec_hex(value, value.sz * 2)
|
76
|
-
when Integer
|
77
|
-
int_dec_hex(value, value.sz * 2)
|
78
|
-
when String
|
79
|
-
value.to_s.inspect
|
80
|
-
else
|
81
|
-
if value.respond_to? :to_human
|
82
|
-
value.to_human
|
83
|
-
else
|
84
|
-
value.to_s.inspect
|
85
|
-
end
|
86
|
-
end
|
87
|
-
self.format(type, attr, val, level)
|
71
|
+
self.format(type, attr, value.format_inspect, level)
|
88
72
|
end
|
89
73
|
|
90
74
|
# Format a ASN.1 attribute for +#inspect+.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This file is part of PacketGen
|
4
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
5
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
6
|
+
# This program is published under MIT license.
|
7
|
+
|
8
|
+
module PacketGen
|
9
|
+
# Module to add common methods to format types when inspecting packets/headers.
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
# @since 3.1.5
|
12
|
+
module Inspectable
|
13
|
+
# Format attribute for inspecting
|
14
|
+
# @abstract should be overriden by types.
|
15
|
+
# @return [String]
|
16
|
+
def format_inspect
|
17
|
+
to_s.inspect
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -23,9 +23,19 @@ module PacketGen
|
|
23
23
|
# @param [String] iface interface name
|
24
24
|
# @param [Integer] snaplen
|
25
25
|
# @param [Boolean] promisc
|
26
|
+
# @param [Boolean] monitor
|
26
27
|
# @return [PCAPRUB::Pcap]
|
27
|
-
|
28
|
-
|
28
|
+
# @author Sylvain Daubert
|
29
|
+
# @author optix2000 - add support for setting monitor mode
|
30
|
+
# @since 3.1.5 add monitor argument
|
31
|
+
def self.open_iface(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, monitor: nil)
|
32
|
+
pcap = PCAPRUB::Pcap.create(iface)
|
33
|
+
pcap.setsnaplen(snaplen)
|
34
|
+
pcap.setpromisc(promisc)
|
35
|
+
pcap.settimeout(TIMEOUT)
|
36
|
+
# Monitor MUST be set before pcap is activated
|
37
|
+
pcap.setmonitor monitor unless monitor.nil?
|
38
|
+
pcap.activate
|
29
39
|
end
|
30
40
|
|
31
41
|
# Capture packets from a network interface
|
@@ -33,10 +43,14 @@ module PacketGen
|
|
33
43
|
# @param [Integer] snaplen
|
34
44
|
# @param [Boolean] promisc
|
35
45
|
# @param [String] filter BPF filter
|
46
|
+
# @param [Boolean] monitor
|
36
47
|
# @yieldparam [String] packet_data binary packet data
|
37
48
|
# @return [void]
|
38
|
-
|
39
|
-
|
49
|
+
# @author Sylvain Daubert
|
50
|
+
# @author optix2000 - add support for setting monitor mode
|
51
|
+
# @since 3.1.5 add monitor argument
|
52
|
+
def self.capture(iface:, snaplen: DEFAULT_SNAPLEN, promisc: DEFAULT_PROMISC, filter: nil, monitor: nil)
|
53
|
+
pcap = self.open_iface(iface: iface, snaplen: snaplen, promisc: promisc, monitor: monitor)
|
40
54
|
pcap.setfilter filter unless filter.nil?
|
41
55
|
pcap.each do |packet_data|
|
42
56
|
yield packet_data
|
@@ -58,6 +58,8 @@ module PacketGen
|
|
58
58
|
# @since 3.1.0
|
59
59
|
# @since 3.1.1 add +:aliases+ keyword to {#initialize}
|
60
60
|
class AbstractTLV < Types::Fields
|
61
|
+
include Inspectable
|
62
|
+
|
61
63
|
class <<self
|
62
64
|
# @return [Hash]
|
63
65
|
attr_accessor :aliases
|
@@ -169,8 +171,9 @@ module PacketGen
|
|
169
171
|
# @return [String]
|
170
172
|
def to_human
|
171
173
|
my_value = self[:value].is_a?(String) ? self[:value].inspect : self[:value].to_human
|
172
|
-
"type:%s,length:%u,value
|
174
|
+
"type:%s,length:%u,value:%s" % [human_type, length, my_value]
|
173
175
|
end
|
176
|
+
alias format_inspect to_human
|
174
177
|
|
175
178
|
private
|
176
179
|
|
@@ -27,6 +27,9 @@ module PacketGen
|
|
27
27
|
# @author Sylvain Daubert
|
28
28
|
class Array
|
29
29
|
extend Forwardable
|
30
|
+
include Inspectable
|
31
|
+
include Enumerable
|
32
|
+
include LengthFrom
|
30
33
|
|
31
34
|
# @!method [](index)
|
32
35
|
# Return the element at +index+.
|
@@ -54,9 +57,6 @@ module PacketGen
|
|
54
57
|
def_delegators :@array, :[], :clear, :each, :empty?, :first, :last, :size
|
55
58
|
alias length size
|
56
59
|
|
57
|
-
include Enumerable
|
58
|
-
include LengthFrom
|
59
|
-
|
60
60
|
# Separator used in {#to_human}.
|
61
61
|
# May be ovverriden by subclasses
|
62
62
|
HUMAN_SEPARATOR = ','
|
@@ -198,6 +198,7 @@ module PacketGen
|
|
198
198
|
def to_human
|
199
199
|
@array.map(&:to_human).join(self.class::HUMAN_SEPARATOR)
|
200
200
|
end
|
201
|
+
alias format_inspect to_human
|
201
202
|
|
202
203
|
private
|
203
204
|
|
@@ -11,6 +11,8 @@ module PacketGen
|
|
11
11
|
# This class handles null-terminated strings (aka C strings).
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class CString < ::String
|
14
|
+
include Inspectable
|
15
|
+
|
14
16
|
# @param [Hash] options
|
15
17
|
# @option options [Integer] :static_length set a static length for this string
|
16
18
|
def initialize(options={})
|
@@ -66,6 +68,7 @@ module PacketGen
|
|
66
68
|
idx = self.index(+"\x00".encode(self.encoding)) || self.sz
|
67
69
|
self[0, idx]
|
68
70
|
end
|
71
|
+
alias format_inspect to_human
|
69
72
|
end
|
70
73
|
end
|
71
74
|
end
|
data/lib/packetgen/types/enum.rb
CHANGED
@@ -119,6 +119,10 @@ module PacketGen
|
|
119
119
|
# @return [Hash]
|
120
120
|
# @since 3.1.0
|
121
121
|
attr_reader :field_defs
|
122
|
+
# Get bit fields defintions for this class
|
123
|
+
# @return [Hash]
|
124
|
+
# @since 3.1.5
|
125
|
+
attr_reader :bit_fields
|
122
126
|
|
123
127
|
# On inheritage, create +@field_defs+ class variable
|
124
128
|
# @param [Class] klass
|
@@ -129,7 +133,7 @@ module PacketGen
|
|
129
133
|
field_defs[k] = v.clone
|
130
134
|
end
|
131
135
|
ordered = @ordered_fields.clone
|
132
|
-
bf =
|
136
|
+
bf = bit_fields.clone
|
133
137
|
|
134
138
|
klass.class_eval do
|
135
139
|
@ordered_fields = ordered
|
@@ -172,37 +176,15 @@ module PacketGen
|
|
172
176
|
# Define enumeration: hash's keys are +String+, and values are +Integer+.
|
173
177
|
# @return [void]
|
174
178
|
def define_field(name, type, options={})
|
175
|
-
|
176
|
-
if type < Types::Enum
|
177
|
-
define << "def #{name}; self[:#{name}].to_i; end"
|
178
|
-
define << "def #{name}=(val) self[:#{name}].value = val; end"
|
179
|
-
else
|
180
|
-
define << "def #{name}\n" \
|
181
|
-
" if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
|
182
|
-
" self[:#{name}].to_human\n" \
|
183
|
-
" else\n" \
|
184
|
-
" self[:#{name}]\n" \
|
185
|
-
" end\n" \
|
186
|
-
'end'
|
187
|
-
define << "def #{name}=(val)\n" \
|
188
|
-
" if self[:#{name}].respond_to?(:to_human) && self[:#{name}].respond_to?(:from_human)\n" \
|
189
|
-
" self[:#{name}].from_human val\n" \
|
190
|
-
" else\n" \
|
191
|
-
" self[:#{name}].read val\n" \
|
192
|
-
" end\n" \
|
193
|
-
'end'
|
194
|
-
end
|
195
|
-
|
196
|
-
define.delete_at(1) if instance_methods.include? "#{name}=".to_sym
|
197
|
-
define.delete_at(0) if instance_methods.include? name
|
198
|
-
class_eval define.join("\n")
|
179
|
+
fields << name
|
199
180
|
field_defs[name] = FieldDef.new(type,
|
200
181
|
options.delete(:default),
|
201
182
|
options.delete(:builder),
|
202
183
|
options.delete(:optional),
|
203
184
|
options.delete(:enum),
|
204
185
|
options)
|
205
|
-
|
186
|
+
|
187
|
+
add_methods(name, type)
|
206
188
|
end
|
207
189
|
|
208
190
|
# Define a field, before another one
|
@@ -300,8 +282,8 @@ module PacketGen
|
|
300
282
|
total_size = type.new.width * 8
|
301
283
|
idx = total_size - 1
|
302
284
|
|
303
|
-
|
304
|
-
|
285
|
+
until args.empty?
|
286
|
+
field = args.shift
|
305
287
|
next unless field.is_a? Symbol
|
306
288
|
|
307
289
|
size = if args.first.is_a? Integer
|
@@ -309,41 +291,13 @@ module PacketGen
|
|
309
291
|
else
|
310
292
|
1
|
311
293
|
end
|
294
|
+
|
312
295
|
unless field == :_
|
313
|
-
|
314
|
-
|
315
|
-
clear_mask = (2**total_size - 1) & (~field_mask & (2**total_size - 1))
|
316
|
-
|
317
|
-
if size == 1
|
318
|
-
class_eval <<-METHODS
|
319
|
-
def #{field}?
|
320
|
-
val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
321
|
-
val != 0
|
322
|
-
end
|
323
|
-
def #{field}=(v)
|
324
|
-
val = v ? 1 : 0
|
325
|
-
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
326
|
-
self[:#{attr}].value |= val << #{shift}
|
327
|
-
end
|
328
|
-
METHODS
|
329
|
-
else
|
330
|
-
class_eval <<-METHODS
|
331
|
-
def #{field}
|
332
|
-
(self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
333
|
-
end
|
334
|
-
def #{field}=(v)
|
335
|
-
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
336
|
-
self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
|
337
|
-
end
|
338
|
-
METHODS
|
339
|
-
end
|
340
|
-
|
341
|
-
@bit_fields[attr] = {} if @bit_fields[attr].nil?
|
342
|
-
@bit_fields[attr][field] = size
|
296
|
+
add_bit_methods(attr, field, size, total_size, idx)
|
297
|
+
register_bit_field_size(attr, field, size)
|
343
298
|
end
|
344
299
|
|
345
300
|
idx -= size
|
346
|
-
field = args.shift
|
347
301
|
end
|
348
302
|
end
|
349
303
|
|
@@ -352,7 +306,7 @@ module PacketGen
|
|
352
306
|
# @return [void]
|
353
307
|
# @since 2.8.4
|
354
308
|
def remove_bit_fields_on(attr)
|
355
|
-
fields =
|
309
|
+
fields = bit_fields.delete(attr)
|
356
310
|
return if fields.nil?
|
357
311
|
|
358
312
|
fields.each do |field, size|
|
@@ -360,6 +314,62 @@ module PacketGen
|
|
360
314
|
undef_method(size == 1 ? "#{field}?" : field)
|
361
315
|
end
|
362
316
|
end
|
317
|
+
|
318
|
+
private
|
319
|
+
|
320
|
+
def add_methods(name, type)
|
321
|
+
define = []
|
322
|
+
if type < Types::Enum
|
323
|
+
define << "def #{name}; self[:#{name}].to_i; end"
|
324
|
+
define << "def #{name}=(val) self[:#{name}].value = val; end"
|
325
|
+
else
|
326
|
+
define << "def #{name}\n" \
|
327
|
+
" to_and_from_human?(:#{name}) ? self[:#{name}].to_human : self[:#{name}]\n" \
|
328
|
+
'end'
|
329
|
+
define << "def #{name}=(val)\n" \
|
330
|
+
" to_and_from_human?(:#{name}) ? self[:#{name}].from_human(val) : self[:#{name}].read(val)\n" \
|
331
|
+
'end'
|
332
|
+
end
|
333
|
+
|
334
|
+
define.delete_at(1) if instance_methods.include? "#{name}=".to_sym
|
335
|
+
define.delete_at(0) if instance_methods.include? name
|
336
|
+
class_eval define.join("\n")
|
337
|
+
end
|
338
|
+
|
339
|
+
def add_bit_methods(attr, name, size, total_size, idx)
|
340
|
+
shift = idx - (size - 1)
|
341
|
+
field_mask = (2**size - 1) << shift
|
342
|
+
clear_mask = (2**total_size - 1) & (~field_mask & (2**total_size - 1))
|
343
|
+
|
344
|
+
if size == 1
|
345
|
+
class_eval <<-METHODS
|
346
|
+
def #{name}?
|
347
|
+
val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
348
|
+
val != 0
|
349
|
+
end
|
350
|
+
def #{name}=(v)
|
351
|
+
val = v ? 1 : 0
|
352
|
+
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
353
|
+
self[:#{attr}].value |= val << #{shift}
|
354
|
+
end
|
355
|
+
METHODS
|
356
|
+
else
|
357
|
+
class_eval <<-METHODS
|
358
|
+
def #{name}
|
359
|
+
(self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
360
|
+
end
|
361
|
+
def #{name}=(v)
|
362
|
+
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
363
|
+
self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
|
364
|
+
end
|
365
|
+
METHODS
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def register_bit_field_size(attr, field, size)
|
370
|
+
bit_fields[attr] = {} if bit_fields[attr].nil?
|
371
|
+
bit_fields[attr][field] = size
|
372
|
+
end
|
363
373
|
end
|
364
374
|
|
365
375
|
# Create a new fields object
|
@@ -369,36 +379,13 @@ module PacketGen
|
|
369
379
|
@fields = {}
|
370
380
|
@optional_fields = {}
|
371
381
|
|
372
|
-
field_defs = self.class.field_defs
|
373
382
|
self.class.fields.each do |field|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
builder = field_defs[field].builder
|
378
|
-
optional = field_defs[field].optional
|
379
|
-
enum = field_defs[field].enum
|
380
|
-
field_options = field_defs[field].options
|
381
|
-
|
382
|
-
@fields[field] = if builder
|
383
|
-
builder.call(self, type)
|
384
|
-
elsif enum
|
385
|
-
type.new(enum)
|
386
|
-
elsif !field_options.empty?
|
387
|
-
type.new(field_options)
|
388
|
-
else
|
389
|
-
type.new
|
390
|
-
end
|
391
|
-
|
392
|
-
value = options[field] || default
|
393
|
-
if value.class <= type
|
394
|
-
@fields[field] = value
|
395
|
-
elsif @fields[field].respond_to? :from_human
|
396
|
-
@fields[field].from_human(value)
|
397
|
-
end
|
398
|
-
|
399
|
-
@optional_fields[field] = optional if optional
|
383
|
+
build_field field
|
384
|
+
initialize_value field, options[field]
|
385
|
+
initialize_optional field
|
400
386
|
end
|
401
|
-
|
387
|
+
|
388
|
+
self.class.bit_fields.each do |_, hsh|
|
402
389
|
hsh.each_key do |bit_field|
|
403
390
|
self.send "#{bit_field}=", options[bit_field] if options[bit_field]
|
404
391
|
end
|
@@ -528,7 +515,7 @@ module PacketGen
|
|
528
515
|
# @return [Hash,nil] keys: bit fields, values: their size in bits
|
529
516
|
# @since 2.8.3
|
530
517
|
def bits_on(field)
|
531
|
-
self.class.
|
518
|
+
self.class.bit_fields[field]
|
532
519
|
end
|
533
520
|
|
534
521
|
private
|
@@ -547,6 +534,51 @@ module PacketGen
|
|
547
534
|
def force_binary(str)
|
548
535
|
PacketGen.force_binary(str)
|
549
536
|
end
|
537
|
+
|
538
|
+
# @param [Symbol] attr attribute
|
539
|
+
# @return [Boolean] +tru+e if #from_human and #to_human are both defined for given attribute
|
540
|
+
def to_and_from_human?(attr)
|
541
|
+
self[attr].respond_to?(:to_human) && self[attr].respond_to?(:from_human)
|
542
|
+
end
|
543
|
+
|
544
|
+
def field_defs
|
545
|
+
self.class.field_defs
|
546
|
+
end
|
547
|
+
|
548
|
+
def build_field(field)
|
549
|
+
type = field_defs[field].type
|
550
|
+
builder = field_defs[field].builder
|
551
|
+
enum = field_defs[field].enum
|
552
|
+
field_options = field_defs[field].options
|
553
|
+
|
554
|
+
@fields[field] = if builder
|
555
|
+
builder.call(self, type)
|
556
|
+
elsif enum
|
557
|
+
type.new(enum)
|
558
|
+
elsif !field_options.empty?
|
559
|
+
type.new(field_options)
|
560
|
+
else
|
561
|
+
type.new
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
def initialize_value(field, val)
|
566
|
+
type = field_defs[field].type
|
567
|
+
default = field_defs[field].default
|
568
|
+
default = default.to_proc.call(self) if default.is_a?(Proc)
|
569
|
+
|
570
|
+
value = val || default
|
571
|
+
if value.class <= type
|
572
|
+
@fields[field] = value
|
573
|
+
elsif @fields[field].respond_to? :from_human
|
574
|
+
@fields[field].from_human(value)
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
def initialize_optional(field)
|
579
|
+
optional = field_defs[field].optional
|
580
|
+
@optional_fields[field] = optional if optional
|
581
|
+
end
|
550
582
|
end
|
551
583
|
end
|
552
584
|
end
|
data/lib/packetgen/types/int.rb
CHANGED
@@ -12,6 +12,8 @@ module PacketGen
|
|
12
12
|
# @abstract
|
13
13
|
# @author Sylvain Daubert
|
14
14
|
class Int
|
15
|
+
include Inspectable
|
16
|
+
|
15
17
|
# Integer value
|
16
18
|
# @return [Integer]
|
17
19
|
attr_accessor :value
|
@@ -80,6 +82,18 @@ module PacketGen
|
|
80
82
|
def sz
|
81
83
|
width
|
82
84
|
end
|
85
|
+
|
86
|
+
# Format Int type when inspecting header or packet
|
87
|
+
# @return [String]
|
88
|
+
def format_inspect
|
89
|
+
format_str % [to_i.to_s, to_i]
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def format_str
|
95
|
+
"%-16s (0x%0#{width * 2}x)"
|
96
|
+
end
|
83
97
|
end
|
84
98
|
|
85
99
|
# One byte unsigned integer
|
@@ -12,6 +12,8 @@ module PacketGen
|
|
12
12
|
# By default, a null string will have one byte length (length byte set to 0).
|
13
13
|
# @author Sylvain Daubert
|
14
14
|
class IntString
|
15
|
+
include Inspectable
|
16
|
+
|
15
17
|
# internal string
|
16
18
|
# @return [String]
|
17
19
|
attr_reader :string
|
@@ -76,6 +78,7 @@ module PacketGen
|
|
76
78
|
def to_human
|
77
79
|
@string
|
78
80
|
end
|
81
|
+
alias format_inspect to_human
|
79
82
|
|
80
83
|
# Set length from internal string length
|
81
84
|
# @return [Integer]
|
data/lib/packetgen/types/oui.rb
CHANGED
@@ -14,6 +14,8 @@ module PacketGen
|
|
14
14
|
# oui.to_human # => "00:01:02"
|
15
15
|
# @author Sylvain Daubert
|
16
16
|
class OUI < Types::Fields
|
17
|
+
include Inspectable
|
18
|
+
|
17
19
|
# @attribute b2
|
18
20
|
# @return [Integer] left-most byte
|
19
21
|
define_field :b2, Types::Int8
|
@@ -44,6 +46,7 @@ module PacketGen
|
|
44
46
|
def to_human
|
45
47
|
fields.map { |m| '%02x' % self[m] }.join(':')
|
46
48
|
end
|
49
|
+
alias format_inspect to_human
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
data/lib/packetgen/types/tlv.rb
CHANGED
@@ -31,6 +31,8 @@ module PacketGen
|
|
31
31
|
# @deprecated Use {AbstractTLV} instead.
|
32
32
|
# @since 3.1.0 deprecated
|
33
33
|
class TLV < Fields
|
34
|
+
include Inspectable
|
35
|
+
|
34
36
|
# @!attribute type
|
35
37
|
# @return [Integer]
|
36
38
|
define_field :type, Int8
|
@@ -139,6 +141,7 @@ module PacketGen
|
|
139
141
|
"#{name} type:#{@typestr} length:#{@lenstr} value:#{value.inspect}" % [human_type,
|
140
142
|
length]
|
141
143
|
end
|
144
|
+
alias format_inspect to_human
|
142
145
|
|
143
146
|
private
|
144
147
|
|
data/lib/packetgen/utils.rb
CHANGED
@@ -53,7 +53,7 @@ module PacketGen
|
|
53
53
|
timeout = options[:timeout] || 1
|
54
54
|
my_hwaddr = Config.instance.hwaddr(iface)
|
55
55
|
arp_pkt = Packet.gen('Eth', dst: 'ff:ff:ff:ff:ff:ff', src: my_hwaddr)
|
56
|
-
arp_pkt.add('ARP', sha: Config.instance.hwaddr, spa: Config.instance.ipaddr,
|
56
|
+
arp_pkt.add('ARP', sha: Config.instance.hwaddr(iface), spa: Config.instance.ipaddr(iface),
|
57
57
|
tpa: ipaddr)
|
58
58
|
|
59
59
|
capture = Capture.new(iface: iface, timeout: timeout, max: 1,
|
data/lib/packetgen/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packetgen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Daubert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interfacez
|
@@ -208,6 +208,7 @@ files:
|
|
208
208
|
- lib/packetgen/headerable.rb
|
209
209
|
- lib/packetgen/inject.rb
|
210
210
|
- lib/packetgen/inspect.rb
|
211
|
+
- lib/packetgen/inspectable.rb
|
211
212
|
- lib/packetgen/packet.rb
|
212
213
|
- lib/packetgen/pcap.rb
|
213
214
|
- lib/packetgen/pcapng.rb
|
@@ -235,10 +236,11 @@ files:
|
|
235
236
|
- lib/packetgen/utils.rb
|
236
237
|
- lib/packetgen/utils/arp_spoofer.rb
|
237
238
|
- lib/packetgen/version.rb
|
238
|
-
homepage:
|
239
|
+
homepage:
|
239
240
|
licenses:
|
240
241
|
- MIT
|
241
242
|
metadata:
|
243
|
+
homepage_uri: https://github.com/sdaubert/packetgen
|
242
244
|
bug_tracker_uri: https://github.com/sdaubert/packetgen/issues
|
243
245
|
documentation_uri: https://www.rubydoc.info/gems/packetgen
|
244
246
|
source_code_uri: https://github.com/sdaubert/packetgen
|