packetgen 4.0.0 → 4.1.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/README.md +1 -1
- data/lib/packetgen/deprecation.rb +7 -1
- data/lib/packetgen/header/arp.rb +6 -7
- data/lib/packetgen/header/asn1_base.rb +2 -1
- data/lib/packetgen/header/base.rb +27 -24
- data/lib/packetgen/header/bootp.rb +14 -14
- data/lib/packetgen/header/dhcp/option.rb +8 -8
- data/lib/packetgen/header/dhcp/options.rb +2 -2
- data/lib/packetgen/header/dhcp.rb +6 -7
- data/lib/packetgen/header/dhcpv6/duid.rb +1 -1
- data/lib/packetgen/header/dhcpv6/option.rb +37 -15
- data/lib/packetgen/header/dhcpv6/options.rb +3 -3
- data/lib/packetgen/header/dhcpv6/relay.rb +1 -0
- data/lib/packetgen/header/dhcpv6.rb +13 -14
- data/lib/packetgen/header/dns/name.rb +9 -8
- data/lib/packetgen/header/dns/opt.rb +3 -0
- data/lib/packetgen/header/dns/option.rb +7 -7
- data/lib/packetgen/header/dns/qdsection.rb +2 -2
- data/lib/packetgen/header/dns/question.rb +1 -0
- data/lib/packetgen/header/dns/rrsection.rb +2 -2
- data/lib/packetgen/header/dns.rb +76 -60
- data/lib/packetgen/header/dot11/control.rb +5 -5
- data/lib/packetgen/header/dot11/data.rb +11 -10
- data/lib/packetgen/header/dot11/element.rb +1 -1
- data/lib/packetgen/header/dot11/management.rb +18 -15
- data/lib/packetgen/header/dot11/sub_mngt.rb +22 -21
- data/lib/packetgen/header/dot11.rb +38 -38
- data/lib/packetgen/header/dot1q.rb +5 -4
- data/lib/packetgen/header/dot1x.rb +8 -8
- data/lib/packetgen/header/eap/fast.rb +3 -3
- data/lib/packetgen/header/eap/md5.rb +11 -3
- data/lib/packetgen/header/eap/tls.rb +9 -8
- data/lib/packetgen/header/eap/ttls.rb +13 -10
- data/lib/packetgen/header/eap.rb +58 -33
- data/lib/packetgen/header/eth.rb +26 -12
- data/lib/packetgen/header/gre.rb +26 -2
- data/lib/packetgen/header/http/headers.rb +6 -5
- data/lib/packetgen/header/http/request.rb +24 -16
- data/lib/packetgen/header/http/response.rb +22 -15
- data/lib/packetgen/header/icmp.rb +10 -10
- data/lib/packetgen/header/icmpv6.rb +10 -9
- data/lib/packetgen/header/igmp.rb +21 -10
- data/lib/packetgen/header/igmpv3/group_record.rb +7 -2
- data/lib/packetgen/header/igmpv3/mq.rb +1 -1
- data/lib/packetgen/header/igmpv3/mr.rb +1 -1
- data/lib/packetgen/header/igmpv3.rb +11 -10
- data/lib/packetgen/header/ip/addr.rb +6 -2
- data/lib/packetgen/header/ip/option.rb +18 -5
- data/lib/packetgen/header/ip.rb +52 -35
- data/lib/packetgen/header/ipv6/addr.rb +14 -13
- data/lib/packetgen/header/ipv6/extension.rb +9 -7
- data/lib/packetgen/header/ipv6/hop_by_hop.rb +26 -7
- data/lib/packetgen/header/ipv6.rb +31 -22
- data/lib/packetgen/header/llc.rb +20 -13
- data/lib/packetgen/header/mdns.rb +9 -2
- data/lib/packetgen/header/mld.rb +11 -9
- data/lib/packetgen/header/mldv2/mcast_address_record.rb +6 -1
- data/lib/packetgen/header/mldv2/mlq.rb +8 -8
- data/lib/packetgen/header/mldv2/mlr.rb +4 -4
- data/lib/packetgen/header/mldv2.rb +1 -1
- data/lib/packetgen/header/ospfv2/db_description.rb +10 -10
- data/lib/packetgen/header/ospfv2/hello.rb +11 -10
- data/lib/packetgen/header/ospfv2/ls_ack.rb +5 -6
- data/lib/packetgen/header/ospfv2/ls_request.rb +7 -6
- data/lib/packetgen/header/ospfv2/ls_update.rb +7 -7
- data/lib/packetgen/header/ospfv2/lsa.rb +33 -10
- data/lib/packetgen/header/ospfv2/lsa_header.rb +3 -2
- data/lib/packetgen/header/ospfv2.rb +31 -26
- data/lib/packetgen/header/ospfv3/db_description.rb +12 -13
- data/lib/packetgen/header/ospfv3/hello.rb +10 -9
- data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +6 -2
- data/lib/packetgen/header/ospfv3/ls_ack.rb +5 -6
- data/lib/packetgen/header/ospfv3/ls_request.rb +10 -10
- data/lib/packetgen/header/ospfv3/ls_update.rb +7 -7
- data/lib/packetgen/header/ospfv3/lsa.rb +23 -9
- data/lib/packetgen/header/ospfv3/lsa_header.rb +3 -2
- data/lib/packetgen/header/ospfv3.rb +38 -34
- data/lib/packetgen/header/sctp/chunk.rb +38 -17
- data/lib/packetgen/header/sctp/error.rb +169 -197
- data/lib/packetgen/header/sctp/padded32.rb +3 -3
- data/lib/packetgen/header/sctp/parameter.rb +85 -132
- data/lib/packetgen/header/sctp.rb +14 -3
- data/lib/packetgen/header/snmp.rb +108 -7
- data/lib/packetgen/header/tcp/option.rb +7 -0
- data/lib/packetgen/header/tcp/options.rb +11 -3
- data/lib/packetgen/header/tcp.rb +33 -26
- data/lib/packetgen/header/tftp.rb +16 -10
- data/lib/packetgen/header/udp.rb +15 -13
- data/lib/packetgen/header.rb +19 -13
- data/lib/packetgen/headerable.rb +9 -3
- data/lib/packetgen/inspect.rb +2 -7
- data/lib/packetgen/packet.rb +94 -36
- data/lib/packetgen/pcapng/block.rb +2 -1
- data/lib/packetgen/pcapng/file.rb +41 -14
- data/lib/packetgen/pcapng/idb.rb +2 -1
- data/lib/packetgen/pcapng/shb.rb +2 -1
- data/lib/packetgen/pcapng/spb.rb +1 -1
- data/lib/packetgen/pcapng.rb +2 -0
- data/lib/packetgen/proto.rb +4 -0
- data/lib/packetgen/unknown_packet.rb +3 -3
- data/lib/packetgen/utils.rb +2 -1
- data/lib/packetgen/version.rb +1 -1
- data/lib/packetgen.rb +8 -2
- metadata +4 -4
data/lib/packetgen/header/tcp.rb
CHANGED
@@ -29,50 +29,56 @@ module PacketGen
|
|
29
29
|
# | data |
|
30
30
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
31
31
|
# A TCP header consists of:
|
32
|
-
# * a source port ({#sport},
|
33
|
-
# * a destination port ({#dport}, +Int16+ type),
|
34
|
-
# * a sequence number ({#seqnum},
|
35
|
-
# * an acknownledge number ({#acknum}, +Int32+ type),
|
36
|
-
# * a 16-bit field ({#u16}, +Int16+ type) composed of:
|
37
|
-
# * a 4-bit {#data_offset}
|
32
|
+
# * a source port ({#sport}, +BinStruct::Int16+ type),
|
33
|
+
# * a destination port ({#dport}, +BinStruct::Int16+ type),
|
34
|
+
# * a sequence number ({#seqnum}, +BinStruct::Int32+ type),
|
35
|
+
# * an acknownledge number ({#acknum}, +BinStruct::Int32+ type),
|
36
|
+
# * a 16-bit field ({#u16}, +BinStruct::Int16+ type) composed of:
|
37
|
+
# * a 4-bit {#data_offset},
|
38
38
|
# * a 3-bit {#reserved} field,
|
39
39
|
# * a 9-bit {#flags} field,
|
40
|
-
# * a {#window} field (+Int16+ type),
|
41
|
-
# * a {#checksum} field (+Int16+ type),
|
42
|
-
# * a urgent pointer ({#urg_pointer}, +Int16+ type),
|
40
|
+
# * a {#window} field (+BinStruct::Int16+ type),
|
41
|
+
# * a {#checksum} field (+BinStruct::Int16+ type),
|
42
|
+
# * a urgent pointer ({#urg_pointer}, +BinStruct::Int16+ type),
|
43
43
|
# * an optional {#options} field ({Options} type),
|
44
|
-
# * and a {#body} (
|
44
|
+
# * and a {#body} (+BinStruct::String+ type).
|
45
45
|
#
|
46
|
-
#
|
46
|
+
# @example Create a TCP header
|
47
47
|
# # standalone
|
48
48
|
# tcph = PacketGen::Header::TCP.new
|
49
49
|
# # in a IP packet
|
50
50
|
# pkt = PacketGen.gen('IP').add('TCP')
|
51
51
|
# # access to TCP header
|
52
|
-
# pkt.tcp # => PacketGen::Header::TCP
|
52
|
+
# pkt.tcp.class # => PacketGen::Header::TCP
|
53
53
|
#
|
54
|
-
#
|
54
|
+
# @example TCP attributes
|
55
|
+
# tcph = PacketGen::Header::TCP.new
|
55
56
|
# tcph.sport = 4500
|
56
57
|
# tcph.dport = 80
|
57
58
|
# tcph.seqnum = 43
|
58
59
|
# tcph.acknum = 0x45678925
|
59
60
|
# tcph.wsize = 0x240
|
60
61
|
# tcph.urg_pointer = 0x40
|
61
|
-
# tcph.body
|
62
|
+
# tcph.body = 'this is a body'
|
62
63
|
#
|
63
|
-
#
|
64
|
-
# TCP
|
64
|
+
# @example TCP Flags
|
65
|
+
# tcph = PacketGen::Header::TCP.new
|
66
|
+
# # TCP flags may be accesed as a 9-bit integer:
|
65
67
|
# tcph.flags = 0x1002
|
66
|
-
# Each flag may be accessed independently:
|
67
|
-
# tcph.flag_syn? # =>
|
68
|
+
# # Each flag may be accessed independently:
|
69
|
+
# tcph.flag_syn? # => true
|
68
70
|
# tcph.flag_rst = true
|
69
71
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# tcph.options <<
|
72
|
+
# @example TCP Options
|
73
|
+
# tcph = PacketGen::Header::TCP.new
|
74
|
+
# # options TCP attribute is a PacketGen::Header::TCP::Options.
|
75
|
+
# # PacketGen::Header::TCP::Option may added to it:
|
76
|
+
# tcph.options << PacketGen::Header::TCP::MSS.new(value: 1250)
|
77
|
+
# # or
|
78
|
+
# tcph.options << { kind: 'MSS', value: 1250 }
|
79
|
+
# tcph.options.last.class #=> PacketGen::Header::TCP::MSS
|
75
80
|
# @author Sylvain Daubert
|
81
|
+
# @author LemonTree55
|
76
82
|
class TCP < Base
|
77
83
|
end
|
78
84
|
end
|
@@ -151,7 +157,8 @@ module PacketGen
|
|
151
157
|
# @return [Options]
|
152
158
|
define_attr :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
|
153
159
|
# @!attribute body
|
154
|
-
#
|
160
|
+
# TCP body
|
161
|
+
# @return [BinStruct::String,Headerable]
|
155
162
|
define_attr :body, BinStruct::String
|
156
163
|
|
157
164
|
alias source_port sport
|
@@ -181,7 +188,7 @@ module PacketGen
|
|
181
188
|
# @option options [Integer] :window
|
182
189
|
# @option options [Integer] :checksum
|
183
190
|
# @option options [Integer] :urg_pointer
|
184
|
-
# @option options [String] :body
|
191
|
+
# @option options [String, Headerable] :body
|
185
192
|
def initialize(options={})
|
186
193
|
opts = { data_offset: 5 }.merge!(options)
|
187
194
|
super(opts)
|
@@ -195,7 +202,7 @@ module PacketGen
|
|
195
202
|
end
|
196
203
|
|
197
204
|
# Set all flags at once
|
198
|
-
# @
|
205
|
+
# @param [Integer] value
|
199
206
|
# @return [Integer]
|
200
207
|
def flags=(value)
|
201
208
|
new_u16 = (self.u16 & 0xfe00) | (value & 0x1ff)
|
@@ -10,25 +10,26 @@ module PacketGen
|
|
10
10
|
module Header
|
11
11
|
# A TFTP (Trivial File Transfer Protocol,
|
12
12
|
# {https://tools.ietf.org/html/rfc1350 RFC 1350}) header consists of:
|
13
|
-
# *
|
13
|
+
# * an {#opcode} (+BinStruct::Int16Enum+),
|
14
14
|
# * and a body. Its content depends on opcode.
|
15
15
|
#
|
16
16
|
# Specialized subclasses exists to handle {TFTP::RRQ Read Request},
|
17
17
|
# {TFTP::WRQ Write Request}, {TFTP::DATA DATA}, {TFTP::ACK ACK} and
|
18
18
|
# {TFTP::ERROR ERROR} packets.
|
19
19
|
#
|
20
|
-
#
|
20
|
+
# @example Create a TFTP header
|
21
21
|
# # standalone
|
22
22
|
# tftp = PacketGen::Header::TFTP.new
|
23
23
|
# # in a packet
|
24
24
|
# pkt = PacketGen.gen('IP').add('UDP').add('TFTP')
|
25
25
|
# # access to TFTP header
|
26
|
-
# pkt.tftp # => PacketGen::Header::TFTP
|
26
|
+
# pkt.tftp.class # => PacketGen::Header::TFTP
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# @example TFTP attributes
|
29
|
+
# tftp = PacketGen::Header::TFTP.new
|
29
30
|
# tftp.opcode = 'RRQ'
|
30
31
|
# tftp.opcode = 1
|
31
|
-
# tftp.body
|
32
|
+
# tftp.body = 'this is a body'
|
32
33
|
#
|
33
34
|
# == TFTP parsing
|
34
35
|
# When parsing, only first packet (read or write request) should be decoded
|
@@ -46,6 +47,7 @@ module PacketGen
|
|
46
47
|
# packets[0].tftp.decode!(packets[1..-1])
|
47
48
|
# packets.map { |pkt| pkt.headers.last.class.to_s }.join(',') # => TFTP::RRQ,TFTP::DATA,UDP,TFTP::ACK
|
48
49
|
# @author Sylvain Daubert
|
50
|
+
# @author LemonTree55
|
49
51
|
# @since 2.3.0
|
50
52
|
class TFTP < Base
|
51
53
|
# Known opcodes
|
@@ -63,7 +65,8 @@ module PacketGen
|
|
63
65
|
define_attr :opcode, BinStruct::Int16Enum, enum: OPCODES
|
64
66
|
|
65
67
|
# @!attribute body
|
66
|
-
#
|
68
|
+
# TFTP body, if opcode is unknown
|
69
|
+
# @return [String,Headerable]
|
67
70
|
define_attr :body, BinStruct::String
|
68
71
|
|
69
72
|
def initialize(options={})
|
@@ -85,7 +88,7 @@ module PacketGen
|
|
85
88
|
def read(str)
|
86
89
|
if self.instance_of? TFTP
|
87
90
|
super
|
88
|
-
if OPCODES.value?
|
91
|
+
if OPCODES.value?(opcode)
|
89
92
|
TFTP.const_get(human_opcode).new.read(str)
|
90
93
|
else
|
91
94
|
self
|
@@ -145,7 +148,8 @@ module PacketGen
|
|
145
148
|
pkt.udp.dport = udp_dport
|
146
149
|
end
|
147
150
|
|
148
|
-
# TFTP Read Request header
|
151
|
+
# TFTP Read Request header.
|
152
|
+
# This header remove {#body} attribute and repalces it with {#filename} and {#mode}.
|
149
153
|
class RRQ < TFTP
|
150
154
|
remove_attr :body
|
151
155
|
|
@@ -171,7 +175,8 @@ module PacketGen
|
|
171
175
|
define_attr_before :body, :block_num, BinStruct::Int16
|
172
176
|
end
|
173
177
|
|
174
|
-
# TFTP ACK header
|
178
|
+
# TFTP ACK header.
|
179
|
+
# This header remove {#body} attribute and repalces it with {#block_num}.
|
175
180
|
class ACK < TFTP
|
176
181
|
remove_attr :body
|
177
182
|
|
@@ -181,7 +186,8 @@ module PacketGen
|
|
181
186
|
define_attr :block_num, BinStruct::Int16
|
182
187
|
end
|
183
188
|
|
184
|
-
# TFTP ERROR header
|
189
|
+
# TFTP ERROR header.
|
190
|
+
# This header remove {#body} attribute and repalces it with {#error_code} and {#error_msg}.
|
185
191
|
class ERROR < TFTP
|
186
192
|
remove_attr :body
|
187
193
|
|
data/lib/packetgen/header/udp.rb
CHANGED
@@ -17,28 +17,30 @@ module PacketGen
|
|
17
17
|
# | Length | Checksum |
|
18
18
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
19
19
|
# A UDP header consists of:
|
20
|
-
# * a source port field ({#sport},
|
21
|
-
# * a destination port field ({#dport}, +Int16+ type),
|
22
|
-
# * a UDP length field ({#length}, +Int16+ type),
|
23
|
-
# * a {#checksum} field (+Int16+ type),
|
20
|
+
# * a source port field ({#sport}, +BinStruct::Int16+ type),
|
21
|
+
# * a destination port field ({#dport}, +BinStruct:Int16+ type),
|
22
|
+
# * a UDP length field ({#length}, +BinStruct:Int16+ type),
|
23
|
+
# * a {#checksum} field (+BinStruct:Int16+ type),
|
24
24
|
# * and a {#body}.
|
25
25
|
#
|
26
|
-
#
|
26
|
+
# @example Create a UDP header
|
27
27
|
# # standalone
|
28
28
|
# udp = PacketGen::Header::UDP.new
|
29
29
|
# # in a packet
|
30
|
-
# pkt =
|
30
|
+
# pkt = PacketGen.gen('IP').add('UDP')
|
31
31
|
# # access to IP header
|
32
|
-
# pkt.udp # => PacketGen::Header::UDP
|
32
|
+
# pkt.udp.class # => PacketGen::Header::UDP
|
33
33
|
#
|
34
|
-
#
|
34
|
+
# @example UDP attributes
|
35
|
+
# udp = PacketGen::Header::UDP.new
|
35
36
|
# udp.sport = 65432
|
36
37
|
# udp.dport = 53
|
37
38
|
# udp.length = 43
|
38
39
|
# udp.checksum = 0xffff
|
39
|
-
# udp.body
|
40
|
+
# udp.body = 'this is a UDP body'
|
40
41
|
#
|
41
42
|
# @author Sylvain Daubert
|
43
|
+
# @author LemonTree55
|
42
44
|
class UDP < Base
|
43
45
|
# IP protocol number for UDP
|
44
46
|
IP_PROTOCOL = 17
|
@@ -60,7 +62,8 @@ module PacketGen
|
|
60
62
|
# @return [Integer]
|
61
63
|
define_attr :checksum, BinStruct::Int16
|
62
64
|
# @!attribute body
|
63
|
-
#
|
65
|
+
# UDP body
|
66
|
+
# @return [BinStruct::String,Headerable]
|
64
67
|
define_attr :body, BinStruct::String
|
65
68
|
|
66
69
|
alias source_port sport
|
@@ -75,7 +78,7 @@ module PacketGen
|
|
75
78
|
self.length += self[:body].sz if self[:body].sz.positive?
|
76
79
|
end
|
77
80
|
|
78
|
-
# Compute checksum and set
|
81
|
+
# Compute checksum and set {#checksum} field
|
79
82
|
# @return [Integer]
|
80
83
|
def calc_checksum
|
81
84
|
ip = ip_header(self)
|
@@ -86,7 +89,7 @@ module PacketGen
|
|
86
89
|
self.checksum = IP.reduce_checksum(sum)
|
87
90
|
end
|
88
91
|
|
89
|
-
# Compute length and set
|
92
|
+
# Compute length and set {#length} field
|
90
93
|
# @return [Integer]
|
91
94
|
def calc_length
|
92
95
|
Base.calculate_and_set_length(self)
|
@@ -100,7 +103,6 @@ module PacketGen
|
|
100
103
|
self
|
101
104
|
end
|
102
105
|
end
|
103
|
-
|
104
106
|
self.add_class UDP
|
105
107
|
|
106
108
|
IP.bind UDP, protocol: UDP::IP_PROTOCOL
|
data/lib/packetgen/header.rb
CHANGED
@@ -14,21 +14,27 @@ module PacketGen
|
|
14
14
|
#
|
15
15
|
# == Add a foreign header class
|
16
16
|
# PacketGen permits adding your own header classes.
|
17
|
-
# First, define the new header class.
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
17
|
+
# First, define the new header class. Then, this class must be declared to PacketGen using {Header.add_class}.
|
18
|
+
# Finally, bindings must be declared.
|
19
|
+
#
|
20
|
+
# @example Foreign header class
|
21
|
+
# # Define a new header
|
22
|
+
# module MyModule
|
23
|
+
# class MyHeader < PacketGen::Header::Base
|
24
|
+
# define_attr :field1, BinStruct::Int32
|
25
|
+
# define_attr :field2, BinStruct::Int32
|
26
|
+
# end
|
23
27
|
# end
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
28
|
+
#
|
29
|
+
# # Declare the new header to PacketGen
|
30
|
+
# PacketGen::Header.add_class(MyModule::MyHeader)
|
31
|
+
# # bind it as IP protocol number 254 (needed by Packet#parse and Packet#add)
|
32
|
+
# PacketGen::Header::IP.bind(MyModule::MyHeader, protocol: 254)
|
33
|
+
#
|
34
|
+
# # Use it
|
35
|
+
# pkt = PacketGen.gen('IP').add('MyModule::MyHeader', field1: 0x12345678, field3: 0x87654321)
|
31
36
|
# @author Sylvain Daubert
|
37
|
+
# @author LemonTree55
|
32
38
|
module Header
|
33
39
|
@added_header_classes = {}
|
34
40
|
|
data/lib/packetgen/headerable.rb
CHANGED
@@ -9,7 +9,13 @@
|
|
9
9
|
module PacketGen
|
10
10
|
# This mixin module defines minimal API for a class to act as a header
|
11
11
|
# in {Packet}.
|
12
|
+
#
|
13
|
+
# Some others methods may optionally be defined by a {Headerable} object:
|
14
|
+
# * +#calc_length+ to calculate length from content. It should be defined if header as a length attribute.
|
15
|
+
# * +#calc_checksum+ to calculate checksum. It should be defined if header as a checksum attriibute.
|
16
|
+
# * +#reply+ to invert fields in header for a reply.
|
12
17
|
# @author Sylvain Daubert
|
18
|
+
# @author LemonTree55
|
13
19
|
# @since 3.0.2
|
14
20
|
module Headerable
|
15
21
|
# This modules handles class methods for {Headerable headerable classes}.
|
@@ -51,7 +57,7 @@ module PacketGen
|
|
51
57
|
end
|
52
58
|
|
53
59
|
# @abstract Should be redefined by subclasses. This method should check invariant
|
54
|
-
# attributes
|
60
|
+
# attributes from header.
|
55
61
|
# Called by {Packet#parse} when guessing first header to check if header is correct
|
56
62
|
# @return [Boolean]
|
57
63
|
def parse?
|
@@ -74,8 +80,8 @@ module PacketGen
|
|
74
80
|
@packet
|
75
81
|
end
|
76
82
|
|
77
|
-
# @abstract This method
|
78
|
-
#
|
83
|
+
# @abstract This base method does nothing but may be overriden by subclasses.
|
84
|
+
# This method is called when a header is added to a packet.
|
79
85
|
# @param [Packet] packet packet to which self is added
|
80
86
|
# @return [void]
|
81
87
|
def added_to_packet(packet) end
|
data/lib/packetgen/inspect.rb
CHANGED
@@ -61,18 +61,13 @@ module PacketGen
|
|
61
61
|
str << Inspect::FMT_ATTR % [type, attr, value]
|
62
62
|
end
|
63
63
|
|
64
|
-
# Format an attribute for +#inspect+.
|
65
|
-
# 3 cases are handled:
|
66
|
-
# * attribute value is a {BinStruct::Int}: show value as integer and in
|
67
|
-
# hexdecimal format,
|
68
|
-
# * attribute value responds to +#to_human+: call it,
|
69
|
-
# * else, +#to_s+ is used to format attribute value.
|
64
|
+
# Format an attribute for +#inspect+. Call +#format_inspect} on +value+.
|
70
65
|
# @param [Symbol] attr attribute name
|
71
66
|
# @param [Object] value attribute value
|
72
67
|
# @param [Integer] level
|
73
68
|
# @return [String]
|
74
69
|
def self.inspect_attribute(attr, value, level=1)
|
75
|
-
type = value.
|
70
|
+
type = value.type_name
|
76
71
|
self.format(type, attr, value.format_inspect, level)
|
77
72
|
end
|
78
73
|
|
data/lib/packetgen/packet.rb
CHANGED
@@ -7,50 +7,58 @@
|
|
7
7
|
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
8
8
|
# This program is published under MIT license.
|
9
9
|
|
10
|
-
# rubocop:disable Metrics/ClassLength
|
11
|
-
|
12
10
|
module PacketGen
|
13
11
|
# An object of type {Packet} handles a network packet. This packet may contain
|
14
12
|
# multiple protocol headers, starting from MAC layer or from Network (OSI) layer.
|
15
13
|
#
|
16
|
-
#
|
17
|
-
#
|
14
|
+
# A Packet is created using {.gen} method. Headers may be added to this packet using {#add}.
|
15
|
+
# It may also be created from parsing a binary string, using {.parse} method.
|
16
|
+
#
|
17
|
+
# @example Very simple packet
|
18
|
+
# # Create a packet with a single IP header. IP source and destination addresses are set.
|
19
|
+
# pkt = PacketGen::Packet.gen('IP', src: '192.168.1.1', dst: '192.168.1.2')
|
18
20
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# Packet.parse(binary_string)
|
21
|
+
# @example Parsing a binary string
|
22
|
+
# # a IP/ICMP packet, as binary string
|
23
|
+
# binary_string = "E\x00\x00\x1C\xAA`\x00\x00@\x01M-\xC0\xA8\x01\x01\xC0\xA8\x01\x02\x00\b;1abcd".b
|
24
|
+
# pkt = PacketGen::Packet.parse(binary_string)
|
25
|
+
# pkt.is?('IP') #=> true
|
26
|
+
# pkt.is?('ICMP') #=> true
|
23
27
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# # read information
|
27
|
-
# pkt.udp.sport
|
28
|
-
# pkt.ip.ttl
|
29
|
-
# # set information
|
30
|
-
# pkt.udp.dport = 2323
|
31
|
-
# pkt.ip.ttl = 1
|
32
|
-
# pkt.ip(ttl: 1, id: 1234)
|
28
|
+
# Information for each level is accessible through the associated header. Header is accessible through a
|
29
|
+
# method defined with its name at packet level (i.e. +#ip+ for a IP header).
|
33
30
|
#
|
34
|
-
#
|
35
|
-
#
|
31
|
+
# @example Accessing header information
|
32
|
+
# pkt = PacketGen::Packet.gen('IP').add('UDP')
|
33
|
+
# # read information
|
34
|
+
# pkt.udp.sport #=> 0
|
35
|
+
# pkt.ip.ttl #=> 64
|
36
|
+
# # set information
|
37
|
+
# pkt.udp.dport = 2323
|
38
|
+
# pkt.ip.ttl = 1
|
39
|
+
# # Set multiple attributes at once
|
40
|
+
# pkt.ip(ttl: 1, id: 1234)
|
36
41
|
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# do_some_stuffs
|
41
|
-
# end
|
42
|
-
# packets = Packet.capture(iface: 'eth0', max: 5) # get 5 packets from eth0
|
42
|
+
# Packets may be written to files using {#write}:
|
43
|
+
# pkt = PacketGen::Packet.gen('Eth')
|
44
|
+
# pkt.write('file.pcapng')
|
43
45
|
#
|
44
|
-
# Packets may
|
45
|
-
#
|
46
|
+
# Packets may be captured from network interfaces:
|
47
|
+
# # Capture all packets from default interface. Never end.
|
48
|
+
# PacketGen::Packet.capture do |packet|
|
49
|
+
# do_some_stuffs
|
50
|
+
# end
|
46
51
|
#
|
47
|
-
#
|
48
|
-
#
|
52
|
+
# # Get 5 packets from eth0 interface
|
53
|
+
# packets = Packet.capture(iface: 'eth0', max: 5)
|
49
54
|
#
|
55
|
+
# Finally, packets may also be read from a file:
|
56
|
+
# packets = Packet.read(file.pcapng)
|
50
57
|
# @author Sylvain Daubert
|
58
|
+
# @author LemonTree55
|
51
59
|
class Packet
|
52
60
|
# Get packet headers, ordered as they appear in the packet.
|
53
|
-
# @return [Array<
|
61
|
+
# @return [Array<Headerable>]
|
54
62
|
attr_reader :headers
|
55
63
|
# Activaye or deactivate header cache (activated by default)
|
56
64
|
# @return [Boolean]
|
@@ -142,7 +150,15 @@ module PacketGen
|
|
142
150
|
# @param [String] protocol
|
143
151
|
# @param [Hash] options protocol specific options
|
144
152
|
# @return [self]
|
145
|
-
# @raise [
|
153
|
+
# @raise [ArgumentError] unknown protocol
|
154
|
+
# @raise [BindingError] unknown binding
|
155
|
+
# @see #<<
|
156
|
+
# @example
|
157
|
+
# pkt = PacketGen::Packet.gen('Eth')
|
158
|
+
# # Add a IP header
|
159
|
+
# pkt.add('IP')
|
160
|
+
# # Add a TCP header, with some attributes and body set
|
161
|
+
# pkt.add('TCP', dport: 80, seqnum: 123456, body: "abcd".b)
|
146
162
|
def add(protocol, options={})
|
147
163
|
klass = check_protocol(protocol)
|
148
164
|
|
@@ -174,6 +190,7 @@ module PacketGen
|
|
174
190
|
end
|
175
191
|
|
176
192
|
# Check if a protocol header is embedded in packet.
|
193
|
+
# @example
|
177
194
|
# pkt = PacketGen.gen('IP').add('UDP')
|
178
195
|
# pkt.is?('IP') #=> true
|
179
196
|
# pkt.is?('TCP') #=> false
|
@@ -210,16 +227,22 @@ module PacketGen
|
|
210
227
|
end
|
211
228
|
end
|
212
229
|
|
213
|
-
# Get packet body
|
214
|
-
# @return [
|
230
|
+
# Get packet body. If packet (i.e. last header) has no +:body+ field, return +nil+.
|
231
|
+
# @return [Headerable,BinStruct::String,nil]
|
215
232
|
def body
|
216
233
|
last_header[:body] if last_header.respond_to?(:body)
|
217
234
|
end
|
218
235
|
|
219
236
|
# Set packet body
|
220
|
-
# @param [String] str
|
237
|
+
# @param [String] str Binary string
|
221
238
|
# @return [void]
|
239
|
+
# @raise [Error] Packet (i.e. last header) has no +:body+ field.
|
240
|
+
# @note To set a {Headerable} object, prefer #{<<}
|
241
|
+
# @see #<<
|
242
|
+
# @since 4.1.0 raise {Error} if no body on packet
|
222
243
|
def body=(str)
|
244
|
+
raise Error, 'no body in last headeré' unless last_header.respond_to?(:body)
|
245
|
+
|
223
246
|
last_header.body = str
|
224
247
|
end
|
225
248
|
|
@@ -270,6 +293,13 @@ module PacketGen
|
|
270
293
|
# @return [self] +self+ updated with new headers from +other+
|
271
294
|
# @raise [BindingError] do not known how to encapsulate
|
272
295
|
# @since 1.1.0
|
296
|
+
# @example
|
297
|
+
# # Create a first IP packet
|
298
|
+
# ip1 = PacketGen::Packet.gen('IP', id: 1)
|
299
|
+
# # Create second IP packet, to encapsulate in first
|
300
|
+
# ip2 = PacketGen.gen('IP', id: 2)
|
301
|
+
# ip1.encapsulate(ip2)
|
302
|
+
# ip1.ip(2) == ip2.ip
|
273
303
|
def encapsulate(other, parsing: false)
|
274
304
|
other.headers.each_with_index do |h, i|
|
275
305
|
add_header(h, parsing: i.positive? || parsing)
|
@@ -282,6 +312,12 @@ module PacketGen
|
|
282
312
|
# @raise [FormatError] any headers not in +self+
|
283
313
|
# @raise [BindingError] removed headers result in an unknown binding
|
284
314
|
# @since 1.1.0
|
315
|
+
# @example
|
316
|
+
# # IP/IP encapsulation
|
317
|
+
# pkt = PacketGen::Packet.gen('IP', id: 1).add('IP', id:2)
|
318
|
+
# # Remove outer IP header
|
319
|
+
# pkt.decapsulate(pkt.ip(1))
|
320
|
+
# pkt.ip.id #=> 2
|
285
321
|
def decapsulate(*hdrs)
|
286
322
|
hdrs.each do |hdr|
|
287
323
|
prev_hdr = previous_header(hdr)
|
@@ -290,6 +326,7 @@ module PacketGen
|
|
290
326
|
add_header(next_hdr, previous_header: prev_hdr) if prev_hdr && next_hdr
|
291
327
|
end
|
292
328
|
invalidate_header_cache
|
329
|
+
self
|
293
330
|
rescue ArgumentError => e
|
294
331
|
raise FormatError, e.message
|
295
332
|
end
|
@@ -334,7 +371,7 @@ module PacketGen
|
|
334
371
|
to_s == other.to_s
|
335
372
|
end
|
336
373
|
|
337
|
-
# +true+
|
374
|
+
# +true+ if {#==} is +true+ with another packet, or if +other+ is a protocol name String, whose protocol is in Packet.
|
338
375
|
# @param [Packet] other
|
339
376
|
# @return [Boolean]
|
340
377
|
# @since 3.1.2
|
@@ -349,8 +386,9 @@ module PacketGen
|
|
349
386
|
end
|
350
387
|
end
|
351
388
|
|
352
|
-
# Invert all possible attributes
|
389
|
+
# Invert all possible attributes in packet to create a reply.
|
353
390
|
# @return [self]
|
391
|
+
# @note Only modify headers responding to +#reply!+.
|
354
392
|
# @since 2.7.0
|
355
393
|
def reply!
|
356
394
|
headers.each do |header|
|
@@ -362,12 +400,32 @@ module PacketGen
|
|
362
400
|
# Forge a new packet from current one with all possible fields
|
363
401
|
# inverted. The new packet may be a reply to current one.
|
364
402
|
# @return [Packet]
|
403
|
+
# @note Only modify headers responding to +#reply!+.
|
365
404
|
# @since 2.7.0
|
366
405
|
def reply
|
367
406
|
pkt = dup
|
368
407
|
pkt.reply!
|
369
408
|
end
|
370
409
|
|
410
|
+
# Append an already defined header to packet
|
411
|
+
# @param [Headerable] header
|
412
|
+
# @return [self]
|
413
|
+
# @raise [ArgumentError] unknown protocol
|
414
|
+
# @raise [BindingError] unknown binding
|
415
|
+
# @example
|
416
|
+
# pkt = PacketGen.gen('Eth')
|
417
|
+
# # Add a new header from its type
|
418
|
+
# pkt.add('IP')
|
419
|
+
# # Add a new pre-generated header
|
420
|
+
# pkt << PacketGen::Header::TCP.new
|
421
|
+
# @see #add
|
422
|
+
# @since 4.1.0
|
423
|
+
# @author LemonTree55
|
424
|
+
def <<(header)
|
425
|
+
add_header(header)
|
426
|
+
self
|
427
|
+
end
|
428
|
+
|
371
429
|
private
|
372
430
|
|
373
431
|
# Dup +@headers+ instance variable. Internally used by +#dup+ and +#clone+
|
@@ -10,6 +10,7 @@ module PacketGen
|
|
10
10
|
module PcapNG
|
11
11
|
# @abstract Base class for all block types
|
12
12
|
# @author Sylvain Daubert
|
13
|
+
# @author LemonTree55
|
13
14
|
class Block < BinStruct::Struct
|
14
15
|
# @return [:little, :big]
|
15
16
|
attr_accessor :endian
|
@@ -78,7 +79,7 @@ module PacketGen
|
|
78
79
|
def to_io(str_or_io)
|
79
80
|
return str_or_io if str_or_io.respond_to?(:read)
|
80
81
|
|
81
|
-
StringIO.new(
|
82
|
+
StringIO.new(str_or_io.to_s.b)
|
82
83
|
end
|
83
84
|
|
84
85
|
def remove_padding(io, data_len)
|