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
@@ -5,12 +5,12 @@ module PacketGen
5
5
  class CipherError < Error;end
6
6
 
7
7
  # A ESP header consists of:
8
- # * a Security Parameters Index (#{spi}, {Int32} type),
8
+ # * a Security Parameters Index (#{spi}, {Types::Int32} type),
9
9
  # * a Sequence Number ({#sn}, +Int32+ type),
10
10
  # * a {#body} (variable length),
11
11
  # * an optional TFC padding ({#tfc}, variable length),
12
12
  # * an optional {#padding} (to align ESP on 32-bit boundary, variable length),
13
- # * a {#pad_length} ({Int8}),
13
+ # * a {#pad_length} ({Types::Int8}),
14
14
  # * a Next header field ({#next}, +Int8+),
15
15
  # * and an optional Integrity Check Value ({#icv}, variable length).
16
16
  #
@@ -62,11 +62,7 @@ module PacketGen
62
62
  #
63
63
  # pkt.esp.decrypt! cipher, intmode: hmac # => true if ICV check OK
64
64
  # @author Sylvain Daubert
65
- class ESP < Struct.new(:spi, :sn, :body, :tfc, :padding,
66
- :pad_length, :next, :icv)
67
- include StructFu
68
- include HeaderMethods
69
- extend HeaderClassMethods
65
+ class ESP < Base
70
66
 
71
67
  # IP protocol number for ESP
72
68
  IP_PROTOCOL = 50
@@ -74,6 +70,38 @@ module PacketGen
74
70
  # Well-known UDP port for ESP
75
71
  UDP_PORT = 4500
76
72
 
73
+ # @!attribute spi
74
+ # 32-bit Security Parameter Index
75
+ # @return [Integer]
76
+ define_field :spi, Types::Int32
77
+ # @!attribute sn
78
+ # 32-bit Sequence Number
79
+ # @return [Integer]
80
+ define_field :sn, Types::Int32
81
+ # @!attribute body
82
+ # @return [Types::String,Header::Base]
83
+ define_field :body, Types::String
84
+ # @!attribute tfc
85
+ # Traffic Flow Confidentiality padding
86
+ # @return [Types::String,Header::Base]
87
+ define_field :tfc, Types::String
88
+ # @!attribute padding
89
+ # ESP padding
90
+ # @return [Types::String,Header::Base]
91
+ define_field :padding, Types::String
92
+ # @!attribute pad_length
93
+ # 8-bit padding length
94
+ # @return [Integer]
95
+ define_field :pad_length, Types::Int8
96
+ # @!attribute next
97
+ # 8-bit next protocol value
98
+ # @return [Integer]
99
+ define_field :next, Types::Int8
100
+ # @!attribute icv
101
+ # Integrity Check Value
102
+ # @return [Types::String,Header::Base]
103
+ define_field :icv, Types::String
104
+
77
105
  # ICV (Integrity Check Value) length
78
106
  # @return [Integer]
79
107
  attr_accessor :icv_length
@@ -92,14 +120,7 @@ module PacketGen
92
120
  # @option options [::String] :icv Integrity Check Value
93
121
  def initialize(options={})
94
122
  @icv_length = options[:icv_length] || 0
95
- super Int32.new(options[:spi]),
96
- Int32.new(options[:sn]),
97
- StructFu::String.new.read(options[:body]),
98
- StructFu::String.new.read(options[:tfc]),
99
- StructFu::String.new.read(options[:padding]),
100
- Int8.new(options[:pad_length]),
101
- Int8.new(options[:next]),
102
- StructFu::String.new.read(options[:icv])
123
+ super
103
124
  end
104
125
 
105
126
  # Read a ESP packet from string.
@@ -111,7 +132,6 @@ module PacketGen
111
132
  # @return [self]
112
133
  def read(str)
113
134
  return self if str.nil?
114
- raise ParseError, 'string too short for ESP' if str.size < self.sz
115
135
  force_binary str
116
136
  self[:spi].read str[0, 4]
117
137
  self[:sn].read str[4, 4]
@@ -124,58 +144,6 @@ module PacketGen
124
144
  self
125
145
  end
126
146
 
127
- # Getter for SPI attribute
128
- # @return [Integer]
129
- def spi
130
- self[:spi].to_i
131
- end
132
-
133
- # Setter for SPI attribute
134
- # @param [Integer] val
135
- # @return [Integer]
136
- def spi=(val)
137
- typecast val
138
- end
139
-
140
- # Getter for SN attribute
141
- # @return [Integer]
142
- def sn
143
- self[:sn].to_i
144
- end
145
-
146
- # Setter for SN attribute
147
- # @param [Integer] val
148
- # @return [Integer]
149
- def sn=(val)
150
- typecast val
151
- end
152
-
153
- # Getter for +pad_length+ attribute
154
- # @return [Integer]
155
- def pad_length
156
- self[:pad_length].to_i
157
- end
158
-
159
- # Setter for +pad_length+ attribute
160
- # @param [Integer] val
161
- # @return [Integer]
162
- def pad_length=(val)
163
- typecast val
164
- end
165
-
166
- # Getter for +next+ attribute
167
- # @return [Integer]
168
- def next
169
- self[:next].to_i
170
- end
171
-
172
- # Setter for +next+ attribute
173
- # @param [Integer] val
174
- # @return [Integer]
175
- def next=(val)
176
- typecast val
177
- end
178
-
179
147
  # Encrypt in-place ESP payload and trailer.
180
148
  #
181
149
  # This method removes all data from +tfc+ and +padding+ fields, as their
@@ -252,7 +220,7 @@ module PacketGen
252
220
  # as padding is used to pad for CBC mode, this is unused
253
221
  cipher.final
254
222
 
255
- self[:body] = StructFu::String.new(iv) << enc_msg[0..-3]
223
+ self[:body] = Types::String.new(iv) << enc_msg[0..-3]
256
224
  self[:pad_length].read enc_msg[-2]
257
225
  self[:next].read enc_msg[-1]
258
226
 
@@ -364,7 +332,7 @@ module PacketGen
364
332
  def get_auth_data(opt)
365
333
  ad = self[:spi].to_s
366
334
  if opt[:esn]
367
- @esn = StructFu::Int32.new(opt[:esn])
335
+ @esn = Types::Int32.new(opt[:esn])
368
336
  ad << @esn.to_s if @conf.authenticated?
369
337
  end
370
338
  ad << self[:sn].to_s
@@ -9,8 +9,8 @@ module PacketGen
9
9
  # An Ethernet header consists of:
10
10
  # * a destination MAC address ({MacAddr}),
11
11
  # * a source MAC address (MacAddr),
12
- # * a {#ethertype} ({Int16}),
13
- # * and a body (a {String} or another Header class).
12
+ # * a {#ethertype} ({Types::Int16}),
13
+ # * and a body (a {Types::String} or another Header class).
14
14
  #
15
15
  # == Create a Ethernet header
16
16
  # # standalone
@@ -28,33 +28,30 @@ module PacketGen
28
28
  # eth.body = "This is a body"
29
29
  #
30
30
  # @author Sylvain Daubert
31
- class Eth < Struct.new(:dst, :src, :ethertype, :body)
32
- include StructFu
33
- include HeaderMethods
34
- extend HeaderClassMethods
31
+ class Eth < Base
35
32
 
36
33
  # Ethernet MAC address, as a group of 6 bytes
37
34
  # @author Sylvain Daubert
38
- class MacAddr < Struct.new(:a0, :a1, :a2, :a3, :a4, :a5)
39
- include StructFu
35
+ class MacAddr < Base
36
+ # @!attribute a0
37
+ # @return [Integer] first byte from MacAddr
38
+ define_field :a0, Types::Int8
39
+ # @!attribute a1
40
+ # @return [Integer] second byte from MacAddr
41
+ define_field :a1, Types::Int8
42
+ # @!attribute a2
43
+ # @return [Integer] third byte from MacAddr
44
+ define_field :a2, Types::Int8
45
+ # @!attribute a3
46
+ # @return [Integer] fourth byte from MacAddr
47
+ define_field :a3, Types::Int8
48
+ # @!attribute a4
49
+ # @return [Integer] fifth byte from MacAddr
50
+ define_field :a4, Types::Int8
51
+ # @!attribute a5
52
+ # @return [Integer] sixth byte from MacAddr
53
+ define_field :a5, Types::Int8
40
54
 
41
- # @param [Hash] options
42
- # @option options [Integer] :a0
43
- # @option options [Integer] :a1
44
- # @option options [Integer] :a2
45
- # @option options [Integer] :a3
46
- # @option options [Integer] :a4
47
- # @option options [Integer] :a5
48
- def initialize(options={})
49
- super Int8.new(options[:a0]),
50
- Int8.new(options[:a1]),
51
- Int8.new(options[:a2]),
52
- Int8.new(options[:a3]),
53
- Int8.new(options[:a4]),
54
- Int8.new(options[:a5])
55
-
56
- end
57
-
58
55
  # Read a human-readable string to populate +MacAddr+
59
56
  # @param [String] str
60
57
  # @return [self]
@@ -73,27 +70,10 @@ module PacketGen
73
70
  self
74
71
  end
75
72
 
76
- # Read a +MacAddr+ from a binary string
77
- # @param [String] str binary string
78
- # @return [self]
79
- def read(str)
80
- return self if str.nil?
81
- raise ParseError, 'string too short for Eth' if str.size < self.sz
82
- force_binary str
83
- [:a0, :a1, :a2, :a3, :a4, :a5].each_with_index do |byte, i|
84
- self[byte].read str[i, 1]
85
- end
86
- end
87
-
88
- [:a0, :a1, :a2, :a3, :a4, :a5].each do |sym|
89
- class_eval "def #{sym}; self[:#{sym}].to_i; end\n" \
90
- "def #{sym}=(v); self[:#{sym}].read v; end"
91
- end
92
-
93
73
  # +MacAddr+ in human readable form (colon format)
94
74
  # @return [String]
95
75
  def to_human
96
- members.map { |m| "#{'%02x' % self[m]}" }.join(':')
76
+ fields.map { |m| "#{'%02x' % self[m]}" }.join(':')
97
77
  end
98
78
  end
99
79
 
@@ -104,69 +84,18 @@ module PacketGen
104
84
  # @private timeout for PCAPRUB
105
85
  PCAP_TIMEOUT = 1
106
86
 
107
- # @param [Hash] options
108
- # @option options [String] :dst MAC destination address
109
- # @option options [String] :src MAC source address
110
- # @option options [Integer] :ethertype
111
- def initialize(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),
115
- StructFu::String.new.read(options[:body])
116
- end
117
-
118
- # Read a Eth header from a string
119
- # @param [String] str binary string
120
- # @return [self]
121
- def read(str)
122
- return self if str.nil?
123
- raise ParseError, 'string too short for Eth' if str.size < self.sz
124
- force_binary str
125
- self[:dst].read str[0, 6]
126
- self[:src].read str[6, 6]
127
- self[:ethertype].read str[12, 2]
128
- self[:body].read str[14..-1]
129
- self
130
- end
131
-
132
- # Get MAC destination address
133
- # @return [String]
134
- def dst
135
- self[:dst].to_human
136
- end
137
-
138
- # Set MAC destination address
139
- # @param [String] addr
140
- # @return [String]
141
- def dst=(addr)
142
- self[:dst].from_human addr
143
- end
144
-
145
- # Get MAC source address
146
- # @return [String]
147
- def src
148
- self[:src].to_human
149
- end
150
-
151
- # Set MAC source address
152
- # @param [String] addr
153
- # @return [String]
154
- def src=(addr)
155
- self[:src].from_human addr
156
- end
157
-
158
- # Get ethertype field
159
- # @return [Integer]
160
- def ethertype
161
- self[:ethertype].to_i
162
- end
163
-
164
- # Set ethertype field
165
- # @param [Integer] type
166
- # @return [Integer]
167
- def ethertype=(type)
168
- self[:ethertype].value = type
169
- end
87
+ # @!attribute dst
88
+ # @return [MacAddr] Destination MAC address
89
+ define_field :dst, MacAddr, default: '00:00:00:00:00:00'
90
+ # @!attribute src
91
+ # @return [MacAddr] Source MAC address
92
+ define_field :src, MacAddr, default: '00:00:00:00:00:00'
93
+ # @!attribute ethertype
94
+ # @return [Integer] 16-bit integer to determine payload type
95
+ define_field :ethertype, Types::Int16, default: 0
96
+ # @!attribute body
97
+ # @return [Types::String,Header::Base]
98
+ define_field :body, Types::String
170
99
 
171
100
  # send Eth packet on wire.
172
101
  # @param [String] iface interface name
@@ -7,9 +7,9 @@ module PacketGen
7
7
  module Header
8
8
 
9
9
  # A ICMP header consists of:
10
- # * a {#type} field ({Int8} type),
11
- # * a {#code} field ({Int8} type),
12
- # * a {#checksum} field ({Int16} type),
10
+ # * a {#type} field ({Types::Int8} type),
11
+ # * a {#code} field ({Types::Int8} type),
12
+ # * a {#checksum} field ({Types::Int16} type),
13
13
  # * and a {#body}.
14
14
  #
15
15
  # == Create a ICMP header
@@ -26,38 +26,26 @@ module PacketGen
26
26
  # icmp.checksum = 0x248a
27
27
  # icmp.body.read 'this is a body'
28
28
  # @author Sylvain Daubert
29
- class ICMP < Struct.new(:type, :code, :checksum, :body)
30
- include StructFu
31
- include HeaderMethods
32
- extend HeaderClassMethods
29
+ class ICMP < Base
33
30
 
34
31
  # ICMP internet protocol number
35
32
  IP_PROTOCOL = 1
36
33
 
37
- # @param [Hash] options
38
- # @option options [Integer] :type
39
- # @option options [Integer] :code
40
- # @option options [Integer] :checksum
41
- # @option options [String] :body
42
- def initialize(options={})
43
- super Int8.new(options[:type]),
44
- Int8.new(options[:code]),
45
- Int16.new(options[:checksum]),
46
- StructFu::String.new.read(options[:body])
47
- end
48
-
49
- # Read a ICMP header from a string
50
- # @param [String] str binary string
51
- # @return [self]
52
- def read(str)
53
- return self if str.nil?
54
- raise ParseError, 'string too short for ICMP' if str.size < self.sz
55
- force_binary str
56
- self[:type].read str[0, 1]
57
- self[:code].read str[1, 1]
58
- self[:checksum].read str[2, 2]
59
- self[:body].read str[4..-1]
60
- end
34
+ # @!attribute type
35
+ # 8-bit ICMP type
36
+ # @return [Integer]
37
+ define_field :type, Types::Int8
38
+ # @!attribute code
39
+ # 8-bit ICMP code
40
+ # @return [Integer]
41
+ define_field :code, Types::Int8
42
+ # @!attribute checksum
43
+ # 16-bit ICMP checksum
44
+ # @return [Integer]
45
+ define_field :checksum, Types::Int16
46
+ # @!attribute body
47
+ # @return [Types::String,Header::Base]
48
+ define_field :body, Types::String
61
49
 
62
50
  # Compute checksum and set +checksum+ field
63
51
  # @return [Integer]
@@ -74,45 +62,6 @@ module PacketGen
74
62
  sum = ~sum & 0xffff
75
63
  self[:checksum].value = (sum == 0) ? 0xffff : sum
76
64
  end
77
-
78
- # Getter for type attribute
79
- # @return [Integer]
80
- def type
81
- self[:type].to_i
82
- end
83
-
84
- # Setter for type attribute
85
- # @param [Integer] type
86
- # @return [Integer]
87
- def type=(type)
88
- self[:type].value = type
89
- end
90
-
91
- # Getter for code attribute
92
- # @return [Integer]
93
- def code
94
- self[:code].to_i
95
- end
96
-
97
- # Setter for code attribute
98
- # @param [Integer] code
99
- # @return [Integer]
100
- def code=(code)
101
- self[:code].value = code
102
- end
103
-
104
- # Getter for checksum attribute
105
- # @return [Integer]
106
- def checksum
107
- self[:checksum].to_i
108
- end
109
-
110
- # Setter for checksum attribute
111
- # @param [Integer] sum
112
- # @return [Integer]
113
- def checksum=(sum)
114
- self[:checksum].value = sum
115
- end
116
65
  end
117
66
 
118
67
  self.add_class ICMP
@@ -7,9 +7,9 @@ module PacketGen
7
7
  module Header
8
8
 
9
9
  # A ICMPv6 header consists of:
10
- # * a +type+ field ({Int8} type),
11
- # * a +code+ field ({Int8} type),
12
- # * a +checksum+ field ({Int16} type),
10
+ # * a +type+ field ({Types::Int8} type),
11
+ # * a +code+ field ({Types::Int8} type),
12
+ # * a +checksum+ field ({Types::Int16} type),
13
13
  # * and a +body+.
14
14
  #
15
15
  # == Create a ICMPv6 header