packetgen 1.2.0 → 1.3.0

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