packetgen 3.1.3 → 3.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -1
- 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 +33 -7
- 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 +82 -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 +27 -7
- data/lib/packetgen/types/array.rb +22 -15
- data/lib/packetgen/types/cstring.rb +57 -20
- data/lib/packetgen/types/enum.rb +7 -2
- 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 +59 -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 +39 -61
- data/.gitignore +0 -13
- data/.rubocop.yml +0 -30
- data/.travis.yml +0 -19
- 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
|
@@ -374,6 +370,35 @@ module PacketGen
|
|
374
370
|
headers.last
|
375
371
|
end
|
376
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
|
+
|
377
402
|
# @overload header(klass, layer=1)
|
378
403
|
# @param [Class] klass
|
379
404
|
# @param [Integer] layer
|
@@ -388,9 +413,8 @@ module PacketGen
|
|
388
413
|
return header unless arg.is_a? Hash
|
389
414
|
|
390
415
|
arg.each do |key, value|
|
391
|
-
unless header.respond_to? "#{key}="
|
392
|
-
|
393
|
-
end
|
416
|
+
raise ArgumentError, "unknown #{key} attribute for #{klass}" unless header.respond_to? "#{key}="
|
417
|
+
|
394
418
|
header.send "#{key}=", value
|
395
419
|
end
|
396
420
|
|
@@ -408,26 +432,15 @@ module PacketGen
|
|
408
432
|
end
|
409
433
|
|
410
434
|
# Add a header to packet
|
411
|
-
# @param [
|
412
|
-
# @param [
|
435
|
+
# @param [Headerable] header
|
436
|
+
# @param [Headerable] previous_header
|
413
437
|
# @param [Boolean] parsing
|
414
438
|
# @return [void]
|
439
|
+
# @raise [BindingError]
|
415
440
|
def add_header(header, previous_header: nil, parsing: false)
|
416
441
|
prev_header = previous_header || last_header
|
417
|
-
if prev_header
|
418
|
-
bindings = prev_header.class.known_headers[header.class]
|
419
|
-
bindings = prev_header.class.known_headers[header.class.superclass] if bindings.nil?
|
420
|
-
if bindings.nil?
|
421
|
-
msg = "#{prev_header.class} knowns no layer association with #{header.protocol_name}. ".dup
|
422
|
-
msg << "Try #{prev_header.class}.bind_layer(#{header.class}, "
|
423
|
-
msg << "#{prev_header.method_name}_proto_field: "
|
424
|
-
msg << "value_for_#{header.method_name})"
|
425
|
-
raise ArgumentError, msg
|
426
|
-
end
|
442
|
+
add_to_previous_header(prev_header, header, parsing) if prev_header
|
427
443
|
|
428
|
-
bindings.set(prev_header) if !bindings.empty? && !parsing
|
429
|
-
prev_header[:body] = header
|
430
|
-
end
|
431
444
|
header.packet = self
|
432
445
|
headers << header unless previous_header
|
433
446
|
|
@@ -436,6 +449,20 @@ module PacketGen
|
|
436
449
|
add_magic_header_method header
|
437
450
|
end
|
438
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
|
+
|
439
466
|
# Add method to access +header+
|
440
467
|
# @param [Header::Base] header
|
441
468
|
# @return [void]
|
@@ -497,5 +524,7 @@ module PacketGen
|
|
497
524
|
end
|
498
525
|
end
|
499
526
|
|
527
|
+
# rubocop:enable Metrics/ClassLength
|
528
|
+
|
500
529
|
require_relative 'headerable'
|
501
530
|
require_relative 'header'
|