Class: Recog::Nizer
- Inherits:
-
Object
- Object
- Recog::Nizer
- Defined in:
- lib/recog/nizer.rb
Constant Summary collapse
- DEFAULT_OS_CERTAINTY =
Default certainty ratings where none are specified in the fingerprint itself
0.85
- DEFAULT_SERVICE_CERTAINTY =
Most frequent weights are 0.9, 1.0, and 0.5
0.85
- HOST_ATTRIBUTES =
Non-weighted host attributes that can be extracted from fingerprint matches
%W{ host.domain host.id host.ip host.mac host.name host.time hw.device hw.family hw.product hw.vendor }
- @@db_manager =
nil
Class Method Summary collapse
-
.best_os_match(matches) ⇒ Object
Consider an array of match outputs, choose the best result, taking into account the granularity of OS vs Version vs SP vs Language.
-
.best_service_match(matches) ⇒ Object
Consider an array of match outputs, choose the best result, taking into account the granularity of service.
-
.match(match_key, match_string) ⇒ Hash?
Locate a database that corresponds with the
match_key
and attempt to find a matching fingerprint, stopping at the first hit.
Class Method Details
.best_os_match(matches) ⇒ Object
Consider an array of match outputs, choose the best result, taking into account the granularity of OS vs Version vs SP vs Language. Only consider fields relevant to the host (OS, name, mac address, etc).
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/recog/nizer.rb', line 49 def self.best_os_match(matches) # The result hash we return to the caller result = {} # Certain attributes should be evaluated separately host_attrs = {} # Bucket matches into matched OS product names os_products = {} matches.each do |m| # Count how many times each host attribute value is asserted (HOST_ATTRIBUTES & m.keys).each do |ha| host_attrs[ha] ||= {} host_attrs[ha][m[ha]] ||= 0 host_attrs[ha][m[ha]] += 1 end next unless m.has_key?('os.product') # Group matches by OS product and normalize certainty cm = m.dup cm['os.certainty'] = ( m['os.certainty'] || DEFAULT_OS_CERTAINTY ).to_f os_products[ cm['os.product'] ] ||= [] os_products[ cm['os.product'] ] << cm end # # Select the best host attribute value by highest frequency # host_attrs.keys.each do |hk| ranked_attr = host_attrs[hk].keys.sort do |a,b| host_attrs[hk][b] <=> host_attrs[hk][a] end result[hk] = ranked_attr.first end # Unable to guess the OS without OS matches unless os_products.keys.length > 0 return result end # # Select the best operating system name by combined certainty of all # matches within an os.product group. Multiple weak matches can # outweigh a single strong match by design. # ranked_os = os_products.keys.sort do |a,b| os_products[b].map{ |r| r['os.certainty'] }.inject(:+) <=> os_products[a].map{ |r| r['os.certainty'] }.inject(:+) end # Within the best match group, try to fill in missing attributes os_name = ranked_os.first # Find the best match within the winning group ranked_os_matches = os_products[os_name].sort do |a,b| b['os.certainty'] <=> a['os.certainty'] end # Fill in missing result values in descending order of best match ranked_os_matches.each do |rm| rm.each_pair do |k,v| result[k] ||= v end end result end |
.best_service_match(matches) ⇒ Object
Consider an array of match outputs, choose the best result, taking into account the granularity of service. Only consider fields relevant to the service.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/recog/nizer.rb', line 125 def self.best_service_match(matches) # The result hash we return to the caller result = {} # Bucket matches into matched service product names service_products = {} matches.select{ |m| m.has_key?('service.product') }.each do |m| # Group matches by product and normalize certainty cm = m.dup cm['service.certainty'] = ( m['service.certainty'] || DEFAULT_SERVICE_CERTAINTY ).to_f service_products[ cm['service.product'] ] ||= [] service_products[ cm['service.product'] ] << cm end # Unable to guess the service without service matches unless service_products.keys.length > 0 return result end # # Select the best service name by combined certainty of all matches # within an service.product group. Multiple weak matches can # outweigh a single strong match by design. # ranked_service = service_products.keys.sort do |a,b| service_products[b].map{ |r| r['service.certainty'] }.inject(:+) <=> service_products[a].map{ |r| r['service.certainty'] }.inject(:+) end # Within the best match group, try to fill in missing attributes service_name = ranked_service.first # Find the best match within the winning group ranked_service_matches = service_products[service_name].sort do |a,b| b['service.certainty'] <=> a['service.certainty'] end # Fill in missing service values in descending order of best match ranked_service_matches.each do |rm| rm.keys.select{ |k| k.index('service.') == 0 }.each do |k| result[k] ||= rm[k] end end result end |
.match(match_key, match_string) ⇒ Hash?
Locate a database that corresponds with the match_key
and attempt to
find a matching fingerprint, stopping at the first hit. Returns nil
when no matching database or fingerprint is found.
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/recog/nizer.rb', line 31 def self.match(match_key, match_string) match_string = match_string.to_s.unpack("C*").pack("C*") @@db_manager ||= Recog::DBManager.new @@db_manager.databases.each do |db| next unless db.match_key == match_key db.fingerprints.each do |fprint| m = fprint.match(match_string) return m if m end end nil end |