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,327 @@
1
+ %w[iconv stringio].each {|x| require x}
2
+
3
+ class String
4
+ module StringExtensions
5
+ # Convert a string to "Unicode", ie, the way Win32 expects it, including
6
+ # trailing NUL.
7
+ def to_utf16
8
+ Iconv.iconv("utf-16LE", "utf-8", self).first + "\x00\x00"
9
+ end
10
+
11
+ # Convert a "Unicode" (Win32-style) string back to native Ruby UTF-8;
12
+ # get rid of any trailing NUL.
13
+ def from_utf16
14
+ ret = Iconv.iconv("utf-8", "utf-16le", self).first
15
+ if ret[-1] == 0
16
+ ret = ret[0..-2]
17
+ end
18
+ end
19
+ alias_method :to_utf8, :from_utf16
20
+ alias_method :to_ascii, :from_utf16
21
+
22
+ # Convenience for parsing UNICODE strings from a buffer
23
+ # Assumes last char ends in 00, which is not always true but works in English
24
+ def from_utf16_buffer
25
+ self[0..index("\0\0\0")+2].from_utf16
26
+ end
27
+
28
+ # Sometimes string buffers passed through Win32 interfaces come with
29
+ # garbage after the trailing NUL; this method gets rid of that, like
30
+ # String#trim
31
+ def asciiz
32
+ begin
33
+ self[0..self.index("\x00")-1]
34
+ rescue
35
+ self
36
+ end
37
+ end
38
+
39
+ # My entry into the hexdump race. Outputs canonical hexdump, uses
40
+ # StringIO for speed, could be cleaned up with "ljust", and should
41
+ # probably use table lookup instead of to_s(16) method calls.
42
+ def hexdump(capture=false)
43
+ sio = StringIO.new
44
+ rem = size - 1
45
+ off = 0
46
+
47
+ while rem > 0
48
+ pbuf = ""
49
+ pad = (15 - rem) if rem < 16
50
+ pad ||= 0
51
+
52
+ sio.write(("0" * (8 - (x = off.to_s(16)).size)) + x + " ")
53
+
54
+ 0.upto(15-pad) do |i|
55
+ c = self[off]
56
+ x = c.to_s(16)
57
+ sio.write(("0" * (2 - x.size)) + x + " ")
58
+ if c.printable?
59
+ pbuf << c
60
+ else
61
+ pbuf << "."
62
+ end
63
+ off += 1
64
+ rem -= 1
65
+ sio.write(" ") if i == 7
66
+ end
67
+
68
+ sio.write("-- " * pad) if pad > 0
69
+ sio.write(" |#{ pbuf }|\n")
70
+ end
71
+
72
+ sio.rewind()
73
+ if capture
74
+ sio.read()
75
+ else
76
+ puts sio.read()
77
+ end
78
+ end
79
+
80
+ # convert a string to its idiomatic ruby class name
81
+ def class_name
82
+ r = ""
83
+ up = true
84
+ each_byte do |c|
85
+ if c == 95
86
+ if up
87
+ r << "::"
88
+ else
89
+ up = true
90
+ end
91
+ else
92
+ m = up ? :upcase : :to_s
93
+ r << (c.chr.send(m))
94
+ up = false
95
+ end
96
+ end
97
+ r
98
+ end
99
+
100
+ # Insane that this isn't in the library by default.
101
+ def starts_with? x
102
+ self[0..x.size-1] == x
103
+ end
104
+
105
+ def ends_with? x
106
+ self[-(x.size)..-1] == x
107
+ end
108
+
109
+ # Cribbed from Ero Carrera's pefile; a relatively expensive entropy
110
+ # function, gives a float result of random-bits-per-byte.
111
+ def entropy
112
+ e = 0
113
+ 0.upto(255) do |i|
114
+ x = count(i.chr)/size.to_f
115
+ if x > 0
116
+ e += - x * Math.log2(x)
117
+ end
118
+ end
119
+
120
+ return e
121
+ end
122
+
123
+ # The driver function for String#strings below; really, this will
124
+ # run on any Enumerable that contains Fixnums.
125
+ def nextstring(opts={})
126
+ off = opts[:offset] || 0
127
+ sz = opts[:minimum] || 7
128
+ u = opts[:unicode] || false
129
+ l = size
130
+ i = off
131
+ while i < l
132
+ if self[i].printable?
133
+ start = i
134
+ cnt = 1
135
+ i += 1
136
+ lastu = false
137
+ while i < l
138
+ if self[i].printable?
139
+ lastu = false
140
+ cnt += 1
141
+ i += 1
142
+ elsif u and self[i] == 0 and not lastu
143
+ lastu = true
144
+ i += 1
145
+ else
146
+ break
147
+ end
148
+ end
149
+
150
+ return([start, i - start]) if cnt >= sz
151
+ else
152
+ i += 1
153
+ end
154
+ end
155
+
156
+ return false, false
157
+ end
158
+
159
+ # A la Unix strings(1). With a block, yields offset, string length,
160
+ # and contents. Otherwise returns a list. Accepts options:
161
+ # :unicode: superficial but effective Win32 Unicode support, skips NULs
162
+ # :minimum: minimum length of returned strings, ala strings -10
163
+ def strings(opts={})
164
+ ret = []
165
+ opts[:offset] ||= 0
166
+ while 1
167
+ off, size = nextstring(opts)
168
+ break if not off
169
+ opts[:offset] += (off + size)
170
+ if block_given?
171
+ yield off, size, self[off,size]
172
+ else
173
+ ret << [off, size, self[off,size]]
174
+ end
175
+ end
176
+ ret
177
+ end
178
+
179
+ # A hacked up adler16 checksum, a la Andrew Tridgell. This is probably
180
+ # even slower than Ruby's native CRC support. A weak, trivial checksum,
181
+ # part of rsync.
182
+ def adler
183
+ a, b = 0, 0
184
+ 0.upto(size-1) {|i| a += self[i]}
185
+ a %= 65536
186
+ 0.upto(size-1) {|i| b += ((size-i)+1) * self[i]}
187
+ b %= 65536
188
+ return (a|(b<<16))
189
+ end
190
+
191
+ # Convert binary strings back to integers
192
+ def to_l32; unpack("L").first; end
193
+ def to_b32; unpack("N").first; end
194
+ def to_l16; unpack("v").first; end
195
+ def to_b16; unpack("n").first; end
196
+ def to_u8; self[0]; end
197
+ def shift_l32; shift(4).to_l32; end
198
+ def shift_b32; shift(4).to_b32; end
199
+ def shift_l16; shift(2).to_l16; end
200
+ def shift_b16; shift(2).to_b16; end
201
+ def shift_u8; shift(1).to_u8; end
202
+
203
+ # oh, it's exactly what it sounds like.
204
+ def method_name
205
+ r = ""
206
+ scoped = false
207
+ each_byte do |c|
208
+ if c == 58
209
+ if not scoped
210
+ r << "_"
211
+ scoped = true
212
+ else
213
+ scoped = false
214
+ end
215
+ else
216
+ if r.size == 0
217
+ r << c.chr.downcase
218
+ else
219
+ if c.upper?
220
+ r << "_"
221
+ r << c.chr.downcase
222
+ else
223
+ r << c.chr
224
+ end
225
+ end
226
+ end
227
+ end
228
+ return r
229
+ end
230
+
231
+ # I love you String#ljust
232
+ def pad(size, char="\x00")
233
+ ljust(size, char)
234
+ end
235
+
236
+ # Convert a string into hex characters
237
+ def hexify
238
+ l = []
239
+ each_byte{|b| l << "%02x" % b}
240
+ l.join
241
+ end
242
+
243
+ # convert a string to hex characters in place
244
+ def hexify!
245
+ self.replace hexify
246
+ end
247
+
248
+
249
+ # Convert a string of raw hex characters (no %'s or anything) into binary
250
+ def dehexify
251
+ (ret||="") << (me||=clone).shift(2).to_i(16).chr while not (me||=clone).empty?
252
+ return ret
253
+ end
254
+
255
+ # Convert a string of raw hex characters (no %'s or anything) into binary in place
256
+ def dehexify!
257
+ (ret||="") << (me||=clone).shift(2).to_i(16).chr while not (me||=clone).empty?
258
+ self.replace ret
259
+ end
260
+
261
+ # OR two strings together. Slow. Handles mismatched lengths by zero-extending
262
+ def or(str)
263
+ max = size < str.size ? str.size : size
264
+ ret = ""
265
+ 0.upto(max-1) do |i|
266
+ x = self[i] || 0
267
+ y = str[i] || 0
268
+ ret << (x | y).chr
269
+ end
270
+ return ret
271
+ end
272
+
273
+ # XOR two strings. wrapping around if str is shorter thn self.
274
+ def xor(str)
275
+ r = []
276
+ size.times do |i|
277
+ r << (self[i] ^ str[i % str.size]).chr
278
+ end
279
+ return r.join
280
+ end
281
+
282
+ def xor!(str)
283
+ size.times do |i|
284
+ self[i] ^= str[i % str.size]
285
+ end
286
+ end
287
+
288
+ # byte rotation cypher (yes it's been useful)
289
+ def rotate_bytes(k=0)
290
+ # XXX not used
291
+ r = []
292
+ each_byte do |b|
293
+ r << ((b + k) % 256).chr
294
+ end
295
+ return r.join
296
+ end
297
+
298
+ # Insanely useful shorthand: pop bytes off the front of a string
299
+ def shift(count=1)
300
+ return self if count == 0
301
+ slice! 0..(count-1)
302
+ end
303
+
304
+ def underscore
305
+ first = false
306
+ gsub(/[a-z0-9][A-Z]/) do |m|
307
+ "#{ m[0].chr }_#{ m[1].chr.downcase }"
308
+ end
309
+ end
310
+
311
+ # "foo: bar".shift_tok /:\s*/ => "foo" # leaving "bar"
312
+ def shift_tok(rx)
313
+ # XXX not used
314
+ src = rx.source if rx.kind_of? Regexp
315
+ rx = Regexp.new "(#{ src })"
316
+ idx = (self =~ rx)
317
+ if idx
318
+ ret = shift(idx)
319
+ shift($1.size)
320
+ return ret
321
+ else
322
+ shift(self.size)
323
+ end
324
+ end
325
+ end
326
+ include StringExtensions
327
+ end
@@ -0,0 +1,16 @@
1
+ module Ruckus
2
+ class Filter < Parsel
3
+ def initialize(val, &block)
4
+ raise "need a block" if not block_given?
5
+ val = val.clone
6
+ val.parent = self
7
+ opts = { :value => val }
8
+ @block = block
9
+ super(opts)
10
+ end
11
+
12
+ def to_s
13
+ @block.call(@value.to_s)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,79 @@
1
+ ## Human display methods
2
+ # Here are various methods for ruckus base types to display human-readable
3
+ # data representations. No particular attempt is made at efficiency. These
4
+ # are for dissectors, analysis, debugging, etc...
5
+
6
+ module Ruckus
7
+ Blob.class_eval do
8
+ def to_human(indent=nil)
9
+ indent ||= ""
10
+ vals = []
11
+ vals << "#{indent}#{name.to_s} = " if @name
12
+ indent += " "
13
+ vals += @value.map do |it|
14
+ if it.respond_to?(:format) and it.format.kind_of? Proc
15
+ "#{indent}#{it.name} = #{it.format.call(it)}"
16
+ elsif it.respond_to?(:to_human)
17
+ it.to_human(indent)
18
+ else
19
+ "#{indent}#{it.name} = #{it.value}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+ Structure.class_eval do
27
+ def to_human(indent=nil)
28
+ "#{ indent || '' }#{self.class}".to_a + super(indent)
29
+ end
30
+ end
31
+
32
+
33
+ IP.class_eval do
34
+ def to_human(indent=nil)
35
+ s = to_s
36
+ "#{ indent || '' }#{name.to_s} = #{s[0]}.#{s[1]}.#{s[2]}.#{s[3]}"
37
+ end
38
+ end
39
+
40
+
41
+ Choice.class_eval do
42
+ def to_human(indent=nil)
43
+ indent ||= ''
44
+ head = "#{indent}#{name.to_s} = "
45
+ if (val=@value.to_human(indent)).kind_of?(Array) and @name
46
+ val.unshift head
47
+ else
48
+ head + val.to_s.strip
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ Str.class_eval do
55
+ def to_human(indent=nil)
56
+ "#{ indent || '' }#{@name} = " +
57
+ (@value.empty? ? "<empty>" : "\n%%\n#{@value.hexdump(:out => StringIO.new)}%%\n")
58
+ end
59
+ end
60
+
61
+
62
+ Number.class_eval do
63
+ def to_human(indent=nil)
64
+ if self.value.kind_of?(Numeric) then
65
+ "#{ indent ||'' }#{@name} = %d (0x%x)" %[ self.value, self.value ]
66
+ else
67
+ "#{ indent ||'' }#{@name} = #{self.value}"
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ Null.class_eval do
74
+ def to_human(indent=nil)
75
+ "#{ indent || '' }#{@name} = <nil>"
76
+ end
77
+ end
78
+ end
79
+
@@ -0,0 +1,38 @@
1
+ # === IP addresses are integers with special assignment
2
+ # You can use a Ruckus::Number as an IP address (or an IPv6
3
+ # address, if you make it 128 bits wide), but Ruckus::IP
4
+ # converts from dotted-quad strings (and, I guess if I wanted,
5
+ # DNS hostnames)
6
+ #
7
+ module Ruckus
8
+ class IP < Parsel
9
+ def initialize(opts={})
10
+ opts[:value] ||= 0
11
+ super(opts)
12
+ end
13
+
14
+ def to_s(off=nil)
15
+ @rendered_offset = off || 0
16
+
17
+ val = resolve(@value)
18
+ val = IPAddr.inet_addr(val) if val.kind_of? String
19
+ r = [val].pack("I")
20
+ r = r.reverse if self.class.endian? == :little
21
+
22
+ if off
23
+ return r, off + 4
24
+ else
25
+ return r
26
+ end
27
+ end
28
+
29
+ def capture(str)
30
+ cap = str.shift 4
31
+ sel = self.class.endian? == :little ? :reverse : :to_s
32
+ @value = cap.send(sel).unpack("I").first
33
+ return str
34
+ end
35
+
36
+ def size; 4; end
37
+ end
38
+ end