[or-cvs] r11044: fixed permutation bugs and added new general and control stu (in topf/trunk: . lib lib/fuzz-struct)

benedikt at seul.org benedikt at seul.org
Sat Aug 4 11:54:44 UTC 2007


Author: benedikt
Date: 2007-08-04 07:54:43 -0400 (Sat, 04 Aug 2007)
New Revision: 11044

Added:
   topf/trunk/LICENSE
   topf/trunk/lib/state_pattern.rb
Removed:
   topf/trunk/control.rb
   topf/trunk/lib/fuzz-test.rb
Modified:
   topf/trunk/TODO
   topf/trunk/config.yml
   topf/trunk/lib/control.rb
   topf/trunk/lib/dir.rb
   topf/trunk/lib/fuzz-generic.rb
   topf/trunk/lib/fuzz-struct/fuzz-struct.rb
   topf/trunk/lib/fuzz.rb
   topf/trunk/lib/topf.rb
   topf/trunk/tor-control-fuzz.rb
   topf/trunk/tor-dir-fuzz.rb
Log:
fixed permutation bugs and added new general and control stuff

Added: topf/trunk/LICENSE
===================================================================
--- topf/trunk/LICENSE	                        (rev 0)
+++ topf/trunk/LICENSE	2007-08-04 11:54:43 UTC (rev 11044)
@@ -0,0 +1,49 @@
+                    This file contains the license for Tor,
+        a free software project to provide anonymity on the Internet.
+
+        It also lists the licenses for other components used by Tor.
+
+       For more information about Tor, see http://www.torproject.org/.
+
+             If you got this file as a part of a larger bundle,
+        there may be other license terms that you should be aware of.
+
+
+===============================================================================
+Tor is distributed under this license:
+
+Copyright (c) 2001-2004, Roger Dingledine
+Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+    * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
+If you got Tor as a static binary with OpenSSL included, then you should know:
+ "This product includes software developed by the OpenSSL Project
+ for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+===============================================================================

Modified: topf/trunk/TODO
===================================================================
--- topf/trunk/TODO	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/TODO	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,7 +1,9 @@
+- FIX BitStruct Rest-Field problem
+
 - Fix pkcs1 signature
 - add more tests
 - implement other tor protocols 
-- calculate all possible permutations instead of random probing
+- calculate all possible permutations instead of random probing => DONE
 - implement fancy web frontend
 - easy to install and setup testing network
 - distributed testing

Modified: topf/trunk/config.yml
===================================================================
--- topf/trunk/config.yml	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/config.yml	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,3 +1,8 @@
+
+############################################################
+# This file holds information about our running tor-service
+############################################################
+
 DIRPORT: "2324"
 CONTROLPORT: "2323"
 HOST: "127.0.0.1" 
@@ -2 +7,2 @@
 KEYFILE: stuff/fuzz-private.pem
+DEBUG: true 

Deleted: topf/trunk/control.rb
===================================================================

Modified: topf/trunk/lib/control.rb
===================================================================
--- topf/trunk/lib/control.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/control.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,8 +1,96 @@
 module TOPF
     module Control
-        class ConfItem < BitStruct
-            text :item, 7 
-            text :keyword, 10
+        class ItemFuzz
+            attr_reader :item
+            def initialize(item, fields, values)
+                raise "item is not a BitStruct" if !item.is_a?(BitStruct)
+                @item = item
+                @fields = fields
+                @values = values
+                @count = 0
+            end
+
+            def set_next
+                @fields.each_with_index do |field, index|
+                    method = field.to_s + "="
+                    value = @values[@count][index]
+                    raise "item has no method #{field}" if !@item.methods.include?(method)
+                    @item.send(method, value )
+                end
+                @count += 1
+            end
+            
+            def prepare!
+                @item.prepare!
+            end
+
+            def fuzz!
+                @item.fuzz!
+            end
+
+        end
+
+        SETCONF_KEYS = [
+            [ "version", "Tor 0.0.9.4" ],
+            [ "config-file", "PATH TO CONFIFILE" ],
+            [ "exit-policy/prepend", "NOT IMPLEMENTED"],
+            [ "exit-policy/default", ""],
+            [ "desc/id/", "or identity" ],
+            [ "desc/name", "or nickname" ],
+            [ "exit-policy/default", "" ],
+            [ "ns/id/", "or identity"], 
+            [ "ns/name/", "or nickname" ],
+            [ "ns/all", "" ],
+            [ "desc/all-recent", "" ],
+            [ "network-status", "" ],
+            [ "address-mappings/all", "" ],
+            [ "address-mappings/config", "" ],
+            [ "address-mappings/cache", "" ],
+            [ "address-mappings/control", "" ]
+            [ "addr-mappings/*", "" ]
+            [ "address", "127.0.0.1" ] 
+            [ "fingerprint", "contents of fingerprint file" ]
+            [ "circuit-status", "" ]
+=begin
+                                                  A series of lines as for a circuit status event. Each line is of
+                                                  the form:
+                                                     CircuitID SP CircStatus [SP Path] CRLF
+
+                                                "stream-status"
+                                                  A series of lines as for a stream status event.  Each is of the form:
+                                                     StreamID SP StreamStatus SP CircID SP Target CRLF
+
+                                                "orconn-status"
+                                                  A series of lines as for an OR connection status event.  Each is of the
+                                                  form:
+                                                     ServerID SP ORStatus CRLF
+
+                                                "entry-guards"
+                                                  A series of lines listing the currently chosen entry guards, if any.
+                                                  Each is of the form:
+                                                     ServerID  SP (Status-with-time / Status) CRLF
+
+                                                     Status-with-time = ("down" / "unlisted") SP ISOTime
+                                                     Status = ("up" / "never-connected")
+
+                                                  [From 0.1.1.4-alpha to 0.1.1.10-alpha, this was called "helper-nodes".
+                                                   Tor still supports calling it that for now, but support will be
+                                                   removed in 0.1.3.x.]
+
+                                                "accounting/enabled"
+                                                "accounting/hibernating"
+                                                "accounting/bytes"
+                                                "accounting/bytes-left"
+                                                "accounting/interval-start"
+                                                "accounting/interval-wake"
+                                                "accounting/interval-end"
+
+=end
+        ]
+
+        class SetConfItem < BitStruct
+            text :item, 7, :fuzzable => true 
+            text :keyword, 30, :fuzzable => false
             text :assign, 1
             rest :value
 
@@ -10,6 +98,13 @@
             initial_value.assign = "="
         end
 
+        SETCONF_REPLYS = [
+            "250 configuration values set",
+            "552 Unrecognized option",
+            "513 syntax error in configuration values",
+            "553 impossible configuration setting"
+        ]
+
         class ResetConfItem < BitStruct
             text :item, 9
             text :keyword, 10
@@ -30,12 +125,95 @@
             initial_value.assign    = "="
         end
 
+        SETEVENTS_REPLYS = [
+            "250 OK",
+            "552 Unrecognized event"
+        ] 
+
+        SETEVENTS_CODES = [
+            "CIRC",
+            "STREAM",
+            "ORCONN",
+            "BW", 
+            "DEBUG",
+            "INFO",
+            "NOTICE", 
+            "WARN", 
+            "ERR", 
+            "NEWDESC", 
+            "ADDRMAP",
+            "AUTHDIR_NEWDESCS", 
+            "DESCCHANGED", 
+            "STATUS_GENERAL",
+            "STATUS_CLIENT",
+            "STATUS_SERVER", 
+            "GUARD",
+            "NS",
+            "STREAM_BW"
+        ]
+
+        class SetEventsItem < BitStruct
+            text :item, 9
+            text :extended, 8 
+            
+            rest :events
+
+            initial_value.item = "SETEVENTS"
+            initial_value.extended = " "*8
+        end
+
+        AUTHENTICATE_REPLYS = [
+            "250 OK",
+            "515 Bad authentication",
+            "514 authentication required"
+        ]
+
         class AuthenticateItem < BitStruct
-            text :item, 12
+            text :item, 13
+            text :password, 8 
             rest :crlf
 
-            initial_value.item      = "AUTHENTICATE"
-            initial_value.crlf      = "\n"
+            initial_value.item      = "AUTHENTICATE "
+            initial_value.password  = "\"foobar\""
+            initial_value.crlf      = " \r\n"
         end
+
+        SAVECONF_REPLYS = [
+            "250 OK",
+            "551 Unable to write configuration to disk"
+        ]
+
+        class SaveConfItem < BitStruct
+            text :item, 8 
+            initial_value.item = "SAVECONF"
+        end
+
+        SIGNAL_ITEMS = [
+             "RELOAD", 
+             "SHUTDOWN", 
+             "DUMP", 
+             "DEBUG", 
+             "HALT", 
+             "HUP", 
+             "INT", 
+             "USR1", 
+             "USR2", 
+             "TERM", 
+             "NEWNYM", 
+             "CLEARDNSCACHE"
+        ]
+
+        class SignalItem < BitStruct
+            text :item, 6
+            rest :signal
+
+            initial_value.item = "SIGNAL" 
+        end
+
+        class Collection < Fuzz::Collection
+        end
+        begin
+            COLLECTION = Collection.new
+        end
     end
 end 

Modified: topf/trunk/lib/dir.rb
===================================================================
--- topf/trunk/lib/dir.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/dir.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -138,7 +138,7 @@
         end
 
         class RouterDescriptor
-            def initialize(publicKey, host = "127.0.0.1", port = 80) 
+            def initialize(publicKey) 
                 @osslkey = OpenSSL::PKey::RSA.new(File.read(publicKey) )
                 @pkcs1 = PKCS1::SignatureScheme::RSASSAPKCS1v1_5.new(Digest::SHA1)
 
@@ -150,21 +150,26 @@
                             SigningKeyItem.new, 
                             BandwidthItem.new,  
                     ]
-
-                @host = host
-                @port = port
-
-                connect!
+                @prepared = false
             end
 
-            def connect!
-            end
-
             def add_item( item )
                 @items.push item
             end
 
+            def prepare_for_test
+                @items.each do |item|
+                    Fuzz::DEFAULT_TESTS.set_struct item
+                    Fuzz::DEFAULT_TESTS.generate_test_data
+                end
+            end
+
             def fuzz!
+                if !@prepared 
+                    prepare_for_test
+                    @prepared = true
+                end
+
                 @items.each do |item|
                     item.fuzz!
                 end
@@ -185,4 +190,3 @@
         end
     end
 end
-

Modified: topf/trunk/lib/fuzz-generic.rb
===================================================================
--- topf/trunk/lib/fuzz-generic.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-generic.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -2,5 +2,7 @@
 $:.unshift(File.dirname(dir)) unless
 $:.include?(File.dirname(dir)) || $:.include?(File.expand_path(File.dirname(dir)))
 
+require "timeout"
 require "fuzz-struct"
 require "fuzz"
+require "logger"

Modified: topf/trunk/lib/fuzz-struct/fuzz-struct.rb
===================================================================
--- topf/trunk/lib/fuzz-struct/fuzz-struct.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-struct/fuzz-struct.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -145,7 +145,7 @@
     #
     # ------------------------
 
-    # Return the list of fields for this class.
+    # Return the list of fields for this class including the rest field.
     def fields
       @fields ||= self == BitStruct ? [] : superclass.fields.dup
     end
@@ -228,7 +228,8 @@
     
     # Length, in bits, of this object.
     def bit_length
-      @bit_length ||= fields.inject(0) {|a, f| a + f.length}
+      @bit_length ||= fields.inject(0) {|a, f| 
+          a + f.length}
     end
     
     # Length, in bytes (rounded up), of this object.
@@ -252,9 +253,9 @@
 
   end
   
-  # Return the list of fields for this class.
+  # Return the list of fields(including the rest field) for this class.
   def fields
-    self.class.fields
+      [ self.class.fields, self.class.rest_field].flatten
   end
   
   # Return the field with the given name.
@@ -350,7 +351,14 @@
     
     self.class.closed!
     yield self if block_given?
-     
+    
+    # this is where our test_data goes
+    @tests = nil
+    # this is where we save our permutation indeces 
+    @permutations
+    @permutation_index = 0
+    # dimension of our permutation
+    @dimension = 0
   end
   
   DEFAULT_TO_H_OPTS = {
@@ -483,18 +491,89 @@
     opts[:format] % [self.class, body]
   end
 
+  def prepare!(tests)
+      # build our testdata...
+      raise "argument must be of class Tests" if !tests.is_a?(Fuzz::Tests)
+      result = []
+      self.fields.each do |field|
+          arg = self.method(field.name).call
+          if field.fuzzable
+              temp = []
+              length = field.length
+              case field.class.to_s
+              when "BitStruct::SignedField"
+                  tests.signed_tests.each do |test|
+                  temp.push( test.run(arg, length) )
+                  end
+              result.push(temp)
+              when "BitStruct::UnsignedField"
+                  tests.unsigned_tests.each do |test|
+                  temp.push( test.run(arg, length) )
+                  end
+              result.push(temp)
+              when "BitStruct::TextField", "BitStruct::CharField", "BitStruct::Field"
+                  tests.char_tests.each do |test|
+                      temp.push( test.run(arg, length) )
+                  end
+              result.push(temp)
+              else
+                  Fuzz::LOGGER.debug "new field-type: %s" % field.class.to_s
+              end
+          else
+              result.push( [ arg ] )
+          end
+      end
+      @tests = result
+       
+      # build our permutations...
+      sizes =  @tests.collect {|element| element.size}
+
+      @dimension = sizes.inject(1){|prod, element| prod*element }
+      
+      permutations = Array.new(sizes.size, Array.new(@dimension, 0) )
+
+      result = []
+      permutations.each_with_index do |element, index|
+          count = 0 
+          temp  = 0 
+
+          tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}-1
+          result.push element.collect{|entry|
+              if count == tempdimension
+                  temp+= 1 
+                  temp = 0 if temp == (sizes[index])
+                  count = -1
+              end
+              count+=1
+              temp
+          }
+      end
+
+      Fuzz::LOGGER.debug "[x] calculated %d permutations of struct %s" % [result.first.size, self.class]
+      @permutations = result
+=begin
+# debugging stuff
+      @permutations[0].each_with_index do |element, index|
+          pp @permutations.collect{|el| el[index] }
+      end
+=end
+      @permutation_index = 0
+  end
+
   def fuzz!(opts = DEFAULT_INSPECT_OPTS)
-    field_format = opts[:field_format]
-    field_name_meth = opts[:field_name_meth]
-    
-    fields_for_inspect = fields.select {|field| field.inspectable?}
-    if opts[:include_rest] and (rest_field = self.class.rest_field)
-      fields_for_inspect << rest_field
-    end
-    
-    fields_for_inspect.map do |field|
-        field.fuzz(self, opts)
-    end
+      raise "no tests have been generated yet" if !@permutations or !@tests
+      raise "end of tests" if @permutation_index.to_i == @dimension.to_i
+      test = []
+      perm = @permutations.collect{|element| element[@permutation_index] }
+      @permutation_index += 1
+
+      tempcount = 0
+      ret = @tests.collect{ |element|
+          result = element[ perm[tempcount] ]
+          tempcount+=1
+          result
+      }
+      ret
   end
 
   def format(opts = DEFAULT_INSPECT_OPTS)

Deleted: topf/trunk/lib/fuzz-test.rb
===================================================================
--- topf/trunk/lib/fuzz-test.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz-test.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,17 +0,0 @@
-# This file includes a default test-case object
-#
-# test template
-# default_tests.register Fuzz::Test.new("") {|arg|    }
-
-default_tests = Tests.new
-# Tests for character fields aka strings
-default_tests.register Fuzz::Test.new("char") {|arg, size|  arg     } # Return string
-default_tests.register Fuzz::Test.new("char") {|arg, size|  ""      } # Return empty String 
-default_tests.register Fuzz::Test.new("char") {|arg, size|  "A"*Fuzz::MAX_RAND    } # LONG STRING
-default_tests.register Fuzz::Test.new("char") {|arg, size|  "%n"*Fuzz::MAX_RAND   } # FORMAT STRING
-
-# Tests for signed numbers
-default_tests.register Fuzz::Test.new("signed") {|arg, size|  rand(5) } # return a small number 
-default_tests.register Fuzz::Test.new("signed") {|arg, size|  -1      } # return -1 
-default_tests.register Fuzz::Test.new("signed") {|arg, size|  (2.power!(size)/2)-1      } # biggest  2s complement number 
-default_tests.register Fuzz::Test.new("signed") {|arg, size|  -(2.power!(size)/2)       } # smallest 2s complement number 

Modified: topf/trunk/lib/fuzz.rb
===================================================================
--- topf/trunk/lib/fuzz.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/fuzz.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,11 +1,64 @@
 module Fuzz
     MAX_RAND = 1000
-    MAX_STRING_PERMUTATIONS = 3 
 
+    class Collection
+        def initialize
+            @structs = []
+        end
+        def add(struct)
+            raise "argument must be a Fuzz::Test object" if !struct.is_a?(BitStruct)
+            @structs.push struct
+        end
+        # fuzzes only one struct at the time
+        def linear_fuzz
+            @structs.each do |struct|
+                
+            end
+        end
+        # joins all structs together but only fuzzes one struct after another
+        def join_fuzz
+        end
+    end
+
+    class Observer
+        def initialize
+        end
+    end
+
+    class BinaryObserver < Observer
+        def initialize( programname, *arguments )
+            @programname = programname
+            @arguments = arguments.to_a
+            @pid = nil
+        end
+        def observe!
+            Process.fork do 
+                @pid = Process.fork do
+                    exec("#{@programname} #{@arguments.join(" ")} ")
+                end
+                Process.wait
+                process_status = $?
+                #            Fuzz::LOGGER.debug "[!] %d coredumped? %s" % [@pid, process_status.coredump?]
+                #            Fuzz::LOGGER.debug "[!] %d get uncaught signal %d" % [@pid, process_status.termsig] if process_status.signaled?
+                #            Fuzz::LOGGER.debug "[!] %d stopped by signal %d" % [@pid, process_status.stopsig] if process_status.stopped?
+                #            Fuzz::LOGGER.debug "[!] %d exited %d" % [@pid, process_status.exitstatus] if process_status.exited?
+            end
+        end
+        def get_pid
+            @pid
+        end
+        def exit
+           Process.kill "KILL", @pid 
+        end
+    end
+
+    class ProcessObserver < Observer
+    end
+
     # This Class holds all tests to related to a given field-type
     class Tests
-        attr_reader :tests, :permutations
-        def initialize(struct)
+        attr_reader :tests, :permutations, :signed_tests, :char_tests, :unsigned_tests
+        def initialize(struct=nil)
             @char_tests      = []
             @unsigned_tests  = []
             @signed_tests    = []
@@ -14,7 +67,10 @@
             @tests           = []
             @struct          = struct
             @count           = 0
+            @dimension       = nil
         end
+
+        # register a new test to a given type
         def register(test)
             raise "argument must be a Fuzz::Test object" if !test.is_a?(Fuzz::Test)
             case test.type
@@ -28,14 +84,20 @@
                     @octet_tests.push test
             end
         end
-        def generate_test
-            generate_test_data
+        
+        # generate all possible permutations
+        def generate_test_data
+            Fuzz::LOGGER.debug "[x] generating %d char %d unsigned %d signed tests" % [@char_tests.size, @unsigned_tests.size, @signed_tests.size]
+
+            generate_test_data!
             permutate
             @count = 0
         end
 
-        def get_test
+        # get the next permutation
+        def get_permutation
             raise "no tests have been generated yet" if !@permutations or !@tests
+            raise "end of tests" if @count.to_i == @dimension.to_i
             test = []
             perm = @permutations.collect{|element| element[@count] }
             tempcount = 0
@@ -45,10 +107,26 @@
                 tempcount+=1
                 result
             }
+        end
 
+        def get_all
         end
+
+        def set_struct(struct)
+            raise "argument not a bitstruct!" if !struct.is_a?(BitStruct)
+            @struct = struct
+            generate_test_data!
+            permutate!
+        end
+
+        # debug function...
+        def show_permutation_indices
+            @permutations[0].each_with_index do |element, index|
+                pp @permutations.collect{|el| el[index] }
+            end
+        end
     private
-        def generate_test_data
+        def generate_test_data!
             result = []
             raise "argument must be a BitStruct object" if !@struct.is_a?(BitStruct)
             @struct.fields.each do |field|
@@ -71,20 +149,23 @@
                         temp.push( test.run(arg, length) )
                     end
                     result.push(temp)
+                else
+                    Fuzz::LOGGER.debug "new field-type: %s" % field.class.to_s
                 end
             end
             @tests = result
         end
-        def permutate
+    
+        def permutate!
             raise "tests have not been generated yet" if !@tests
 
             sizes =  @tests.collect {|element| element.size}
-            dimension = sizes.inject(1){|prod, element| prod*element }
-            permutations = Array.new(sizes.size, Array.new(dimension, 1) )
+            @dimension = sizes.inject(1){|prod, element| prod*element }
+            permutations = Array.new(sizes.size, Array.new(@dimension+1, 0) )
             result = []
             permutations.each_with_index do |element, index|
                 count = 0 
-                temp  = 1
+                temp  = 0 
                 tempdimension = sizes[(index+1)..-1].inject(1){|prod, el| prod*el}
                 result.push element.collect{|entry|
                     if count == tempdimension
@@ -97,9 +178,9 @@
                     temp  
                 }
             end
+            Fuzz::LOGGER.debug "[x] calculated %d permutations of struct %s" % [result.first.size, self.class]
             @permutations = result
         end
-
     end
 
     # This Class holds our test which is a ruby-block that must be able to process one argument
@@ -125,93 +206,7 @@
                 @test.call arg, size
         end
     end
-    # sample test-case
-    # Fuzz::Test.new("char") {|arg| arg.insert( rand(arg.size), "A"*rand(1024) ) } 
-
-    def Fuzz.fuzzField(type, length, value)
-        case type.to_s
-            when "BitStruct::CharField"
-                return Fuzz::fuzzString(value, length )
-            when "BitStruct::UnsignedField"
-                return Fuzz::fuzzUnsignedNumber(length.to_i)
-            when "BitStruct::SignedField"
-                return Fuzz::fuzzSignedNumber(length.to_i)
-            when "BitStruct::OctetField"
-                return value.split(".").collect{ |octet| Fuzz::fuzzString(octet, 2) }.join( "." )
-            else
-                if value.class.to_s == "String"
-                    return Fuzz::fuzzString(value, length/8 )
-                else
-                    return value
-                end
-        end
-    end
-
-    def Fuzz.fuzzString(string, length)
-        if Fuzz::MAX_STRING_PERMUTATIONS > 0
-            rand( Fuzz::MAX_STRING_PERMUTATIONS ).times do |i|
-                case rand(5)
-                when 0 
-                    string.insert( rand(string.size), "A"*rand( length ))
-                when 1
-                    string.insert( rand(string.size), "%n"*rand( length ))
-                when 2
-                    string.insert( rand(string.size), Fuzz::randCharacter( string[rand(string.size)] )*rand( length ))
-                when 3
-                    rand(5) == 0 ? string = "" : nil
-                end
-            end
-        end
-        string.gsub(/\\+/, "\\")
-    end
-
-    def Fuzz.randCharacter(default)
-        case rand(9)
-        when 0
-            return '\0'
-        when 1
-            return 0x0.chr
-        when 2
-            return ']'
-        when 3
-            return ')'
-        when 4
-            return '}'
-        when 5
-            return '>'
-        when 6
-            return '\n'
-        when 7
-            return '\''
-        when 8
-            return '\"'
-        else 
-            return default
-        end
-    end
-
-    def Fuzz.fuzzSignedNumber(bits)
-        case rand(3)
-            when 0
-                rand(5).to_i   # small numbers
-            when 1
-                return -1.to_i
-            when 2
-                return (2.power!(bits)-1)/2 #biggest 2s complement number
-            when 3
-                return -(2.power!(bits))/2  #smallest 2s complement number     
-        end
-    end
-
-    def Fuzz.fuzzUnsignedNumber(bits)
-        case rand(1)
-        when 0
-            rand(5).to_i # small numbers
-        when 1
-            return 2.power!(bits)-1       #biggest number
-        end
-    end
-
+   
     def Fuzz.coreObserver(file)
         if Dir.new(File.expand_path(File.dirname(file)) ).entries.select{|x| x=~/\.core/}.size != 0
             return true
@@ -222,7 +217,7 @@
 
     # makes a Connection to a given target and sends our raw data to it
     # see yourself what options are needed :>
-    class Host
+    class Connection
         def initialize(args)
             @type = args[:type]
             @host = args[:host]
@@ -231,14 +226,13 @@
             @http_direction = args[:http_direction]
             @http_url       = args[:http_url]
             @object         = args[:object]
+            args[:timeout] ? @timeout = args[:timeout] : @timeout = 0.2
 
-            @socket = connect 
+            Fuzz::LOGGER.level = Logger::INFO if !args[:debug]
+
+            @socket = connect
         end
 
-        def fuzz
-            send @object.to_s
-        end
-        
         def send( data )
             case @type
                 when :http
@@ -252,8 +246,34 @@
                     @socket.write data
             end
         end
-        
-        def stop
+
+        def fuzz!(struct, join_character="", args={})
+            begin
+                while true
+                    data = struct.fuzz!.join( join_character )
+                    Fuzz::LOGGER.debug "sending data: %s" % data
+                    self.send data
+                    assert(args[:assert] )
+                end
+            rescue Exception
+                puts "[!] ERROR: %s" % $!
+            end
+        end
+
+        # receives data from the socket and tests it against a supplied array of strings, values 
+        def assert(reply = [])
+            begin
+                timeout(@timeout) do 
+                    reply_data = @socket.readline()
+                    raise "ASSERTION %s FAILED" % reply.join(",") if !reply.include?(reply_data.strip)
+                    Fuzz::LOGGER.debug "reply: %s" % reply_data
+                end
+            rescue Exception
+                Fuzz::LOGGER.debug "[!] Exception: %s" % $!
+            end
+        end
+
+        def close
             @socket.close
         end
 private
@@ -270,13 +290,39 @@
                         raise "not implemented yet"
                 end 
             rescue Exception
-                puts "Exception: " + $!
-                raise
+                Fuzz::LOGGER.debug "[!] Exception: %s" % $!
+                exit 0
             end         
         end        
+    end
+
+    begin
+        DEFAULT_TESTS = Tests.new
+        # Tests for character fields aka strings
+        DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  arg     } # Return string
+        DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  ""      } # Return empty String 
+        DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  "A"*arg.size    } # FAULTING ARGUMENT STRING
+        DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  "A"*Fuzz::MAX_RAND    } # LONG STRING
+        DEFAULT_TESTS.register Fuzz::Test.new("char") {|arg, size|  "%n"*Fuzz::MAX_RAND   } # FORMAT STRING
+
+        # Tests for signed numbers
+        DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size|  0 } # return zero 
+        DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size|  rand(5) } # return a small number 
+        DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size|  -1      } # return -1 
+        DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size|  (2.power!(size)/2)-1      } # biggest  2s complement number 
+        DEFAULT_TESTS.register Fuzz::Test.new("signed") {|arg, size|  -(2.power!(size)/2)       } # smallest 2s complement number
+        
+        # Tests for unsigned numbers
+        DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size|  0 } # return zero 
+        DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size|  rand(5) } # return a small number 
+        DEFAULT_TESTS.register Fuzz::Test.new("unsigned") {|arg, size|  2.power!(bits) } # return biggest number 
+
+        DEBUG_TESTS = Tests.new
+        DEBUG_TESTS.register Fuzz::Test.new("char") {|arg, size|  arg     } # Return string
+        DEBUG_TESTS.register Fuzz::Test.new("char") {|arg, size|  ""      } # Return empty String 
+
+        # debugging output
+        LOGGER = Logger.new(STDOUT)
+        LOGGER.level = Logger::DEBUG
     end 
 end
-
-begin
-    
-end 

Added: topf/trunk/lib/state_pattern.rb
===================================================================
--- topf/trunk/lib/state_pattern.rb	                        (rev 0)
+++ topf/trunk/lib/state_pattern.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -0,0 +1,110 @@
+#! /usr/bin/ruby
+
+#   Copyright (C) 2006 Maurice Codik - maurice.codik at gmail.com
+#
+#   Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+#   associated documentation files (the "Software"), to deal in the Software without restriction,
+#   including without limitation the rights to use, copy, modify, merge, publish, distribute,
+#   sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+#   furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included in all copies or substantial
+#   portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+#   LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+#   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+#   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# an example:
+#
+# class Connection
+#   include StatePattern
+#   state :initial do # you always need a state named initial. this is where you begin.
+#     def connect
+#       puts "connected"
+#    # move to state :connected. all other args to transition_to are passed to the new state's constructor
+#       transition_to :connected, "hello from initial state" 
+#     end
+#     def disconnect
+#       puts "not connected yet"
+#     end
+#   end
+#   state :connected do
+#     def initialize(msg)
+#       puts "initialize got msg: #{msg}"
+#     end
+#     def connect
+#       puts "already connected"
+#     end
+#     def disconnect
+#       puts "disconnecting"
+#       transition_to :initial
+#     end
+#   end
+#   def reset
+#     puts "reseting outside a state"
+#     # you can also change the state from outside of the state objects
+#     transition_to :initial
+#   end
+# end
+
+# how's it work:
+# Each call to state defines a new subclass of Connection that is stored in a hash. 
+# Then, a call to transition_to instantiates one of these subclasses and sets it to the be the active state.
+# Method calls to Connection are delegated to the active state object via method_missing. 
+
+module StatePattern
+  class UnknownStateException < Exception
+  end
+  
+  def StatePattern.included(mod)
+    mod.extend StatePattern::ClassMethods
+  end
+  
+  module ClassMethods
+    attr_reader :state_classes
+    def state(state_name, &block)
+      @state_classes ||= {}
+      
+      new_klass = Class.new(self, &block)
+      new_klass.class_eval do
+        alias_method :__old_init, :initialize
+        def initialize(context, *args, &block)
+          @context = context
+          __old_init(*args, &block)
+        end
+      end
+      
+      @state_classes[state_name] = new_klass
+    end
+  end
+  
+  attr_accessor :current_state, :current_state_obj
+  
+  def transition_to(state_name, *args, &block)
+    new_context = @context || self
+    
+    klass = new_context.class.state_classes[state_name]
+    if klass
+      new_context.current_state = state_name
+      new_context.current_state_obj = klass.new(new_context, *args, &block)
+    else
+      raise UnknownStateException, "tried to transition to unknown state, #{state_name}"      
+    end
+  end
+  
+  def method_missing(method, *args, &block)
+    unless @current_state_obj
+      transition_to :initial
+    end
+    if @current_state_obj
+      @current_state_obj.send(method, *args, &block)
+    else
+      super
+    end
+  end
+  
+end

Modified: topf/trunk/lib/topf.rb
===================================================================
--- topf/trunk/lib/topf.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/lib/topf.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -2,9 +2,15 @@
 $:.unshift(File.dirname(dir)) unless
 $:.include?(File.dirname(dir)) || $:.include?(File.expand_path(File.dirname(dir)))
 
+require "pkcs1"
+require "base64"
+require "logger"
+require "yaml"
+require "net/http"
+require "timeout"
+
 require "fuzz-struct"
 require "fuzz"
-require "pkcs1"
-require "base64"
+
 require "dir"
 require "control"

Modified: topf/trunk/tor-control-fuzz.rb
===================================================================
--- topf/trunk/tor-control-fuzz.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/tor-control-fuzz.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,24 +1,50 @@
 require "lib/topf"
 
-require "net/http"
-require "base64"
-require "yaml"
+begin
+    Fuzz::LOGGER.debug "[x] starting tor"
+    observer = Fuzz::BinaryObserver.new "tor", "-f torrc", "&> /dev/null"
+    observer.observe!
+    
+    Fuzz::LOGGER.debug "[x] tor pid: %d" % observer.get_pid
+    sleep 1 
+    
+    Fuzz::LOGGER.debug "[x] loading options"
 
-begin
     config = YAML::load_file "config.yml"
 
-    setconf = TOPF::Control::ConfItem.new
-    setconf.keyword = "blah" 
-    setconf.value   = "test"
-
     options = {
-        :object => setconf,
         :host => config["HOST"], 
         :port => config["CONTROLPORT"],
-        :type => :tcp
+        :type => :tcp,
+        :debug => true
     }
 
-    fuzzer = Fuzz::Host.new( options )
-    fuzzer.send TOPF::Control::AuthenticateItem.new
-    fuzzer.fuzz
+    Fuzz::LOGGER.debug "[x] connecting to control port"
+    fuzzer = Fuzz::Connection.new( options )
+    
+    Fuzz::LOGGER.debug "[x] sending authentication"
+    auth = TOPF::Control::AuthenticateItem.new
+    
+    fuzzer.send auth 
+    fuzzer.assert ["250 OK"]
+    
+    setconf = TOPF::Control::SetConfItem.new
+
+    setconf.keyword = "blah" 
+    setconf.value   = "test"
+    setconf.prepare! Fuzz::DEBUG_TESTS
+    
+    Fuzz::LOGGER.debug "[x] start fuzzing #{setconf.class}"
+
+    fuzzer.fuzz! setconf, " ", { :append => "\r\n",
+                                 :assert => TOPF::Control::SETCONF_REPLYS }
+    fuzzer.close 
+
+    observer.exit
+rescue Exception => blah
+    Fuzz::LOGGER.debug "[!] ERROR: %s" % $!
+    Fuzz::LOGGER.debug "[!] \n%s" % blah.backtrace.join("\n")
+    Fuzz::LOGGER.debug "[!] closing everything down"
+    fuzzer.close if fuzzer
+    observer.exit if observer
 end

Modified: topf/trunk/tor-dir-fuzz.rb
===================================================================
--- topf/trunk/tor-dir-fuzz.rb	2007-08-03 07:57:41 UTC (rev 11043)
+++ topf/trunk/tor-dir-fuzz.rb	2007-08-04 11:54:43 UTC (rev 11044)
@@ -1,13 +1,9 @@
 require "lib/topf"
 
-require "net/http"
-require "base64"
-require "yaml"
-
 begin
     config = YAML::load_file "config.yml"
 
-    rd = TOPF::Dir::RouterDescriptor.new( config["KEYFILE"], config["HOST"], config["PORT"] )
+    rd = TOPF::Dir::RouterDescriptor.new( config["KEYFILE"])
     
     options = {
         :object => rd,
@@ -15,10 +11,11 @@
         :port   => config["DIRPORT"],
         :type   => :http,
         :http_direction => :post,
-        :http_url       => "/tor/" 
+        :http_url       => "/tor/",
+        :debug => config["DEBUG"] 
     }
 
-    fuzzer = Fuzz::Host.new( options )  
-    fuzzer.fuzz
+    fuzzer = Fuzz::Host.new( options ) 
+    fuzzer.fuzz!
     fuzzer.stop
 end



More information about the tor-commits mailing list