Class/Module Index [+]

Quicksearch

Rex::Socket

Base class for all sockets.

Constants

MATCH_IPV4
MATCH_IPV4_PRIVATE
MATCH_IPV6

Common Regular Expressions

Attributes

context[R]

Contextual information that describes the source and other instance-specific attributes. This comes from the param.context attribute.

ipv[R]

The IP version of the socket

localhost[R]

The local host of the connected socket.

localport[R]

The local port of the connected socket.

peerhost[R]

The peer host of the connected socket.

peerport[R]

The peer port of the connected socket.

Public Class Methods

addr_atoc(mask) click to toggle source

Converts an ASCII IP address to a CIDR mask. Returns nil if it's not convertable.

# File lib/rex/socket.rb, line 318
def self.addr_atoc(mask)
        mask_i = resolv_nbo_i(mask)
        cidr = nil
        0.upto(32) do |i|
                if ((1 << i)-1) << (32-i) == mask_i
                        cidr = i
                        break
                end
        end
        return cidr
end
addr_atoi(addr) click to toggle source

Converts a ascii address into an integer

# File lib/rex/socket.rb, line 349
def self.addr_atoi(addr)
        resolv_nbo_i(addr)
end
addr_atoi_list(addr) click to toggle source

Converts a ascii address into a list of addresses

# File lib/rex/socket.rb, line 356
def self.addr_atoi_list(addr)
        resolv_nbo_i_list(addr)
end
addr_aton(addr) click to toggle source

Converts a ascii address to network byte order

# File lib/rex/socket.rb, line 379
def self.addr_aton(addr)
        resolv_nbo(addr)
end
addr_ctoa(cidr) click to toggle source

Resolves a CIDR bitmask into a dotted-quad. Returns nil if it's not convertable.

# File lib/rex/socket.rb, line 334
def self.addr_ctoa(cidr)
        return nil unless (0..32) === cidr.to_i
        addr_itoa(((1 << cidr)-1) << 32-cidr)
end
addr_itoa(addr, v6=false) click to toggle source

Converts an integer address into ascii

# File lib/rex/socket.rb, line 363
def self.addr_itoa(addr, v6=false)

        nboa = addr_iton(addr, v6)

        # IPv4
        if (addr < 0x100000000 and not v6)
                addr_ntoa(nboa)
        # IPv6
        else
                addr_ntoa(nboa)
        end
end
addr_iton(addr, v6=false) click to toggle source

Converts an integer into a network byte order address

# File lib/rex/socket.rb, line 444
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
addr_ntoa(addr) click to toggle source

Converts a network byte order address to ascii

# File lib/rex/socket.rb, line 386
def self.addr_ntoa(addr)
        # IPv4
        if (addr.length == 4)
                return addr.unpack('C4').join('.')
        end

        # IPv6
        if (addr.length == 16)
                return compress_address(addr.unpack('n8').map{ |c| "%x" % c }.join(":"))
        end

        raise RuntimeError, "Invalid address format"
end
addr_ntoi(addr) click to toggle source

Converts a network byte order address to an integer

# File lib/rex/socket.rb, line 424
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
bit2netmask(bitmask, ipv6=false) click to toggle source

Converts a bitmask (28) into a netmask (255.255.255.240)

# File lib/rex/socket.rb, line 510
def self.bit2netmask(bitmask, ipv6=false)
        if bitmask > 32 or ipv6
                i = ((~((2 ** (128 - bitmask)) - 1)) & (2**128-1))
                n = Rex::Socket.addr_iton(i, true)
                return Rex::Socket.addr_ntoa(n)
        else
                [ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
        end
end
cidr_crack(cidr, v6=false) click to toggle source

Converts a CIDR subnet into an array (base, bcast)

# File lib/rex/socket.rb, line 460
def self.cidr_crack(cidr, v6=false)
        tmp = cidr.split('/')

        tst,scope = tmp[0].split("%",2)
        scope     = "%" + scope if scope
        scope   ||= ""

        addr = addr_atoi(tst)

        bits = 32
        mask = 0
        use6 = false

        if (addr > 0xffffffff or v6 or cidr =~ /:/)
                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) + scope, self.addr_itoa(stop, use6) + scope]
end
compress_address(addr) click to toggle source

Implement zero compression for IPv6 addresses. Uses the compression method from Marco Ceresa's IPAddress GEM

https://github.com/bluemonk/ipaddress/blob/master/lib/ipaddress/ipv6.rb
# File lib/rex/socket.rb, line 405
def self.compress_address(addr)
        return addr unless is_ipv6?(addr)
        addr = addr.dup
        while true
                break if addr.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
                break if addr.sub!(/\b0:0:0:0:0:0:0\b/, ':')
                break if addr.sub!(/\b0:0:0:0:0:0\b/, ':')
                break if addr.sub!(/\b0:0:0:0:0\b/, ':')
                break if addr.sub!(/\b0:0:0:0\b/, ':')
                break if addr.sub!(/\b0:0:0\b/, ':')
                break if addr.sub!(/\b0:0\b/, ':')
                break
        end
        addr.sub(/:{3,}/, '::')
end
create(opts = {}) click to toggle source

Create a socket instance using the supplied parameter hash.

# File lib/rex/socket.rb, line 38
def self.create(opts = {})
        return create_param(Rex::Socket::Parameters.from_hash(opts))
end
create_ip(opts = {}) click to toggle source

Create a IP socket using the supplied parameter hash.

# File lib/rex/socket.rb, line 73
def self.create_ip(opts = {})
        return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'ip')))
end
create_param(param) click to toggle source

Create a socket using the supplied Rex::Socket::Parameter instance.

# File lib/rex/socket.rb, line 45
def self.create_param(param)
        return param.comm.create(param)
end
create_tcp(opts = {}) click to toggle source

Create a TCP socket using the supplied parameter hash.

# File lib/rex/socket.rb, line 52
def self.create_tcp(opts = {})
        return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'tcp')))
end
create_tcp_server(opts = {}) click to toggle source

Create a TCP server socket using the supplied parameter hash.

# File lib/rex/socket.rb, line 59
def self.create_tcp_server(opts = {})
        return create_tcp(opts.merge('Server' => true))
end
create_udp(opts = {}) click to toggle source

Create a UDP socket using the supplied parameter hash.

# File lib/rex/socket.rb, line 66
def self.create_udp(opts = {})
        return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'udp')))
end
dotted_ip?(addr) click to toggle source

Checks to see if the supplied address is in "dotted" form

# File lib/rex/socket.rb, line 135
def self.dotted_ip?(addr)
        # Match IPv6
        return true if (support_ipv6? and addr =~ MATCH_IPV6)

        # Match IPv4
        return true if (addr =~ MATCH_IPV4)

        false
end
from_sockaddr(saddr) click to toggle source

Returns the address family, host, and port of the supplied sockaddr as

af, host, port
# File lib/rex/socket.rb, line 277
def self.from_sockaddr(saddr)
        port, host = ::Socket::unpack_sockaddr_in(saddr)
        af = ::Socket::AF_INET
        if (support_ipv6?() and is_ipv6?(host))
                af = ::Socket::AF_INET6
        end
        return [ af, host, port ]
end
getaddress(addr, accept_ipv6 = true) click to toggle source

Wrapper for Resolv.getaddress that takes special care to see if the supplied address is already a dotted quad, for instance. This is necessary to prevent calls to gethostbyaddr (which occurs on windows). These calls can be quite slow. This also fixes an issue with the Resolv.getaddress() call being non-functional on Ruby 1.9.1 (Win32).

# File lib/rex/socket.rb, line 164
def self.getaddress(addr, accept_ipv6 = true)
        begin
                if addr =~ MATCH_IPV4 or (accept_ipv6 and addr =~ MATCH_IPV6)
                        return addr
                end

                res = ::Socket.gethostbyname(addr)
                return nil if not res

                # Shift the first three elements out
                rname  = res.shift
                ralias = res.shift
                rtype  = res.shift

                # Rubinius has a bug where gethostbyname returns dotted quads instead of
                # NBO, but that's what we want anyway, so just short-circuit here.
                if res[0] =~ MATCH_IPV4 || res[0] =~ MATCH_IPV6
                        res.each { |r|
                                # if the caller doesn't mind ipv6, just return whatever we have
                                return r if accept_ipv6
                                # otherwise, take the first v4 address
                                return r if r =~ MATCH_IPV4
                        }
                        # didn't find one
                        return nil
                end

                # Reject IPv6 addresses if we don't accept them
                if not accept_ipv6
                        res.reject!{|nbo| nbo.length != 4}
                end

                # Make sure we have at least one name
                return nil if res.length == 0

                # Return the first address of the result
                self.addr_ntoa( res[0] )
        rescue ::ArgumentError # Win32 bug
                nil
        end
end
getaddresses(addr, accept_ipv6 = true) click to toggle source

Wrapper for Resolv.getaddress that takes special care to see if the supplied address is already a dotted quad, for instance. This is necessary to prevent calls to gethostbyaddr (which occurs on windows). These calls can be quite slow. This also fixes an issue with the Resolv.getaddress() call being non-functional on Ruby 1.9.1 (Win32).

# File lib/rex/socket.rb, line 213
def self.getaddresses(addr, accept_ipv6 = true)
        begin
                if addr =~ MATCH_IPV4 or (accept_ipv6 and addr =~ MATCH_IPV6)
                        return [addr]
                end

                res = ::Socket.gethostbyname(addr)
                return [] if not res

                # Shift the first three elements out
                rname  = res.shift
                ralias = res.shift
                rtype  = res.shift

                # Reject IPv6 addresses if we don't accept them
                if not accept_ipv6
                        res.reject!{|nbo| nbo.length != 4}
                end

                # Make sure we have at least one name
                return [] if res.length == 0

                # Return an array of all addresses
                res.map{ |addr| self.addr_ntoa(addr) }
        rescue ::ArgumentError # Win32 bug
                []
        end
end
gethostbyname(host) click to toggle source

Wrapper for Socket.gethostbyname which takes into account whether or not an IP address is supplied. If it is, then reverse DNS resolution does not occur. This is done in order to prevent delays, such as would occur on Windows.

# File lib/rex/socket.rb, line 248
def self.gethostbyname(host)
        if (is_ipv4?(host))
                return [ host, [], 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
        end

        if is_ipv6?(host)
                host, scope_id = host.split('%', 2)
        end

        ::Socket.gethostbyname(host)
end
ipv6_mac(intf) click to toggle source

Identifies the mac address of a given interface (if IPv6 is enabled)

# File lib/rex/socket.rb, line 621
def self.ipv6_mac(intf)
        r = ipv6_link_address(intf)
        return if not r
        raw = addr_aton(r)[-8, 8]
        (raw[0,3] + raw[5,3]).unpack("C*").map{|c| "%.2x" % c}.join(":")
end
is_internal?(addr) click to toggle source

Return true if addr is within the ranges specified in RFC1918, or RFC5735/RFC3927

# File lib/rex/socket.rb, line 149
def self.is_internal?(addr)
        if self.dotted_ip?(addr)
                addr =~ MATCH_IPV4_PRIVATE
        else
                false
        end
end
is_ipv4?(addr) click to toggle source

Determine whether this is an IPv4 address

# File lib/rex/socket.rb, line 121
def self.is_ipv4?(addr)
        ( addr =~ MATCH_IPV4 ) ? true : false
end
is_ipv6?(addr) click to toggle source

Determine whether this is an IPv6 address

# File lib/rex/socket.rb, line 128
def self.is_ipv6?(addr)
        ( addr =~ MATCH_IPV6 ) ? true : false
end
net2bitmask(netmask) click to toggle source

Converts a netmask (255.255.255.240) into a bitmask (28). This is the lame kid way of doing it.

# File lib/rex/socket.rb, line 489
def self.net2bitmask(netmask)

        nmask = resolv_nbo(netmask)
        imask = addr_ntoi(nmask)
        bits  = 32

        if (imask > 0xffffffff)
                bits = 128
        end

        0.upto(bits-1) do |bit|
                p = 2 ** bit
                return (bits - bit) if ((imask & p) == p)
        end

        0
end
portlist_to_portspec(parr) click to toggle source

Converts a port list like [1,2,3,4,5,100] into a range specification like "1-5,100"

# File lib/rex/socket.rb, line 552
def self.portlist_to_portspec(parr)
        ranges = []
        range  = []
        lastp  = nil

        parr.uniq.sort{|a,b| a<=>b}.map{|a| a.to_i}.each do |n|
                next if (n < 1 or n > 65535)
                if not lastp
                        range = [n]
                        lastp = n
                        next
                end

                if lastp == n - 1
                        range << n
                else
                        ranges << range
                        range = [n]
                end
                lastp = n
        end

        ranges << range
        ranges.delete(nil)
        ranges.uniq.map{|x| x.length == 1 ? "#{x[0]}" : "#{x[0]}-#{x[-1]}"}.join(",")
end
portspec_crack(pspec) click to toggle source
# File lib/rex/socket.rb, line 521
def self.portspec_crack(pspec)
        portspec_to_portlist(pspec)
end
portspec_to_portlist(pspec) click to toggle source

Converts a port specification like "80,21-23,443" into a sorted, unique array of valid port numbers like [21,22,23,80,443]

# File lib/rex/socket.rb, line 529
def self.portspec_to_portlist(pspec)
        ports = []

        # Build ports array from port specification
        pspec.split(/,/).each do |item|
                start, stop = item.split(/-/).map { |p| p.to_i }

                start ||= 0
                stop ||= item.match(/-/) ? 65535 : start

                start, stop = stop, start if stop < start

                start.upto(stop) { |p| ports << p }
        end

        # Sort, and remove dups and invalid ports
        ports.sort.uniq.delete_if { |p| p < 1 or p > 65535 }
end
resolv_nbo(host) click to toggle source

Resolves a host to raw network-byte order.

# File lib/rex/socket.rb, line 289
def self.resolv_nbo(host)
        self.gethostbyname( Rex::Socket.getaddress(host, true) )[3]
end
resolv_nbo_i(host) click to toggle source

Resolves a host to a network-byte order ruby integer.

# File lib/rex/socket.rb, line 303
def self.resolv_nbo_i(host)
        addr_ntoi(resolv_nbo(host))
end
resolv_nbo_i_list(host) click to toggle source

Resolves a host to a list of network-byte order ruby integers.

# File lib/rex/socket.rb, line 310
def self.resolv_nbo_i_list(host)
        resolv_nbo_list(host).map{|addr| addr_ntoi(addr) }
end
resolv_nbo_list(host) click to toggle source

Resolves a host to raw network-byte order.

# File lib/rex/socket.rb, line 296
def self.resolv_nbo_list(host)
        Rex::Socket.getaddresses(host).map{|addr| self.gethostbyname(addr)[3] }
end
resolv_to_dotted(host) click to toggle source

Resolves a host to a dotted address.

# File lib/rex/socket.rb, line 342
def self.resolv_to_dotted(host)
        addr_ntoa(addr_aton(host))
end
source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local) click to toggle source

This method does NOT send any traffic to the destination, instead, it uses a "bound" UDP socket to determine what source address we would use to communicate with the specified destination. The destination defaults to Google's DNS server to make the standard behavior determine which IP we would use to communicate with the internet.

# File lib/rex/socket.rb, line 592
def self.source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local)
        begin
                s = self.create_udp(
                        'PeerHost' => dest,
                        'PeerPort' => 31337,
                        'Comm'     => comm
                )
                r = s.getsockname[1]
                s.close

                # Trim off the trailing interface ID for link-local IPv6
                return r.split('%').first
        rescue ::Exception
                return '127.0.0.1'
        end
end
support_ipv6?() click to toggle source

Determine whether we support IPv6

# File lib/rex/socket.rb, line 101
def self.support_ipv6?
        return @@support_ipv6 if not @@support_ipv6.nil?

        @@support_ipv6 = false

        if (::Socket.const_defined?('AF_INET6'))
                begin
                        s = ::Socket.new(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
                        s.close
                        @@support_ipv6 = true
                rescue
                end
        end

        return @@support_ipv6
end
tcp_socket_pair() click to toggle source

Create a TCP socket pair.

sf: This create a socket pair using native ruby sockets and will work on Windows where ::Socket.pair is not implemented. Note: OpenSSL requires native ruby sockets for its io.

Note: Even though sub-threads are smashing the parent threads local, there

is no concurrent use of the same locals and this is safe.
# File lib/rex/socket.rb, line 637
def self.tcp_socket_pair
        lsock   = nil
        rsock   = nil
        laddr   = '127.0.0.1'
        lport   = 0
        threads = []
        mutex   = ::Mutex.new

        threads << Rex::ThreadFactory.spawn('TcpSocketPair', false) {
                server = nil
                mutex.synchronize {
                        threads << Rex::ThreadFactory.spawn('TcpSocketPairClient', false) {
                                mutex.synchronize {
                                        rsock = ::TCPSocket.new( laddr, lport )
                                }
                        }
                        server = ::TCPServer.new(laddr, 0)
                        if (server.getsockname =~ /127\.0\.0\.1:/)
                                # JRuby ridiculousness
                                caddr, lport = server.getsockname.split(":")
                                caddr = caddr[1,caddr.length]
                                lport = lport.to_i
                        else
                                # Sane implementations where Socket#getsockname returns a
                                # sockaddr
                                lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
                        end
                }
                lsock, saddr = server.accept
                server.close
        }

        threads.each { |t| t.join }

        return [lsock, rsock]
end
to_sockaddr(ip, port) click to toggle source

Create a sockaddr structure using the supplied IP address, port, and address family

# File lib/rex/socket.rb, line 264
def self.to_sockaddr(ip, port)

        if (ip == '::ffff:0.0.0.0')
                ip = support_ipv6?() ? '::' : '0.0.0.0'
        end

        return ::Socket.pack_sockaddr_in(port, ip)
end
udp_socket_pair() click to toggle source

Create a UDP socket pair using native ruby UDP sockets.

# File lib/rex/socket.rb, line 677
def self.udp_socket_pair
        laddr = '127.0.0.1'

        lsock = ::UDPSocket.new
        lsock.bind( laddr, 0 )

        rsock = ::UDPSocket.new
        rsock.bind( laddr, 0 )

        rsock.connect( *lsock.addr.values_at(3,1) )

        lsock.connect( *rsock.addr.values_at(3,1) )

        return [lsock, rsock]
end

Public Instance Methods

fd() click to toggle source

By default, all sockets are themselves selectable file descriptors.

# File lib/rex/socket.rb, line 717
def fd
        self
end
getlocalname() click to toggle source

Wrapper around getsockname

# File lib/rex/socket.rb, line 731
def getlocalname
        getsockname
end
getpeername() click to toggle source

Return peer connection information.

# File lib/rex/socket.rb, line 738
def getpeername
        return Socket.from_sockaddr(super)
end
getsockname() click to toggle source

Returns local connection information.

# File lib/rex/socket.rb, line 724
def getsockname
        Socket.from_sockaddr(super)
end
initsock(params = nil) click to toggle source

Initialize general socket parameters.

# File lib/rex/socket.rb, line 703
def initsock(params = nil)
        if (params)
                self.peerhost  = params.peerhost
                self.peerport  = params.peerport
                self.localhost = params.localhost
                self.localport = params.localport
                self.context   = params.context || {}
                self.ipv       = params.v6 ? 6 : 4
        end
end
type?() click to toggle source

Returns a string that indicates the type of the socket, such as 'tcp'.

# File lib/rex/socket.rb, line 745
def type?
        raise NotImplementedError, "Socket type is not supported."
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.