ruckus 0.5.4

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 (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