packetgen 0.3.0 → 1.0.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/lib/packetgen/capture.rb +5 -0
- data/lib/packetgen/header/arp.rb +118 -76
- data/lib/packetgen/header/eth.rb +48 -23
- data/lib/packetgen/header/header_class_methods.rb +75 -1
- data/lib/packetgen/header/header_methods.rb +16 -0
- data/lib/packetgen/header/icmp.rb +39 -16
- data/lib/packetgen/header/icmpv6.rb +28 -5
- data/lib/packetgen/header/ip.rb +140 -58
- data/lib/packetgen/header/ipv6.rb +87 -31
- data/lib/packetgen/header/tcp/option.rb +254 -0
- data/lib/packetgen/header/tcp/options.rb +86 -0
- data/lib/packetgen/header/tcp.rb +299 -0
- data/lib/packetgen/header/udp.rb +45 -19
- data/lib/packetgen/header.rb +6 -0
- data/lib/packetgen/inspect.rb +76 -0
- data/lib/packetgen/packet.rb +12 -51
- data/lib/packetgen/pcapng/block.rb +5 -0
- data/lib/packetgen/pcapng/epb.rb +5 -0
- data/lib/packetgen/pcapng/file.rb +5 -0
- data/lib/packetgen/pcapng/idb.rb +5 -0
- data/lib/packetgen/pcapng/shb.rb +5 -0
- data/lib/packetgen/pcapng/spb.rb +5 -0
- data/lib/packetgen/pcapng/unknown_block.rb +5 -0
- data/lib/packetgen/pcapng.rb +4 -0
- data/lib/packetgen/structfu.rb +5 -3
- data/lib/packetgen/version.rb +6 -1
- data/lib/packetgen.rb +7 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45af460b696e393ab1c89b3e27fba605246eafc5
|
4
|
+
data.tar.gz: 18f621d8edd0c5c5fee18a97c5ffb9c1d31043c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dfc16c31052743888efb32945d26d16995e975d6affb47c3a52f4fa4338e7906b75548f8d87e14c963ea89d21e08d877e3f9b62cfa723cf35da90b33a42d3cd4
|
7
|
+
data.tar.gz: d88d482c4eb651b4175453b29c1e71215935d8ff630598dfcb44c33662b272227bda2aea46f7c219c52cd57c9f5093cf2d03dc668e097c03c58f4a89f725dbf3
|
data/lib/packetgen/capture.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
|
3
8
|
# Capture packets from wire
|
data/lib/packetgen/header/arp.rb
CHANGED
@@ -1,35 +1,59 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
4
|
-
# ARP header
|
9
|
+
# An ARP header consists of:
|
10
|
+
# * a hardware type ({#hrd} or {#htype}) field ({Int16}),
|
11
|
+
# * a protocol type ({#pro} or {#ptype}) field (+Int16+),
|
12
|
+
# * a hardware address length ({#hln} or {#hlen}) field ({Int8}),
|
13
|
+
# * a protocol address length ({#pln} or {#plen}) field (+Int8+),
|
14
|
+
# * a {#opcode} (or {#op}) field (+Int16+),
|
15
|
+
# * a source hardware address ({#sha} or {#src_mac}) field ({Eth::MacAddr}),
|
16
|
+
# * a source protocol address ({#spa} or {#src_ip}) field ({IP::Addr}),
|
17
|
+
# * a target hardware address ({#tha} or {#dst_mac}) field (+Eth::MacAddr+),
|
18
|
+
# * a target protocol address ({#tpa} or {#dst_ip}) field (+IP::Addr+),
|
19
|
+
# * and a {#body}.
|
20
|
+
#
|
21
|
+
# == Create a ARP header
|
22
|
+
# # standalone
|
23
|
+
# arp = PacketGen::Header::ARP.new
|
24
|
+
# # in a packet
|
25
|
+
# pkt = PacketGen.gen('Eth').add('ARP')
|
26
|
+
# # access to ARP header
|
27
|
+
# pkt.arp # => PacketGen::Header::ARP
|
28
|
+
#
|
5
29
|
# @author Sylvain Daubert
|
6
|
-
class ARP < Struct.new(:
|
7
|
-
|
30
|
+
class ARP < Struct.new(:hrd, :pro, :hln, :pln, :op,
|
31
|
+
:sha, :spa, :tha, :tpa, :body)
|
8
32
|
include StructFu
|
9
33
|
include HeaderMethods
|
10
34
|
extend HeaderClassMethods
|
11
35
|
|
12
36
|
# @param [Hash] options
|
13
|
-
# @option options [Integer] :
|
14
|
-
# @option options [Integer] :
|
15
|
-
# @option options [Integer] :
|
16
|
-
# @option options [Integer] :
|
17
|
-
# @option options [Integer] :
|
37
|
+
# @option options [Integer] :hrd network protocol type (default: 1)
|
38
|
+
# @option options [Integer] :pro internet protocol type (default: 0x800)
|
39
|
+
# @option options [Integer] :hln length of hardware addresses (default: 6)
|
40
|
+
# @option options [Integer] :pln length of internet addresses (default: 4)
|
41
|
+
# @option options [Integer] :op operation performing by sender (default: 1).
|
18
42
|
# known values are +request+ (1) and +reply+ (2)
|
19
|
-
# @option options [String] :
|
20
|
-
# @option options [String] :
|
21
|
-
# @option options [String] :
|
22
|
-
# @option options [String] :
|
43
|
+
# @option options [String] :sha sender hardware address
|
44
|
+
# @option options [String] :spa sender internet address
|
45
|
+
# @option options [String] :tha target hardware address
|
46
|
+
# @option options [String] :tpa targetr internet address
|
23
47
|
def initialize(options={})
|
24
|
-
super Int16.new(options[:
|
25
|
-
Int16.new(options[:
|
26
|
-
Int8.new(options[:
|
27
|
-
Int8.new(options[:
|
28
|
-
Int16.new(options[:opcode] || 1),
|
29
|
-
Eth::MacAddr.new.
|
30
|
-
IP::Addr.new.
|
31
|
-
Eth::MacAddr.new.
|
32
|
-
IP::Addr.new.
|
48
|
+
super Int16.new(options[:hrd] || options[:htype] || 1),
|
49
|
+
Int16.new(options[:pro] || options[:ptype] || 0x800),
|
50
|
+
Int8.new(options[:hln] || options[:hlen] || 6),
|
51
|
+
Int8.new(options[:pln] || options[:plen] || 4),
|
52
|
+
Int16.new(options[:op] || options[:opcode] || 1),
|
53
|
+
Eth::MacAddr.new.from_human(options[:sha] || options[:src_mac]),
|
54
|
+
IP::Addr.new.from_human(options[:spa] || options[:src_ip]),
|
55
|
+
Eth::MacAddr.new.from_human(options[:tha] || options[:dst_mac]),
|
56
|
+
IP::Addr.new.from_human(options[:tpa] || options[:dst_ip]),
|
33
57
|
StructFu::String.new.read(options[:body])
|
34
58
|
end
|
35
59
|
|
@@ -39,110 +63,128 @@ module PacketGen
|
|
39
63
|
def read(str)
|
40
64
|
force_binary str
|
41
65
|
raise ParseError, 'string too short for ARP' if str.size < self.sz
|
42
|
-
self[:
|
43
|
-
self[:
|
44
|
-
self[:
|
45
|
-
self[:
|
46
|
-
self[:
|
47
|
-
self[:
|
48
|
-
self[:
|
49
|
-
self[:
|
50
|
-
self[:
|
66
|
+
self[:hrd].read str[0, 2]
|
67
|
+
self[:pro].read str[2, 2]
|
68
|
+
self[:hln].read str[4, 1]
|
69
|
+
self[:pln].read str[5, 1]
|
70
|
+
self[:op].read str[6, 2]
|
71
|
+
self[:sha].read str[8, 6]
|
72
|
+
self[:spa].read str[14, 4]
|
73
|
+
self[:tha].read str[18, 6]
|
74
|
+
self[:tpa].read str[24, 4]
|
51
75
|
self[:body].read str[28..-1]
|
52
76
|
end
|
53
77
|
|
54
|
-
# @!attribute [rw]
|
78
|
+
# @!attribute [rw] hrd
|
55
79
|
# @return [Integer]
|
56
|
-
def
|
57
|
-
self[:
|
80
|
+
def hrd
|
81
|
+
self[:hrd].to_i
|
58
82
|
end
|
83
|
+
alias :htype :hrd
|
59
84
|
|
60
|
-
def
|
61
|
-
self[:
|
85
|
+
def hrd=(i)
|
86
|
+
self[:hrd].read i
|
62
87
|
end
|
88
|
+
alias :htype= :hrd=
|
63
89
|
|
64
|
-
# @!attribute [rw]
|
90
|
+
# @!attribute [rw] pro
|
65
91
|
# @return [Integer]
|
66
|
-
def
|
67
|
-
self[:
|
92
|
+
def pro
|
93
|
+
self[:pro].to_i
|
68
94
|
end
|
95
|
+
alias :ptype :pro
|
69
96
|
|
70
|
-
def
|
71
|
-
self[:
|
97
|
+
def pro=(i)
|
98
|
+
self[:pro].read i
|
72
99
|
end
|
100
|
+
alias :ptype= :pro=
|
73
101
|
|
74
|
-
# @!attribute [rw]
|
102
|
+
# @!attribute [rw] hln
|
75
103
|
# @return [Integer]
|
76
|
-
def
|
77
|
-
self[:
|
104
|
+
def hln
|
105
|
+
self[:hln].to_i
|
78
106
|
end
|
107
|
+
alias :hlen :hln
|
79
108
|
|
80
|
-
def
|
81
|
-
self[:
|
109
|
+
def hln=(i)
|
110
|
+
self[:hln].read i
|
82
111
|
end
|
112
|
+
alias :hlen= :hln=
|
83
113
|
|
84
|
-
# @!attribute [rw]
|
114
|
+
# @!attribute [rw] pln
|
85
115
|
# @return [Integer]
|
86
|
-
def
|
87
|
-
self[:
|
116
|
+
def pln
|
117
|
+
self[:pln].to_i
|
88
118
|
end
|
119
|
+
alias :plen :pln
|
89
120
|
|
90
|
-
def
|
91
|
-
self[:
|
121
|
+
def pln=(i)
|
122
|
+
self[:pln].read i
|
92
123
|
end
|
124
|
+
alias :plen= :pln=
|
93
125
|
|
94
|
-
# @!attribute [rw]
|
126
|
+
# @!attribute [rw] op
|
95
127
|
# @return [Integer]
|
96
|
-
def
|
97
|
-
self[:
|
128
|
+
def op
|
129
|
+
self[:op].to_i
|
98
130
|
end
|
131
|
+
alias :opcode :op
|
99
132
|
|
100
|
-
def
|
101
|
-
self[:
|
133
|
+
def op=(i)
|
134
|
+
self[:op].read i
|
102
135
|
end
|
136
|
+
alias :opcode= :op=
|
103
137
|
|
104
|
-
# @!attribute [rw]
|
138
|
+
# @!attribute [rw] sha
|
105
139
|
# @return [String]
|
106
|
-
def
|
107
|
-
self[:
|
140
|
+
def sha
|
141
|
+
self[:sha].to_human
|
108
142
|
end
|
143
|
+
alias :src_mac :sha
|
109
144
|
|
110
|
-
def
|
111
|
-
self[:
|
145
|
+
def sha=(addr)
|
146
|
+
self[:sha].from_human addr
|
112
147
|
end
|
148
|
+
alias :src_mac= :sha=
|
113
149
|
|
114
|
-
# @!attribute [rw]
|
150
|
+
# @!attribute [rw] spa
|
115
151
|
# @return [String]
|
116
|
-
def
|
117
|
-
self[:
|
152
|
+
def spa
|
153
|
+
self[:spa].to_human
|
118
154
|
end
|
155
|
+
alias :src_ip :spa
|
119
156
|
|
120
|
-
def
|
121
|
-
self[:
|
157
|
+
def spa=(addr)
|
158
|
+
self[:spa].from_human addr
|
122
159
|
end
|
160
|
+
alias :src_ip= :spa=
|
123
161
|
|
124
|
-
# @!attribute [rw]
|
162
|
+
# @!attribute [rw] tha
|
125
163
|
# @return [String]
|
126
|
-
def
|
127
|
-
self[:
|
164
|
+
def tha
|
165
|
+
self[:tha].to_human
|
128
166
|
end
|
167
|
+
alias :dst_mac :tha
|
129
168
|
|
130
|
-
def
|
131
|
-
self[:
|
169
|
+
def tha=(addr)
|
170
|
+
self[:tha].from_human addr
|
132
171
|
end
|
172
|
+
alias :dst_mac= :tha=
|
133
173
|
|
134
|
-
# @!attribute [rw]
|
174
|
+
# @!attribute [rw] tpa
|
135
175
|
# @return [String]
|
136
|
-
def
|
137
|
-
self[:
|
176
|
+
def tpa
|
177
|
+
self[:tpa].to_human
|
138
178
|
end
|
179
|
+
alias :dst_ip :tpa
|
139
180
|
|
140
|
-
def
|
141
|
-
self[:
|
181
|
+
def tpa=(addr)
|
182
|
+
self[:tpa].from_human addr
|
142
183
|
end
|
184
|
+
alias :dst_ip= :tpa=
|
143
185
|
end
|
144
186
|
|
145
|
-
Eth.bind_header ARP,
|
187
|
+
Eth.bind_header ARP, ethertype: 0x806
|
146
188
|
end
|
147
189
|
end
|
148
190
|
|
data/lib/packetgen/header/eth.rb
CHANGED
@@ -1,9 +1,34 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
4
|
-
# Ethernet header
|
9
|
+
# An Ethernet header consists of:
|
10
|
+
# * a destination MAC address ({MacAddr}),
|
11
|
+
# * a source MAC address (MacAddr),
|
12
|
+
# * a {#ethertype} ({Int16}),
|
13
|
+
# * and a body (a {String} or another Header class).
|
14
|
+
#
|
15
|
+
# == Create a Ethernet header
|
16
|
+
# # standalone
|
17
|
+
# eth = PacketGen::Header::Eth.new
|
18
|
+
# # in a packet
|
19
|
+
# pkt = PacketGen.gen('Eth')
|
20
|
+
# # access to Ethernet header
|
21
|
+
# pkt.eth # => PacketGen::Header::Eth
|
22
|
+
#
|
23
|
+
# == Ethernet attributes
|
24
|
+
# eth.dst = "00:01:02:03:04:05'
|
25
|
+
# eth.src # => "00:01:01:01:01:01"
|
26
|
+
# eth[:src] # => PacketGen::Header::Eth::MacAddr
|
27
|
+
# eth.ethertype # => 16-bit Integer
|
28
|
+
# eth.body = "This is a body"
|
29
|
+
#
|
5
30
|
# @author Sylvain Daubert
|
6
|
-
class Eth < Struct.new(:dst, :src, :
|
31
|
+
class Eth < Struct.new(:dst, :src, :ethertype, :body)
|
7
32
|
include StructFu
|
8
33
|
include HeaderMethods
|
9
34
|
extend HeaderClassMethods
|
@@ -30,10 +55,10 @@ module PacketGen
|
|
30
55
|
|
31
56
|
end
|
32
57
|
|
33
|
-
#
|
58
|
+
# Read a human-readable string to populate +MacAddr+
|
34
59
|
# @param [String] str
|
35
60
|
# @return [self]
|
36
|
-
def
|
61
|
+
def from_human(str)
|
37
62
|
return self if str.nil?
|
38
63
|
bytes = str.split(/:/)
|
39
64
|
unless bytes.size == 6
|
@@ -48,7 +73,7 @@ module PacketGen
|
|
48
73
|
self
|
49
74
|
end
|
50
75
|
|
51
|
-
# Read a MacAddr from a string
|
76
|
+
# Read a +MacAddr+ from a binary string
|
52
77
|
# @param [String] str binary string
|
53
78
|
# @return [self]
|
54
79
|
def read(str)
|
@@ -65,9 +90,9 @@ module PacketGen
|
|
65
90
|
"def #{sym}=(v); self[:#{sym}].read v; end"
|
66
91
|
end
|
67
92
|
|
68
|
-
#
|
93
|
+
# +MacAddr+ in human readable form (colon format)
|
69
94
|
# @return [String]
|
70
|
-
def
|
95
|
+
def to_human
|
71
96
|
members.map { |m| "#{'%02x' % self[m]}" }.join(':')
|
72
97
|
end
|
73
98
|
end
|
@@ -82,11 +107,11 @@ module PacketGen
|
|
82
107
|
# @param [Hash] options
|
83
108
|
# @option options [String] :dst MAC destination address
|
84
109
|
# @option options [String] :src MAC source address
|
85
|
-
# @option options [Integer] :
|
110
|
+
# @option options [Integer] :ethertype
|
86
111
|
def initialize(options={})
|
87
|
-
super MacAddr.new.
|
88
|
-
MacAddr.new.
|
89
|
-
Int16.new(options[:
|
112
|
+
super MacAddr.new.from_human(options[:dst] || '00:00:00:00:00:00'),
|
113
|
+
MacAddr.new.from_human(options[:src] || '00:00:00:00:00:00'),
|
114
|
+
Int16.new(options[:ethertype] || 0),
|
90
115
|
StructFu::String.new.read(options[:body])
|
91
116
|
end
|
92
117
|
|
@@ -99,7 +124,7 @@ module PacketGen
|
|
99
124
|
force_binary str
|
100
125
|
self[:dst].read str[0, 6]
|
101
126
|
self[:src].read str[6, 6]
|
102
|
-
self[:
|
127
|
+
self[:ethertype].read str[12, 2]
|
103
128
|
self[:body].read str[14..-1]
|
104
129
|
self
|
105
130
|
end
|
@@ -107,40 +132,40 @@ module PacketGen
|
|
107
132
|
# Get MAC destination address
|
108
133
|
# @return [String]
|
109
134
|
def dst
|
110
|
-
self[:dst].
|
135
|
+
self[:dst].to_human
|
111
136
|
end
|
112
137
|
|
113
138
|
# Set MAC destination address
|
114
139
|
# @param [String] addr
|
115
140
|
# @return [String]
|
116
141
|
def dst=(addr)
|
117
|
-
self[:dst].
|
142
|
+
self[:dst].from_human addr
|
118
143
|
end
|
119
144
|
|
120
145
|
# Get MAC source address
|
121
146
|
# @return [String]
|
122
147
|
def src
|
123
|
-
self[:src].
|
148
|
+
self[:src].to_human
|
124
149
|
end
|
125
150
|
|
126
151
|
# Set MAC source address
|
127
152
|
# @param [String] addr
|
128
153
|
# @return [String]
|
129
154
|
def src=(addr)
|
130
|
-
self[:src].
|
155
|
+
self[:src].from_human addr
|
131
156
|
end
|
132
157
|
|
133
|
-
# Get
|
158
|
+
# Get ethertype field
|
134
159
|
# @return [Integer]
|
135
|
-
def
|
136
|
-
self[:
|
160
|
+
def ethertype
|
161
|
+
self[:ethertype].to_i
|
137
162
|
end
|
138
163
|
|
139
|
-
# Set
|
140
|
-
# @param [Integer]
|
164
|
+
# Set ethertype field
|
165
|
+
# @param [Integer] type
|
141
166
|
# @return [Integer]
|
142
|
-
def
|
143
|
-
self[:
|
167
|
+
def ethertype=(type)
|
168
|
+
self[:ethertype].value = type
|
144
169
|
end
|
145
170
|
|
146
171
|
# send Eth packet on wire.
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
@@ -22,7 +27,76 @@ module PacketGen
|
|
22
27
|
def known_headers
|
23
28
|
@known_headers ||= {}
|
24
29
|
end
|
25
|
-
end
|
26
30
|
|
31
|
+
# Define a bitfield on given attribute
|
32
|
+
# class MyHeader < Struct.new(:flags)
|
33
|
+
#
|
34
|
+
# def initialize(options={})
|
35
|
+
# super Int16.new(options[:flags])
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # define a bit field on :flag attribute:
|
39
|
+
# # flag1, flag2 and flag3 are 1-bit fields
|
40
|
+
# # type and stype are 3-bit fields. reserved is a 6-bit field
|
41
|
+
# define_bit_fields_on :flags, :flag1, :flag2, :flag3, :type, 3, :stype, 3, :reserved: 6
|
42
|
+
# end
|
43
|
+
# A bitfield of size 1 bit defines 2 methods:
|
44
|
+
# * +#field?+ which returns a Boolean,
|
45
|
+
# * +#field=+ which takes and returns a Boolean.
|
46
|
+
# A bitfield of more bits defines 2 methods:
|
47
|
+
# * +#field+ which returns an Integer,
|
48
|
+
# * +#field=+ which takes and returns an Integer.
|
49
|
+
# @param [Symbol] attr attribute name (attribute should a {StructFu::Int}
|
50
|
+
# subclass)
|
51
|
+
# @param [Array] args list of bitfield names. Name may be followed
|
52
|
+
# by bitfield size. If no size is given, 1 bit is assumed.
|
53
|
+
# @return [void]
|
54
|
+
def define_bit_fields_on(attr, *args)
|
55
|
+
total_size = self.new[attr].width * 8
|
56
|
+
idx = total_size - 1
|
57
|
+
|
58
|
+
field = args.shift
|
59
|
+
while field
|
60
|
+
next unless field.is_a? Symbol
|
61
|
+
size = if args.first.is_a? Integer
|
62
|
+
args.shift
|
63
|
+
else
|
64
|
+
1
|
65
|
+
end
|
66
|
+
unless field == :_
|
67
|
+
shift = idx - (size - 1)
|
68
|
+
field_mask = (2**size - 1) << shift
|
69
|
+
clear_mask = (2**total_size - 1) & (~field_mask & (2**total_size - 1))
|
70
|
+
|
71
|
+
if size == 1
|
72
|
+
class_eval <<-EOM
|
73
|
+
def #{field}?
|
74
|
+
val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
75
|
+
val != 0
|
76
|
+
end
|
77
|
+
def #{field}=(v)
|
78
|
+
val = v ? 1 : 0
|
79
|
+
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
80
|
+
self[:#{attr}].value |= val << #{shift}
|
81
|
+
end
|
82
|
+
EOM
|
83
|
+
else
|
84
|
+
class_eval <<-EOM
|
85
|
+
def #{field}
|
86
|
+
(self[:#{attr}].to_i & #{field_mask}) >> #{shift}
|
87
|
+
end
|
88
|
+
def #{field}=(v)
|
89
|
+
self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
|
90
|
+
self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
|
91
|
+
end
|
92
|
+
EOM
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
idx -= size
|
97
|
+
field = args.shift
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
27
101
|
end
|
28
102
|
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
@@ -46,6 +51,17 @@ module PacketGen
|
|
46
51
|
raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?
|
47
52
|
iph
|
48
53
|
end
|
54
|
+
|
55
|
+
# Common inspect method for headers
|
56
|
+
# @return [String]
|
57
|
+
def inspect
|
58
|
+
str = Inspect.dashed_line(self.class, 2)
|
59
|
+
to_h.each do |attr, value|
|
60
|
+
next if attr == :body
|
61
|
+
str << Inspect.inspect_attribute(attr, value, 2)
|
62
|
+
end
|
63
|
+
str
|
64
|
+
end
|
49
65
|
end
|
50
66
|
end
|
51
67
|
end
|
@@ -1,9 +1,32 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen for more informations
|
3
|
+
# Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
|
4
|
+
# This program is published under MIT license.
|
5
|
+
|
1
6
|
module PacketGen
|
2
7
|
module Header
|
3
8
|
|
4
|
-
# ICMP header
|
9
|
+
# A ICMP header consists of:
|
10
|
+
# * a {#type} field ({Int8} type),
|
11
|
+
# * a {#code} field ({Int8} type),
|
12
|
+
# * a {#checksum} field ({Int16} type),
|
13
|
+
# * and a {#body}.
|
14
|
+
#
|
15
|
+
# == Create a ICMP header
|
16
|
+
# # standalone
|
17
|
+
# icmp = PacketGen::Header::ICMP.new
|
18
|
+
# # in a packet
|
19
|
+
# pkt = PacketGen.gen('IP').add('ICMP')
|
20
|
+
# # access to ICMP header
|
21
|
+
# pkt.icmp # => PacketGen::Header::ICMP
|
22
|
+
#
|
23
|
+
# == ICMP attributes
|
24
|
+
# icmp.code = 0
|
25
|
+
# icmp.type = 200
|
26
|
+
# icmp.checksum = 0x248a
|
27
|
+
# icmp.body.read 'this is a body'
|
5
28
|
# @author Sylvain Daubert
|
6
|
-
class ICMP < Struct.new(:type, :code, :
|
29
|
+
class ICMP < Struct.new(:type, :code, :checksum, :body)
|
7
30
|
include StructFu
|
8
31
|
include HeaderMethods
|
9
32
|
extend HeaderClassMethods
|
@@ -14,12 +37,12 @@ module PacketGen
|
|
14
37
|
# @param [Hash] options
|
15
38
|
# @option options [Integer] :type
|
16
39
|
# @option options [Integer] :code
|
17
|
-
# @option options [Integer] :
|
40
|
+
# @option options [Integer] :checksum
|
18
41
|
# @option options [String] :body
|
19
42
|
def initialize(options={})
|
20
43
|
super Int8.new(options[:type]),
|
21
44
|
Int8.new(options[:code]),
|
22
|
-
Int16.new(options[:
|
45
|
+
Int16.new(options[:checksum]),
|
23
46
|
StructFu::String.new.read(options[:body])
|
24
47
|
end
|
25
48
|
|
@@ -28,17 +51,17 @@ module PacketGen
|
|
28
51
|
# @return [self]
|
29
52
|
def read(str)
|
30
53
|
return self if str.nil?
|
31
|
-
raise ParseError, 'string too short for
|
54
|
+
raise ParseError, 'string too short for ICMP' if str.size < self.sz
|
32
55
|
force_binary str
|
33
56
|
self[:type].read str[0, 1]
|
34
57
|
self[:code].read str[1, 1]
|
35
|
-
self[:
|
58
|
+
self[:checksum].read str[2, 2]
|
36
59
|
self[:body].read str[4..-1]
|
37
60
|
end
|
38
61
|
|
39
|
-
# Compute checksum and set +
|
62
|
+
# Compute checksum and set +checksum+ field
|
40
63
|
# @return [Integer]
|
41
|
-
def
|
64
|
+
def calc_checksum
|
42
65
|
sum = (type << 8) | code
|
43
66
|
|
44
67
|
payload = body.to_s
|
@@ -49,7 +72,7 @@ module PacketGen
|
|
49
72
|
sum = (sum & 0xffff) + (sum >> 16)
|
50
73
|
end
|
51
74
|
sum = ~sum & 0xffff
|
52
|
-
self[:
|
75
|
+
self[:checksum].value = (sum == 0) ? 0xffff : sum
|
53
76
|
end
|
54
77
|
|
55
78
|
# Getter for type attribute
|
@@ -78,20 +101,20 @@ module PacketGen
|
|
78
101
|
self[:code].value = code
|
79
102
|
end
|
80
103
|
|
81
|
-
# Getter for
|
104
|
+
# Getter for checksum attribute
|
82
105
|
# @return [Integer]
|
83
|
-
def
|
84
|
-
self[:
|
106
|
+
def checksum
|
107
|
+
self[:checksum].to_i
|
85
108
|
end
|
86
109
|
|
87
|
-
# Setter for
|
110
|
+
# Setter for checksum attribute
|
88
111
|
# @param [Integer] sum
|
89
112
|
# @return [Integer]
|
90
|
-
def
|
91
|
-
self[:
|
113
|
+
def checksum=(sum)
|
114
|
+
self[:checksum].value = sum
|
92
115
|
end
|
93
116
|
end
|
94
117
|
|
95
|
-
IP.bind_header ICMP,
|
118
|
+
IP.bind_header ICMP, protocol: ICMP::IP_PROTOCOL
|
96
119
|
end
|
97
120
|
end
|