ruckus 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/README +0 -0
  4. data/README.markdown +51 -0
  5. data/Rakefile +54 -0
  6. data/VERSION +1 -0
  7. data/lib/ruckus.rb +70 -0
  8. data/lib/ruckus/blob.rb +113 -0
  9. data/lib/ruckus/choice.rb +55 -0
  10. data/lib/ruckus/dfuzz.rb +231 -0
  11. data/lib/ruckus/dictionary.rb +119 -0
  12. data/lib/ruckus/enum.rb +39 -0
  13. data/lib/ruckus/extensions/array.rb +33 -0
  14. data/lib/ruckus/extensions/class.rb +168 -0
  15. data/lib/ruckus/extensions/duplicable.rb +37 -0
  16. data/lib/ruckus/extensions/file.rb +24 -0
  17. data/lib/ruckus/extensions/fixnum.rb +26 -0
  18. data/lib/ruckus/extensions/hash.rb +10 -0
  19. data/lib/ruckus/extensions/integer.rb +26 -0
  20. data/lib/ruckus/extensions/ipaddr.rb +155 -0
  21. data/lib/ruckus/extensions/irb.rb +30 -0
  22. data/lib/ruckus/extensions/math.rb +6 -0
  23. data/lib/ruckus/extensions/module.rb +37 -0
  24. data/lib/ruckus/extensions/numeric.rb +117 -0
  25. data/lib/ruckus/extensions/object.rb +22 -0
  26. data/lib/ruckus/extensions/range.rb +16 -0
  27. data/lib/ruckus/extensions/socket.rb +20 -0
  28. data/lib/ruckus/extensions/string.rb +327 -0
  29. data/lib/ruckus/filter.rb +16 -0
  30. data/lib/ruckus/human_display.rb +79 -0
  31. data/lib/ruckus/ip.rb +38 -0
  32. data/lib/ruckus/mac_addr.rb +31 -0
  33. data/lib/ruckus/mutator.rb +318 -0
  34. data/lib/ruckus/null.rb +24 -0
  35. data/lib/ruckus/number.rb +360 -0
  36. data/lib/ruckus/parsel.rb +363 -0
  37. data/lib/ruckus/selector.rb +92 -0
  38. data/lib/ruckus/str.rb +164 -0
  39. data/lib/ruckus/structure.rb +263 -0
  40. data/lib/ruckus/structure/atcreate.rb +23 -0
  41. data/lib/ruckus/structure/beforebacks.rb +28 -0
  42. data/lib/ruckus/structure/defaults.rb +57 -0
  43. data/lib/ruckus/structure/factory.rb +42 -0
  44. data/lib/ruckus/structure/fixupfields.rb +16 -0
  45. data/lib/ruckus/structure/initializers.rb +14 -0
  46. data/lib/ruckus/structure/relate.rb +34 -0
  47. data/lib/ruckus/structure/replacement.rb +30 -0
  48. data/lib/ruckus/structure/searchmods.rb +33 -0
  49. data/lib/ruckus/structure/structureproxies.rb +28 -0
  50. data/lib/ruckus/structure/validate.rb +12 -0
  51. data/lib/ruckus/structure_shortcuts.rb +109 -0
  52. data/lib/ruckus/time_t.rb +26 -0
  53. data/lib/ruckus/vector.rb +97 -0
  54. data/ruckus.gemspec +104 -0
  55. data/test/test_decides.rb +61 -0
  56. data/test/test_mutator.rb +29 -0
  57. data/test/test_override.rb +23 -0
  58. data/test/test_replace.rb +39 -0
  59. metadata +138 -0
@@ -0,0 +1,28 @@
1
+ module Ruckus
2
+ module StructureBeforeCallbacks
3
+ def self.included(klass)
4
+ klass.extend(ClassMethods)
5
+
6
+ klass.class_eval {
7
+ class_inheritable_array :before_callbacks
8
+ write_inheritable_array :before_callbacks, []
9
+ }
10
+ end
11
+
12
+ def before_render_hook
13
+ self.class.before_callbacks.each {|cb| self.instance_eval(&cb)}
14
+ end
15
+
16
+ module ClassMethods
17
+ def before_render(arg=nil, &block)
18
+ if not block_given?
19
+ raise "need a callback function" if not arg
20
+ arg = arg.intern if not arg.kind_of? Symbol
21
+ block = lambda { send(arg) }
22
+ end
23
+
24
+ self.before_callbacks << block
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,57 @@
1
+ module Ruckus
2
+ module StructureDefaultValues
3
+ def self.included(klass)
4
+ klass.extend(ClassMethods)
5
+ end
6
+
7
+ def final_initialization_hook
8
+ instance_variables.grep(/^@with_.*/).each do |v|
9
+ v =~ /@with_(.*)/
10
+ var = $1
11
+ send((var + "=").intern, instance_variable_get(v.intern))
12
+ end
13
+ super
14
+ end
15
+
16
+ # XXX probably not needed
17
+ # def template_entry_added_hook(obj)
18
+ # obj.instance_variables.grep(/^@with_.*/).each do |v|
19
+ # v =~ /@with_(.*)/
20
+ # var = $1
21
+ # obj.send((var + "=").intern, obj.instance_variable_get(v.intern))
22
+ # end
23
+ # super
24
+ # end
25
+
26
+ def method_missing_hook(meth, args)
27
+ m = meth.to_s
28
+ setter = (m[-1].chr == "=") ? true : false
29
+ m = m[0..-2] if setter
30
+ if setter and (field = self[m.intern])
31
+ if(field.kind_of? Structure)
32
+ if args[0].kind_of? field.class
33
+ args[0].each_field do |name, f|
34
+ field.value = f.value
35
+ end
36
+ else
37
+ if((deft = field.instance_variable_get :@default_field))
38
+ field.send(deft.to_s + "=", args[0])
39
+ return false
40
+ else
41
+ puts "WARNING: attempt to set structure field with no default_field declared"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ true
47
+ end
48
+
49
+ module ClassMethods
50
+ def default_field(f)
51
+ self.initializers << lambda do
52
+ @default_field = f
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,42 @@
1
+ module Ruckus
2
+ module StructureDetectFactory
3
+ def factory?
4
+ self.respond_to? :factory
5
+ end
6
+
7
+ def structure_field_def_hook(*a)
8
+ args = a[0]
9
+ opts = args[0].respond_to?(:has_key?) ? args[0] : args[1]
10
+ include StructureFactory if opts.try(:has_key?, :decides)
11
+ super
12
+ end
13
+ end
14
+
15
+ module StructureFactory
16
+ def self.included(klass)
17
+ klass.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ def factory(str)
22
+ orig = str.clone
23
+ (tmp = self.new).capture(str)
24
+ tmp.each_field do |n, f|
25
+ if (m = f.try(:decides))
26
+ klass = m[f.value]
27
+ if klass
28
+ o = derive_search_module.const_get(klass.to_s.class_name).new
29
+ if o.class.factory?
30
+ o, orig = o.class.factory(orig)
31
+ else
32
+ orig = o.capture(orig)
33
+ end
34
+ return o, orig
35
+ end
36
+ end
37
+ end
38
+ return false
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ module Ruckus
2
+ module StructureFixupFieldNames
3
+ def structure_field_def_hook(*a)
4
+ args = a[0]
5
+ if args[0] and args[0].kind_of? Symbol
6
+ if args[1]
7
+ args[1][:name] = args[0]
8
+ else
9
+ args[1] = { :name => args[0] }
10
+ end
11
+ args.shift
12
+ end
13
+ super
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Ruckus
2
+ module StructureInitializers
3
+ def self.included(klass)
4
+ klass.class_eval {
5
+ class_inheritable_array :initializers
6
+ write_inheritable_array :initializers, []
7
+ }
8
+ end
9
+
10
+ def final_initialization_hook
11
+ self.initializers.each {|cb| self.instance_eval(&cb) }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ module Ruckus
2
+ module StructureRelateDeclaration
3
+ def class_method_missing_hook(meth, *args)
4
+ if meth.to_s =~ /^relate_(.*)/
5
+ relate($1.intern, *args)
6
+ return false
7
+ end
8
+ true
9
+ end
10
+
11
+ def relate(attr, field, opts={})
12
+ opts[:through] ||= :value
13
+ raise "need a valid field to relate" if not field
14
+ raise "need :to argument" if not opts[:to]
15
+
16
+ self.initializers << lambda do
17
+ f = send(field)
18
+
19
+ case attr
20
+ when :value
21
+ f.value = opts[:through]
22
+ f.instance_eval { @from_field = opts[:to] }
23
+ when :size
24
+ f.instance_eval {
25
+ @in_size = {
26
+ :meth => opts[:through],
27
+ :from_field => opts[:to]
28
+ }
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ module Ruckus
2
+ module StructureAllowFieldReplacement
3
+ def template_entry_added_hook(obj)
4
+ ## -------------------------------------------
5
+ ## a quick dance to allow fields to replace other
6
+ ## fields
7
+
8
+ # check to see if it already exists, in which
9
+ # case we want to replace the previous definition
10
+ found = false
11
+ @value.each_with_index do |x,i|
12
+ if x.try(:name) == obj.try(:name)
13
+ found = i
14
+ break
15
+ end
16
+ end
17
+
18
+ # it didn't exist, so add it to the structure
19
+ if found
20
+ # it did exist, so update the names index
21
+ # and the previous entry in the structure
22
+
23
+ self.class.structure_field_names[obj.try(:name)] = found
24
+ @value[found] = obj
25
+ else
26
+ false
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Ruckus
2
+ module StructureSearchModules
3
+ def self.included(klass)
4
+ klass.class_eval {
5
+ class_inheritable_array :search_modules
6
+ write_inheritable_array :search_modules, []
7
+ }
8
+
9
+ klass.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def derive_search_module
14
+ if self.search_modules.empty?
15
+ return Ruckus
16
+ else
17
+ mod = Module.new
18
+ self.search_modules.each do |m|
19
+ mod.module_eval "include #{ m.to_s.class_name }"
20
+ end
21
+ mod.module_eval "include Ruckus"
22
+ return mod
23
+ end
24
+ end
25
+
26
+ def search_module(*args)
27
+ args.each do |m|
28
+ self.search_modules << m
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Ruckus
2
+ module StructureProxies
3
+ class ValueProxy
4
+ def initialize(target); @t = target; end
5
+ def method_missing(meth, *args)
6
+ if meth.to_s.ends_with? "="
7
+ @t.send(meth, *args)
8
+ else
9
+ @t.send(meth).send(:value)
10
+ end
11
+ end
12
+ end
13
+
14
+ class NodeProxy
15
+ def initialize(target); @t = target; end
16
+ def method_missing(meth, *args)
17
+ if meth.to_s.ends_with? "="
18
+ @t.send(meth, *args)
19
+ else
20
+ @t[meth]
21
+ end
22
+ end
23
+ end
24
+
25
+ def v; ValueProxy.new(self); end
26
+ def n; NodeProxy.new(self); end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ require 'pp'
2
+
3
+ module Ruckus
4
+ module StructureValidateField
5
+ def structure_field_def_hook(*a)
6
+ args = a[0]
7
+ if [ "value", "name", "size" ].include?(nm = args[0][:name] && args[0][:name].to_s) or (nm and nm.starts_with? "relate_")
8
+ raise "can't have fields named #{ nm }, because we suck; rename the field"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,109 @@
1
+ # === A sort of half-baked DSL for defining packet fields.
2
+ # These are all classmethods of Structure.
3
+ module Ruckus
4
+ class Structure
5
+ # Any number, ie
6
+ # num :len, :width => 32, :endianness => :little
7
+ #
8
+ def self.num(name, opts)
9
+ add(Number, opts.merge(:name => name))
10
+ end
11
+
12
+ def self.char(*args); with_args(*args) {|name, opts| str opts.merge(:name => name, :size => 1)}; end
13
+
14
+ def self.decimal(*args); with_args(*args) {|name, opts| num name, opts.merge(:ascii => true, :radix => 10)}; end
15
+ def self.hex_number(*args); with_args(*args) {|name, opts| num name, opts.merge(:ascii => true, :radix => 16)}; end
16
+
17
+ def self.tag_bit(*args); with_args(*args) {|name, opts| num name, opts.merge(:width => 1, :tag => name)}; end
18
+
19
+ # A string (ie, multiple of 8 bits wide) containing all zeroes.
20
+ # You could also just use
21
+ # num :width => whatever, :value => 0
22
+ #
23
+ def self.zero_pad(*args)
24
+ with_args(*args) do |name, opts|
25
+ str opts.merge(:name => name, :padding => "\x00")
26
+ end
27
+ end
28
+
29
+ # A bounded string, takes its size from the preceding element
30
+ #
31
+ def self.bounded(*args)
32
+ with_args(*args) do |name, opts|
33
+ opts[:size] ||= :value
34
+ opts[:offset] ||= -1
35
+ str name, opts
36
+ end
37
+ end
38
+
39
+ # A string.
40
+ def self.string(*args)
41
+ with_args(*args) do |name, opts|
42
+ str opts.merge(:name => name)
43
+ end
44
+ end
45
+
46
+ # A Null byte
47
+ def self.mark(*args)
48
+ with_args(*args) do |name, opts|
49
+ null opts.merge(:name => name)
50
+ end
51
+ end
52
+
53
+ # 4-byte IP address (IPv4)
54
+ def self.ipv4(*args)
55
+ with_args(*args) do |name, opts|
56
+ add(Ruckus::IP, opts.merge(:name => name))
57
+ end
58
+ end
59
+
60
+ def self.choose(name, tag=nil, &block)
61
+ add(Ruckus::Choice, :name => name, :block => block)
62
+ end
63
+
64
+ def self.base_pad(name, tag=nil)
65
+ string name, :value => {:offset => :this, :block => lambda do |this|
66
+ r = this.root
67
+ r = r.find_tag_struct(tag) if tag
68
+ if ((k = this.rendered_offset - r.rendered_offset) % 4) != 0
69
+ pad = 4 - ((this.rendered_offset - r.rendered_offset) % 4)
70
+ else
71
+ pad = 0
72
+ end
73
+ "\x00" * pad
74
+ end
75
+ }
76
+ end
77
+
78
+ def self.word_len(*args); with_args(*args) do |name, opts|
79
+ opts[:value] ||= :size
80
+ opts[:width] ||= 16
81
+ opts[:modifier] = lambda {|o, s| s/=2}
82
+ num name, opts
83
+ end
84
+ end
85
+
86
+ def self.msg_len(*args); with_args(*args) do |name, opts|
87
+ opts[:value] = { :block => lambda do |n|
88
+ if not n.rendering
89
+ begin
90
+ n.rendering = true
91
+ n.parent_struct.size
92
+ ensure
93
+ n.rendering = false
94
+ end
95
+ else
96
+ 4
97
+ end
98
+ end
99
+ }
100
+ opts[:width] ||= 32
101
+ num name, opts
102
+ end
103
+ end
104
+ end
105
+
106
+ class Padding < Structure
107
+ base_pad :pad
108
+ end
109
+ end
@@ -0,0 +1,26 @@
1
+
2
+ module Ruckus
3
+ class TimeT < Number
4
+ def initialize(opts={})
5
+ opts[:width] ||= 32
6
+ super(opts)
7
+ end
8
+
9
+ def to_human(indent="")
10
+ "#{indent}#{@name} = #{@value.to_hex} (#{time})"
11
+ end
12
+
13
+ def utc(*args)
14
+ @value=( Time.utc(*args) ).to_i
15
+ end
16
+ alias :gm :utc
17
+
18
+ def local(*args)
19
+ @value=( t=Time.local(*args)).to_i
20
+ end
21
+
22
+ def time
23
+ Time.at(@value)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,97 @@
1
+ module Ruckus
2
+
3
+ # A vector of count elements of the same class, as in
4
+ # [elt0] [elt1] ... [eltN]
5
+ class Vector < Parsel
6
+
7
+ # Options include:
8
+ # * <tt>:class</tt> the class of each element
9
+ # * <tt>:e_opts</tt> opts to pass when creating each element (:name is always deleted)
10
+ # * <tt>:count</tt> the number of elements of class :class in the vector. Can be a reference to another field
11
+ # via :from_field
12
+ def initialize(opts={})
13
+ opts[:count] = 0x1fffffff if opts[:count] == :unlimited # grotesque hack XXX
14
+ opts[:e_opts] ||= {}
15
+
16
+ raise "need a class" if not opts[:class] and not opts[:classes_from]
17
+
18
+ if opts[:classes_from]
19
+ if not opts[:keys_from]
20
+ raise "need a module to pull keys from (protocol numbers, command IDs, whatever) as :keys_from"
21
+ end
22
+
23
+ begin
24
+ @keys = (m = opts[:keys_from]).constants.
25
+ select {|x| m.const_get(x).kind_of? Numeric}.
26
+ map {|x| [m.const_get(x), x]}.
27
+ to_hash
28
+ rescue => e
29
+ raise "can't look up keys:\n #{ e }"
30
+ end
31
+
32
+ begin
33
+ @classes = (m = opts[:classes_from]).constants.
34
+ select {|x| m.const_get(x).kind_of? Class}.
35
+ map do |x|
36
+ name = (klass = m.const_get(x)).
37
+ to_s.
38
+ underscore.
39
+ upcase
40
+ name = name[name.rindex(":")+1..-1]
41
+ [ name, klass ]
42
+ end.to_hash
43
+ rescue => e
44
+ raise "can't generate class dictionary:\n #{ e }"
45
+ end
46
+
47
+ raise "need a :key_field or :key_finder" if not opts[:key_field] and not opts[:key_finder]
48
+ end
49
+
50
+ super(opts)
51
+ @value = Blob.new
52
+ @value.parent = self
53
+ end
54
+
55
+ def capture(str)
56
+ count = resolve(@count)
57
+ if not count
58
+ raise "You need to provide a :count value to parse a vector; did you give it :size by mistake?"
59
+ end
60
+
61
+ count.downto(1) do |i|
62
+ break if not str or str.empty?
63
+
64
+ if @class
65
+ o = @class.new(@e_opts.merge(:parent => self))
66
+ str = o.capture(str)
67
+ @value << o
68
+ else
69
+ if @key_field
70
+ key = parent_struct.send(@key_field)
71
+ end
72
+
73
+ if @key_finder
74
+ key = @key_finder.call(str)
75
+ end
76
+
77
+ begin
78
+ o = @classes[@keys[key]].new(@e_opts.merge(:parent => self))
79
+ str = o.capture(str)
80
+ @value << o
81
+ rescue => e
82
+ raise "couldn't create an object from key:\n#{ e }"
83
+ end
84
+ end
85
+ end
86
+ @count = @value.count
87
+ str
88
+ end
89
+
90
+ def to_s(off=nil)
91
+ @rendered_offset = off || 0
92
+ (@value)? @value.to_s(off) : ""
93
+ end
94
+
95
+ end
96
+
97
+ end