integrated switch board routing singleton
git-svn-id: file:///home/svn/incoming/trunk@2917 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
6ec3700b16
commit
3320bc9f0d
|
@ -85,6 +85,32 @@ module Socket
|
|||
return to_sockaddr(host, 0)[4,4]
|
||||
end
|
||||
|
||||
def self.resolv_nbo_i(host)
|
||||
return resolv_nbo(host).unpack('N')[0]
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a netmask (255.255.255.240) into a bitmask (28). This is the
|
||||
# lame kid way of doing it.
|
||||
#
|
||||
def self.net2bitmask(netmask)
|
||||
raw = resolv_nbo(netmask).unpack('N')[0]
|
||||
|
||||
0.upto(31) { |bit|
|
||||
p = 2 ** bit
|
||||
return (32 - bit) if ((raw & p) == p)
|
||||
}
|
||||
|
||||
0
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a bitmask (28) into a netmask (255.255.255.240)
|
||||
#
|
||||
def self.bit2netmask(bitmask)
|
||||
[ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Class initialization
|
||||
|
|
|
@ -58,4 +58,19 @@ class Rex::Socket::UnitTest < Test::Unit::TestCase
|
|||
assert_equal("\x04\x03\x02\x01", Rex::Socket.resolv_nbo("4.3.2.1"))
|
||||
end
|
||||
|
||||
def test_net2bitmask
|
||||
assert_equal(32, Rex::Socket.net2bitmask('255.255.255.255'))
|
||||
assert_equal(28, Rex::Socket.net2bitmask('255.255.255.240'))
|
||||
assert_equal(24, Rex::Socket.net2bitmask('255.255.255.0'))
|
||||
assert_equal(16, Rex::Socket.net2bitmask('255.255.0.0'))
|
||||
end
|
||||
|
||||
def test_bit2netmask
|
||||
assert_equal("255.255.255.255", Rex::Socket.bit2netmask(32))
|
||||
assert_equal("255.255.255.254", Rex::Socket.bit2netmask(31))
|
||||
assert_equal("255.255.255.240", Rex::Socket.bit2netmask(28))
|
||||
assert_equal("255.255.255.0", Rex::Socket.bit2netmask(24))
|
||||
assert_equal("255.255.0.0", Rex::Socket.bit2netmask(16))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
require 'singleton'
|
||||
require 'thread'
|
||||
require 'rex'
|
||||
require 'rex/socket'
|
||||
|
||||
module Rex
|
||||
module Socket
|
||||
|
||||
###
|
||||
#
|
||||
# SwitchBoard
|
||||
# -----------
|
||||
#
|
||||
# This class provides a global routing table that associates subnets with Comm
|
||||
# classes. Comm classes are used to instantiate objects that are tied to
|
||||
# remote network entities. For example, the Local Comm class is used to
|
||||
# building network connections directly from the local machine whereas, for
|
||||
# instance, a Meterpreter Comm would build a local socket pair that is
|
||||
# associated with a connection established by a remote entity. This can be
|
||||
# seen as a uniform way of communicating with hosts through arbitrary
|
||||
# channels.
|
||||
#
|
||||
###
|
||||
class SwitchBoard
|
||||
|
||||
include Singleton
|
||||
include Enumerable
|
||||
|
||||
###
|
||||
#
|
||||
# Route
|
||||
# -----
|
||||
#
|
||||
# This class represents a logical switch board route.
|
||||
#
|
||||
###
|
||||
class Route
|
||||
def initialize(subnet, netmask, comm)
|
||||
self.subnet = subnet
|
||||
self.netmask = netmask
|
||||
self.comm = comm
|
||||
self.subnet_nbo = Socket.resolv_nbo_i(subnet)
|
||||
self.netmask_nbo = Socket.resolv_nbo_i(netmask)
|
||||
end
|
||||
|
||||
#
|
||||
# Sort according to bitmask
|
||||
#
|
||||
def <=>(other)
|
||||
self.bitmask <=> other.bitmask
|
||||
end
|
||||
|
||||
#
|
||||
# Convert the netmask to a bitmask and cache it.
|
||||
#
|
||||
def bitmask
|
||||
@_bitmask = Socket.net2bitmask(self.netmask) if (@_bitmask == nil)
|
||||
@_bitmask
|
||||
end
|
||||
|
||||
attr_reader :subnet, :netmask, :comm
|
||||
attr_reader :subnet_nbo, :netmask_nbo
|
||||
protected
|
||||
attr_writer :subnet, :netmask, :comm
|
||||
attr_writer :subnet_nbo, :netmask_nbo
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Class method wrappers
|
||||
#
|
||||
##
|
||||
|
||||
def self.add_route(subnet, mask, comm)
|
||||
self.instance.add_route(subnet, mask, comm)
|
||||
end
|
||||
|
||||
def self.remove_route(subnet, mask, comm)
|
||||
self.instance.remove_route(subnet, mask, comm)
|
||||
end
|
||||
|
||||
def self.flush_routes
|
||||
self.instance.flush_routes
|
||||
end
|
||||
|
||||
def self.each(&block)
|
||||
self.instance.each(&block)
|
||||
end
|
||||
|
||||
def self.routes
|
||||
self.instance.routes
|
||||
end
|
||||
|
||||
def self.best_comm(addr)
|
||||
self.instance.best_comm(addr)
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Instance methods
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Adds a route for a given subnet and netmask destined through a given comm
|
||||
# instance.
|
||||
#
|
||||
def add_route(subnet, mask, comm)
|
||||
# If a bitmask was supplied, convert it.
|
||||
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
|
||||
rv = true
|
||||
|
||||
_init
|
||||
|
||||
mutex.synchronize {
|
||||
# If the route already exists, return false to the caller.
|
||||
if (route_exists?(subnet, netmask) == false)
|
||||
self.routes << Route.new(subnet, netmask, comm)
|
||||
else
|
||||
rv = false
|
||||
end
|
||||
}
|
||||
|
||||
rv
|
||||
end
|
||||
|
||||
#
|
||||
# Removes a route for a given subnet and netmask destined through a given
|
||||
# comm instance.
|
||||
#
|
||||
def remove_route(subnet, mask, comm)
|
||||
# If a bitmask was supplied, convert it.
|
||||
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
|
||||
rv = false
|
||||
|
||||
_init
|
||||
|
||||
mutex.synchronize {
|
||||
self.routes.delete_if { |route|
|
||||
if (route.subnet == subnet and route.netmask == netmask and route.comm == comm)
|
||||
rv = true
|
||||
else
|
||||
false
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
rv
|
||||
end
|
||||
|
||||
#
|
||||
# Flushes all established routes.
|
||||
#
|
||||
def flush_routes
|
||||
_init
|
||||
|
||||
self.routes = Array.new
|
||||
end
|
||||
|
||||
#
|
||||
# Checks to see if a route already exists for the supplied subnet and
|
||||
# netmask.
|
||||
#
|
||||
def route_exists?(subnet, netmask)
|
||||
each { |route|
|
||||
return true if (route.subnet == subnet and route.netmask == netmask)
|
||||
}
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Enumerates each entry in the routing table.
|
||||
#
|
||||
def each(&block)
|
||||
_init
|
||||
|
||||
routes.each(&block)
|
||||
end
|
||||
|
||||
#
|
||||
# Finds the best possible comm for the supplied target address.
|
||||
#
|
||||
def best_comm(addr)
|
||||
addr_nbo = Socket.resolv_nbo_i(addr)
|
||||
comm = nil
|
||||
msb = 0
|
||||
|
||||
each { |route|
|
||||
if ((route.subnet_nbo & route.netmask_nbo) ==
|
||||
(addr_nbo & route.netmask_nbo))
|
||||
if (route.bitmask >= msb)
|
||||
comm = route.comm
|
||||
msb = route.bitmask
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
comm
|
||||
end
|
||||
|
||||
attr_reader :routes, :mutex
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :routes, :mutex
|
||||
|
||||
def _init
|
||||
if (@_initialized != true)
|
||||
@_initialized = true
|
||||
self.routes = Array.new
|
||||
self.mutex = Mutex.new
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
require 'test/unit'
|
||||
require 'rex/socket/switch_board'
|
||||
|
||||
class Rex::Socket::SwitchBoard::UnitTest < Test::Unit::TestCase
|
||||
|
||||
Klass = Rex::Socket::SwitchBoard
|
||||
|
||||
def test_add
|
||||
Klass.flush_routes
|
||||
assert_equal(true, Klass.add_route('0.0.0.0', 0, 'foo'))
|
||||
assert_equal(false, Klass.add_route('0.0.0.0', 0, 'foo'))
|
||||
assert_equal(1, Klass.routes.length)
|
||||
|
||||
assert_equal('0.0.0.0', Klass.routes[0].subnet)
|
||||
assert_equal('0.0.0.0', Klass.routes[0].netmask)
|
||||
assert_equal(0, Klass.routes[0].bitmask)
|
||||
assert_equal('foo', Klass.routes[0].comm)
|
||||
end
|
||||
|
||||
def test_remove
|
||||
Klass.flush_routes
|
||||
assert_equal(true, Klass.add_route('0.0.0.0', 0, 'foo'))
|
||||
assert_equal(true, Klass.remove_route('0.0.0.0', 0, 'foo'))
|
||||
assert_equal(false, Klass.remove_route('0.0.0.0', 0, 'foo'))
|
||||
assert_equal(0, Klass.routes.length)
|
||||
end
|
||||
|
||||
def test_best_comm
|
||||
Klass.flush_routes
|
||||
Klass.add_route('0.0.0.0', 0, 'default')
|
||||
Klass.add_route('1.2.3.0', 24, 'spec')
|
||||
|
||||
assert_equal('default', Klass.best_comm('4.5.6.7'))
|
||||
assert_equal('spec', Klass.best_comm('1.2.3.7'))
|
||||
end
|
||||
|
||||
end
|
|
@ -62,6 +62,9 @@ module ThreadSafe
|
|||
|
||||
# Keep chugging until we run out of time, if time was supplied.
|
||||
end while ((left == nil) or (left > 0))
|
||||
|
||||
# Nothin.
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue