packetgen 2.6.0 → 2.7.0
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/.gitignore +1 -0
- data/.rubocop.yml +28 -0
- data/Rakefile +6 -6
- data/bin/pgconsole +6 -6
- data/lib/packetgen.rb +4 -3
- data/lib/packetgen/capture.rb +5 -7
- data/lib/packetgen/config.rb +3 -3
- data/lib/packetgen/deprecation.rb +17 -0
- data/lib/packetgen/header.rb +40 -38
- data/lib/packetgen/header/arp.rb +46 -31
- data/lib/packetgen/header/asn1_base.rb +8 -8
- data/lib/packetgen/header/base.rb +108 -36
- data/lib/packetgen/header/bootp.rb +28 -19
- data/lib/packetgen/header/crypto.rb +6 -8
- data/lib/packetgen/header/dhcp.rb +4 -5
- data/lib/packetgen/header/dhcp/option.rb +46 -34
- data/lib/packetgen/header/dhcp/options.rb +0 -1
- data/lib/packetgen/header/dhcpv6.rb +10 -10
- data/lib/packetgen/header/dhcpv6/duid.rb +2 -3
- data/lib/packetgen/header/dhcpv6/option.rb +16 -21
- data/lib/packetgen/header/dhcpv6/relay.rb +6 -4
- data/lib/packetgen/header/dns.rb +13 -11
- data/lib/packetgen/header/dns/name.rb +4 -6
- data/lib/packetgen/header/dns/opt.rb +31 -31
- data/lib/packetgen/header/dns/option.rb +0 -2
- data/lib/packetgen/header/dns/qdsection.rb +1 -2
- data/lib/packetgen/header/dns/question.rb +19 -13
- data/lib/packetgen/header/dns/rr.rb +11 -14
- data/lib/packetgen/header/dns/rrsection.rb +5 -7
- data/lib/packetgen/header/dot11.rb +45 -29
- data/lib/packetgen/header/dot11/control.rb +3 -5
- data/lib/packetgen/header/dot11/data.rb +34 -6
- data/lib/packetgen/header/dot11/element.rb +0 -1
- data/lib/packetgen/header/dot11/management.rb +9 -5
- data/lib/packetgen/header/dot11/sub_mngt.rb +13 -14
- data/lib/packetgen/header/dot1q.rb +2 -2
- data/lib/packetgen/header/dot1x.rb +3 -4
- data/lib/packetgen/header/eap.rb +62 -53
- data/lib/packetgen/header/eap/fast.rb +0 -1
- data/lib/packetgen/header/eap/md5.rb +1 -2
- data/lib/packetgen/header/eap/tls.rb +9 -10
- data/lib/packetgen/header/eap/ttls.rb +9 -10
- data/lib/packetgen/header/esp.rb +33 -33
- data/lib/packetgen/header/eth.rb +11 -8
- data/lib/packetgen/header/gre.rb +5 -6
- data/lib/packetgen/header/http/headers.rb +11 -14
- data/lib/packetgen/header/http/request.rb +20 -20
- data/lib/packetgen/header/http/response.rb +16 -18
- data/lib/packetgen/header/http/verbs.rb +5 -5
- data/lib/packetgen/header/icmp.rb +1 -3
- data/lib/packetgen/header/icmpv6.rb +1 -3
- data/lib/packetgen/header/igmp.rb +5 -6
- data/lib/packetgen/header/igmpv3.rb +5 -9
- data/lib/packetgen/header/igmpv3/group_record.rb +4 -5
- data/lib/packetgen/header/igmpv3/mq.rb +2 -2
- data/lib/packetgen/header/igmpv3/mr.rb +4 -3
- data/lib/packetgen/header/ike.rb +33 -8
- data/lib/packetgen/header/ike/auth.rb +4 -6
- data/lib/packetgen/header/ike/cert.rb +0 -2
- data/lib/packetgen/header/ike/certreq.rb +1 -3
- data/lib/packetgen/header/ike/id.rb +1 -3
- data/lib/packetgen/header/ike/ke.rb +0 -2
- data/lib/packetgen/header/ike/nonce.rb +0 -2
- data/lib/packetgen/header/ike/notify.rb +22 -24
- data/lib/packetgen/header/ike/payload.rb +198 -199
- data/lib/packetgen/header/ike/sa.rb +21 -30
- data/lib/packetgen/header/ike/sk.rb +16 -17
- data/lib/packetgen/header/ike/ts.rb +22 -24
- data/lib/packetgen/header/ike/vendor_id.rb +0 -2
- data/lib/packetgen/header/ip.rb +30 -23
- data/lib/packetgen/header/ip/addr.rb +5 -6
- data/lib/packetgen/header/ip/option.rb +11 -15
- data/lib/packetgen/header/ip/options.rb +1 -2
- data/lib/packetgen/header/ipv6.rb +27 -12
- data/lib/packetgen/header/ipv6/addr.rb +2 -2
- data/lib/packetgen/header/ipv6/extension.rb +1 -1
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +11 -11
- data/lib/packetgen/header/llc.rb +4 -3
- data/lib/packetgen/header/mdns.rb +11 -5
- data/lib/packetgen/header/mld.rb +4 -4
- data/lib/packetgen/header/mldv2.rb +4 -3
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +3 -4
- data/lib/packetgen/header/mldv2/mlq.rb +3 -4
- data/lib/packetgen/header/mldv2/mlr.rb +4 -3
- data/lib/packetgen/header/netbios.rb +18 -5
- data/lib/packetgen/header/ospfv2.rb +6 -7
- data/lib/packetgen/header/ospfv2/db_description.rb +3 -4
- data/lib/packetgen/header/ospfv2/hello.rb +2 -3
- data/lib/packetgen/header/ospfv2/ls_ack.rb +2 -3
- data/lib/packetgen/header/ospfv2/ls_request.rb +2 -3
- data/lib/packetgen/header/ospfv2/ls_update.rb +5 -6
- data/lib/packetgen/header/ospfv2/lsa.rb +13 -14
- data/lib/packetgen/header/ospfv2/lsa_header.rb +4 -5
- data/lib/packetgen/header/ospfv3.rb +3 -4
- data/lib/packetgen/header/ospfv3/db_description.rb +3 -5
- data/lib/packetgen/header/ospfv3/hello.rb +2 -3
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +7 -8
- data/lib/packetgen/header/ospfv3/ls_ack.rb +2 -3
- data/lib/packetgen/header/ospfv3/ls_request.rb +2 -3
- data/lib/packetgen/header/ospfv3/ls_update.rb +5 -6
- data/lib/packetgen/header/ospfv3/lsa.rb +10 -11
- data/lib/packetgen/header/ospfv3/lsa_header.rb +3 -4
- data/lib/packetgen/header/snmp.rb +45 -32
- data/lib/packetgen/header/tcp.rb +13 -9
- data/lib/packetgen/header/tcp/option.rb +16 -11
- data/lib/packetgen/header/tcp/options.rb +3 -4
- data/lib/packetgen/header/tftp.rb +15 -17
- data/lib/packetgen/header/udp.rb +10 -4
- data/lib/packetgen/inspect.rb +7 -9
- data/lib/packetgen/packet.rb +44 -22
- data/lib/packetgen/pcapng.rb +1 -5
- data/lib/packetgen/pcapng/block.rb +17 -11
- data/lib/packetgen/pcapng/epb.rb +6 -11
- data/lib/packetgen/pcapng/file.rb +37 -44
- data/lib/packetgen/pcapng/idb.rb +17 -22
- data/lib/packetgen/pcapng/shb.rb +7 -10
- data/lib/packetgen/pcapng/spb.rb +21 -17
- data/lib/packetgen/pcapng/unknown_block.rb +17 -13
- data/lib/packetgen/proto.rb +1 -2
- data/lib/packetgen/types/array.rb +119 -34
- data/lib/packetgen/types/cstring.rb +1 -5
- data/lib/packetgen/types/enum.rb +8 -10
- data/lib/packetgen/types/fields.rb +34 -28
- data/lib/packetgen/types/int.rb +11 -13
- data/lib/packetgen/types/int_string.rb +6 -8
- data/lib/packetgen/types/oui.rb +3 -6
- data/lib/packetgen/types/string.rb +4 -6
- data/lib/packetgen/types/tlv.rb +11 -14
- data/lib/packetgen/utils.rb +15 -23
- data/lib/packetgen/utils/arp_spoofer.rb +12 -18
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +9 -8
- metadata +19 -17
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
|
-
|
11
10
|
# A TCP header consists of:
|
12
11
|
# * a source port ({#sport}, {Types::Int16} type),
|
13
12
|
# * a destination port ({#dport}, +Int16+ type),
|
@@ -147,8 +146,8 @@ module PacketGen
|
|
147
146
|
# @!attribute flags
|
148
147
|
# @return [Integer] 9-bit flags from {#u16}
|
149
148
|
define_bit_fields_on :u16, :data_offset, 4, :reserved, 3, :flags, 9
|
150
|
-
alias
|
151
|
-
alias
|
149
|
+
alias hlen data_offset
|
150
|
+
alias hlen= data_offset=
|
152
151
|
|
153
152
|
# @!attribute flag_ns
|
154
153
|
# @return [Boolean] 1-bit NS flag
|
@@ -205,9 +204,6 @@ module PacketGen
|
|
205
204
|
self[:data_offset] = 5 + self[:options].sz / 4
|
206
205
|
end
|
207
206
|
|
208
|
-
alias hlen data_offset
|
209
|
-
alias hlen= data_offset=
|
210
|
-
|
211
207
|
# @return [String]
|
212
208
|
def inspect
|
213
209
|
str = Inspect.dashed_line(self.class, 2)
|
@@ -220,7 +216,7 @@ module PacketGen
|
|
220
216
|
str << shift + Inspect::FMT_ATTR % ['', 'data_offset', doff]
|
221
217
|
str << shift + Inspect::FMT_ATTR % ['', 'reserved', reserved]
|
222
218
|
flags = ''.dup
|
223
|
-
%w
|
219
|
+
%w[ns cwr ece urg ack psh rst syn fin].each do |fl|
|
224
220
|
flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
|
225
221
|
end
|
226
222
|
str << shift + Inspect::FMT_ATTR % ['', 'flags', flags]
|
@@ -228,11 +224,19 @@ module PacketGen
|
|
228
224
|
end
|
229
225
|
str
|
230
226
|
end
|
227
|
+
|
228
|
+
# Invert source and destination port numbers
|
229
|
+
# @return [self]
|
230
|
+
# @since 2.7.0
|
231
|
+
def reply!
|
232
|
+
self[:sport], self[:dport] = self[:dport], self[:sport]
|
233
|
+
self
|
234
|
+
end
|
231
235
|
end
|
232
236
|
|
233
237
|
self.add_class TCP
|
234
238
|
|
235
|
-
IP.
|
236
|
-
IPv6.
|
239
|
+
IP.bind TCP, protocol: TCP::IP_PROTOCOL
|
240
|
+
IPv6.bind TCP, next: TCP::IP_PROTOCOL
|
237
241
|
end
|
238
242
|
end
|
@@ -8,11 +8,9 @@
|
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
class TCP
|
11
|
-
|
12
11
|
# Base class to describe a TCP option
|
13
12
|
# @author Sylvain Daubert
|
14
13
|
class Option < Base
|
15
|
-
|
16
14
|
# EOL option value
|
17
15
|
EOL_KIND = 0
|
18
16
|
# NOP option value
|
@@ -53,9 +51,9 @@ module PacketGen
|
|
53
51
|
case options[:value]
|
54
52
|
when Integer
|
55
53
|
klass = case self[:length].to_i
|
56
|
-
when 3
|
57
|
-
when 4
|
58
|
-
when 6
|
54
|
+
when 3 then Types::Int8
|
55
|
+
when 4 then Types::Int16
|
56
|
+
when 6 then Types::Int32
|
59
57
|
else
|
60
58
|
raise ArgumentError, 'impossible length'
|
61
59
|
end
|
@@ -77,18 +75,25 @@ module PacketGen
|
|
77
75
|
self[:kind].read str[0, 1]
|
78
76
|
if str[1, 1]
|
79
77
|
self[:length].read str[1, 1]
|
80
|
-
if str[2, 1] && length > 2
|
81
|
-
self[:value].read str[2, length - 2]
|
82
|
-
end
|
78
|
+
self[:value].read str[2, length - 2] if str[2, 1] && length > 2
|
83
79
|
end
|
84
80
|
self
|
85
81
|
end
|
86
82
|
|
83
|
+
# Say if given option has a length field.
|
87
84
|
# @return [Boolean]
|
88
|
-
|
85
|
+
# @since 2.7.0
|
86
|
+
def length?
|
89
87
|
self[:kind].value && kind >= 2
|
90
88
|
end
|
91
89
|
|
90
|
+
# @deprecated Use {#length?}.
|
91
|
+
# @return [Boolean]
|
92
|
+
def has_length?
|
93
|
+
Deprecation.deprecated(self.class, __method__, 'length?')
|
94
|
+
length?
|
95
|
+
end
|
96
|
+
|
92
97
|
# Getter for value attribute
|
93
98
|
# @return [String, Integer]
|
94
99
|
def value
|
@@ -113,7 +118,7 @@ module PacketGen
|
|
113
118
|
# @return [String]
|
114
119
|
def to_human
|
115
120
|
str = self.class == Option ? "unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
|
116
|
-
if length > 2
|
121
|
+
if (length > 2) && !self[:value].to_s.empty?
|
117
122
|
str << ":#{self[:value].to_s.inspect}"
|
118
123
|
end
|
119
124
|
str
|
@@ -121,7 +126,7 @@ module PacketGen
|
|
121
126
|
|
122
127
|
# @return [String]
|
123
128
|
def inspect
|
124
|
-
str = "#<#{self.class} kind=#{self[:kind].value.inspect} "
|
129
|
+
str = +"#<#{self.class} kind=#{self[:kind].value.inspect} "
|
125
130
|
str << "length=#{self[:length].value.inspect} " if self[:length].value
|
126
131
|
str << "value=#{self[:value].inspect}>"
|
127
132
|
end
|
@@ -8,11 +8,9 @@
|
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
class TCP
|
11
|
-
|
12
11
|
# Container for TCP options in {TCP TCP header}.
|
13
12
|
# @author Sylvain Daubert
|
14
13
|
class Options < Types::Array
|
15
|
-
|
16
14
|
# Get {Option} subclasses
|
17
15
|
# @return [Array<Class>]
|
18
16
|
def self.option_classes
|
@@ -44,7 +42,7 @@ module PacketGen
|
|
44
42
|
klasses[kind].new
|
45
43
|
end
|
46
44
|
this_option.read str[i, str.size]
|
47
|
-
unless this_option.
|
45
|
+
unless this_option.length?
|
48
46
|
this_option.length = nil
|
49
47
|
this_option.value = nil
|
50
48
|
end
|
@@ -61,6 +59,7 @@ module PacketGen
|
|
61
59
|
# @return [self]
|
62
60
|
# @raise [ArgumentError] unknown option
|
63
61
|
def add(opt, value=nil)
|
62
|
+
Deprecation.deprecated(self.class, __method__, 'push')
|
64
63
|
option = record_from_hash(opt: opt, value: value)
|
65
64
|
self << option
|
66
65
|
self
|
@@ -69,7 +68,7 @@ module PacketGen
|
|
69
68
|
private
|
70
69
|
|
71
70
|
def record_from_hash(hsh)
|
72
|
-
if hsh.
|
71
|
+
if hsh.key? :opt
|
73
72
|
klassname = hsh.delete(:opt)
|
74
73
|
if TCP.const_defined?(klassname)
|
75
74
|
klass = TCP.const_get(klassname)
|
@@ -7,7 +7,6 @@
|
|
7
7
|
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
|
-
|
11
10
|
# A TFTP (Trivial File Transfer Protocol,
|
12
11
|
# {https://tools.ietf.org/html/rfc1350 RFC 1350}) header consists of:
|
13
12
|
# * a {#opcode} ({Types::Int16Enum}),
|
@@ -46,8 +45,8 @@ module PacketGen
|
|
46
45
|
# packets[0].tftp.decode!(packets[1..-1])
|
47
46
|
# packets.map { |pkt| pkt.headers.last.class.to_s }.join(',') # => TFTP::RRQ,TFTP::DATA,UDP,TFTP::ACK
|
48
47
|
# @author Sylvain Daubert
|
48
|
+
# @since 2.3.0
|
49
49
|
class TFTP < Base
|
50
|
-
|
51
50
|
# Known opcodes
|
52
51
|
OPCODES = {
|
53
52
|
'RRQ' => 1,
|
@@ -55,22 +54,22 @@ module PacketGen
|
|
55
54
|
'DATA' => 3,
|
56
55
|
'ACK' => 4,
|
57
56
|
'Error' => 5
|
58
|
-
}
|
57
|
+
}.freeze
|
59
58
|
|
60
59
|
# @!attribute opcode
|
61
60
|
# 16-bit operation code
|
62
61
|
# @return [Integer]
|
63
62
|
define_field :opcode, Types::Int16Enum, enum: OPCODES
|
64
|
-
|
63
|
+
|
65
64
|
# @!attribute body
|
66
65
|
# @return [String]
|
67
66
|
define_field :body, Types::String
|
68
|
-
|
67
|
+
|
69
68
|
def initialize(options={})
|
70
69
|
type = protocol_name.sub(/^.*::/, '')
|
71
70
|
opcode = OPCODES[type]
|
72
|
-
if self.class != TFTP
|
73
|
-
super({opcode: opcode}.merge(options))
|
71
|
+
if (self.class != TFTP) && !opcode.nil?
|
72
|
+
super({ opcode: opcode }.merge(options))
|
74
73
|
else
|
75
74
|
super
|
76
75
|
end
|
@@ -85,7 +84,7 @@ module PacketGen
|
|
85
84
|
def read(str)
|
86
85
|
if self.instance_of? TFTP
|
87
86
|
super
|
88
|
-
if OPCODES.
|
87
|
+
if OPCODES.value? opcode
|
89
88
|
TFTP.const_get(human_opcode).new.read str
|
90
89
|
else
|
91
90
|
self
|
@@ -94,7 +93,7 @@ module PacketGen
|
|
94
93
|
old_read str
|
95
94
|
end
|
96
95
|
end
|
97
|
-
|
96
|
+
|
98
97
|
# Decode subsequent TFTP packets to this one. Packets are modified
|
99
98
|
# in place in +ary+.
|
100
99
|
# @param [Array<Packet>] ary
|
@@ -104,7 +103,7 @@ module PacketGen
|
|
104
103
|
server_tid = nil
|
105
104
|
ary.each do |pkt|
|
106
105
|
if server_tid.nil?
|
107
|
-
next unless pkt.is?('UDP')
|
106
|
+
next unless pkt.is?('UDP') && (pkt.udp.dport == client_tid)
|
108
107
|
server_tid = pkt.udp.sport
|
109
108
|
else
|
110
109
|
next unless pkt.is?('UDP')
|
@@ -120,7 +119,7 @@ module PacketGen
|
|
120
119
|
end
|
121
120
|
end
|
122
121
|
|
123
|
-
|
122
|
+
# Get human readable opcode
|
124
123
|
# @return [String]
|
125
124
|
def human_opcode
|
126
125
|
self[:opcode].to_human
|
@@ -132,16 +131,15 @@ module PacketGen
|
|
132
131
|
# @param [Packet] packet
|
133
132
|
# @return [void]
|
134
133
|
def added_to_packet(packet)
|
135
|
-
|
136
|
-
|
137
|
-
end
|
134
|
+
return if packet.respond_to? :tftp
|
135
|
+
packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end")
|
138
136
|
end
|
139
137
|
|
140
138
|
# TFTP Read Request header
|
141
139
|
class RRQ < TFTP
|
142
140
|
delete_field :body
|
143
141
|
undef body
|
144
|
-
|
142
|
+
|
145
143
|
# @!attribute filename
|
146
144
|
# Filename to access
|
147
145
|
# @return [String]
|
@@ -168,7 +166,7 @@ module PacketGen
|
|
168
166
|
class ACK < TFTP
|
169
167
|
delete_field :body
|
170
168
|
undef body
|
171
|
-
|
169
|
+
|
172
170
|
# @!attribute block_num
|
173
171
|
# 16-bit block number
|
174
172
|
# @return [Integer]
|
@@ -192,6 +190,6 @@ module PacketGen
|
|
192
190
|
alias error_message error_msg
|
193
191
|
end
|
194
192
|
end
|
195
|
-
UDP.
|
193
|
+
UDP.bind TFTP, dport: 69
|
196
194
|
end
|
197
195
|
end
|
data/lib/packetgen/header/udp.rb
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
|
-
|
11
10
|
# A UDP header consists of:
|
12
11
|
# * a source port field ({#sport}, {Types::Int16} type),
|
13
12
|
# * a destination port field ({#dport}, +Int16+ type),
|
@@ -32,7 +31,6 @@ module PacketGen
|
|
32
31
|
#
|
33
32
|
# @author Sylvain Daubert
|
34
33
|
class UDP < Base
|
35
|
-
|
36
34
|
# IP protocol number for UDP
|
37
35
|
IP_PROTOCOL = 17
|
38
36
|
|
@@ -84,11 +82,19 @@ module PacketGen
|
|
84
82
|
def calc_length
|
85
83
|
Base.calculate_and_set_length self
|
86
84
|
end
|
85
|
+
|
86
|
+
# Invert source and destination port numbers
|
87
|
+
# @return [self]
|
88
|
+
# @since 2.7.0
|
89
|
+
def reply!
|
90
|
+
self[:sport], self[:dport] = self[:dport], self[:sport]
|
91
|
+
self
|
92
|
+
end
|
87
93
|
end
|
88
94
|
|
89
95
|
self.add_class UDP
|
90
96
|
|
91
|
-
IP.
|
92
|
-
IPv6.
|
97
|
+
IP.bind UDP, protocol: UDP::IP_PROTOCOL
|
98
|
+
IPv6.bind UDP, next: UDP::IP_PROTOCOL
|
93
99
|
end
|
94
100
|
end
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -6,12 +6,10 @@
|
|
6
6
|
# frozen_string_literal: true
|
7
7
|
|
8
8
|
module PacketGen
|
9
|
-
|
10
9
|
# {Inspect} module provides methods to help writing +inspect+
|
11
10
|
# @api private
|
12
11
|
# @author Sylvain Daubert
|
13
12
|
module Inspect
|
14
|
-
|
15
13
|
# Maximum number of characters on a line for INSPECT
|
16
14
|
MAX_WIDTH = 70
|
17
15
|
|
@@ -53,7 +51,7 @@ module PacketGen
|
|
53
51
|
str = shift_level(level)
|
54
52
|
val = if value.is_a?(Types::Enum)
|
55
53
|
"%-10s (0x%0#{value.sz * 2}x)" % [value.to_human, value.to_i]
|
56
|
-
elsif value.is_a?(Types::Int)
|
54
|
+
elsif value.is_a?(Types::Int) || value.is_a?(Integer)
|
57
55
|
int_dec_hex(value, value.sz * 2)
|
58
56
|
elsif value.is_a?(String)
|
59
57
|
value.to_s.inspect
|
@@ -96,16 +94,16 @@ module PacketGen
|
|
96
94
|
# @param [#to_s] body
|
97
95
|
# @return [String]
|
98
96
|
def self.inspect_body(body, name='Body')
|
99
|
-
return '' if body.nil?
|
97
|
+
return '' if body.nil? || body.empty?
|
100
98
|
str = dashed_line(name, 2)
|
101
|
-
str << (0..15).to_a.map { |v|
|
99
|
+
str << (0..15).to_a.map { |v| ' %02d' % v }.join << "\n"
|
102
100
|
str << '-' * MAX_WIDTH << "\n"
|
103
|
-
|
101
|
+
unless body.empty?
|
104
102
|
(body.size / 16 + 1).times do |i|
|
105
|
-
octets = body.to_s[i*16, 16].unpack('C*')
|
106
|
-
o_str = octets.map { |v|
|
103
|
+
octets = body.to_s[i * 16, 16].unpack('C*')
|
104
|
+
o_str = octets.map { |v| ' %02x' % v }.join
|
107
105
|
str << o_str
|
108
|
-
str << ' ' * (3*16 - o_str.size) unless o_str.size >= 3*16
|
106
|
+
str << ' ' * (3 * 16 - o_str.size) unless o_str.size >= 3 * 16
|
109
107
|
str << ' ' << octets.map { |v| v < 128 && v > 31 ? v.chr : '.' }.join
|
110
108
|
str << "\n"
|
111
109
|
end
|
data/lib/packetgen/packet.rb
CHANGED
@@ -5,10 +5,10 @@
|
|
5
5
|
# This program is published under MIT license.
|
6
6
|
|
7
7
|
# frozen_string_literal: true
|
8
|
+
|
8
9
|
require 'pcaprub'
|
9
10
|
|
10
11
|
module PacketGen
|
11
|
-
|
12
12
|
# An object of type {Packet} handles a network packet. This packet may contain
|
13
13
|
# multiple protocol headers, starting from MAC layer or from Network (OSI) layer.
|
14
14
|
#
|
@@ -107,17 +107,15 @@ module PacketGen
|
|
107
107
|
# @author Sylvain Daubert
|
108
108
|
# @author Kent Gruber
|
109
109
|
def self.read(filename)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
packets << packet
|
118
|
-
end
|
119
|
-
packets
|
110
|
+
PcapNG::File.new.read_packets filename
|
111
|
+
rescue StandardError => e
|
112
|
+
raise ArgumentError, e unless File.extname(filename.downcase) == '.pcap'
|
113
|
+
packets = []
|
114
|
+
PCAPRUB::Pcap.open_offline(filename).each_packet do |packet|
|
115
|
+
next unless (packet = PacketGen.parse(packet.to_s))
|
116
|
+
packets << packet
|
120
117
|
end
|
118
|
+
packets
|
121
119
|
end
|
122
120
|
|
123
121
|
# Write packets to +filename+
|
@@ -225,7 +223,7 @@ module PacketGen
|
|
225
223
|
def to_f(filename)
|
226
224
|
PcapNG::File.new.array_to_file(filename: filename, array: [self])
|
227
225
|
end
|
228
|
-
alias
|
226
|
+
alias write to_f
|
229
227
|
|
230
228
|
# send packet on wire. Use first header +#to_w+ method.
|
231
229
|
# @param [String] iface interface name. Default to first non-loopback interface
|
@@ -277,9 +275,9 @@ module PacketGen
|
|
277
275
|
raise FormatError, 'header not in packet!' if idx.nil?
|
278
276
|
|
279
277
|
prev_header = idx > 0 ? @headers[idx - 1] : nil
|
280
|
-
next_header = (idx+1) < @headers.size ? @headers[idx + 1] : nil
|
278
|
+
next_header = (idx + 1) < @headers.size ? @headers[idx + 1] : nil
|
281
279
|
@headers.delete_at(idx)
|
282
|
-
if prev_header
|
280
|
+
if prev_header && next_header
|
283
281
|
add_header(next_header, previous_header: prev_header)
|
284
282
|
end
|
285
283
|
end
|
@@ -325,12 +323,32 @@ module PacketGen
|
|
325
323
|
to_s == other.to_s
|
326
324
|
end
|
327
325
|
|
326
|
+
# Invert all possible fields in packet to create a reply.
|
327
|
+
# @return [self]
|
328
|
+
def reply!
|
329
|
+
@headers.each do |header|
|
330
|
+
header.reply! if header.respond_to?(:reply!)
|
331
|
+
end
|
332
|
+
self
|
333
|
+
end
|
334
|
+
|
335
|
+
# Forge a new packet from current one with all possible fields
|
336
|
+
# inverted. The new packet may be a reply to current one.
|
337
|
+
# @return [Packet]
|
338
|
+
def reply
|
339
|
+
pkt = dup
|
340
|
+
pkt.reply!
|
341
|
+
end
|
342
|
+
|
328
343
|
private
|
329
344
|
|
330
345
|
# Dup +@headers+ instance variable. Internally used by +#dup+ and +#clone+
|
331
346
|
# @return [void]
|
332
|
-
def initialize_copy(
|
333
|
-
@headers = @headers.dup
|
347
|
+
def initialize_copy(_other)
|
348
|
+
@headers = @headers.map(&:dup)
|
349
|
+
@headers.each do |header|
|
350
|
+
add_magic_header_method header
|
351
|
+
end
|
334
352
|
end
|
335
353
|
|
336
354
|
# @overload header(klass, layer=1)
|
@@ -386,15 +404,19 @@ module PacketGen
|
|
386
404
|
raise ArgumentError, msg
|
387
405
|
end
|
388
406
|
end
|
389
|
-
bindings.set(prev_header) if !bindings.empty?
|
407
|
+
bindings.set(prev_header) if !bindings.empty? && !parsing
|
390
408
|
prev_header[:body] = header
|
391
409
|
end
|
392
410
|
header.packet = self
|
393
411
|
@headers << header unless previous_header
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
412
|
+
|
413
|
+
return if respond_to? header.method_name
|
414
|
+
add_magic_header_method header
|
415
|
+
end
|
416
|
+
|
417
|
+
def add_magic_header_method(header)
|
418
|
+
self.instance_eval "def #{header.method_name}(arg=nil);" \
|
419
|
+
"header(#{header.class}, arg); end"
|
398
420
|
end
|
399
421
|
|
400
422
|
def guess_first_header(binary_str)
|
@@ -418,7 +440,7 @@ module PacketGen
|
|
418
440
|
|
419
441
|
def decode_bottom_up
|
420
442
|
decode_packet_bottom_up = true
|
421
|
-
while decode_packet_bottom_up
|
443
|
+
while decode_packet_bottom_up
|
422
444
|
last_known_hdr = @headers.last
|
423
445
|
break unless last_known_hdr.respond_to? :body
|
424
446
|
break if last_known_hdr.body.empty?
|