This patch adds IPv6 support to most feartures of the framework. The major missing component is IPv6-enabled payloads.
git-svn-id: file:///home/svn/framework3/trunk@4814 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
699e013121
commit
83a8ece022
|
@ -381,7 +381,9 @@ class OptAddressRange < OptBase
|
|||
tmp = Rex::Socket.addr_itoa(Rex::Socket.addr_atoi(range))
|
||||
sets << [tmp, tmp]
|
||||
end
|
||||
rescue
|
||||
rescue ::Exception => e
|
||||
p e
|
||||
p e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -77,6 +77,13 @@ module Socket
|
|||
#
|
||||
##
|
||||
|
||||
#
|
||||
# Determine whether we support IPv6
|
||||
#
|
||||
def self.support_ipv6?
|
||||
::Socket.const_defined?('AF_INET6') ? true : false
|
||||
end
|
||||
|
||||
#
|
||||
# Determine whether this is an IPv4 address
|
||||
#
|
||||
|
@ -95,9 +102,12 @@ module Socket
|
|||
|
||||
#
|
||||
# Checks to see if the supplied address is a dotted quad.
|
||||
# TODO: IPV6
|
||||
#
|
||||
def self.dotted_ip?(addr)
|
||||
# Assume anything with a colon is IPv6
|
||||
return true if (support_ipv6? and addr =~ /:/)
|
||||
|
||||
# Otherwise assume this is IPv4
|
||||
(addr =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/) ? true : false
|
||||
end
|
||||
|
||||
|
@ -118,7 +128,13 @@ module Socket
|
|||
# on Windows.
|
||||
#
|
||||
def self.gethostbyname(host)
|
||||
dotted_ip?(host) ? [ host, host, 2, host.split('.').map{ |o| o.to_i }.pack('C*') ] : ::Socket.gethostbyname(host)
|
||||
if (dotted_ip?(host))
|
||||
if (is_ipv4?(host))
|
||||
return [ host, host, 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
|
||||
end
|
||||
end
|
||||
|
||||
::Socket.gethostbyname(host)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -126,8 +142,11 @@ module Socket
|
|||
# address family
|
||||
#
|
||||
def self.to_sockaddr(ip, port)
|
||||
ip = "0.0.0.0" unless ip
|
||||
return ::Socket::pack_sockaddr_in(port, ip)
|
||||
if (not ip or ip == '0.0.0.0' or ip == '::ffff:0.0.0.0')
|
||||
ip = support_ipv6?() ? '::' : '0.0.0.0'
|
||||
end
|
||||
|
||||
return ::Socket.pack_sockaddr_in(port, ip)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -136,14 +155,16 @@ module Socket
|
|||
#
|
||||
def self.from_sockaddr(saddr)
|
||||
port, host = ::Socket::unpack_sockaddr_in(saddr)
|
||||
af = host.match(/:/) ? ::Socket::AF_INET6 : ::Socket::AF_INET
|
||||
af = ::Socket::AF_INET
|
||||
if (support_ipv6?() and is_ipv6?(host))
|
||||
af = ::Socket::AF_INET6
|
||||
end
|
||||
return [ af, host, port ]
|
||||
end
|
||||
|
||||
#
|
||||
# Resolves a host to raw network-byte order.
|
||||
# TODO: All this to work with IPV6 sockets
|
||||
|
||||
#
|
||||
def self.resolv_nbo(host)
|
||||
self.gethostbyname(Rex::Socket.getaddress(host))[3]
|
||||
end
|
||||
|
@ -152,24 +173,121 @@ module Socket
|
|||
# Resolves a host to a network-byte order ruby integer.
|
||||
#
|
||||
def self.resolv_nbo_i(host)
|
||||
ret = resolv_nbo(host).unpack('N*')
|
||||
case ret.length
|
||||
when 1
|
||||
return ret[0]
|
||||
when 4
|
||||
val = 0
|
||||
ret.each_index { |i| val += ( ret[i] << (96 - (i * 32)) ) }
|
||||
return val
|
||||
else
|
||||
raise RuntimeError, "Invalid address format"
|
||||
end
|
||||
addr_ntoi(resolv_nbo(host))
|
||||
end
|
||||
|
||||
#
|
||||
# Resolves a host to a dotted address.
|
||||
#
|
||||
def self.resolv_to_dotted(host)
|
||||
Rex::Socket.getaddress(host)
|
||||
addr_ntoa(addr_aton(host))
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a ascii address into an integer
|
||||
#
|
||||
def self.addr_atoi(addr)
|
||||
resolv_nbo_i(addr)
|
||||
end
|
||||
|
||||
#
|
||||
# Converts an integer address into ascii
|
||||
#
|
||||
def self.addr_itoa(addr, v6=false)
|
||||
|
||||
nboa = addr_iton(addr, v6)
|
||||
|
||||
# IPv4
|
||||
if (addr < 0x100000000 and not v6)
|
||||
nboa.unpack('C4').join('.')
|
||||
# IPv6
|
||||
else
|
||||
nboa.unpack('n8').map{ |c| "%.4x" % c }.join(":")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a ascii address to network byte order
|
||||
#
|
||||
def self.addr_aton(addr)
|
||||
resolv_nbo(addr)
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a network byte order address to ascii
|
||||
#
|
||||
def self.addr_ntoa(addr)
|
||||
|
||||
# IPv4
|
||||
if (addr.length == 4)
|
||||
return [addr].pack('N').unpack('C4').join('.')
|
||||
end
|
||||
|
||||
# IPv6
|
||||
if (addr.length == 16)
|
||||
return addr.unpack('n8').map{ |c| "%.4x" % c }.join(":")
|
||||
end
|
||||
|
||||
raise RuntimeError, "Invalid address format"
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a network byte order address to an integer
|
||||
#
|
||||
def self.addr_ntoi(addr)
|
||||
|
||||
bits = addr.unpack("N*")
|
||||
|
||||
if (bits.length == 1)
|
||||
return bits[0]
|
||||
end
|
||||
|
||||
if (bits.length == 4)
|
||||
val = 0
|
||||
bits.each_index { |i| val += ( bits[i] << (96 - (i * 32)) ) }
|
||||
return val
|
||||
end
|
||||
|
||||
raise RuntimeError, "Invalid address format"
|
||||
end
|
||||
|
||||
#
|
||||
# Converts an integer into a network byte order address
|
||||
#
|
||||
def self.addr_iton(addr, v6=false)
|
||||
if(addr < 0x100000000 and not v6)
|
||||
return [addr].pack('N')
|
||||
else
|
||||
w = []
|
||||
w[0] = (addr >> 96) & 0xffffffff
|
||||
w[1] = (addr >> 64) & 0xffffffff
|
||||
w[2] = (addr >> 32) & 0xffffffff
|
||||
w[3] = addr & 0xffffffff
|
||||
return w.pack('N4')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a CIDR subnet into an array (base, bcast)
|
||||
#
|
||||
def self.cidr_crack(cidr, v6=false)
|
||||
tmp = cidr.split('/')
|
||||
addr = addr_atoi(tmp[0])
|
||||
|
||||
bits = 32
|
||||
mask = 0
|
||||
use6 = false
|
||||
|
||||
if (addr > 0xffffffff or v6)
|
||||
use6 = true
|
||||
bits = 128
|
||||
end
|
||||
|
||||
mask = (2 ** bits) - (2 ** (bits - tmp[1].to_i))
|
||||
base = addr & mask
|
||||
|
||||
stop = base + (2 ** (bits - tmp[1].to_i)) - 1
|
||||
return [self.addr_itoa(base, use6), self.addr_itoa(stop, use6)]
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -177,45 +295,26 @@ module Socket
|
|||
# lame kid way of doing it.
|
||||
#
|
||||
def self.net2bitmask(netmask)
|
||||
raw = resolv_nbo(netmask).unpack('N')[0]
|
||||
|
||||
nmask = resolv_nbo(netmask)
|
||||
imask = addr_ntoi(nmask)
|
||||
bits = 32
|
||||
|
||||
if (imask > 0xffffffff)
|
||||
bits = 128
|
||||
end
|
||||
|
||||
0.upto(31) { |bit|
|
||||
0.upto(bits-1) do |bit|
|
||||
p = 2 ** bit
|
||||
return (32 - bit) if ((raw & p) == p)
|
||||
}
|
||||
|
||||
return (bits - bit) if ((imask & p) == p)
|
||||
end
|
||||
|
||||
0
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a dotted-quad address into an integer
|
||||
#
|
||||
def self.addr_atoi(addr)
|
||||
addr.split('.').map{|i| i.to_i }.pack('C4').unpack('N')[0]
|
||||
end
|
||||
|
||||
#
|
||||
# Converts an integer into a dotted-quad
|
||||
#
|
||||
def self.addr_itoa(addr)
|
||||
[addr].pack('N').unpack('C4').join('.')
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a CIDR subnet into an array (base, bcast)
|
||||
#
|
||||
def self.cidr_crack(cidr)
|
||||
tmp = cidr.split('/')
|
||||
addr = self.addr_atoi(tmp[0])
|
||||
mask = (2 ** 32) - (2 ** (32 - tmp[1].to_i))
|
||||
base = addr & mask
|
||||
stop = base + (2 ** (32 - tmp[1].to_i)) - 1
|
||||
return [self.addr_itoa(base), self.addr_itoa(stop)]
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Converts a bitmask (28) into a netmask (255.255.255.240)
|
||||
# TODO: IPv6 (use is ambiguous right now)
|
||||
#
|
||||
def self.bit2netmask(bitmask)
|
||||
[ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
|
||||
|
@ -269,6 +368,7 @@ module Socket
|
|||
self.localhost = params.localhost
|
||||
self.localport = params.localport
|
||||
self.context = params.context || {}
|
||||
self.ipv = params.v6 ? 6 : 4
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -324,6 +424,10 @@ module Socket
|
|||
#
|
||||
attr_reader :localport
|
||||
#
|
||||
# The IP version of the socket
|
||||
#
|
||||
attr_reader :ipv
|
||||
#
|
||||
# Contextual information that describes the source and other
|
||||
# instance-specific attributes. This comes from the param.context
|
||||
# attribute.
|
||||
|
@ -334,6 +438,7 @@ protected
|
|||
|
||||
attr_writer :peerhost, :peerport, :localhost, :localport # :nodoc:
|
||||
attr_writer :context # :nodoc:
|
||||
attr_writer :ipv # :nodoc:
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -34,11 +34,60 @@ class Rex::Socket::Comm::Local
|
|||
# Creates a socket using the supplied Parameter instance.
|
||||
#
|
||||
def self.create_by_type(param, type, proto = 0)
|
||||
|
||||
# Whether to use IPv6 addressing
|
||||
usev6 = false
|
||||
|
||||
# Detect IPv6 addresses and enable IPv6 accordingly
|
||||
if ( Rex::Socket.support_ipv6?())
|
||||
|
||||
# Allow the caller to force IPv6
|
||||
if (param.v6)
|
||||
usev6 = true
|
||||
end
|
||||
|
||||
# Force IPv6 mode for non-connected UDP sockets
|
||||
if (type == ::Socket::SOCK_DGRAM and not param.peerhost)
|
||||
usev6 = true
|
||||
end
|
||||
|
||||
local = Rex::Socket.resolv_nbo(param.localhost) if param.localhost
|
||||
peer = Rex::Socket.resolv_nbo(param.peerhost) if param.peerhost
|
||||
|
||||
if (local and local.length == 16)
|
||||
usev6 = true
|
||||
end
|
||||
|
||||
if (peer and peer.length == 16)
|
||||
usev6 = true
|
||||
end
|
||||
|
||||
if (usev6)
|
||||
if (local and local.length == 4)
|
||||
param.localhost = '::ffff:' + Rex::Socket.getaddress(param.localhost)
|
||||
end
|
||||
|
||||
if (peer and peer.length == 4)
|
||||
param.peerhost = '::ffff:' + Rex::Socket.getaddress(param.peerhost)
|
||||
end
|
||||
|
||||
param.v6 = true
|
||||
end
|
||||
else
|
||||
# No IPv6 support
|
||||
param.v6 = false
|
||||
end
|
||||
|
||||
# Notify handlers of the before socket create event.
|
||||
self.instance.notify_before_socket_create(self, param)
|
||||
|
||||
# Create the socket
|
||||
sock = ::Socket.new(::Socket::AF_INET, type, proto)
|
||||
sock = nil
|
||||
if (param.v6)
|
||||
sock = ::Socket.new(::Socket::AF_INET6, type, proto)
|
||||
else
|
||||
sock = ::Socket.new(::Socket::AF_INET, type, proto)
|
||||
end
|
||||
|
||||
# Bind to a given local address and/or port if they are supplied
|
||||
if (param.localhost || param.localport)
|
||||
|
|
|
@ -152,6 +152,9 @@ class Rex::Socket::Parameters
|
|||
|
||||
# The number of seconds before a connect attempt times out (client only)
|
||||
self.timeout = hash['Timeout'] || 5
|
||||
|
||||
# Whether to force IPv6 addressing
|
||||
self.v6 = hash['IPv6'] || false
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -203,6 +206,14 @@ class Rex::Socket::Parameters
|
|||
return ssl
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if IPv6 has been enabled
|
||||
#
|
||||
def v6?
|
||||
return v6
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Attributes
|
||||
|
@ -261,6 +272,10 @@ class Rex::Socket::Parameters
|
|||
# Whether or not SSL should be used to wrap the connection.
|
||||
#
|
||||
attr_accessor :ssl
|
||||
#
|
||||
# Whether we should use IPv6
|
||||
#
|
||||
attr_accessor :v6
|
||||
|
||||
|
||||
attr_accessor :proxies
|
||||
|
|
|
@ -92,6 +92,13 @@ module Rex::Socket::Udp
|
|||
# Sends a datagram to the supplied host:port with optional flags.
|
||||
#
|
||||
def sendto(gram, peerhost, peerport, flags = 0)
|
||||
|
||||
# Catch unconnected IPv6 sockets talking to IPv4 addresses
|
||||
peer = Rex::Socket.resolv_nbo(peerhost)
|
||||
if (peer.length == 4 and self.ipv == 6)
|
||||
peerhost = '::ffff:' + Rex::Socket.getaddress(peerhost)
|
||||
end
|
||||
|
||||
return send(gram, flags, Rex::Socket.to_sockaddr(peerhost, peerport))
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue