packetgen 3.1.1 → 3.1.6
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/bin/pgconsole +1 -0
- data/lib/packetgen.rb +33 -4
- data/lib/packetgen/capture.rb +51 -28
- data/lib/packetgen/config.rb +17 -11
- data/lib/packetgen/deprecation.rb +34 -8
- data/lib/packetgen/header.rb +2 -9
- data/lib/packetgen/header/arp.rb +2 -2
- data/lib/packetgen/header/asn1_base.rb +2 -2
- data/lib/packetgen/header/base.rb +70 -74
- data/lib/packetgen/header/bootp.rb +3 -3
- data/lib/packetgen/header/dhcp.rb +2 -2
- data/lib/packetgen/header/dhcp/option.rb +2 -2
- data/lib/packetgen/header/dhcp/options.rb +2 -2
- data/lib/packetgen/header/dhcpv6.rb +12 -12
- data/lib/packetgen/header/dhcpv6/duid.rb +11 -5
- data/lib/packetgen/header/dhcpv6/option.rb +8 -16
- data/lib/packetgen/header/dhcpv6/options.rb +2 -2
- data/lib/packetgen/header/dhcpv6/relay.rb +2 -2
- data/lib/packetgen/header/dns.rb +9 -9
- data/lib/packetgen/header/dns/name.rb +20 -9
- data/lib/packetgen/header/dns/opt.rb +2 -2
- data/lib/packetgen/header/dns/option.rb +2 -2
- data/lib/packetgen/header/dns/qdsection.rb +3 -3
- data/lib/packetgen/header/dns/question.rb +37 -35
- data/lib/packetgen/header/dns/rr.rb +3 -3
- data/lib/packetgen/header/dns/rrsection.rb +2 -2
- data/lib/packetgen/header/dot11.rb +30 -51
- data/lib/packetgen/header/dot11/control.rb +5 -5
- data/lib/packetgen/header/dot11/data.rb +11 -7
- data/lib/packetgen/header/dot11/element.rb +16 -16
- data/lib/packetgen/header/dot11/management.rb +2 -2
- data/lib/packetgen/header/dot11/sub_mngt.rb +2 -12
- data/lib/packetgen/header/dot1q.rb +2 -2
- data/lib/packetgen/header/dot1x.rb +7 -20
- data/lib/packetgen/header/eap.rb +30 -33
- data/lib/packetgen/header/eap/fast.rb +2 -2
- data/lib/packetgen/header/eap/md5.rb +2 -2
- data/lib/packetgen/header/eap/tls.rb +2 -2
- data/lib/packetgen/header/eap/ttls.rb +2 -2
- data/lib/packetgen/header/eth.rb +13 -11
- data/lib/packetgen/header/gre.rb +2 -2
- data/lib/packetgen/header/http.rb +2 -0
- data/lib/packetgen/header/http/headers.rb +6 -4
- data/lib/packetgen/header/http/request.rb +36 -21
- data/lib/packetgen/header/http/response.rb +7 -7
- data/lib/packetgen/header/http/verbs.rb +3 -3
- data/lib/packetgen/header/icmp.rb +2 -2
- data/lib/packetgen/header/icmpv6.rb +2 -2
- data/lib/packetgen/header/igmp.rb +4 -4
- data/lib/packetgen/header/igmpv3.rb +3 -3
- data/lib/packetgen/header/igmpv3/group_record.rb +8 -6
- data/lib/packetgen/header/igmpv3/mq.rb +2 -2
- data/lib/packetgen/header/igmpv3/mr.rb +2 -2
- data/lib/packetgen/header/ip.rb +30 -31
- data/lib/packetgen/header/ip/addr.rb +10 -3
- data/lib/packetgen/header/ip/option.rb +8 -10
- data/lib/packetgen/header/ip/options.rb +3 -5
- data/lib/packetgen/header/ipv6.rb +2 -2
- data/lib/packetgen/header/ipv6/addr.rb +9 -2
- data/lib/packetgen/header/ipv6/extension.rb +2 -2
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +3 -3
- data/lib/packetgen/header/llc.rb +2 -2
- data/lib/packetgen/header/mdns.rb +2 -2
- data/lib/packetgen/header/mld.rb +2 -2
- data/lib/packetgen/header/mldv2.rb +2 -2
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +4 -2
- data/lib/packetgen/header/mldv2/mlq.rb +2 -2
- data/lib/packetgen/header/mldv2/mlr.rb +2 -2
- data/lib/packetgen/header/ospfv2.rb +9 -9
- data/lib/packetgen/header/ospfv2/db_description.rb +2 -2
- data/lib/packetgen/header/ospfv2/hello.rb +2 -2
- data/lib/packetgen/header/ospfv2/ls_ack.rb +2 -2
- data/lib/packetgen/header/ospfv2/ls_request.rb +4 -2
- data/lib/packetgen/header/ospfv2/ls_update.rb +2 -2
- data/lib/packetgen/header/ospfv2/lsa.rb +9 -5
- data/lib/packetgen/header/ospfv2/lsa_header.rb +8 -7
- data/lib/packetgen/header/ospfv3.rb +2 -2
- data/lib/packetgen/header/ospfv3/db_description.rb +2 -2
- data/lib/packetgen/header/ospfv3/hello.rb +2 -2
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +4 -2
- data/lib/packetgen/header/ospfv3/ls_ack.rb +2 -2
- data/lib/packetgen/header/ospfv3/ls_request.rb +4 -2
- data/lib/packetgen/header/ospfv3/ls_update.rb +2 -2
- data/lib/packetgen/header/ospfv3/lsa.rb +5 -5
- data/lib/packetgen/header/ospfv3/lsa_header.rb +9 -8
- data/lib/packetgen/header/snmp.rb +33 -29
- data/lib/packetgen/header/tcp.rb +4 -23
- data/lib/packetgen/header/tcp/option.rb +11 -11
- data/lib/packetgen/header/tcp/options.rb +2 -2
- data/lib/packetgen/header/tftp.rb +6 -6
- data/lib/packetgen/header/udp.rb +3 -3
- data/lib/packetgen/headerable.rb +5 -4
- data/lib/packetgen/inject.rb +23 -0
- data/lib/packetgen/inspect.rb +23 -20
- data/lib/packetgen/packet.rb +96 -53
- data/lib/packetgen/pcap.rb +29 -0
- data/lib/packetgen/pcapng.rb +13 -13
- data/lib/packetgen/pcapng/block.rb +26 -13
- data/lib/packetgen/pcapng/epb.rb +25 -22
- data/lib/packetgen/pcapng/file.rb +260 -138
- data/lib/packetgen/pcapng/idb.rb +36 -38
- data/lib/packetgen/pcapng/shb.rb +51 -53
- data/lib/packetgen/pcapng/spb.rb +19 -19
- data/lib/packetgen/pcapng/unknown_block.rb +5 -13
- data/lib/packetgen/pcaprub_wrapper.rb +81 -0
- data/lib/packetgen/proto.rb +2 -2
- data/lib/packetgen/types.rb +3 -0
- data/lib/packetgen/types/abstract_tlv.rb +28 -8
- data/lib/packetgen/types/array.rb +22 -15
- data/lib/packetgen/types/cstring.rb +40 -16
- data/lib/packetgen/types/enum.rb +8 -3
- data/lib/packetgen/types/fieldable.rb +65 -0
- data/lib/packetgen/types/fields.rb +182 -117
- data/lib/packetgen/types/int.rb +18 -6
- data/lib/packetgen/types/int_string.rb +10 -2
- data/lib/packetgen/types/length_from.rb +20 -12
- data/lib/packetgen/types/oui.rb +4 -2
- data/lib/packetgen/types/string.rb +46 -8
- data/lib/packetgen/types/tlv.rb +4 -2
- data/lib/packetgen/utils.rb +4 -4
- data/lib/packetgen/utils/arp_spoofer.rb +2 -2
- data/lib/packetgen/version.rb +3 -3
- metadata +35 -50
- data/.gitignore +0 -13
- data/.rubocop.yml +0 -28
- data/.travis.yml +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -21
- data/packetgen.gemspec +0 -36
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
# TCP header ({https://tools.ietf.org/html/rfc793 RFC 793})
|
@@ -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]
|
@@ -235,7 +216,7 @@ module PacketGen
|
|
235
216
|
doff = Inspect.int_dec_hex(data_offset, 1)
|
236
217
|
str << shift << Inspect::FMT_ATTR % ['', 'data_offset', doff]
|
237
218
|
str << shift << Inspect::FMT_ATTR % ['', 'reserved', reserved]
|
238
|
-
flags = ''
|
219
|
+
flags = +''
|
239
220
|
%w[ns cwr ece urg ack psh rst syn fin].each do |fl|
|
240
221
|
flags << (send("flag_#{fl}?") ? fl[0].upcase : '.')
|
241
222
|
end
|
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
class TCP
|
11
11
|
# Base class to describe a TCP option
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Option < Types::Fields
|
14
|
+
include Types::Fieldable
|
15
|
+
|
14
16
|
# EOL option value
|
15
17
|
EOL_KIND = 0
|
16
18
|
# NOP option value
|
@@ -91,15 +93,15 @@ module PacketGen
|
|
91
93
|
# Setter for value attribute
|
92
94
|
# @param[String,Integer]
|
93
95
|
# @return [String, Integer]
|
94
|
-
def value=(
|
96
|
+
def value=(val)
|
95
97
|
case self[:value]
|
96
98
|
when Types::Int
|
97
99
|
self.length = 2 + self[:value].sz
|
98
|
-
when String
|
99
|
-
self.length = 2 + Types::String.new.read(
|
100
|
+
when Types::String
|
101
|
+
self.length = 2 + Types::String.new.read(val).sz
|
100
102
|
end
|
101
|
-
self[:value].read
|
102
|
-
|
103
|
+
self[:value].read val
|
104
|
+
val
|
103
105
|
end
|
104
106
|
|
105
107
|
# Get binary string
|
@@ -112,10 +114,8 @@ module PacketGen
|
|
112
114
|
# Get option as a human readable string
|
113
115
|
# @return [String]
|
114
116
|
def to_human
|
115
|
-
str = self.
|
116
|
-
if (length > 2) && !self[:value].to_s.empty?
|
117
|
-
str << ":#{self[:value].to_s.inspect}"
|
118
|
-
end
|
117
|
+
str = self.instance_of?(Option) ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
|
118
|
+
str << ":#{self[:value].to_s.inspect}" if (length > 2) && !self[:value].to_s.empty?
|
119
119
|
str
|
120
120
|
end
|
121
121
|
|
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
require_relative 'option'
|
9
9
|
|
10
10
|
module PacketGen
|
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
# A TFTP (Trivial File Transfer Protocol,
|
@@ -49,10 +49,10 @@ module PacketGen
|
|
49
49
|
class TFTP < Base
|
50
50
|
# Known opcodes
|
51
51
|
OPCODES = {
|
52
|
-
'RRQ'
|
53
|
-
'WRQ'
|
54
|
-
'DATA'
|
55
|
-
'ACK'
|
52
|
+
'RRQ' => 1,
|
53
|
+
'WRQ' => 2,
|
54
|
+
'DATA' => 3,
|
55
|
+
'ACK' => 4,
|
56
56
|
'Error' => 5
|
57
57
|
}.freeze
|
58
58
|
|
data/lib/packetgen/header/udp.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
module Header
|
10
10
|
# UDP header ({https://tools.ietf.org/html/rfc768 RFC 768})
|
@@ -71,7 +71,7 @@ module PacketGen
|
|
71
71
|
# option is set.
|
72
72
|
def initialize(options={})
|
73
73
|
super
|
74
|
-
self.length += self[:body].sz if self[:body].sz
|
74
|
+
self.length += self[:body].sz if self[:body].sz.positive?
|
75
75
|
end
|
76
76
|
|
77
77
|
# Compute checksum and set +checksum+ field
|
data/lib/packetgen/headerable.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
# This mixin module defines minimal API for a class to act as a header
|
10
10
|
# in {Packet}.
|
@@ -85,9 +85,10 @@ module PacketGen
|
|
85
85
|
# @return [self]
|
86
86
|
# @raise [NotImplementedError]
|
87
87
|
def read(str)
|
88
|
+
# Do not call super and rescue NoMethodError: too slow
|
89
|
+
raise NotImplementedError, "#{self.class} should implement #read" if method(:read).super_method.nil?
|
90
|
+
|
88
91
|
super
|
89
|
-
rescue NoMethodError
|
90
|
-
raise NotImplementedError, "#{self.class} should implement #read"
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -0,0 +1,23 @@
|
|
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
|
+
require_relative 'pcaprub_wrapper'
|
8
|
+
|
9
|
+
module PacketGen
|
10
|
+
# Module to inject packets on wire
|
11
|
+
# @author Sylvain Daubert
|
12
|
+
# @api private
|
13
|
+
# @since 3.1.4
|
14
|
+
module Inject
|
15
|
+
# Inject given data onto wire
|
16
|
+
# @param [String] iface interface name
|
17
|
+
# @param [String,Packet,Header::Base] data to inject
|
18
|
+
# @return [void]
|
19
|
+
def self.inject(iface:, data:)
|
20
|
+
PCAPRUBWrapper.inject(iface: iface, data: data.to_s)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file is part of PacketGen
|
2
4
|
# See https://github.com/sdaubert/packetgen for more informations
|
3
5
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
6
|
# This program is published under MIT license.
|
5
7
|
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
8
|
module PacketGen
|
9
9
|
# {Inspect} module provides methods to help writing +inspect+
|
10
10
|
# @api private
|
@@ -37,6 +37,25 @@ module PacketGen
|
|
37
37
|
"%-16s (0x%0#{hexsize}x)" % [value.to_i, value.to_i]
|
38
38
|
end
|
39
39
|
|
40
|
+
# @param [String] str
|
41
|
+
# @param [Integer] int
|
42
|
+
# @param [Integer] hexsize
|
43
|
+
# @return [String]
|
44
|
+
def self.enum_human_hex(str, int, hexsize)
|
45
|
+
"%-16s (0x%0#{hexsize}x)" % [str, int]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Simple formatter to inspect an attribute
|
49
|
+
# @param [String] type attribute type
|
50
|
+
# @param [String] attr attribute name
|
51
|
+
# @param [String] value
|
52
|
+
# @param [Integer] level
|
53
|
+
# @return [String]
|
54
|
+
def self.format(type, attr, value, level=1)
|
55
|
+
str = Inspect.shift_level(level)
|
56
|
+
str << Inspect::FMT_ATTR % [type, attr, value]
|
57
|
+
end
|
58
|
+
|
40
59
|
# Format an attribute for +#inspect+.
|
41
60
|
# 3 cases are handled:
|
42
61
|
# * attribute value is a {Types::Int}: show value as integer and in
|
@@ -48,24 +67,8 @@ module PacketGen
|
|
48
67
|
# @param [Integer] level
|
49
68
|
# @return [String]
|
50
69
|
def self.inspect_attribute(attr, value, level=1)
|
51
|
-
|
52
|
-
|
53
|
-
when Types::Enum
|
54
|
-
"%-16s (0x%0#{value.sz * 2}x)" % [value.to_human, value.to_i]
|
55
|
-
when Types::Int
|
56
|
-
int_dec_hex(value, value.sz * 2)
|
57
|
-
when Integer
|
58
|
-
int_dec_hex(value, value.sz * 2)
|
59
|
-
when String
|
60
|
-
value.to_s.inspect
|
61
|
-
else
|
62
|
-
if value.respond_to? :to_human
|
63
|
-
value.to_human
|
64
|
-
else
|
65
|
-
value.to_s.inspect
|
66
|
-
end
|
67
|
-
end
|
68
|
-
str << FMT_ATTR % [value.class.to_s.sub(/.*::/, ''), attr, val]
|
70
|
+
type = value.class.to_s.sub(/.*::/, '')
|
71
|
+
self.format(type, attr, value.format_inspect, level)
|
69
72
|
end
|
70
73
|
|
71
74
|
# Format a ASN.1 attribute for +#inspect+.
|
data/lib/packetgen/packet.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
# This file is part of PacketGen
|
3
5
|
# See https://github.com/sdaubert/packetgen for more informations
|
4
6
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
5
7
|
# This program is published under MIT license.
|
6
8
|
|
7
|
-
#
|
8
|
-
|
9
|
-
require 'pcaprub'
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
10
10
|
|
11
11
|
module PacketGen
|
12
12
|
# An object of type {Packet} handles a network packet. This packet may contain
|
@@ -79,36 +79,31 @@ module PacketGen
|
|
79
79
|
# @yieldparam [Packet,String] packet if a block is given, yield each
|
80
80
|
# captured packet (Packet or raw data String, depending on +:parse+ option)
|
81
81
|
# @return [Array<Packet>] captured packet
|
82
|
-
def self.capture(**kwargs)
|
83
|
-
capture = Capture.new(kwargs)
|
82
|
+
def self.capture(**kwargs, &block)
|
83
|
+
capture = Capture.new(**kwargs)
|
84
84
|
if block_given?
|
85
|
-
capture.start
|
85
|
+
capture.start(&block)
|
86
86
|
else
|
87
87
|
capture.start
|
88
88
|
end
|
89
89
|
capture.packets
|
90
90
|
end
|
91
91
|
|
92
|
-
# Read packets from +filename+.
|
92
|
+
# Read packets from +filename+. May read Pcap and Pcap-NG formats.
|
93
93
|
#
|
94
|
-
# For more control, see {PcapNG::File}
|
94
|
+
# For more control (on Pcap-ng only), see {PcapNG::File}.
|
95
95
|
# @param [String] filename PcapNG or Pcap file.
|
96
96
|
# @return [Array<Packet>]
|
97
|
+
# @raise [ArgumentError] unknown file format
|
97
98
|
# @author Sylvain Daubert
|
98
99
|
# @author Kent Gruber - Pcap format
|
99
100
|
# @since 2.0.0 Also read Pcap format.
|
100
101
|
def self.read(filename)
|
101
|
-
PcapNG::File.new.read_packets
|
102
|
+
PcapNG::File.new.read_packets(filename)
|
102
103
|
rescue StandardError => e
|
103
104
|
raise ArgumentError, e unless File.extname(filename.downcase) == '.pcap'
|
104
105
|
|
105
|
-
|
106
|
-
PCAPRUB::Pcap.open_offline(filename).each_packet do |packet|
|
107
|
-
next unless (packet = PacketGen.parse(packet.to_s))
|
108
|
-
|
109
|
-
packets << packet
|
110
|
-
end
|
111
|
-
packets
|
106
|
+
Pcap.read(filename)
|
112
107
|
end
|
113
108
|
|
114
109
|
# Write packets to +filename+
|
@@ -132,11 +127,13 @@ module PacketGen
|
|
132
127
|
# @param [String] protocol
|
133
128
|
# @param [Hash] options protocol specific options
|
134
129
|
# @return [self]
|
135
|
-
# @raise [
|
130
|
+
# @raise [BindingError] unknown protocol
|
136
131
|
def add(protocol, options={})
|
137
132
|
klass = check_protocol(protocol)
|
138
133
|
|
139
|
-
|
134
|
+
# options[:packet]= self is speedier than options.merge(packet: self)
|
135
|
+
options[:packet] = self
|
136
|
+
header = klass.new(options)
|
140
137
|
add_header header
|
141
138
|
self
|
142
139
|
end
|
@@ -146,12 +143,14 @@ module PacketGen
|
|
146
143
|
# @param [String] protocol protocol to insert
|
147
144
|
# @param [Hash] options protocol specific options
|
148
145
|
# @return [self]
|
149
|
-
# @raise [
|
146
|
+
# @raise [BindingError] unknown protocol
|
150
147
|
def insert(prev, protocol, options={})
|
151
148
|
klass = check_protocol(protocol)
|
152
149
|
|
153
150
|
nxt = prev.body
|
154
|
-
|
151
|
+
# options[:packet]= self is speedier than options.merge(packet: self)
|
152
|
+
options[:packet] = self
|
153
|
+
header = klass.new(options)
|
155
154
|
add_header header, previous_header: prev
|
156
155
|
idx = headers.index(prev) + 1
|
157
156
|
headers[idx, 0] = header
|
@@ -217,7 +216,7 @@ module PacketGen
|
|
217
216
|
# @return [Array] see return from {PcapNG::File#to_file}
|
218
217
|
# @see File
|
219
218
|
def to_f(filename)
|
220
|
-
PcapNG::File.new.array_to_file(
|
219
|
+
PcapNG::File.new.array_to_file(file: filename, array: [self])
|
221
220
|
end
|
222
221
|
alias write to_f
|
223
222
|
|
@@ -251,10 +250,11 @@ module PacketGen
|
|
251
250
|
# from binding with first other's one. Use only when current header field
|
252
251
|
# has its value set accordingly.
|
253
252
|
# @return [self] +self+ with new headers from +other+
|
253
|
+
# @raise [BindingError] do not known how to encapsulate
|
254
254
|
# @since 1.1.0
|
255
255
|
def encapsulate(other, parsing: false)
|
256
256
|
other.headers.each_with_index do |h, i|
|
257
|
-
add_header h, parsing:
|
257
|
+
add_header h, parsing: i.positive? || parsing
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
@@ -262,36 +262,32 @@ module PacketGen
|
|
262
262
|
# @param [Array<Header>] hdrs
|
263
263
|
# @return [self] +self+ with some headers removed
|
264
264
|
# @raise [FormatError] any headers not in +self+
|
265
|
-
# @raise [
|
265
|
+
# @raise [BindingError] removed headers result in an unknown binding
|
266
266
|
# @since 1.1.0
|
267
267
|
def decapsulate(*hdrs)
|
268
268
|
hdrs.each do |hdr|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
prev_hdr = idx > 0 ? headers[idx - 1] : nil
|
273
|
-
next_hdr = (idx + 1) < headers.size ? headers[idx + 1] : nil
|
274
|
-
headers.delete_at(idx)
|
269
|
+
prev_hdr = previous_header(hdr)
|
270
|
+
next_hdr = next_header(hdr)
|
271
|
+
headers.delete(hdr)
|
275
272
|
add_header(next_hdr, previous_header: prev_hdr) if prev_hdr && next_hdr
|
276
273
|
end
|
277
|
-
rescue ArgumentError =>
|
278
|
-
raise FormatError,
|
274
|
+
rescue ArgumentError => e
|
275
|
+
raise FormatError, e.message
|
279
276
|
end
|
280
277
|
|
281
278
|
# Parse a binary string and populate Packet from it.
|
282
279
|
# @param [String] binary_str
|
283
280
|
# @param [String,nil] first_header First protocol header. +nil+ means discover it!
|
284
281
|
# @return [Packet] self
|
285
|
-
# @raise [
|
282
|
+
# @raise [ParseError] +first_header+ is an unknown header
|
283
|
+
# @raise [BindingError] unknwon binding between some headers
|
286
284
|
def parse(binary_str, first_header: nil)
|
287
285
|
headers.clear
|
288
286
|
|
289
287
|
if first_header.nil?
|
290
288
|
# No decoding forced for first header. Have to guess it!
|
291
289
|
first_header = guess_first_header(binary_str)
|
292
|
-
if first_header.nil?
|
293
|
-
raise ParseError, 'cannot identify first header in string'
|
294
|
-
end
|
290
|
+
raise ParseError, 'cannot identify first header in string' if first_header.nil?
|
295
291
|
end
|
296
292
|
|
297
293
|
add first_header
|
@@ -318,6 +314,20 @@ module PacketGen
|
|
318
314
|
to_s == other.to_s
|
319
315
|
end
|
320
316
|
|
317
|
+
# @param [Packet] other
|
318
|
+
# @return [Boolean]
|
319
|
+
# @since 3.1.2
|
320
|
+
def ===(other)
|
321
|
+
case other
|
322
|
+
when PacketGen::Packet
|
323
|
+
self == other
|
324
|
+
when String
|
325
|
+
is? other
|
326
|
+
else
|
327
|
+
false
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
321
331
|
# Invert all possible fields in packet to create a reply.
|
322
332
|
# @return [self]
|
323
333
|
# @since 2.7.0
|
@@ -360,6 +370,35 @@ module PacketGen
|
|
360
370
|
headers.last
|
361
371
|
end
|
362
372
|
|
373
|
+
# Give header index in packet
|
374
|
+
# @param [Headerable] hdr
|
375
|
+
# @return [Integer]
|
376
|
+
# @raise [FormatError] +hdr+ not in packet
|
377
|
+
def header_index(hdr)
|
378
|
+
idx = headers.index(hdr)
|
379
|
+
raise FormatError, 'header not in packet!' if idx.nil?
|
380
|
+
|
381
|
+
idx
|
382
|
+
end
|
383
|
+
|
384
|
+
# Give header previous +hdr+ in packet
|
385
|
+
# @param [Headerable] hdr
|
386
|
+
# @return [Headerable,nil] May return +nil+ if +hdr+ is the first header in packet
|
387
|
+
# @raise [FormatError] +hdr+ not in packet
|
388
|
+
def previous_header(hdr)
|
389
|
+
idx = header_index(hdr)
|
390
|
+
idx.positive? ? headers[idx - 1] : nil
|
391
|
+
end
|
392
|
+
|
393
|
+
# Give header next +hdr+ in packet
|
394
|
+
# @param [Headerable] hdr
|
395
|
+
# @return [Headerable,nil] May return +nil+ if +hdr+ is the last header in packet
|
396
|
+
# @raise [FormatError] +hdr+ not in packet
|
397
|
+
def next_header(hdr)
|
398
|
+
idx = header_index(hdr)
|
399
|
+
(idx + 1) < headers.size ? headers[idx + 1] : nil
|
400
|
+
end
|
401
|
+
|
363
402
|
# @overload header(klass, layer=1)
|
364
403
|
# @param [Class] klass
|
365
404
|
# @param [Integer] layer
|
@@ -374,9 +413,8 @@ module PacketGen
|
|
374
413
|
return header unless arg.is_a? Hash
|
375
414
|
|
376
415
|
arg.each do |key, value|
|
377
|
-
unless header.respond_to? "#{key}="
|
378
|
-
|
379
|
-
end
|
416
|
+
raise ArgumentError, "unknown #{key} attribute for #{klass}" unless header.respond_to? "#{key}="
|
417
|
+
|
380
418
|
header.send "#{key}=", value
|
381
419
|
end
|
382
420
|
|
@@ -394,26 +432,15 @@ module PacketGen
|
|
394
432
|
end
|
395
433
|
|
396
434
|
# Add a header to packet
|
397
|
-
# @param [
|
398
|
-
# @param [
|
435
|
+
# @param [Headerable] header
|
436
|
+
# @param [Headerable] previous_header
|
399
437
|
# @param [Boolean] parsing
|
400
438
|
# @return [void]
|
439
|
+
# @raise [BindingError]
|
401
440
|
def add_header(header, previous_header: nil, parsing: false)
|
402
441
|
prev_header = previous_header || last_header
|
403
|
-
if prev_header
|
404
|
-
bindings = prev_header.class.known_headers[header.class]
|
405
|
-
bindings = prev_header.class.known_headers[header.class.superclass] if bindings.nil?
|
406
|
-
if bindings.nil?
|
407
|
-
msg = "#{prev_header.class} knowns no layer association with #{header.protocol_name}. ".dup
|
408
|
-
msg << "Try #{prev_header.class}.bind_layer(#{header.class}, "
|
409
|
-
msg << "#{prev_header.method_name}_proto_field: "
|
410
|
-
msg << "value_for_#{header.method_name})"
|
411
|
-
raise ArgumentError, msg
|
412
|
-
end
|
442
|
+
add_to_previous_header(prev_header, header, parsing) if prev_header
|
413
443
|
|
414
|
-
bindings.set(prev_header) if !bindings.empty? && !parsing
|
415
|
-
prev_header[:body] = header
|
416
|
-
end
|
417
444
|
header.packet = self
|
418
445
|
headers << header unless previous_header
|
419
446
|
|
@@ -422,6 +449,20 @@ module PacketGen
|
|
422
449
|
add_magic_header_method header
|
423
450
|
end
|
424
451
|
|
452
|
+
# Bind +header+ to +prev_header+.
|
453
|
+
# @param [Headerable] prev_header
|
454
|
+
# @param [Headerable] header
|
455
|
+
# @param [Boolean] parsing
|
456
|
+
# @return [void]
|
457
|
+
# @raise [BindingError]
|
458
|
+
def add_to_previous_header(prev_header, header, parsing)
|
459
|
+
bindings = prev_header.class.known_headers[header.class] || prev_header.class.known_headers[header.class.superclass]
|
460
|
+
raise BindingError.new(prev_header, header) if bindings.nil?
|
461
|
+
|
462
|
+
bindings.set(prev_header) if !bindings.empty? && !parsing
|
463
|
+
prev_header[:body] = header
|
464
|
+
end
|
465
|
+
|
425
466
|
# Add method to access +header+
|
426
467
|
# @param [Header::Base] header
|
427
468
|
# @return [void]
|
@@ -483,5 +524,7 @@ module PacketGen
|
|
483
524
|
end
|
484
525
|
end
|
485
526
|
|
527
|
+
# rubocop:enable Metrics/ClassLength
|
528
|
+
|
486
529
|
require_relative 'headerable'
|
487
530
|
require_relative 'header'
|