packetgen 3.3.3 → 4.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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -22
  3. data/lib/packetgen/capture.rb +2 -2
  4. data/lib/packetgen/config.rb +0 -1
  5. data/lib/packetgen/deprecation.rb +14 -8
  6. data/lib/packetgen/header/arp.rb +17 -18
  7. data/lib/packetgen/header/asn1_base.rb +2 -1
  8. data/lib/packetgen/header/base.rb +42 -40
  9. data/lib/packetgen/header/bootp.rb +35 -37
  10. data/lib/packetgen/header/dhcp/option.rb +21 -21
  11. data/lib/packetgen/header/dhcp/options.rb +3 -3
  12. data/lib/packetgen/header/dhcp.rb +8 -9
  13. data/lib/packetgen/header/dhcpv6/duid.rb +16 -16
  14. data/lib/packetgen/header/dhcpv6/option.rb +83 -61
  15. data/lib/packetgen/header/dhcpv6/options.rb +4 -4
  16. data/lib/packetgen/header/dhcpv6/relay.rb +6 -5
  17. data/lib/packetgen/header/dhcpv6.rb +17 -18
  18. data/lib/packetgen/header/dns/name.rb +21 -16
  19. data/lib/packetgen/header/dns/opt.rb +5 -2
  20. data/lib/packetgen/header/dns/option.rb +14 -14
  21. data/lib/packetgen/header/dns/qdsection.rb +3 -3
  22. data/lib/packetgen/header/dns/question.rb +7 -8
  23. data/lib/packetgen/header/dns/rr.rb +56 -43
  24. data/lib/packetgen/header/dns/rrsection.rb +6 -6
  25. data/lib/packetgen/header/dns.rb +103 -90
  26. data/lib/packetgen/header/dot11/control.rb +12 -12
  27. data/lib/packetgen/header/dot11/data.rb +25 -24
  28. data/lib/packetgen/header/dot11/element.rb +4 -4
  29. data/lib/packetgen/header/dot11/management.rb +21 -18
  30. data/lib/packetgen/header/dot11/sub_mngt.rb +40 -53
  31. data/lib/packetgen/header/dot11.rb +117 -122
  32. data/lib/packetgen/header/dot1q.rb +12 -13
  33. data/lib/packetgen/header/dot1x.rb +13 -13
  34. data/lib/packetgen/header/eap/fast.rb +4 -4
  35. data/lib/packetgen/header/eap/md5.rb +16 -8
  36. data/lib/packetgen/header/eap/tls.rb +18 -19
  37. data/lib/packetgen/header/eap/ttls.rb +22 -21
  38. data/lib/packetgen/header/eap.rb +73 -48
  39. data/lib/packetgen/header/eth.rb +41 -27
  40. data/lib/packetgen/header/gre.rb +33 -11
  41. data/lib/packetgen/header/http/headers.rb +7 -6
  42. data/lib/packetgen/header/http/request.rb +38 -29
  43. data/lib/packetgen/header/http/response.rb +35 -27
  44. data/lib/packetgen/header/http/verbs.rb +1 -3
  45. data/lib/packetgen/header/icmp.rb +14 -14
  46. data/lib/packetgen/header/icmpv6.rb +10 -9
  47. data/lib/packetgen/header/igmp.rb +26 -15
  48. data/lib/packetgen/header/igmpv3/group_record.rb +18 -13
  49. data/lib/packetgen/header/igmpv3/mq.rb +16 -18
  50. data/lib/packetgen/header/igmpv3/mr.rb +5 -5
  51. data/lib/packetgen/header/igmpv3.rb +12 -11
  52. data/lib/packetgen/header/ip/addr.rb +19 -15
  53. data/lib/packetgen/header/ip/option.rb +47 -36
  54. data/lib/packetgen/header/ip/options.rb +1 -1
  55. data/lib/packetgen/header/ip.rb +77 -95
  56. data/lib/packetgen/header/ipv6/addr.rb +28 -27
  57. data/lib/packetgen/header/ipv6/extension.rb +13 -11
  58. data/lib/packetgen/header/ipv6/hop_by_hop.rb +32 -13
  59. data/lib/packetgen/header/ipv6.rb +42 -35
  60. data/lib/packetgen/header/llc.rb +28 -21
  61. data/lib/packetgen/header/mdns.rb +10 -3
  62. data/lib/packetgen/header/mld.rb +15 -13
  63. data/lib/packetgen/header/mldv2/mcast_address_record.rb +17 -12
  64. data/lib/packetgen/header/mldv2/mlq.rb +22 -24
  65. data/lib/packetgen/header/mldv2/mlr.rb +8 -8
  66. data/lib/packetgen/header/mldv2.rb +1 -1
  67. data/lib/packetgen/header/ospfv2/db_description.rb +17 -18
  68. data/lib/packetgen/header/ospfv2/hello.rb +18 -17
  69. data/lib/packetgen/header/ospfv2/ls_ack.rb +6 -7
  70. data/lib/packetgen/header/ospfv2/ls_request.rb +14 -13
  71. data/lib/packetgen/header/ospfv2/ls_update.rb +9 -9
  72. data/lib/packetgen/header/ospfv2/lsa.rb +79 -60
  73. data/lib/packetgen/header/ospfv2/lsa_header.rb +12 -11
  74. data/lib/packetgen/header/ospfv2.rb +49 -46
  75. data/lib/packetgen/header/ospfv3/db_description.rb +20 -22
  76. data/lib/packetgen/header/ospfv3/hello.rb +17 -16
  77. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +22 -20
  78. data/lib/packetgen/header/ospfv3/ls_ack.rb +7 -8
  79. data/lib/packetgen/header/ospfv3/ls_request.rb +18 -18
  80. data/lib/packetgen/header/ospfv3/ls_update.rb +10 -10
  81. data/lib/packetgen/header/ospfv3/lsa.rb +62 -51
  82. data/lib/packetgen/header/ospfv3/lsa_header.rb +12 -11
  83. data/lib/packetgen/header/ospfv3.rb +54 -52
  84. data/lib/packetgen/header/sctp/chunk.rb +80 -56
  85. data/lib/packetgen/header/sctp/error.rb +174 -202
  86. data/lib/packetgen/header/sctp/padded32.rb +3 -3
  87. data/lib/packetgen/header/sctp/parameter.rb +89 -136
  88. data/lib/packetgen/header/sctp.rb +19 -8
  89. data/lib/packetgen/header/snmp.rb +108 -7
  90. data/lib/packetgen/header/tcp/option.rb +52 -39
  91. data/lib/packetgen/header/tcp/options.rb +13 -5
  92. data/lib/packetgen/header/tcp.rb +83 -65
  93. data/lib/packetgen/header/tftp.rb +31 -25
  94. data/lib/packetgen/header/udp.rb +21 -19
  95. data/lib/packetgen/header.rb +23 -18
  96. data/lib/packetgen/headerable.rb +21 -5
  97. data/lib/packetgen/inspect.rb +3 -8
  98. data/lib/packetgen/packet.rb +146 -71
  99. data/lib/packetgen/pcap.rb +15 -4
  100. data/lib/packetgen/pcapng/block.rb +20 -18
  101. data/lib/packetgen/pcapng/epb.rb +13 -15
  102. data/lib/packetgen/pcapng/file.rb +44 -111
  103. data/lib/packetgen/pcapng/idb.rb +11 -12
  104. data/lib/packetgen/pcapng/shb.rb +15 -16
  105. data/lib/packetgen/pcapng/spb.rb +9 -11
  106. data/lib/packetgen/pcapng/unknown_block.rb +6 -17
  107. data/lib/packetgen/pcapng.rb +6 -4
  108. data/lib/packetgen/pcaprub_wrapper.rb +17 -1
  109. data/lib/packetgen/proto.rb +5 -1
  110. data/lib/packetgen/unknown_packet.rb +5 -5
  111. data/lib/packetgen/utils/arp_spoofer.rb +18 -19
  112. data/lib/packetgen/utils.rb +4 -3
  113. data/lib/packetgen/version.rb +1 -1
  114. data/lib/packetgen.rb +12 -5
  115. metadata +29 -38
  116. data/lib/packetgen/types/abstract_tlv.rb +0 -278
  117. data/lib/packetgen/types/array.rb +0 -287
  118. data/lib/packetgen/types/cstring.rb +0 -109
  119. data/lib/packetgen/types/enum.rb +0 -171
  120. data/lib/packetgen/types/fieldable.rb +0 -66
  121. data/lib/packetgen/types/fields.rb +0 -622
  122. data/lib/packetgen/types/int.rb +0 -473
  123. data/lib/packetgen/types/int_string.rb +0 -102
  124. data/lib/packetgen/types/length_from.rb +0 -54
  125. data/lib/packetgen/types/oui.rb +0 -52
  126. data/lib/packetgen/types/string.rb +0 -97
  127. data/lib/packetgen/types/tlv.rb +0 -161
  128. data/lib/packetgen/types.rb +0 -26
@@ -11,8 +11,8 @@ module PacketGen
11
11
  class TCP
12
12
  # Base class to describe a TCP option
13
13
  # @author Sylvain Daubert
14
- class Option < Types::Fields
15
- include Types::Fieldable
14
+ class Option < BinStruct::Struct
15
+ include BinStruct::Structable
16
16
 
17
17
  # EOL option value
18
18
  EOL_KIND = 0
@@ -36,15 +36,15 @@ module PacketGen
36
36
  # @!attribute kind
37
37
  # Option kind
38
38
  # @return [Integer] 8-bit option kind
39
- define_field :kind, Types::Int8
39
+ define_attr :kind, BinStruct::Int8
40
40
  # @!attribute length
41
41
  # Option length
42
42
  # @return [Integer] 8-bit option length
43
- define_field :length, Types::Int8, optional: ->(h) { h.length? }
43
+ define_attr :length, BinStruct::Int8, optional: lambda(&:length?)
44
44
  # @!attribute value
45
45
  # @return [Integer,String] option value
46
- define_field :value, Types::String, optional: ->(h) { h.length? && h.length > 2 },
47
- builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
46
+ define_attr :value, BinStruct::String, optional: ->(h) { h.length? && h.length > 2 },
47
+ builder: ->(h, t) { t.new(length_from: -> { h.length - 2 }) }
48
48
 
49
49
  # @param [hash] options
50
50
  # @option options [Integer] :kind
@@ -55,18 +55,18 @@ module PacketGen
55
55
  case options[:value]
56
56
  when Integer
57
57
  klass = case self[:length].to_i
58
- when 3 then Types::Int8
59
- when 4 then Types::Int16
60
- when 6 then Types::Int32
58
+ when 3 then BinStruct::Int8
59
+ when 4 then BinStruct::Int16
60
+ when 6 then BinStruct::Int32
61
61
  else
62
62
  raise ArgumentError, 'impossible length'
63
63
  end
64
- self[:value] = klass.new(options[:value])
64
+ self[:value] = klass.new(value: options[:value])
65
65
  when NilClass
66
66
  # Nothing to do
67
67
  else
68
- self[:value] = Types::String.new.read(options[:value])
69
- self[:length].read(self[:value].sz + 2) unless options[:length]
68
+ self[:value] = BinStruct::String.new.read(options[:value])
69
+ self[:length].from_human(self[:value].sz + 2) unless options[:length]
70
70
  end
71
71
  end
72
72
 
@@ -83,25 +83,33 @@ module PacketGen
83
83
  # @return [String, Integer]
84
84
  def value
85
85
  case self[:value]
86
- when Types::Int
86
+ when BinStruct::Int
87
87
  self[:value].to_i
88
88
  else
89
89
  self[:value].to_s
90
90
  end
91
91
  end
92
92
 
93
+ # @private
93
94
  alias old_set_value value=
95
+
94
96
  # Setter for value attribute
95
- # @param[String,Integer]
97
+ # @param[String,Integer] val
96
98
  # @return [String, Integer]
97
99
  def value=(val)
98
100
  case self[:value]
99
- when Types::Int
101
+ when BinStruct::Int
100
102
  self.length = 2 + self[:value].sz
101
- when Types::String
102
- self.length = 2 + Types::String.new.read(val).sz
103
+ when BinStruct::String
104
+ self.length = 2 + BinStruct::String.new.read(val).sz
105
+ end
106
+
107
+ case val
108
+ when Integer
109
+ self[:value].from_human(val)
110
+ else
111
+ self[:value].read(val)
103
112
  end
104
- self[:value].read val
105
113
  val
106
114
  end
107
115
 
@@ -115,14 +123,14 @@ module PacketGen
115
123
  # Get option as a human readable string
116
124
  # @return [String]
117
125
  def to_human
118
- str = self.instance_of?(Option) ? +"unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
126
+ str = self.instance_of?(Option) ? "unk-#{kind}" : self.class.to_s.sub(/.*::/, '')
119
127
  str << ":#{self[:value].to_s.inspect}" if (length > 2) && !self[:value].to_s.empty?
120
128
  str
121
129
  end
122
130
 
123
131
  # @return [String]
124
132
  def inspect
125
- str = +"#<#{self.class} kind=#{self[:kind].value.inspect} "
133
+ str = "#<#{self.class} kind=#{self[:kind].value.inspect} "
126
134
  str << "length=#{self[:length].value.inspect} " if self[:length].value
127
135
  str << "value=#{self[:value].inspect}>"
128
136
  end
@@ -131,28 +139,29 @@ module PacketGen
131
139
  # End Of Option TCP option
132
140
  # @author Sylvain Daubert
133
141
  class EOL < Option
134
- update_field :kind, default: EOL_KIND
142
+ update_attr :kind, default: EOL_KIND
135
143
  end
136
144
 
137
145
  # No OPeration TCP option
138
146
  # @author Sylvain Daubert
139
147
  class NOP < Option
140
148
  # @see Option#initialize
141
- update_field :kind, default: NOP_KIND
149
+ update_attr :kind, default: NOP_KIND
142
150
  end
143
151
 
144
152
  # Maximum Segment Size TCP option
145
153
  # @author Sylvain Daubert
146
154
  class MSS < Option
147
- update_field :kind, default: MSS_KIND
148
- update_field :length, default: 4
155
+ update_attr :kind, default: MSS_KIND
156
+ update_attr :length, default: 4
149
157
 
150
158
  # @see Option#initialize
151
159
  def initialize(options={})
152
160
  super
153
- self[:value] = Types::Int16.new(options[:value])
161
+ self[:value] = BinStruct::Int16.new(value: options[:value])
154
162
  end
155
163
 
164
+ # Get human-readable description
156
165
  # @return [String]
157
166
  def to_human
158
167
  "MSS:#{value}"
@@ -162,15 +171,16 @@ module PacketGen
162
171
  # Window Size TCP option
163
172
  # @author Sylvain Daubert
164
173
  class WS < Option
165
- update_field :kind, default: WS_KIND
166
- update_field :length, default: 3
174
+ update_attr :kind, default: WS_KIND
175
+ update_attr :length, default: 3
167
176
 
168
177
  # @see Option#initialize
169
178
  def initialize(options={})
170
179
  super
171
- self[:value] = Types::Int8.new(options[:value])
180
+ self[:value] = BinStruct::Int8.new(value: options[:value])
172
181
  end
173
182
 
183
+ # Get human-readable description
174
184
  # @return [String]
175
185
  def to_human
176
186
  "WS:#{value}"
@@ -180,28 +190,29 @@ module PacketGen
180
190
  # Selective Acknowledgment OK TCP option
181
191
  # @author Sylvain Daubert
182
192
  class SACKOK < Option
183
- update_field :kind, default: SACKOK_KIND
184
- update_field :length, default: 2
193
+ update_attr :kind, default: SACKOK_KIND
194
+ update_attr :length, default: 2
185
195
  end
186
196
 
187
197
  # Selective Acknowledgment TCP option
188
198
  # @author Sylvain Daubert
189
199
  class SACK < Option
190
- update_field :kind, default: SACK_KIND
200
+ update_attr :kind, default: SACK_KIND
191
201
  end
192
202
 
193
203
  # Echo TCP option
194
204
  # @author Sylvain Daubert
195
205
  class ECHO < Option
196
- update_field :kind, default: ECHO_KIND
197
- update_field :length, default: 6
206
+ update_attr :kind, default: ECHO_KIND
207
+ update_attr :length, default: 6
198
208
 
199
209
  # @see Option#initialize
200
210
  def initialize(options={})
201
211
  super
202
- self[:value] = Types::Int32.new(options[:value])
212
+ self[:value] = BinStruct::Int32.new(value: options[:value])
203
213
  end
204
214
 
215
+ # Get human-readable description
205
216
  # @return [String]
206
217
  def to_human
207
218
  "WS:#{value}"
@@ -211,15 +222,16 @@ module PacketGen
211
222
  # Echo Reply TCP option
212
223
  # @author Sylvain Daubert
213
224
  class ECHOREPLY < Option
214
- update_field :kind, default: ECHOREPLY_KIND
215
- update_field :length, default: 6
225
+ update_attr :kind, default: ECHOREPLY_KIND
226
+ update_attr :length, default: 6
216
227
 
217
228
  # @see Option#initialize
218
229
  def initialize(options={})
219
230
  super
220
- self[:value] = Types::Int32.new(options[:value])
231
+ self[:value] = BinStruct::Int32.new(value: options[:value])
221
232
  end
222
233
 
234
+ # Get human-readable description
223
235
  # @return [String]
224
236
  def to_human
225
237
  "WS:#{value}"
@@ -229,8 +241,8 @@ module PacketGen
229
241
  # Timestamp TCP option
230
242
  # @author Sylvain Daubert
231
243
  class TS < Option
232
- update_field :kind, default: TS_KIND
233
- update_field :length, default: 10
244
+ update_attr :kind, default: TS_KIND
245
+ update_attr :length, default: 10
234
246
 
235
247
  # @see Option#initialize
236
248
  def initialize(options={})
@@ -238,6 +250,7 @@ module PacketGen
238
250
  self[:value].read(options[:value] || "\0" * 8)
239
251
  end
240
252
 
253
+ # Get human-readable description
241
254
  # @return [String]
242
255
  def to_human
243
256
  value, echo_reply = self[:value].unpack('NN')
@@ -11,9 +11,17 @@ require_relative 'option'
11
11
  module PacketGen
12
12
  module Header
13
13
  class TCP
14
- # Container for TCP options in {TCP TCP header}.
14
+ # Container for TCP {Option options} in {TCP TCP header}.
15
15
  # @author Sylvain Daubert
16
- class Options < Types::Array
16
+ # @since 1.0.0
17
+ # @since 4.1.0 +#<<+ accepts +:kind+ parameter in hash
18
+ # @example Add an option from a hash
19
+ # opts = PacketGen::Header::TCP::Options.new
20
+ # # Option kind may be set using :opt
21
+ # opts << { opt: 'MSS', value: 1250 }
22
+ # # It may aldo be set using :kind
23
+ # opts << { kind: 'EOL' }
24
+ class Options < BinStruct::Array
17
25
  set_of Option
18
26
 
19
27
  # Get {Option} subclasses
@@ -23,7 +31,7 @@ module PacketGen
23
31
 
24
32
  @klasses = []
25
33
  Option.constants.each do |cst|
26
- next unless cst.to_s.end_with? '_KIND'
34
+ next unless cst.to_s.end_with?('_KIND')
27
35
 
28
36
  optname = cst.to_s.sub('_KIND', '')
29
37
  @klasses[Option.const_get(cst)] = TCP.const_get(optname)
@@ -34,8 +42,8 @@ module PacketGen
34
42
  private
35
43
 
36
44
  def record_from_hash(hsh)
37
- if hsh.key? :opt
38
- klassname = hsh.delete(:opt)
45
+ if hsh.key?(:opt) || hsh.key?(:kind)
46
+ klassname = hsh.delete(:opt) || hsh.delete(:kind)
39
47
  raise ArgumentError, 'opt should be a TCP::Option subclass' unless TCP.const_defined?(klassname)
40
48
 
41
49
  klass = TCP.const_get(klassname)
@@ -29,56 +29,62 @@ module PacketGen
29
29
  # | data |
30
30
  # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
31
  # A TCP header consists of:
32
- # * a source port ({#sport}, {Types::Int16} type),
33
- # * a destination port ({#dport}, +Int16+ type),
34
- # * a sequence number ({#seqnum}, {Types::Int32} type),
35
- # * an acknownledge number ({#acknum}, +Int32+ type),
36
- # * a 16-bit field ({#u16}, +Int16+ type) composed of:
37
- # * a 4-bit {#data_offset} self[attr],
32
+ # * a source port ({#sport}, +BinStruct::Int16+ type),
33
+ # * a destination port ({#dport}, +BinStruct::Int16+ type),
34
+ # * a sequence number ({#seqnum}, +BinStruct::Int32+ type),
35
+ # * an acknownledge number ({#acknum}, +BinStruct::Int32+ type),
36
+ # * a 16-bit field ({#u16}, +BinStruct::Int16+ type) composed of:
37
+ # * a 4-bit {#data_offset},
38
38
  # * a 3-bit {#reserved} field,
39
39
  # * a 9-bit {#flags} field,
40
- # * a {#window} field (+Int16+ type),
41
- # * a {#checksum} field (+Int16+ type),
42
- # * a urgent pointer ({#urg_pointer}, +Int16+ type),
40
+ # * a {#window} field (+BinStruct::Int16+ type),
41
+ # * a {#checksum} field (+BinStruct::Int16+ type),
42
+ # * a urgent pointer ({#urg_pointer}, +BinStruct::Int16+ type),
43
43
  # * an optional {#options} field ({Options} type),
44
- # * and a {#body} ({Types::String} type).
44
+ # * and a {#body} (+BinStruct::String+ type).
45
45
  #
46
- # == Create a TCP header
46
+ # @example Create a TCP header
47
47
  # # standalone
48
48
  # tcph = PacketGen::Header::TCP.new
49
49
  # # in a IP packet
50
50
  # pkt = PacketGen.gen('IP').add('TCP')
51
51
  # # access to TCP header
52
- # pkt.tcp # => PacketGen::Header::TCP
52
+ # pkt.tcp.class # => PacketGen::Header::TCP
53
53
  #
54
- # == TCP attributes
54
+ # @example TCP attributes
55
+ # tcph = PacketGen::Header::TCP.new
55
56
  # tcph.sport = 4500
56
57
  # tcph.dport = 80
57
58
  # tcph.seqnum = 43
58
59
  # tcph.acknum = 0x45678925
59
60
  # tcph.wsize = 0x240
60
61
  # tcph.urg_pointer = 0x40
61
- # tcph.body.read 'this is a body'
62
+ # tcph.body = 'this is a body'
62
63
  #
63
- # == Flags
64
- # TCP flags may be accesed as a 9-bit integer:
64
+ # @example TCP Flags
65
+ # tcph = PacketGen::Header::TCP.new
66
+ # # TCP flags may be accesed as a 9-bit integer:
65
67
  # tcph.flags = 0x1002
66
- # Each flag may be accessed independently:
67
- # tcph.flag_syn? # => Boolean
68
+ # # Each flag may be accessed independently:
69
+ # tcph.flag_syn? # => true
68
70
  # tcph.flag_rst = true
69
71
  #
70
- # == Options
71
- # {#options} TCP attribute is a {Options}. {Option} may added to it:
72
- # tcph.options << PacketGen::Header::TCP::MSS.new(1250)
73
- # or:
74
- # tcph.options << { opt: 'MSS', self[attr]: 1250 }
72
+ # @example TCP Options
73
+ # tcph = PacketGen::Header::TCP.new
74
+ # # options TCP attribute is a PacketGen::Header::TCP::Options.
75
+ # # PacketGen::Header::TCP::Option may added to it:
76
+ # tcph.options << PacketGen::Header::TCP::MSS.new(value: 1250)
77
+ # # or
78
+ # tcph.options << { kind: 'MSS', value: 1250 }
79
+ # tcph.options.last.class #=> PacketGen::Header::TCP::MSS
75
80
  # @author Sylvain Daubert
81
+ # @author LemonTree55
76
82
  class TCP < Base
77
83
  end
78
84
  end
79
85
  end
80
86
 
81
- # Need to load Options now, as this is used through define_bit_fields_on,
87
+ # Need to load Options now, as this is used through define_bit_attr,
82
88
  # which make a call to TCP.new, which needs Options
83
89
  require_relative 'tcp/options'
84
90
 
@@ -91,41 +97,69 @@ module PacketGen
91
97
  # @!attribute sport
92
98
  # 16-bit TCP source port
93
99
  # @return [Integer]
94
- define_field :sport, Types::Int16
100
+ define_attr :sport, BinStruct::Int16
95
101
  # @!attribute dport
96
102
  # 16-bit TCP destination port
97
103
  # @return [Integer]
98
- define_field :dport, Types::Int16
104
+ define_attr :dport, BinStruct::Int16
99
105
  # @!attribute seqnum
100
106
  # 32-bit TCP sequence number
101
107
  # @return [Integer]
102
- define_field :seqnum, Types::Int32, default: ->(_) { rand(2**32) }
108
+ define_attr :seqnum, BinStruct::Int32, default: ->(_) { rand(2**32) }
103
109
  # @!attribute acknum
104
110
  # 32-bit TCP acknowledgement number
105
111
  # @return [Integer]
106
- define_field :acknum, Types::Int32
112
+ define_attr :acknum, BinStruct::Int32
107
113
  # @!attribute u16
108
114
  # @return [Integer] 16-bit word used by flags and bit fields
109
- define_field :u16, Types::Int16
115
+ # @!attribute data_offset
116
+ # @return [Integer] 4-bit data offset from {#u16}
117
+ # @!attribute reserved
118
+ # @return [Integer] 3-bit reserved from {#u16}
119
+ # @!attribute flags
120
+ # @return [Integer] 9-bit flags from {#u16}
121
+ # @!attribute flag_ns
122
+ # @return [Integer] 1-bit NS flag
123
+ # @!attribute flag_cwr
124
+ # @return [Integer] 1-bit CWR flag
125
+ # @!attribute flag_ece
126
+ # @return [Integer] 1-bit ECE flag
127
+ # @!attribute flag_urg
128
+ # @return [Integer] 1-bit URG flag
129
+ # @!attribute flag_ack
130
+ # @return [Integer] 1-bit ACK flag
131
+ # @!attribute flag_psh
132
+ # @return [Integer] 1-bit PSH flag
133
+ # @!attribute flag_rst
134
+ # @return [Integer] 1-bit RST flag
135
+ # @!attribute flag_syn
136
+ # @return [Integer] 1-bit SYN flag
137
+ # @!attribute flag_fin
138
+ # @return [Integer] 1-bit FIN flag
139
+ define_bit_attr :u16, data_offset: 4, reserved: 3, flag_ns: 1, flag_cwr: 1, flag_ece: 1, flag_urg: 1, flag_ack: 1, flag_psh: 1,
140
+ flag_rst: 1, flag_syn: 1, flag_fin: 1
141
+ alias hlen data_offset
142
+ alias hlen= data_offset=
110
143
  # @!attribute window
111
144
  # 16-bit TCP window size
112
145
  # @return [Integer]
113
- define_field :window, Types::Int16
146
+ define_attr :window, BinStruct::Int16
114
147
  # @!attribute checksum
115
148
  # 16-bit TCP checksum
116
149
  # @return [Integer]
117
- define_field :checksum, Types::Int16
150
+ define_attr :checksum, BinStruct::Int16
118
151
  # @!attribute urg_pointer
119
152
  # 16-bit TCP urgent data pointer
120
153
  # @return [Integer]
121
- define_field :urg_pointer, Types::Int16
154
+ define_attr :urg_pointer, BinStruct::Int16
122
155
  # @!attribute options
123
156
  # TCP options
124
157
  # @return [Options]
125
- define_field :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
158
+ define_attr :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
126
159
  # @!attribute body
127
- # @return [Types::String,Header::Base]
128
- define_field :body, Types::String
160
+ # TCP body
161
+ # @return [BinStruct::String,Headerable]
162
+ define_attr :body, BinStruct::String
129
163
 
130
164
  alias source_port sport
131
165
  alias source_port= sport=
@@ -154,42 +188,26 @@ module PacketGen
154
188
  # @option options [Integer] :window
155
189
  # @option options [Integer] :checksum
156
190
  # @option options [Integer] :urg_pointer
157
- # @option options [String] :body
191
+ # @option options [String, Headerable] :body
158
192
  def initialize(options={})
159
193
  opts = { data_offset: 5 }.merge!(options)
160
194
  super(opts)
195
+ self.flags = opts[:flags] if opts.key?(:flags)
161
196
  end
162
197
 
163
- # @!attribute data_offset
164
- # @return [Integer] 4-bit data offset from {#u16}
165
- # @!attribute reserved
166
- # @return [Integer] 3-bit reserved from {#u16}
167
- # @!attribute flags
168
- # @return [Integer] 9-bit flags from {#u16}
169
- define_bit_fields_on :u16, :data_offset, 4, :reserved, 3, :flags, 9
170
- alias hlen data_offset
171
- alias hlen= data_offset=
198
+ # Get all flags value from [#u16]
199
+ # @return [Integer]
200
+ def flags
201
+ self.u16 & 0x1ff
202
+ end
172
203
 
173
- # @!attribute flag_ns
174
- # @return [Boolean] 1-bit NS flag
175
- # @!attribute flag_cwr
176
- # @return [Boolean] 1-bit CWR flag
177
- # @!attribute flag_ece
178
- # @return [Boolean] 1-bit ECE flag
179
- # @!attribute flag_urg
180
- # @return [Boolean] 1-bit URG flag
181
- # @!attribute flag_ack
182
- # @return [Boolean] 1-bit ACK flag
183
- # @!attribute flag_psh
184
- # @return [Boolean] 1-bit PSH flag
185
- # @!attribute flag_rst
186
- # @return [Boolean] 1-bit RST flag
187
- # @!attribute flag_syn
188
- # @return [Boolean] 1-bit SYN flag
189
- # @!attribute flag_fin
190
- # @return [Boolean] 1-bit FIN flag
191
- define_bit_fields_on :u16, :_, 7, :flag_ns, :flag_cwr, :flag_ece, :flag_urg,
192
- :flag_ack, :flag_psh, :flag_rst, :flag_syn, :flag_fin
204
+ # Set all flags at once
205
+ # @param [Integer] value
206
+ # @return [Integer]
207
+ def flags=(value)
208
+ new_u16 = (self.u16 & 0xfe00) | (value & 0x1ff)
209
+ self[:u16].from_human(new_u16)
210
+ end
193
211
 
194
212
  # Compute checksum and set +checksum+ field
195
213
  # @return [Integer]
@@ -10,25 +10,26 @@ module PacketGen
10
10
  module Header
11
11
  # A TFTP (Trivial File Transfer Protocol,
12
12
  # {https://tools.ietf.org/html/rfc1350 RFC 1350}) header consists of:
13
- # * a {#opcode} ({Types::Int16Enum}),
13
+ # * an {#opcode} (+BinStruct::Int16Enum+),
14
14
  # * and a body. Its content depends on opcode.
15
15
  #
16
16
  # Specialized subclasses exists to handle {TFTP::RRQ Read Request},
17
17
  # {TFTP::WRQ Write Request}, {TFTP::DATA DATA}, {TFTP::ACK ACK} and
18
18
  # {TFTP::ERROR ERROR} packets.
19
19
  #
20
- # == Create a TFTP header
20
+ # @example Create a TFTP header
21
21
  # # standalone
22
22
  # tftp = PacketGen::Header::TFTP.new
23
23
  # # in a packet
24
24
  # pkt = PacketGen.gen('IP').add('UDP').add('TFTP')
25
25
  # # access to TFTP header
26
- # pkt.tftp # => PacketGen::Header::TFTP
26
+ # pkt.tftp.class # => PacketGen::Header::TFTP
27
27
  #
28
- # == TFTP attributes
28
+ # @example TFTP attributes
29
+ # tftp = PacketGen::Header::TFTP.new
29
30
  # tftp.opcode = 'RRQ'
30
31
  # tftp.opcode = 1
31
- # tftp.body.read 'this is a body'
32
+ # tftp.body = 'this is a body'
32
33
  #
33
34
  # == TFTP parsing
34
35
  # When parsing, only first packet (read or write request) should be decoded
@@ -46,6 +47,7 @@ module PacketGen
46
47
  # packets[0].tftp.decode!(packets[1..-1])
47
48
  # packets.map { |pkt| pkt.headers.last.class.to_s }.join(',') # => TFTP::RRQ,TFTP::DATA,UDP,TFTP::ACK
48
49
  # @author Sylvain Daubert
50
+ # @author LemonTree55
49
51
  # @since 2.3.0
50
52
  class TFTP < Base
51
53
  # Known opcodes
@@ -60,11 +62,12 @@ module PacketGen
60
62
  # @!attribute opcode
61
63
  # 16-bit operation code
62
64
  # @return [Integer]
63
- define_field :opcode, Types::Int16Enum, enum: OPCODES
65
+ define_attr :opcode, BinStruct::Int16Enum, enum: OPCODES
64
66
 
65
67
  # @!attribute body
66
- # @return [String]
67
- define_field :body, Types::String
68
+ # TFTP body, if opcode is unknown
69
+ # @return [String,Headerable]
70
+ define_attr :body, BinStruct::String
68
71
 
69
72
  def initialize(options={})
70
73
  type = protocol_name.sub(/^.*::/, '')
@@ -85,13 +88,13 @@ module PacketGen
85
88
  def read(str)
86
89
  if self.instance_of? TFTP
87
90
  super
88
- if OPCODES.value? opcode
89
- TFTP.const_get(human_opcode).new.read str
91
+ if OPCODES.value?(opcode)
92
+ TFTP.const_get(human_opcode).new.read(str)
90
93
  else
91
94
  self
92
95
  end
93
96
  else
94
- old_read str
97
+ old_read(str)
95
98
  end
96
99
  end
97
100
 
@@ -130,7 +133,7 @@ module PacketGen
130
133
  # @param [Packet] packet
131
134
  # @return [void]
132
135
  def added_to_packet(packet)
133
- return if packet.respond_to? :tftp
136
+ return if packet.respond_to?(:tftp)
134
137
 
135
138
  packet.instance_eval("def tftp(arg=nil); header(#{self.class}, arg); end") # def tftp(arg=nil); header(TFTP, arg); end
136
139
  end
@@ -140,24 +143,25 @@ module PacketGen
140
143
  def decode_tftp_packet(pkt)
141
144
  tftp = Packet.parse(pkt.body, first_header: 'TFTP')
142
145
  udp_dport = pkt.udp.dport
143
- pkt.encapsulate tftp
146
+ pkt.encapsulate(tftp)
144
147
  # need to fix it as #encapsulate force it to 69
145
148
  pkt.udp.dport = udp_dport
146
149
  end
147
150
 
148
- # TFTP Read Request header
151
+ # TFTP Read Request header.
152
+ # This header remove {#body} attribute and repalces it with {#filename} and {#mode}.
149
153
  class RRQ < TFTP
150
- remove_field :body
154
+ remove_attr :body
151
155
 
152
156
  # @!attribute filename
153
157
  # Filename to access
154
158
  # @return [String]
155
- define_field :filename, Types::CString
159
+ define_attr :filename, BinStruct::CString
156
160
 
157
161
  # @!attribute mode
158
162
  # Mode used. Should be +netascii+, +octet+ or +mail+
159
163
  # @return [String]
160
- define_field :mode, Types::CString
164
+ define_attr :mode, BinStruct::CString
161
165
  end
162
166
 
163
167
  # TFTP Write Request header
@@ -168,32 +172,34 @@ module PacketGen
168
172
  # @!attribute block_num
169
173
  # 16-bit block number
170
174
  # @return [Integer]
171
- define_field_before :body, :block_num, Types::Int16
175
+ define_attr_before :body, :block_num, BinStruct::Int16
172
176
  end
173
177
 
174
- # TFTP ACK header
178
+ # TFTP ACK header.
179
+ # This header remove {#body} attribute and repalces it with {#block_num}.
175
180
  class ACK < TFTP
176
- remove_field :body
181
+ remove_attr :body
177
182
 
178
183
  # @!attribute block_num
179
184
  # 16-bit block number
180
185
  # @return [Integer]
181
- define_field :block_num, Types::Int16
186
+ define_attr :block_num, BinStruct::Int16
182
187
  end
183
188
 
184
- # TFTP ERROR header
189
+ # TFTP ERROR header.
190
+ # This header remove {#body} attribute and repalces it with {#error_code} and {#error_msg}.
185
191
  class ERROR < TFTP
186
- remove_field :body
192
+ remove_attr :body
187
193
 
188
194
  # @!attribute error_code
189
195
  # 16-bit error code
190
196
  # @return [Integer]
191
- define_field :error_code, Types::Int16
197
+ define_attr :error_code, BinStruct::Int16
192
198
 
193
199
  # @!attribute error_msg
194
200
  # Error message
195
201
  # @return [String]
196
- define_field :error_msg, Types::CString
202
+ define_attr :error_msg, BinStruct::CString
197
203
  alias error_message error_msg
198
204
  end
199
205
  end