packetgen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,357 @@
1
+ # -*- coding: binary -*-
2
+ module PacketGen
3
+ # StructFu, a nifty way to leverage Ruby's built in Struct class
4
+ # to create meaningful binary data.
5
+ #
6
+ # Copied from PacketFu:
7
+ #
8
+ # Copyright (c) 2008-2014, Tod Beardsley
9
+ # All rights reserved.
10
+ #
11
+ # Redistribution and use in source and binary forms, with or without
12
+ # modification, are permitted provided that the following conditions are met:
13
+ #
14
+ # * Redistributions of source code must retain the above copyright
15
+ # notice, this list of conditions and the following disclaimer.
16
+ # * Redistributions in binary form must reproduce the above copyright
17
+ # notice, this list of conditions and the following disclaimer in the
18
+ # documentation and/or other materials provided with the distribution.
19
+ # * Neither the name of Tod Beardsley nor the
20
+ # names of its contributors may be used to endorse or promote products
21
+ # derived from this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY TOD BEARDSLEY ''AS IS'' AND ANY
24
+ # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL TOD BEARDSLEY BE LIABLE FOR ANY
27
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ module StructFu
34
+
35
+ # Normally, self.size and self.length will refer to the Struct
36
+ # size as an array. It's a hassle to redefine, so this introduces some
37
+ # shorthand to get at the size of the resultant string.
38
+ def sz
39
+ self.to_s.size
40
+ end
41
+
42
+ alias len sz
43
+
44
+ # Typecast is used mostly by packet header classes, such as IPHeader,
45
+ # TCPHeader, and the like. It takes an argument, and casts it to the
46
+ # expected type for that element.
47
+ def typecast(i)
48
+ c = caller[0].match(/.*`([^']+)='/)[1]
49
+ self[c.intern].read i
50
+ end
51
+
52
+ # Used like typecast(), but specifically for casting Strings to StructFu::Strings.
53
+ def body=(i)
54
+ if i.kind_of? ::String
55
+ typecast(i)
56
+ elsif i.kind_of? StructFu
57
+ self[:body] = i
58
+ elsif i.nil?
59
+ self[:body] = StructFu::String.new.read("")
60
+ else
61
+ raise ArgumentError, "Can't cram a #{i.class} into a StructFu :body"
62
+ end
63
+ end
64
+
65
+ # Handle deep copies correctly.
66
+ def clone
67
+ Marshal.load(Marshal.dump(self))
68
+ end
69
+
70
+ # Set the endianness for the various Int classes handled by self
71
+ # @param [:little, :big] e
72
+ # @return [:little, :big] returns e
73
+ def set_endianness(e)
74
+ unless [:little, :big].include? e
75
+ raise ArgumentError, "unknown endianness for #{self.class}"
76
+ end
77
+ @int64 = e == :little ? Int64le : Int64be
78
+ @int32 = e == :little ? Int32le : Int32be
79
+ @int16 = e == :little ? Int16le : Int16be
80
+ e
81
+ end
82
+
83
+ # Get binary string
84
+ # @return [String]
85
+ def to_s
86
+ to_a.map { |field| field.to_s }.join
87
+ end
88
+
89
+ # Ints all have a value, an endianness, and a default value.
90
+ # Note that the signedness of Int values are implicit as
91
+ # far as the subclasses are concerned; to_i and to_f will
92
+ # return Integer/Float versions of the input value, instead
93
+ # of attempting to unpack the pack value. (This can be a useful
94
+ # hint to other functions).
95
+ #
96
+ # ==== Header Definition
97
+ #
98
+ # Fixnum :value
99
+ # Symbol :endian
100
+ # Fixnum :width
101
+ # Fixnum :default
102
+ class Int < Struct.new(:value, :endian, :width, :default)
103
+ alias :v= :value=
104
+ alias :v :value
105
+ alias :e= :endian=
106
+ alias :e :endian
107
+ alias :w= :width=
108
+ alias :w :width
109
+ alias :d= :default=
110
+ alias :d :default
111
+
112
+ # This is a parent class definition and should not be used directly.
113
+ def to_s
114
+ raise StandardError, "StructFu::Int#to_s accessed, must be redefined."
115
+ end
116
+
117
+ # Returns the Int as an Integer.
118
+ def to_i
119
+ (self.v || self.d).to_i
120
+ end
121
+
122
+ # Returns the Int as a Float.
123
+ def to_f
124
+ (self.v || self.d).to_f
125
+ end
126
+
127
+ def initialize(value=nil, endian=nil, width=nil, default=nil)
128
+ super(value,endian,width,default=0)
129
+ end
130
+
131
+ # Reads either an Integer or a packed string, and populates the value accordingly.
132
+ def read(i)
133
+ self.v = i.kind_of?(Integer) ? i.to_i : i.to_s.unpack(@packstr).first
134
+ self
135
+ end
136
+ end
137
+
138
+ # Int8 is a one byte value.
139
+ class Int8 < Int
140
+
141
+ def initialize(v=nil)
142
+ super(v,nil,w=1)
143
+ @packstr = "C"
144
+ end
145
+
146
+ # Returns a one byte value as a packed string.
147
+ def to_s
148
+ [(self.v || self.d)].pack("C")
149
+ end
150
+ end
151
+
152
+ # Int16 is a two byte value.
153
+ class Int16 < Int
154
+ def initialize(v=nil, e=:big)
155
+ super(v,e,w=2)
156
+ @packstr = (self.e == :big) ? "n" : "v"
157
+ end
158
+
159
+ # Returns a two byte value as a packed string.
160
+ def to_s
161
+ @packstr = (self.e == :big) ? "n" : "v"
162
+ [(self.v || self.d)].pack(@packstr)
163
+ end
164
+ end
165
+
166
+ # Int16be is a two byte value in big-endian format. The endianness cannot be altered.
167
+ class Int16be < Int16
168
+ undef :endian=
169
+ end
170
+
171
+ # Int16le is a two byte value in little-endian format. The endianness cannot be altered.
172
+ class Int16le < Int16
173
+ undef :endian=
174
+ def initialize(v=nil, e=:little)
175
+ super(v,e)
176
+ @packstr = (self.e == :big) ? "n" : "v"
177
+ end
178
+ end
179
+
180
+ # Int32 is a four byte value.
181
+ class Int32 < Int
182
+ def initialize(v=nil, e=:big)
183
+ super(v,e,w=4)
184
+ @packstr = (self.e == :big) ? "N" : "V"
185
+ end
186
+
187
+ # Returns a four byte value as a packed string.
188
+ def to_s
189
+ @packstr = (self.e == :big) ? "N" : "V"
190
+ [(self.v || self.d)].pack(@packstr)
191
+ end
192
+ end
193
+
194
+ # Int32be is a four byte value in big-endian format. The endianness cannot be altered.
195
+ class Int32be < Int32
196
+ undef :endian=
197
+ end
198
+
199
+ # Int32le is a four byte value in little-endian format. The endianness cannot be altered.
200
+ class Int32le < Int32
201
+ undef :endian=
202
+ def initialize(v=nil, e=:little)
203
+ super(v,e)
204
+ end
205
+ end
206
+
207
+ # Int64 is a eight byte value.
208
+ class Int64 < Int
209
+ def initialize(v=nil, e=:big)
210
+ super(v, e, w=4)
211
+ @packstr = (self.e == :big) ? 'Q>' : 'Q<'
212
+ end
213
+
214
+ # Returns a eight byte value as a packed string.
215
+ def to_s
216
+ @packstr = (self.e == :big) ? 'Q>' : 'Q<'
217
+ [(self.v || self.d)].pack(@packstr)
218
+ end
219
+ end
220
+
221
+ # Int64be is a eight byte value in big-endian format. The endianness cannot be altered.
222
+ class Int64be < Int64
223
+ undef :endian=
224
+ end
225
+
226
+ # Int64le is a eight byte value in little-endian format. The endianness cannot be altered.
227
+ class Int64le < Int64
228
+ undef :endian=
229
+ def initialize(v=nil, e=:little)
230
+ super(v,e)
231
+ end
232
+ end
233
+
234
+ # Strings are just like regular strings, except it comes with a read() function
235
+ # so that it behaves like other StructFu elements.
236
+ class String < ::String
237
+ def read(str)
238
+ str = str.to_s
239
+ self.replace str
240
+ self
241
+ end
242
+ end
243
+
244
+ # Provides a primitive for creating strings, preceeded by
245
+ # an Int type of length. By default, a string of length zero with
246
+ # a one-byte length is presumed.
247
+ #
248
+ # Note that IntStrings aren't used for much, but it seemed like a good idea at the time.
249
+ class IntString < Struct.new(:int, :string, :mode)
250
+
251
+ def initialize(string='',int=Int8,mode=nil)
252
+ if int < Int
253
+ super(int.new,string,mode)
254
+ calc
255
+ else
256
+ raise "IntStrings need a StructFu::Int for a length."
257
+ end
258
+ end
259
+
260
+ # Calculates the size of a string, and sets it as the value.
261
+ def calc
262
+ int.v = string.to_s.size
263
+ self.to_s
264
+ end
265
+
266
+ # Returns the object as a string, depending on the mode set upon object creation.
267
+ def to_s
268
+ if mode == :parse
269
+ "#{int}" + [string].pack("a#{len}")
270
+ elsif mode == :fix
271
+ self.int.v = string.size
272
+ "#{int}#{string}"
273
+ else
274
+ "#{int}#{string}"
275
+ end
276
+ end
277
+
278
+ # By redefining #string=, we can ensure the correct value
279
+ # is calculated upon assignment. If you'd prefer to have
280
+ # an incorrect value, use the syntax, obj[:string]="value"
281
+ # instead. Note, by using the alternate form, you must
282
+ # #calc before you can trust the int's value. Think of the =
283
+ # assignment as "set to equal," while the []= assignment
284
+ # as "boxing in" the value. Maybe.
285
+ def string=(s)
286
+ self[:string] = s
287
+ calc
288
+ end
289
+
290
+ # Shorthand for querying a length. Note that the usual "length"
291
+ # and "size" refer to the number of elements of this struct.
292
+ def len
293
+ self[:int].value
294
+ end
295
+
296
+ # Override the size, if you must.
297
+ def len=(i)
298
+ self[:int].value=i
299
+ end
300
+
301
+ # Read takes a string, assumes an int width as previously
302
+ # defined upon initialization, but makes no guarantees
303
+ # the int value isn't lying. You're on your own to test
304
+ # for that (or use parse() with a :mode set).
305
+ def read(s)
306
+ unless s[0,int.width].size == int.width
307
+ raise StandardError, "String is too short for type #{int.class}"
308
+ else
309
+ int.read(s[0,int.width])
310
+ self[:string] = s[int.width,s.size]
311
+ end
312
+ self.to_s
313
+ end
314
+
315
+ # parse() is like read(), except that it interprets the string, either
316
+ # based on the declared length, or the actual length. Which strategy
317
+ # is used is dependant on which :mode is set (with self.mode).
318
+ #
319
+ # :parse : Read the length, and then read in that many bytes of the string.
320
+ # The string may be truncated or padded out with nulls, as dictated by the value.
321
+ #
322
+ # :fix : Skip the length, read the rest of the string, then set the length
323
+ # to what it ought to be.
324
+ #
325
+ # else : If neither of these modes are set, just perfom a normal read().
326
+ # This is the default.
327
+ def parse(s)
328
+ unless s[0,int.width].size == int.width
329
+ raise StandardError, "String is too short for type #{int.class}"
330
+ else
331
+ case mode
332
+ when :parse
333
+ int.read(s[0,int.width])
334
+ self[:string] = s[int.width,int.value]
335
+ if string.size < int.value
336
+ self[:string] += ("\x00" * (int.value - self[:string].size))
337
+ end
338
+ when :fix
339
+ self.string = s[int.width,s.size]
340
+ else
341
+ return read(s)
342
+ end
343
+ end
344
+ self.to_s
345
+ end
346
+ end
347
+ end
348
+ end
349
+
350
+ class Struct
351
+ # Monkeypatch for Struct to include some string safety -- anything that uses
352
+ # Struct is going to presume binary strings anyway.
353
+ # Modified by S. Daubert to not call PacketFu.force_binary
354
+ def force_binary(str)
355
+ str.force_encoding Encoding::BINARY
356
+ end
357
+ end
@@ -0,0 +1,7 @@
1
+ # PacketGen is a network packet generator and analyzor.
2
+ #
3
+ # @author Sylvain Daubert
4
+ module PacketGen
5
+ # PacketGen version
6
+ VERSION = "0.1.0"
7
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'packetgen/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'packetgen'
8
+ spec.version = PacketGen::VERSION
9
+ spec.authors = ['Sylvain Daubert']
10
+ spec.email = ['sylvain.daubert@laposte.net']
11
+
12
+ spec.summary = %q{Network packet generator and analyzor}
13
+ #spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ spec.homepage = 'https://github.com/sdaubert/packetgen'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'pcaprub', '~>0.12.4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.7'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'simplecov', '~> 0.12'
29
+ spec.add_development_dependency 'yard', '~> 0.9'
30
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: packetgen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sylvain Daubert
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-12-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pcaprub
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.12.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ description:
98
+ email:
99
+ - sylvain.daubert@laposte.net
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - lib/packetgen.rb
111
+ - lib/packetgen/capture.rb
112
+ - lib/packetgen/header.rb
113
+ - lib/packetgen/header/arp.rb
114
+ - lib/packetgen/header/eth.rb
115
+ - lib/packetgen/header/header_class_methods.rb
116
+ - lib/packetgen/header/header_methods.rb
117
+ - lib/packetgen/header/ip.rb
118
+ - lib/packetgen/header/ipv6.rb
119
+ - lib/packetgen/header/udp.rb
120
+ - lib/packetgen/packet.rb
121
+ - lib/packetgen/pcapng.rb
122
+ - lib/packetgen/pcapng/block.rb
123
+ - lib/packetgen/pcapng/epb.rb
124
+ - lib/packetgen/pcapng/file.rb
125
+ - lib/packetgen/pcapng/idb.rb
126
+ - lib/packetgen/pcapng/shb.rb
127
+ - lib/packetgen/pcapng/spb.rb
128
+ - lib/packetgen/pcapng/unknown_block.rb
129
+ - lib/packetgen/structfu.rb
130
+ - lib/packetgen/version.rb
131
+ - packetgen.gemspec
132
+ homepage: https://github.com/sdaubert/packetgen
133
+ licenses: []
134
+ metadata: {}
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 2.5.1
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: Network packet generator and analyzor
155
+ test_files: []