packetgen 0.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.
@@ -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: []