Class: Dot11::PacketSet

Inherits:
Object
  • Object
show all
Defined in:
lib/dot11/packetset.rb

Defined Under Namespace

Classes: Pair

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, parameters) ⇒ PacketSet

Returns a new instance of PacketSet.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/dot11/packetset.rb', line 8

def initialize(klass, parameters)
  @fields = []

  @packet_class = klass

  parameters.each_pair do |key, value|
    @fields << Pair.new(key, value)
  end
    
  @field_sizes = @fields.map do |field|
    if field.value.respond_to?(:size) && !(field.value.kind_of?(String) || field.value.kind_of?(Numeric))
      field.value.size
    elsif field.value.respond_to?(:entries)
      field.value.entries.size
    else
      field.value = [field.value]
      1
    end
  end
end

Instance Attribute Details

#fieldsObject (readonly)

Returns the value of attribute fields.



6
7
8
# File 'lib/dot11/packetset.rb', line 6

def fields
  @fields
end

#packet_classObject

Returns the value of attribute packet_class.



5
6
7
# File 'lib/dot11/packetset.rb', line 5

def packet_class
  @packet_class
end

Instance Method Details

#[](index) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/dot11/packetset.rb', line 29

def [](index)          
  indices = @field_sizes.inject([]) do |accumulator, size|
    remainder = index % size 
    index /= size # yeah textmate isn't perfect and that's why I need this slash: /      
    accumulator << remainder
  end

  field_hash = {}

  indices.each_with_index do |index, i|  
    value = @fields[i].value
  
    if value.kind_of?(Array) or value.kind_of?(Range)
      field_hash[@fields[i].name] = @fields[i].value.entries[index]
    else
      field_hash[@fields[i].name] = @fields[i].value
    end      
  end

  out = @packet_class.new(field_hash)

  out
end

#bitrange_to_filter(offset, size, bitrange, desired, negated = false) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/dot11/packetset.rb', line 78

def bitrange_to_filter(offset, size, bitrange, desired, negated = false)
  # TODO: Take bitrange.exclude_end? into account
  mask = ((2 << (bitrange.end - bitrange.begin)) - 1) << bitrange.begin
  
  value = "(ether[#{offset}:#{size}] & #{'%#x' % mask}) >> #{bitrange.begin}"
  
  case desired
  when Range
    "(#{value} >= #{'%#x' % desired.begin} && #{value} #{desired.exclude_end? ? "<" : "<="} #{'%#x' % desired.end})"
  when Array
    # TODO: deal with arrays of ranges
    '(' + desired.map {|d| "#{value} = #{'%#x' % d}"}.join(" || ") + ')'
  when Numeric, String
    "#{value} #{negated ? '!' : ''}= #{'%#x' % desired.to_i}"
  else
    raise "unknown"
  end
end

#decode_condition(fields, condition) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/dot11/packetset.rb', line 145

def decode_condition(fields, condition)
  case condition
  when Array
    condition.map{|x| decode_condition(fields, x)}.join(" || ")
  when Hash
    condition.map do |key, value|
      # Decode the nasty negation syntax
      negated, value = value.kind_of?(Array) && value.size == 1 ? [true, value[0]] : [false, value]

      field_info = fields.find{|x| key == x[0]}[1]
      
      case field_info[:type]
      when :int
        if field_info.has_key?(:bitrange)
          bitrange_to_filter(field_info[:offset], field_info[:size], field_info[:bitrange], value, negated)
        else
          int_to_filter(field_info[:offset], field_info[:size], value, negated)
        end
      when :mac
        mac_to_filter(field_info[:offset], field_info[:size], value, negated)
      else
        raise "unknown"  
      end
    end.join(" && ")
  end
end

#each(prefix = []) ⇒ Object



57
58
59
60
61
# File 'lib/dot11/packetset.rb', line 57

def each(prefix = [])
  size.times do |i|
    yield self[i]
  end
end

#each_with_indexObject



63
64
65
66
67
# File 'lib/dot11/packetset.rb', line 63

def each_with_index
  size.times do |i|
    yield self[i], i
  end
end

#include?(packet) ⇒ Boolean

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
# File 'lib/dot11/packetset.rb', line 69

def include?(packet)
  # This is horrrrrribly inefficient. FIXME
  each do |pkt|
    return true if packet == pkt
  end

  false
end

#int_to_filter(offset, size, desired, negated = false) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/dot11/packetset.rb', line 97

def int_to_filter(offset, size, desired, negated = false)
  value = "ether[#{offset}:#{size}]"
  
  case desired
  when Range
    "(#{value} >= #{'%#x' % desired.begin} && #{value} #{desired.exclude_end? ? "<" : "<="} #{'%#x' % desired.end})"
  when Array
    # TODO: deal with arrays of ranges
    desired.map {|d| "#{value} #{negated ? '!' : ''}= #{'%#x' % d}"}.join(" || ")
  when Numeric
    "#{value} #{negated ? '!' : ''}= #{'%#x' % desired}"
  else
    raise "unknown desired: #{desired.inspect}"  
  end      
end

#mac_to_filter(offset, size, desired, negated = false) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/dot11/packetset.rb', line 113

def mac_to_filter(offset, size, desired, negated = false)      
  case desired
  when Range
    raise "Range of MAC addresses in filter not yet implemented"
  when Array
    '(' + desired.map do |d| 
      desired = MACAddress.new(desired) if desired.kind_of?(String)
      first_four = desired[0, 4].pack("CCCC").unpack("N")[0]
      second_two = desired[4, 2].pack("CC").unpack("n")[0]

      "(ether[#{offset}:2] = #{'%#x' % first_four} && ether[#{offset + 4}:2] = #{'%#x' % second_two})"
    end.join(" || ") + ')'
  when Numeric

  when MACAddress, String
    desired = MACAddress.new(desired) if desired.kind_of?(String)
    first_four = desired[0, 4].pack("CCCC").unpack("N")[0]
    second_two = desired[4, 2].pack("CC").unpack("n")[0]
    
    
    if desired.prefix_length == 32
      "ether[#{offset}:4] = #{'%#x' % first_four}"
    elsif desired.prefix_length == 48 || desired.prefix_length == 0
      "(ether[#{offset}:4] = #{'%#x' % first_four} && ether[#{offset + 4}:2] = #{'%#x' % second_two})"
    else
      raise "unsupport prefix length #{desired.prefix_length}"  
    end
  else
    raise "unknown"  
  end
end

#sizeObject



53
54
55
# File 'lib/dot11/packetset.rb', line 53

def size
  @field_sizes.inject(1) { |product, size| size * product }
end

#to_filterObject



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/dot11/packetset.rb', line 172

def to_filter
  fields = @packet_class.fields

  @fields.map do |field|
    '(' + begin
      field_info = fields.find{|x| field.name == x[0]}
      
      if field_info.nil?
        raise "nil field_info"
      end
      
      field_info = field_info[1]
      
      # We don't really want to do this
      if field_info.nil?
        raise "nil field_info 2"
      end
            
      if field_info.has_key?(:condition)
        if !field_info[:offset].kind_of?(Numeric)
          field_info[:offset].map do |key, value|
            '(' + begin
              if key == :else
                field_info[:offset].keys.reject{|k| k == :else}.map do |k|
                  '!(' + decode_condition(fields, k) + ')'
                end.join(" && ")
              else
                '(' + decode_condition(fields, key) + ') && (' + begin
                  case field_info[:type]
                  when :int
                    if field_info.has_key?(:bitrange)
                      bitrange_to_filter(value, field_info[:size], field_info[:bitrange], field.value)
                    else
                      int_to_filter(value, field_info[:size], field.value)
                    end
                  when :mac
                    mac_to_filter(value, field_info[:size], field.value)
                  else
                    raise "unknown"  
                  end
                end
              end
            end + ')'
          end.join(" && ")
        else
          '((' + decode_condition(fields, field_info[:condition]) +') && ('+ case field_info[:type]
          when :int
            if field_info.has_key?(:bitrange)
              bitrange_to_filter(field_info[:offset], field_info[:size], field_info[:bitrange], field.value)
            else
              int_to_filter(field_info[:offset], field_info[:size], field.value)
            end
          when :mac
            mac_to_filter(field_info[:offset], field_info[:size], field.value)
          else
            raise "unknown"  
          end + '))'
        end
      else
        if !field_info[:offset].kind_of?(Numeric)
          p "moo"
          "can"
        else
          case field_info[:type]
          when :int
            if field_info.has_key?(:bitrange)
              bitrange_to_filter(field_info[:offset], field_info[:size], field_info[:bitrange], field.value)
            else
              int_to_filter(field_info[:offset], field_info[:size], field.value)
            end
          when :mac
            mac_to_filter(field_info[:offset], field_info[:size], field.value)
          else
            raise "unknown"  
          end
        end
      end
    end + ')'
  end.join(" && ")
end