packetgen 1.2.0 → 1.3.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/packetgen/header/arp.rb +54 -125
  4. data/lib/packetgen/header/base.rb +175 -0
  5. data/lib/packetgen/header/dns/name.rb +110 -0
  6. data/lib/packetgen/header/dns/opt.rb +137 -0
  7. data/lib/packetgen/header/dns/option.rb +17 -0
  8. data/lib/packetgen/header/dns/qdsection.rb +39 -0
  9. data/lib/packetgen/header/dns/question.rb +129 -0
  10. data/lib/packetgen/header/dns/rr.rb +89 -0
  11. data/lib/packetgen/header/dns/rrsection.rb +72 -0
  12. data/lib/packetgen/header/dns.rb +276 -0
  13. data/lib/packetgen/header/esp.rb +38 -70
  14. data/lib/packetgen/header/eth.rb +35 -106
  15. data/lib/packetgen/header/icmp.rb +19 -70
  16. data/lib/packetgen/header/icmpv6.rb +3 -3
  17. data/lib/packetgen/header/ip.rb +54 -210
  18. data/lib/packetgen/header/ipv6.rb +73 -164
  19. data/lib/packetgen/header/tcp/option.rb +34 -50
  20. data/lib/packetgen/header/tcp/options.rb +19 -20
  21. data/lib/packetgen/header/tcp.rb +66 -129
  22. data/lib/packetgen/header/udp.rb +31 -88
  23. data/lib/packetgen/header.rb +5 -10
  24. data/lib/packetgen/inspect.rb +5 -4
  25. data/lib/packetgen/packet.rb +74 -57
  26. data/lib/packetgen/pcapng/block.rb +49 -7
  27. data/lib/packetgen/pcapng/epb.rb +36 -34
  28. data/lib/packetgen/pcapng/file.rb +24 -8
  29. data/lib/packetgen/pcapng/idb.rb +28 -33
  30. data/lib/packetgen/pcapng/shb.rb +35 -39
  31. data/lib/packetgen/pcapng/spb.rb +18 -27
  32. data/lib/packetgen/pcapng/unknown_block.rb +11 -21
  33. data/lib/packetgen/pcapng.rb +9 -7
  34. data/lib/packetgen/types/array.rb +56 -0
  35. data/lib/packetgen/types/fields.rb +325 -0
  36. data/lib/packetgen/types/int.rb +164 -0
  37. data/lib/packetgen/types/int_string.rb +69 -0
  38. data/lib/packetgen/types/string.rb +36 -0
  39. data/lib/packetgen/types/tlv.rb +41 -0
  40. data/lib/packetgen/types.rb +13 -0
  41. data/lib/packetgen/version.rb +1 -1
  42. data/lib/packetgen.rb +1 -1
  43. metadata +19 -6
  44. data/lib/packetgen/header/header_class_methods.rb +0 -106
  45. data/lib/packetgen/header/header_methods.rb +0 -73
  46. data/lib/packetgen/structfu.rb +0 -363
@@ -0,0 +1,164 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ module PacketGen
8
+ module Types
9
+
10
+ # Base integer class to handle binary integers
11
+ # @abstract
12
+ # @author Sylvain Daubert
13
+ class Int
14
+
15
+ # Integer value
16
+ # @return [Integer]
17
+ attr_accessor :value
18
+ # Integer endianness
19
+ # @return [:little,:big]
20
+ attr_accessor :endian
21
+ # Integer size, in bytes
22
+ # @return [Integer]
23
+ attr_accessor :width
24
+ # Integer default value
25
+ # @return [Integer]
26
+ attr_accessor :default
27
+
28
+ # @param [Integer,nil] value
29
+ # @param [:little,:big,nil] endian
30
+ # @param [Integer,nil] width
31
+ # @param [Integer] default
32
+ def initialize(value=nil, endian=nil, width=nil, default=0)
33
+ @value = value
34
+ @endian = endian
35
+ @width = width
36
+ @default = default
37
+ end
38
+
39
+ def read(value)
40
+ @value = if value.is_a?(Integer)
41
+ value.to_i
42
+ else
43
+ value.to_s.unpack(@packstr[@endian]).first
44
+ end
45
+ self
46
+ end
47
+
48
+ # @abstract
49
+ # @return [::String]
50
+ # @raise [StandardError] This is an abstrat method and must be redefined
51
+ def to_s
52
+ unless defined? @packstr
53
+ raise StandardError, 'PacketGen::Types::Int#to_s is an abstract method'
54
+ end
55
+ [to_i].pack(@packstr[@endian])
56
+ end
57
+
58
+ def to_i
59
+ @value || @default
60
+ end
61
+
62
+ def to_f
63
+ to_i.to_f
64
+ end
65
+ end
66
+
67
+ # One byte integer
68
+ # @author Sylvain Daubert
69
+ class Int8 < Int
70
+ # @param [Integer,nil] value
71
+ def initialize(value=nil)
72
+ super(value, nil, 1)
73
+ @packstr = { nil => 'C' }
74
+ end
75
+ end
76
+
77
+ # 2-byte integer
78
+ # @author Sylvain Daubert
79
+ class Int16 < Int
80
+ # @param [Integer,nil] value
81
+ # @param [:big, :little] endian
82
+ def initialize(value=nil, endian=:big)
83
+ super(value, endian, 2)
84
+ @packstr = { big: 'n', little: 'v' }
85
+ end
86
+ end
87
+
88
+ # big endian 2-byte integer
89
+ # @author Sylvain Daubert
90
+ class Int16be < Int16
91
+ undef endian=
92
+ end
93
+
94
+ # little endian 2-byte integer
95
+ # @author Sylvain Daubert
96
+ class Int16le < Int16
97
+ # @param [Integer,nil] value
98
+ undef endian=
99
+
100
+ # @param [Integer, nil] value
101
+ def initialize(value=nil)
102
+ super(value, :little)
103
+ end
104
+ end
105
+
106
+ # 4-byte integer
107
+ # @author Sylvain Daubert
108
+ class Int32 < Int
109
+ # @param [Integer,nil] value
110
+ # @param [:big, :little] endian
111
+ def initialize(value=nil, endian=:big)
112
+ super(value, endian, 4)
113
+ @packstr = { big: 'N', little: 'V' }
114
+ end
115
+ end
116
+
117
+ # big endian 4-byte integer
118
+ # @author Sylvain Daubert
119
+ class Int32be < Int32
120
+ undef endian=
121
+ end
122
+
123
+ # little endian 4-byte integer
124
+ # @author Sylvain Daubert
125
+ class Int32le < Int32
126
+ # @param [Integer,nil] value
127
+ undef endian=
128
+
129
+ # @param [Integer, nil] value
130
+ def initialize(value=nil)
131
+ super(value, :little)
132
+ end
133
+ end
134
+
135
+ # 8-byte integer
136
+ # @author Sylvain Daubert
137
+ class Int64 < Int
138
+ # @param [Integer,nil] value
139
+ # @param [:big, :little] endian
140
+ def initialize(value=nil, endian=:big)
141
+ super(value, endian, 8)
142
+ @packstr = { big: 'Q>', little: 'Q<' }
143
+ end
144
+ end
145
+
146
+ # big endian 8-byte integer
147
+ # @author Sylvain Daubert
148
+ class Int64be < Int64
149
+ undef endian=
150
+ end
151
+
152
+ # little endian 8-byte integer
153
+ # @author Sylvain Daubert
154
+ class Int64le < Int64
155
+ # @param [Integer,nil] value
156
+ undef endian=
157
+
158
+ # @param [Integer, nil] value
159
+ def initialize(value=nil)
160
+ super(value, :little)
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,69 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ module PacketGen
8
+ module Types
9
+
10
+ # Provides a class for creating strings preceeded by their length as a {Int}.
11
+ # By default, a null string will have one byte length (length byte set to 0).
12
+ # @author Sylvain Daubert
13
+ class IntString
14
+
15
+ # internal string
16
+ # @return [String]
17
+ attr_accessor :string
18
+
19
+ # @param [::String] str
20
+ # @param [Class] len_type should be a {Int} subclass
21
+ def initialize(str='', len_type=Int8)
22
+ @string = Types::String.new(str)
23
+ @length = len_type.new
24
+ calc_length
25
+ end
26
+
27
+ # @param [::String] str
28
+ # @return [IntString] self
29
+ def read(str)
30
+ unless str[0, @length.width].size == @length.width
31
+ raise ParseError, "String too short for type #{@length.type}"
32
+ end
33
+ @length.read str[0, @length.width]
34
+ @string.read str[@length.width, @length.to_i]
35
+ self
36
+ end
37
+
38
+ # @param [Integer] l
39
+ # @return [Integer]
40
+ def length=(l)
41
+ @length.read l
42
+ l
43
+ end
44
+
45
+ # @return [Integer]
46
+ def length
47
+ @length.to_i
48
+ end
49
+
50
+ # Get binary string
51
+ # @return [::String]
52
+ def to_s
53
+ @length.to_s << @string.to_s
54
+ end
55
+
56
+ # Set length from internal string length
57
+ # @return [Integer]
58
+ def calc_length
59
+ @length.read @string.length
60
+ end
61
+
62
+ # Give binary string length
63
+ # @return [Integer]
64
+ def sz
65
+ to_s.size
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+
7
+ module PacketGen
8
+ module Types
9
+
10
+ # This class is just like regular String. It only adds #read and #sz methods
11
+ # to be compatible with others {Types}.
12
+ # @author Sylvain Daubert
13
+ class String < ::String
14
+
15
+ # @param [String] str
16
+ # @param [Hash] options
17
+ # @option options [Types::Int] :length_from object from which takes length when
18
+ # reading
19
+ def initialize(str='', options={})
20
+ super(str)
21
+ @length_from = options[:length_from]
22
+ end
23
+
24
+ # @param [::String] str
25
+ # @return [String] self
26
+ def read(str)
27
+ s = str.to_s
28
+ s = s[0, @length_from.to_i] unless @length_from.nil?
29
+ self.replace s
30
+ self
31
+ end
32
+
33
+ alias sz length
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ module PacketGen
2
+ module Types
3
+
4
+ # Class to handle Type-Length-Value attributes
5
+ # @author Sylvain Daubert
6
+ class TLV < Fields
7
+ # @!attribute type
8
+ # @return [Integer]
9
+ define_field :type, Int8
10
+ # @!attribute length
11
+ # @return [Integer]
12
+ define_field :length, Int8
13
+ # @!attribute value
14
+ # @return [String]
15
+ define_field :value, String,
16
+ builder: ->(tlv) { String.new('', length_from: tlv[:length]) }
17
+
18
+ # @param [Hash] options
19
+ # @option options [Integer] :type
20
+ # @option options [Integer] :length
21
+ # @option options [String] :value
22
+ # @option options [Class] :t {Int} subclass for +:type+ attribute.
23
+ # Default: {Int8}.
24
+ # @option options [Class] :l {Int} subclass for +:length+ attribute.
25
+ # Default: {Int8}.
26
+ def initialize(options={})
27
+ super
28
+ self[:type] = options[:t].new(type) if options[:t]
29
+ if options[:l]
30
+ self[:length] = options[:l].new(length)
31
+ self[:value] = String.new('', length_from: self[:length])
32
+ end
33
+ end
34
+
35
+ # @return [String]
36
+ def to_human
37
+ "type=#{type},len=#{length},value=#{value.inspect}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ module PacketGen
2
+
3
+ # Module to group all type definitions
4
+ module Types
5
+ end
6
+ end
7
+
8
+ require_relative 'types/int'
9
+ require_relative 'types/string'
10
+ require_relative 'types/int_string'
11
+ require_relative 'types/fields'
12
+ require_relative 'types/array'
13
+ require_relative 'types/tlv'
@@ -8,5 +8,5 @@
8
8
  # @author Sylvain Daubert
9
9
  module PacketGen
10
10
  # PacketGen version
11
- VERSION = "1.2.0"
11
+ VERSION = "1.3.0"
12
12
  end
data/lib/packetgen.rb CHANGED
@@ -83,7 +83,7 @@ module PacketGen
83
83
  end
84
84
  end
85
85
 
86
- require 'packetgen/structfu'
86
+ require 'packetgen/types'
87
87
  require 'packetgen/inspect'
88
88
  require 'packetgen/packet'
89
89
  require 'packetgen/capture'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packetgen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Daubert
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-10 00:00:00.000000000 Z
11
+ date: 2017-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pcaprub
@@ -111,10 +111,17 @@ files:
111
111
  - lib/packetgen/capture.rb
112
112
  - lib/packetgen/header.rb
113
113
  - lib/packetgen/header/arp.rb
114
+ - lib/packetgen/header/base.rb
115
+ - lib/packetgen/header/dns.rb
116
+ - lib/packetgen/header/dns/name.rb
117
+ - lib/packetgen/header/dns/opt.rb
118
+ - lib/packetgen/header/dns/option.rb
119
+ - lib/packetgen/header/dns/qdsection.rb
120
+ - lib/packetgen/header/dns/question.rb
121
+ - lib/packetgen/header/dns/rr.rb
122
+ - lib/packetgen/header/dns/rrsection.rb
114
123
  - lib/packetgen/header/esp.rb
115
124
  - lib/packetgen/header/eth.rb
116
- - lib/packetgen/header/header_class_methods.rb
117
- - lib/packetgen/header/header_methods.rb
118
125
  - lib/packetgen/header/icmp.rb
119
126
  - lib/packetgen/header/icmpv6.rb
120
127
  - lib/packetgen/header/ip.rb
@@ -133,7 +140,13 @@ files:
133
140
  - lib/packetgen/pcapng/shb.rb
134
141
  - lib/packetgen/pcapng/spb.rb
135
142
  - lib/packetgen/pcapng/unknown_block.rb
136
- - lib/packetgen/structfu.rb
143
+ - lib/packetgen/types.rb
144
+ - lib/packetgen/types/array.rb
145
+ - lib/packetgen/types/fields.rb
146
+ - lib/packetgen/types/int.rb
147
+ - lib/packetgen/types/int_string.rb
148
+ - lib/packetgen/types/string.rb
149
+ - lib/packetgen/types/tlv.rb
137
150
  - lib/packetgen/version.rb
138
151
  - packetgen.gemspec
139
152
  homepage: https://github.com/sdaubert/packetgen
@@ -155,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
168
  version: '0'
156
169
  requirements: []
157
170
  rubyforge_project:
158
- rubygems_version: 2.6.8
171
+ rubygems_version: 2.5.2
159
172
  signing_key:
160
173
  specification_version: 4
161
174
  summary: Network packet generator and analyzor
@@ -1,106 +0,0 @@
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
-
6
- module PacketGen
7
- module Header
8
-
9
- module HeaderClassMethods
10
-
11
- # @api private
12
- # Simple class to handle header association
13
- Binding = Struct.new(:key, :value)
14
-
15
- # Bind a upper header to current class
16
- # @param [Class] header_klass header class to bind to current class
17
- # @param [Hash] args current class fields and their value when +header_klass+
18
- # is embedded in current class
19
- # @return [void]
20
- def bind_header(header_klass, args={})
21
- @known_headers ||= {}
22
- @known_headers[header_klass] ||= []
23
- args.each do |key, value|
24
- @known_headers[header_klass] << Binding.new(key, value)
25
- end
26
- end
27
-
28
- # @api private
29
- # Get knwon headers
30
- # @return [Hash] keys: header classes, values: array of {Binding}
31
- def known_headers
32
- @known_headers ||= {}
33
- end
34
-
35
- # Define a bitfield on given attribute
36
- # class MyHeader < Struct.new(:flags)
37
- #
38
- # def initialize(options={})
39
- # super Int16.new(options[:flags])
40
- # end
41
- #
42
- # # define a bit field on :flag attribute:
43
- # # flag1, flag2 and flag3 are 1-bit fields
44
- # # type and stype are 3-bit fields. reserved is a 6-bit field
45
- # define_bit_fields_on :flags, :flag1, :flag2, :flag3, :type, 3, :stype, 3, :reserved: 6
46
- # end
47
- # A bitfield of size 1 bit defines 2 methods:
48
- # * +#field?+ which returns a Boolean,
49
- # * +#field=+ which takes and returns a Boolean.
50
- # A bitfield of more bits defines 2 methods:
51
- # * +#field+ which returns an Integer,
52
- # * +#field=+ which takes and returns an Integer.
53
- # @param [Symbol] attr attribute name (attribute should a {StructFu::Int}
54
- # subclass)
55
- # @param [Array] args list of bitfield names. Name may be followed
56
- # by bitfield size. If no size is given, 1 bit is assumed.
57
- # @return [void]
58
- def define_bit_fields_on(attr, *args)
59
- total_size = self.new[attr].width * 8
60
- idx = total_size - 1
61
-
62
- field = args.shift
63
- while field
64
- next unless field.is_a? Symbol
65
- size = if args.first.is_a? Integer
66
- args.shift
67
- else
68
- 1
69
- end
70
- unless field == :_
71
- shift = idx - (size - 1)
72
- field_mask = (2**size - 1) << shift
73
- clear_mask = (2**total_size - 1) & (~field_mask & (2**total_size - 1))
74
-
75
- if size == 1
76
- class_eval <<-EOM
77
- def #{field}?
78
- val = (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
79
- val != 0
80
- end
81
- def #{field}=(v)
82
- val = v ? 1 : 0
83
- self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
84
- self[:#{attr}].value |= val << #{shift}
85
- end
86
- EOM
87
- else
88
- class_eval <<-EOM
89
- def #{field}
90
- (self[:#{attr}].to_i & #{field_mask}) >> #{shift}
91
- end
92
- def #{field}=(v)
93
- self[:#{attr}].value = self[:#{attr}].to_i & #{clear_mask}
94
- self[:#{attr}].value |= (v & #{2**size - 1}) << #{shift}
95
- end
96
- EOM
97
- end
98
- end
99
-
100
- idx -= size
101
- field = args.shift
102
- end
103
- end
104
- end
105
- end
106
- end
@@ -1,73 +0,0 @@
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
-
6
- module PacketGen
7
- module Header
8
-
9
- # Mixin for various headers
10
- # @author Sylvain Daubert
11
- module HeaderMethods
12
-
13
- # @api private
14
- # Set reference of packet which owns this header
15
- # @param [Packet] packet
16
- # @return [void]
17
- def packet=(packet)
18
- @packet = packet
19
- end
20
-
21
- # @api private
22
- # Get rference on packet which owns this header
23
- # @return [Packet]
24
- def packet
25
- @packet
26
- end
27
-
28
- # @api private
29
- # Get +header+ id in packet headers array
30
- # @param [Header] header
31
- # @return [Integer]
32
- # @raise FormatError +header+ not in a packet
33
- def header_id(header)
34
- raise FormatError, "header of type #{header.class} not in a packet" if packet.nil?
35
- id = packet.headers.index(header)
36
- if id.nil?
37
- raise FormatError, "header of type #{header.class} not in packet #{packet}"
38
- end
39
- id
40
- end
41
-
42
- # @api private
43
- # Get IP or IPv6 previous header from +header+
44
- # @param [Header] header
45
- # @return [Header]
46
- # @raise FormatError no IP or IPv6 header previous +header+ in packet
47
- # @raise FormatError +header+ not in a packet
48
- def ip_header(header)
49
- hid = header_id(header)
50
- iph = packet.headers[0...hid].reverse.find { |h| h.is_a? IP or h.is_a? IPv6 }
51
- raise FormatError, 'no IP or IPv6 header in packet' if iph.nil?
52
- iph
53
- end
54
-
55
- # Return header protocol name
56
- # @return [String]
57
- def protocol_name
58
- self.class.to_s.sub(/.*::/, '')
59
- end
60
-
61
- # Common inspect method for headers
62
- # @return [String]
63
- def inspect
64
- str = Inspect.dashed_line(self.class, 2)
65
- to_h.each do |attr, value|
66
- next if attr == :body
67
- str << Inspect.inspect_attribute(attr, value, 2)
68
- end
69
- str
70
- end
71
- end
72
- end
73
- end