Base class for all sockets.
Common Regular Expressions
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
Converts a ascii address into an integer
# File lib/rex/socket.rb, line 349 def self.addr_atoi(addr) resolv_nbo_i(addr) end
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
Converts a ascii address to network byte order
# File lib/rex/socket.rb, line 379 def self.addr_aton(addr) resolv_nbo(addr) end
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
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
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
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
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
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
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
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 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 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 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 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 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 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
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
Returns the address family, host, and port of the supplied sockaddr as
# 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
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
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
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
Identifies the link-local address of a given interface (if IPv6 is enabled)
# File lib/rex/socket.rb, line 612 def self.ipv6_link_address(intf) r = source_address("FF02::1%#{intf}") return if not (r and r =~ /^fe80/) r end
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
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
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
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
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
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
# File lib/rex/socket.rb, line 521 def self.portspec_crack(pspec) portspec_to_portlist(pspec) end
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
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
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
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
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
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
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
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
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
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
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
By default, all sockets are themselves selectable file descriptors.
# File lib/rex/socket.rb, line 717 def fd self end
Wrapper around getsockname
# File lib/rex/socket.rb, line 731 def getlocalname getsockname end
Return peer connection information.
# File lib/rex/socket.rb, line 738 def getpeername return Socket.from_sockaddr(super) end
Returns local connection information.
# File lib/rex/socket.rb, line 724 def getsockname Socket.from_sockaddr(super) end
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
Generated with the Darkfish Rdoc Generator 2.