packetgen 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|