class PacketGen::Header::Dot11
IEEE 802.11 header @abstract This is a base class to demultiplex different IEEE 802.11 frames when
parsing.
A IEEE 802.11 header may consist of at least:
-
a {#frame_ctrl} ({Types::Int16}),
-
a {#id}/duration ({Types::Int16le}),
-
and a {#mac1} ({Eth::MacAddr}).
Depending on frame type and subtype, it may also contains:
-
a {#mac2} ({Eth::MacAddr}),
-
a {#mac3} ({Eth::MacAddr}),
-
a {#sequence_ctrl} ({Types::Int16}),
-
a {#mac4} ({Eth::MacAddr}),
-
a {#qos_ctrl} ({Types::Int16}),
-
a {#ht_ctrl} ({Types::Int32}),
-
a {#body} (a {Types::String} or another {Base} class),
-
a Frame check sequence ({#fcs}, of type {Types::Int32le})
Header
accessors¶ ↑
As Dot11
header types are defined under Dot11
namespace, Dot11
header accessors have a specific name. By example, to access to a {Dot11::Beacon} header, accessor is #dot11_beacon
.
Create Dot11
packets¶ ↑
As {Dot11} is an abstract class, you have to use one of its subclasses to instanciate a IEEE802.11 header.
IEEE802.11 control frames¶ ↑
Control
frames may be created this way:
pkt = PacketGen.gen('Dot11::Control', subtype: 13) # Ack control frame pkt.dot11_control # => PacketGen::Header::Dot11::Control # #dot11 is a shortcut for #dot11_control pkt.dot11 # => PacketGen::Header::Dot11::Control
IEEE802.11 management frames¶ ↑
Management
frames may be created this way:
pkt = PacketGen.gen('Dot11::Management') pkt.dot11_management # => PacketGen::Header::Dot11::Management # #dot11 is a shortcut for #dot11_management pkt.dot11 # => PacketGen::Header::Dot11::Management
Management
frames are usually specialized, AssociationRequest by example:
pkt.add('Dot11::AssoReq') pkt.dot11_assoreq # => PacketGen::Header::Dot11::AssoReq
Management
frames also may contain some elements (see IEEE 802.11 standard):
pkt.dot11_assoreq.add_elements(type: 'SSID', value: "My SSID") pkt.dot11_assoreq.add_elements(type: 'Rates', value: supported_rates)
IEEE802.11 data frames¶ ↑
Data
frames may be created this way:
pkt = PacketGen.gen('Dot11::Data') pkt.dot11_data # => PacketGen::Header::Dot11::Data # #dot11 is a shortcut for #dot11_data pkt.dot11 # => PacketGen::Header::Dot11::Data
Parse Dot11
packets¶ ↑
When parsing a Dot11
packet, Dot11
subclass is created from type
value. Dot11
header should then be accessed through +Packet#dot11+, whatever the frame type is. But, specialized methods also exist: by example, for a control frame, +Packet#dot11_control+ may also be used.
Send Dot11
packets¶ ↑
To send a Dot11
packet, a RadioTap
header is needed:
pkt = PacketGen.gen('RadioTap') pkt.add('Dot11::Management', mac1: client, mac2: bssid, mac3: bssid) pkt.add('Dot11::Beacon') pkt.dot11_beacon.add_element(type: 'SSID', value: 'My SSID') pkt.dot11_beacon.add_element(type: 'Rates', value: "\x85\x0c") pkt.calc pkt.to_w('wlan0')
@author Sylvain Daubert @since 1.4.0
Constants
- Element
@!parse
# IEEE 802.11 information element # # An {Element} is a piece of data contained in a Dot11 management frame. # @since 1.4.0 # @since 3.1.0 subclass of {Types::AbstractTLV} class Element < Types::AbstractTLV; end
@private
- TYPES
Frame types
Attributes
Set a flag for parsing Dot11
packets. If set to true
, parse FCS field, else don't. Default is true
. @return [Boolean]
Set a flag for parsing Dot11
packets. If set to true
, parse FCS field, else don't. Default is true
. @return [Boolean]
Public Class Methods
@param [Hash] options @see Base#initialize
PacketGen::Header::Base::new
# File lib/packetgen/header/dot11.rb, line 262 def initialize(options={}) super @applicable_fields = old_fields end
Public Instance Methods
Callback called when a Dot11
header is added to a packet Here, add #dot11
method as a shortcut to existing +#dot11_(control|management|data)+. @param [Packet] packet @return [void]
# File lib/packetgen/header/dot11.rb, line 355 def added_to_packet(packet) return if packet.respond_to? :dot11 packet.instance_eval("def dot11(arg=nil); header(#{self.class}, arg); end") end
Compute checksum and set fcs
field @return [Integer]
# File lib/packetgen/header/dot11.rb, line 306 def calc_checksum fcs = Zlib.crc32(to_s[0...-4]) self.fcs = fcs fcs end
Get all used field names @return [Array<Symbol>]
# File lib/packetgen/header/dot11.rb, line 269 def fields @applicable_fields end
Get human readable type @return [String]
# File lib/packetgen/header/dot11.rb, line 320 def human_type TYPES[type] end
@return [String]
# File lib/packetgen/header/dot11.rb, line 325 def inspect str = if self.instance_of? Dot11 Inspect.dashed_line("#{self.class} #{human_type}", 1) elsif self.respond_to? :human_subtype Inspect.dashed_line("#{self.class} #{human_subtype}", 1) else Inspect.dashed_line(self.class.to_s, 1) end define_applicable_fields @applicable_fields.each do |attr| next if attr == :body str << Inspect.inspect_attribute(attr, @fields[attr], 1) end str end
Populate object from a binary string @param [String] str @return [Dot11] may return a subclass object if a more specific class
may be determined
# File lib/packetgen/header/dot11.rb, line 280 def read(str) fcs = Dot11.fcs? if self.instance_of? Dot11 return self if str.nil? force_binary str self[:frame_ctrl].read str[0, 2] case type when 0 Dot11::Management.new.read str when 1 Dot11::Control.new.read str when 2 Dot11::Data.new.read str else private_read str, fcs end else private_read str, fcs end end
@return [String]
# File lib/packetgen/header/dot11.rb, line 313 def to_s define_applicable_fields @applicable_fields.map { |f| force_binary @fields[f].to_s }.join end
send Dot11
packet on wire. @param [String] iface interface name @return [void]
# File lib/packetgen/header/dot11.rb, line 346 def to_w(iface) Inject.inject(iface: iface, data: self) end
Private Instance Methods
# File lib/packetgen/header/dot11.rb, line 395 def define_applicable_fields handle_mac4 handle_ht_ctrl handle_fcs end
# File lib/packetgen/header/dot11.rb, line 387 def handle_fcs if Dot11.fcs? @applicable_fields << :fcs unless @applicable_fields.include? :fcs else remove_from_applicable_fields :fcs end end
# File lib/packetgen/header/dot11.rb, line 376 def handle_ht_ctrl if order? unless @applicable_fields.include? :ht_ctrl idx = @applicable_fields.index(:body) @applicable_fields[idx, 0] = :ht_ctrl end else remove_from_applicable_fields %i[ht_ctrl] end end
# File lib/packetgen/header/dot11.rb, line 368 def handle_mac4 if to_ds? && from_ds? @applicable_fields[6, 0] = :mac4 unless @applicable_fields.include? :mac4 else remove_from_applicable_fields :mac4 end end
# File lib/packetgen/header/dot11.rb, line 401 def private_read(str, fcs) self[:frame_ctrl].read str[0, 2] define_applicable_fields if fcs old_read str[0...-4] self[:fcs].read str[-4..-1] else old_read str end self end
# File lib/packetgen/header/dot11.rb, line 363 def remove_from_applicable_fields(fields) fields = [fields] unless fields.is_a? Array @applicable_fields -= fields end