f1950c2fe1
Fixes #3289. This commit adds back the bit-struct library because in the end, it is useful for some modules, especially pello's. It's small and it has a nice license, so why not. After all, it /is/ useful for quicky application headers. Eventually, should be replaced by StructFu, but that requires some doc work on my part to get that transition in place. This also adds pello's DNS fuzzer module which makes use of BitStruct to create sometimes malformed-on-purpose DNS headers. Tested against 3 different DNS servers, caused one to reboot, so I'd say it works.
78 lines
2.2 KiB
Ruby
78 lines
2.2 KiB
Ruby
require 'bit-struct/vector'
|
|
|
|
class BitStruct
|
|
# Class for embedding a BitStruct::Vector as a field within a BitStruct.
|
|
# Declared with BitStruct.vector.
|
|
class VectorField < Field
|
|
# Used in describe.
|
|
def self.class_name
|
|
@class_name ||= "vector"
|
|
end
|
|
|
|
# Used in describe.
|
|
def class_name
|
|
@class_name ||= vector_class.name[/\w+$/]
|
|
end
|
|
|
|
# Returns the subclass of Vector that is used to manage the value of this
|
|
# field. If the class was specified in the BitStruct.vector declaration,
|
|
# #vector_class will return it, otherwise it will be an anonymous class
|
|
# (which you can assign to a constant to make nonymous ;).
|
|
def vector_class
|
|
@vector_class ||= options[:vector_class] || options["vector_class"]
|
|
end
|
|
|
|
def describe opts # :nodoc:
|
|
if opts[:expand]
|
|
opts = opts.dup
|
|
opts[:byte_offset] = offset / 8
|
|
opts[:omit_header] = opts[:omit_footer] = true
|
|
vector_class.describe(nil, opts) {|desc| yield desc}
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
def add_accessors_to(cl, attr = name) # :nodoc:
|
|
unless offset % 8 == 0
|
|
raise ArgumentError,
|
|
"Bad offset, #{offset}, for vector field #{name}." +
|
|
" Must be multiple of 8."
|
|
end
|
|
|
|
unless length % 8 == 0
|
|
raise ArgumentError,
|
|
"Bad length, #{length}, for vector field #{name}." +
|
|
" Must be multiple of 8."
|
|
end
|
|
|
|
offset_byte = offset / 8
|
|
length_byte = length / 8
|
|
last_byte = offset_byte + length_byte - 1
|
|
byte_range = offset_byte..last_byte
|
|
|
|
vc = vector_class
|
|
|
|
cl.class_eval do
|
|
define_method attr do ||
|
|
vc.new(self[byte_range])
|
|
end
|
|
|
|
define_method "#{attr}=" do |val|
|
|
if val.length != length_byte
|
|
raise ArgumentError, "Size mismatch in vector field assignment " +
|
|
"to #{attr} with value #{val.inspect}"
|
|
end
|
|
|
|
if val.class != vc
|
|
warn "Type mismatch in vector field assignment " +
|
|
"to #{attr} with value #{val.inspect}"
|
|
end
|
|
|
|
self[byte_range] = val
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|