PageRenderTime 46ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/rex/socket.rb

https://github.com/Jonono2/metasploit-framework
Ruby | 774 lines | 395 code | 123 blank | 256 comment | 53 complexity | 35954796578192eb948477e0db9f3fd4 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.1, GPL-2.0
  1. # -*- coding: binary -*-
  2. require 'socket'
  3. require 'thread'
  4. require 'resolv'
  5. require 'rex/exceptions'
  6. module Rex
  7. ###
  8. #
  9. # Base class for all sockets.
  10. #
  11. ###
  12. module Socket
  13. module Comm
  14. end
  15. require 'rex/socket/parameters'
  16. require 'rex/socket/tcp'
  17. require 'rex/socket/tcp_server'
  18. require 'rex/socket/comm'
  19. require 'rex/socket/comm/local'
  20. require 'rex/socket/switch_board'
  21. require 'rex/socket/subnet_walker'
  22. require 'rex/socket/range_walker'
  23. ##
  24. #
  25. # Factory methods
  26. #
  27. ##
  28. #
  29. # Create a socket instance using the supplied parameter hash.
  30. #
  31. def self.create(opts = {})
  32. return create_param(Rex::Socket::Parameters.from_hash(opts))
  33. end
  34. #
  35. # Create a socket using the supplied Rex::Socket::Parameter instance.
  36. #
  37. def self.create_param(param)
  38. return param.comm.create(param)
  39. end
  40. #
  41. # Create a TCP socket using the supplied parameter hash.
  42. #
  43. def self.create_tcp(opts = {})
  44. return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'tcp')))
  45. end
  46. #
  47. # Create a TCP server socket using the supplied parameter hash.
  48. #
  49. def self.create_tcp_server(opts = {})
  50. return create_tcp(opts.merge('Server' => true))
  51. end
  52. #
  53. # Create a UDP socket using the supplied parameter hash.
  54. #
  55. def self.create_udp(opts = {})
  56. return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'udp')))
  57. end
  58. #
  59. # Create a IP socket using the supplied parameter hash.
  60. #
  61. def self.create_ip(opts = {})
  62. return create_param(Rex::Socket::Parameters.from_hash(opts.merge('Proto' => 'ip')))
  63. end
  64. #
  65. # Common Regular Expressions
  66. #
  67. MATCH_IPV6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
  68. MATCH_IPV4 = /^\s*(?:(?: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}))\s*$/
  69. MATCH_IPV4_PRIVATE = /^\s*(?:10\.|192\.168|172.(?:1[6-9]|2[0-9]|3[01])\.|169\.254)/
  70. ##
  71. #
  72. # Serialization
  73. #
  74. ##
  75. # Cache our IPv6 support flag
  76. @@support_ipv6 = nil
  77. #
  78. # Determine whether we support IPv6
  79. #
  80. def self.support_ipv6?
  81. return @@support_ipv6 if not @@support_ipv6.nil?
  82. @@support_ipv6 = false
  83. if (::Socket.const_defined?('AF_INET6'))
  84. begin
  85. s = ::Socket.new(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP)
  86. s.close
  87. @@support_ipv6 = true
  88. rescue
  89. end
  90. end
  91. return @@support_ipv6
  92. end
  93. #
  94. # Determine whether this is an IPv4 address
  95. #
  96. def self.is_ipv4?(addr)
  97. ( addr =~ MATCH_IPV4 ) ? true : false
  98. end
  99. #
  100. # Determine whether this is an IPv6 address
  101. #
  102. def self.is_ipv6?(addr)
  103. ( addr =~ MATCH_IPV6 ) ? true : false
  104. end
  105. #
  106. # Checks to see if the supplied address is in "dotted" form
  107. #
  108. def self.dotted_ip?(addr)
  109. # Match IPv6
  110. return true if (support_ipv6? and addr =~ MATCH_IPV6)
  111. # Match IPv4
  112. return true if (addr =~ MATCH_IPV4)
  113. false
  114. end
  115. #
  116. # Return true if +addr+ is within the ranges specified in RFC1918, or
  117. # RFC5735/RFC3927
  118. #
  119. def self.is_internal?(addr)
  120. if self.dotted_ip?(addr)
  121. addr =~ MATCH_IPV4_PRIVATE
  122. else
  123. false
  124. end
  125. end
  126. # Get the first address returned by a DNS lookup for +hostname+.
  127. #
  128. # @see .getaddresses
  129. #
  130. # @param (see .getaddresses)
  131. # @return [String] ASCII IP address
  132. def self.getaddress(hostname, accept_ipv6 = true)
  133. getaddresses(hostname, accept_ipv6).first
  134. end
  135. #
  136. # Wrapper for +::Socket.gethostbyname+ that takes special care to see if the
  137. # supplied address is already an ASCII IP address. This is necessary to
  138. # prevent blocking while waiting on a DNS reverse lookup when we already
  139. # have what we need.
  140. #
  141. # @param hostname [String] A hostname or ASCII IP address
  142. # @return [Array<String>]
  143. def self.getaddresses(hostname, accept_ipv6 = true)
  144. if hostname =~ MATCH_IPV4 or (accept_ipv6 and hostname =~ MATCH_IPV6)
  145. return [hostname]
  146. end
  147. res = ::Socket.gethostbyname(hostname)
  148. return [] if not res
  149. # Shift the first three elements out, leaving just the list of
  150. # addresses
  151. res.shift # name
  152. res.shift # alias hostnames
  153. res.shift # address_family
  154. # Rubinius has a bug where gethostbyname returns dotted quads instead of
  155. # NBO, but that's what we want anyway, so just short-circuit here.
  156. if res[0] =~ MATCH_IPV4 || res[0] =~ MATCH_IPV6
  157. unless accept_ipv6
  158. res.reject!{ |ascii| ascii =~ MATCH_IPV6 }
  159. end
  160. else
  161. unless accept_ipv6
  162. res.reject!{ |nbo| nbo.length != 4 }
  163. end
  164. res.map!{ |nbo| self.addr_ntoa(nbo) }
  165. end
  166. res
  167. end
  168. #
  169. # Wrapper for Socket.gethostbyname which takes into account whether or not
  170. # an IP address is supplied. If it is, then reverse DNS resolution does
  171. # not occur. This is done in order to prevent delays, such as would occur
  172. # on Windows.
  173. #
  174. def self.gethostbyname(host)
  175. if (is_ipv4?(host))
  176. return [ host, [], 2, host.split('.').map{ |c| c.to_i }.pack("C4") ]
  177. end
  178. if is_ipv6?(host)
  179. # pop off the scopeid since gethostbyname isn't smart enough to
  180. # deal with it.
  181. host, _ = host.split('%', 2)
  182. end
  183. ::Socket.gethostbyname(host)
  184. end
  185. #
  186. # Create a sockaddr structure using the supplied IP address, port, and
  187. # address family
  188. #
  189. def self.to_sockaddr(ip, port)
  190. if (ip == '::ffff:0.0.0.0')
  191. ip = support_ipv6?() ? '::' : '0.0.0.0'
  192. end
  193. return ::Socket.pack_sockaddr_in(port, ip)
  194. end
  195. #
  196. # Returns the address family, host, and port of the supplied sockaddr as
  197. # [ af, host, port ]
  198. #
  199. def self.from_sockaddr(saddr)
  200. port, host = ::Socket::unpack_sockaddr_in(saddr)
  201. af = ::Socket::AF_INET
  202. if (support_ipv6?() and is_ipv6?(host))
  203. af = ::Socket::AF_INET6
  204. end
  205. return [ af, host, port ]
  206. end
  207. #
  208. # Resolves a host to raw network-byte order.
  209. #
  210. def self.resolv_nbo(host)
  211. self.gethostbyname( Rex::Socket.getaddress(host, true) )[3]
  212. end
  213. #
  214. # Resolves a host to raw network-byte order.
  215. #
  216. def self.resolv_nbo_list(host)
  217. Rex::Socket.getaddresses(host).map{|addr| self.gethostbyname(addr)[3] }
  218. end
  219. #
  220. # Resolves a host to a network-byte order ruby integer.
  221. #
  222. def self.resolv_nbo_i(host)
  223. addr_ntoi(resolv_nbo(host))
  224. end
  225. #
  226. # Resolves a host to a list of network-byte order ruby integers.
  227. #
  228. def self.resolv_nbo_i_list(host)
  229. resolv_nbo_list(host).map{|addr| addr_ntoi(addr) }
  230. end
  231. #
  232. # Converts an ASCII IP address to a CIDR mask. Returns
  233. # nil if it's not convertable.
  234. #
  235. def self.addr_atoc(mask)
  236. mask_i = resolv_nbo_i(mask)
  237. cidr = nil
  238. 0.upto(32) do |i|
  239. if ((1 << i)-1) << (32-i) == mask_i
  240. cidr = i
  241. break
  242. end
  243. end
  244. return cidr
  245. end
  246. #
  247. # Resolves a CIDR bitmask into a dotted-quad. Returns
  248. # nil if it's not convertable.
  249. #
  250. def self.addr_ctoa(cidr)
  251. return nil unless (0..32) === cidr.to_i
  252. addr_itoa(((1 << cidr)-1) << 32-cidr)
  253. end
  254. #
  255. # Resolves a host to a dotted address.
  256. #
  257. def self.resolv_to_dotted(host)
  258. addr_ntoa(addr_aton(host))
  259. end
  260. #
  261. # Converts a ascii address into an integer
  262. #
  263. def self.addr_atoi(addr)
  264. resolv_nbo_i(addr)
  265. end
  266. #
  267. # Converts a ascii address into a list of addresses
  268. #
  269. def self.addr_atoi_list(addr)
  270. resolv_nbo_i_list(addr)
  271. end
  272. #
  273. # Converts an integer address into ascii
  274. #
  275. # @param (see #addr_iton)
  276. # @return (see #addr_ntoa)
  277. def self.addr_itoa(addr, v6=false)
  278. nboa = addr_iton(addr, v6)
  279. addr_ntoa(nboa)
  280. end
  281. #
  282. # Converts a ascii address to network byte order
  283. #
  284. def self.addr_aton(addr)
  285. resolv_nbo(addr)
  286. end
  287. #
  288. # Converts a network byte order address to ascii
  289. #
  290. # @param addr [String] Packed network-byte-order address
  291. # @return [String] Human readable IP address.
  292. def self.addr_ntoa(addr)
  293. # IPv4
  294. if (addr.length == 4)
  295. return addr.unpack('C4').join('.')
  296. end
  297. # IPv6
  298. if (addr.length == 16)
  299. return compress_address(addr.unpack('n8').map{ |c| "%x" % c }.join(":"))
  300. end
  301. raise RuntimeError, "Invalid address format"
  302. end
  303. #
  304. # Implement zero compression for IPv6 addresses.
  305. # Uses the compression method from Marco Ceresa's IPAddress GEM
  306. #
  307. # @see https://github.com/bluemonk/ipaddress/blob/master/lib/ipaddress/ipv6.rb
  308. #
  309. # @param addr [String] Human readable IPv6 address
  310. # @return [String] Human readable IPv6 address with runs of 0s removed
  311. def self.compress_address(addr)
  312. return addr unless is_ipv6?(addr)
  313. addr = addr.dup
  314. while true
  315. break if addr.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
  316. break if addr.sub!(/\b0:0:0:0:0:0:0\b/, ':')
  317. break if addr.sub!(/\b0:0:0:0:0:0\b/, ':')
  318. break if addr.sub!(/\b0:0:0:0:0\b/, ':')
  319. break if addr.sub!(/\b0:0:0:0\b/, ':')
  320. break if addr.sub!(/\b0:0:0\b/, ':')
  321. break if addr.sub!(/\b0:0\b/, ':')
  322. break
  323. end
  324. addr.sub(/:{3,}/, '::')
  325. end
  326. #
  327. # Converts a network byte order address to an integer
  328. #
  329. def self.addr_ntoi(addr)
  330. bits = addr.unpack("N*")
  331. if (bits.length == 1)
  332. return bits[0]
  333. end
  334. if (bits.length == 4)
  335. val = 0
  336. bits.each_index { |i| val += ( bits[i] << (96 - (i * 32)) ) }
  337. return val
  338. end
  339. raise RuntimeError, "Invalid address format"
  340. end
  341. #
  342. # Converts an integer into a network byte order address
  343. #
  344. # @param addr [Numeric] The address as a number
  345. # @param v6 [Boolean] Whether +addr+ is IPv6
  346. def self.addr_iton(addr, v6=false)
  347. if(addr < 0x100000000 && !v6)
  348. return [addr].pack('N')
  349. else
  350. w = []
  351. w[0] = (addr >> 96) & 0xffffffff
  352. w[1] = (addr >> 64) & 0xffffffff
  353. w[2] = (addr >> 32) & 0xffffffff
  354. w[3] = addr & 0xffffffff
  355. return w.pack('N4')
  356. end
  357. end
  358. #
  359. # Converts a colon-delimited MAC address into a 6-byte binary string
  360. #
  361. def self.eth_aton(mac)
  362. mac.split(":").map{|c| c.to_i(16) }.pack("C*")
  363. end
  364. #
  365. # Converts a 6-byte binary string into a colon-delimited MAC address
  366. #
  367. def self.eth_ntoa(bin)
  368. bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase
  369. end
  370. #
  371. # Converts a CIDR subnet into an array (base, bcast)
  372. #
  373. def self.cidr_crack(cidr, v6=false)
  374. tmp = cidr.split('/')
  375. tst,scope = tmp[0].split("%",2)
  376. scope = "%" + scope if scope
  377. scope ||= ""
  378. addr = addr_atoi(tst)
  379. bits = 32
  380. mask = 0
  381. use6 = false
  382. if (addr > 0xffffffff or v6 or cidr =~ /:/)
  383. use6 = true
  384. bits = 128
  385. end
  386. mask = (2 ** bits) - (2 ** (bits - tmp[1].to_i))
  387. base = addr & mask
  388. stop = base + (2 ** (bits - tmp[1].to_i)) - 1
  389. return [self.addr_itoa(base, use6) + scope, self.addr_itoa(stop, use6) + scope]
  390. end
  391. #
  392. # Converts a netmask (255.255.255.240) into a bitmask (28). This is the
  393. # lame kid way of doing it.
  394. #
  395. def self.net2bitmask(netmask)
  396. nmask = resolv_nbo(netmask)
  397. imask = addr_ntoi(nmask)
  398. bits = 32
  399. if (imask > 0xffffffff)
  400. bits = 128
  401. end
  402. 0.upto(bits-1) do |bit|
  403. p = 2 ** bit
  404. return (bits - bit) if ((imask & p) == p)
  405. end
  406. 0
  407. end
  408. #
  409. # Converts a bitmask (28) into a netmask (255.255.255.240)
  410. #
  411. def self.bit2netmask(bitmask, ipv6=false)
  412. if bitmask > 32 or ipv6
  413. i = ((~((2 ** (128 - bitmask)) - 1)) & (2**128-1))
  414. n = Rex::Socket.addr_iton(i, true)
  415. return Rex::Socket.addr_ntoa(n)
  416. else
  417. [ (~((2 ** (32 - bitmask)) - 1)) & 0xffffffff ].pack('N').unpack('CCCC').join('.')
  418. end
  419. end
  420. def self.portspec_crack(pspec)
  421. portspec_to_portlist(pspec)
  422. end
  423. #
  424. # Converts a port specification like "80,21-23,443" into a sorted,
  425. # unique array of valid port numbers like [21,22,23,80,443]
  426. #
  427. def self.portspec_to_portlist(pspec)
  428. ports = []
  429. # Build ports array from port specification
  430. pspec.split(/,/).each do |item|
  431. start, stop = item.split(/-/).map { |p| p.to_i }
  432. start ||= 0
  433. stop ||= item.match(/-/) ? 65535 : start
  434. start, stop = stop, start if stop < start
  435. start.upto(stop) { |p| ports << p }
  436. end
  437. # Sort, and remove dups and invalid ports
  438. ports.sort.uniq.delete_if { |p| p < 1 or p > 65535 }
  439. end
  440. #
  441. # Converts a port list like [1,2,3,4,5,100] into a
  442. # range specification like "1-5,100"
  443. #
  444. def self.portlist_to_portspec(parr)
  445. ranges = []
  446. range = []
  447. lastp = nil
  448. parr.uniq.sort{|a,b| a<=>b}.map{|a| a.to_i}.each do |n|
  449. next if (n < 1 or n > 65535)
  450. if not lastp
  451. range = [n]
  452. lastp = n
  453. next
  454. end
  455. if lastp == n - 1
  456. range << n
  457. else
  458. ranges << range
  459. range = [n]
  460. end
  461. lastp = n
  462. end
  463. ranges << range
  464. ranges.delete(nil)
  465. ranges.uniq.map{|x| x.length == 1 ? "#{x[0]}" : "#{x[0]}-#{x[-1]}"}.join(",")
  466. end
  467. ##
  468. #
  469. # Utility class methods
  470. #
  471. ##
  472. #
  473. # This method does NOT send any traffic to the destination, instead, it uses a
  474. # "bound" UDP socket to determine what source address we would use to
  475. # communicate with the specified destination. The destination defaults to
  476. # Google's DNS server to make the standard behavior determine which IP
  477. # we would use to communicate with the internet.
  478. #
  479. def self.source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local)
  480. begin
  481. s = self.create_udp(
  482. 'PeerHost' => dest,
  483. 'PeerPort' => 31337,
  484. 'Comm' => comm
  485. )
  486. r = s.getsockname[1]
  487. s.close
  488. # Trim off the trailing interface ID for link-local IPv6
  489. return r.split('%').first
  490. rescue ::Exception
  491. return '127.0.0.1'
  492. end
  493. end
  494. #
  495. # Identifies the link-local address of a given interface (if IPv6 is enabled)
  496. #
  497. def self.ipv6_link_address(intf)
  498. r = source_address("FF02::1%#{intf}")
  499. return nil if r.nil? || r !~ /^fe80/i
  500. r
  501. end
  502. #
  503. # Identifies the mac address of a given interface (if IPv6 is enabled)
  504. #
  505. def self.ipv6_mac(intf)
  506. r = ipv6_link_address(intf)
  507. return if not r
  508. raw = addr_aton(r)[-8, 8]
  509. (raw[0,3] + raw[5,3]).unpack("C*").map{|c| "%.2x" % c}.join(":")
  510. end
  511. #
  512. # Create a TCP socket pair.
  513. #
  514. # sf: This create a socket pair using native ruby sockets and will work
  515. # on Windows where ::Socket.pair is not implemented.
  516. # Note: OpenSSL requires native ruby sockets for its io.
  517. #
  518. # Note: Even though sub-threads are smashing the parent threads local, there
  519. # is no concurrent use of the same locals and this is safe.
  520. def self.tcp_socket_pair
  521. lsock = nil
  522. rsock = nil
  523. laddr = '127.0.0.1'
  524. lport = 0
  525. threads = []
  526. mutex = ::Mutex.new
  527. threads << Rex::ThreadFactory.spawn('TcpSocketPair', false) {
  528. server = nil
  529. mutex.synchronize {
  530. threads << Rex::ThreadFactory.spawn('TcpSocketPairClient', false) {
  531. mutex.synchronize {
  532. rsock = ::TCPSocket.new( laddr, lport )
  533. }
  534. }
  535. server = ::TCPServer.new(laddr, 0)
  536. if (server.getsockname =~ /127\.0\.0\.1:/)
  537. # JRuby ridiculousness
  538. caddr, lport = server.getsockname.split(":")
  539. caddr = caddr[1,caddr.length]
  540. lport = lport.to_i
  541. else
  542. # Sane implementations where Socket#getsockname returns a
  543. # sockaddr
  544. lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
  545. end
  546. }
  547. lsock, _ = server.accept
  548. server.close
  549. }
  550. threads.each { |t| t.join }
  551. return [lsock, rsock]
  552. end
  553. #
  554. # Create a UDP socket pair using native ruby UDP sockets.
  555. #
  556. def self.udp_socket_pair
  557. laddr = '127.0.0.1'
  558. lsock = ::UDPSocket.new
  559. lsock.bind( laddr, 0 )
  560. rsock = ::UDPSocket.new
  561. rsock.bind( laddr, 0 )
  562. rsock.connect( *lsock.addr.values_at(3,1) )
  563. lsock.connect( *rsock.addr.values_at(3,1) )
  564. return [lsock, rsock]
  565. end
  566. ##
  567. #
  568. # Class initialization
  569. #
  570. ##
  571. #
  572. # Initialize general socket parameters.
  573. #
  574. def initsock(params = nil)
  575. if (params)
  576. self.peerhost = params.peerhost
  577. self.peerport = params.peerport
  578. self.localhost = params.localhost
  579. self.localport = params.localport
  580. self.context = params.context || {}
  581. self.ipv = params.v6 ? 6 : 4
  582. end
  583. end
  584. #
  585. # By default, all sockets are themselves selectable file descriptors.
  586. #
  587. def fd
  588. self
  589. end
  590. #
  591. # Returns local connection information.
  592. #
  593. def getsockname
  594. Socket.from_sockaddr(super)
  595. end
  596. #
  597. # Wrapper around getsockname
  598. #
  599. def getlocalname
  600. getsockname
  601. end
  602. #
  603. # Return peer connection information.
  604. #
  605. def getpeername
  606. return Socket.from_sockaddr(super)
  607. end
  608. #
  609. # Returns a string that indicates the type of the socket, such as 'tcp'.
  610. #
  611. def type?
  612. raise NotImplementedError, "Socket type is not supported."
  613. end
  614. #
  615. # The peer host of the connected socket.
  616. #
  617. attr_reader :peerhost
  618. #
  619. # The peer port of the connected socket.
  620. #
  621. attr_reader :peerport
  622. #
  623. # The local host of the connected socket.
  624. #
  625. attr_reader :localhost
  626. #
  627. # The local port of the connected socket.
  628. #
  629. attr_reader :localport
  630. #
  631. # The IP version of the socket
  632. #
  633. attr_reader :ipv
  634. #
  635. # Contextual information that describes the source and other
  636. # instance-specific attributes. This comes from the param.context
  637. # attribute.
  638. #
  639. attr_reader :context
  640. protected
  641. attr_writer :peerhost, :peerport, :localhost, :localport # :nodoc:
  642. attr_writer :context # :nodoc:
  643. attr_writer :ipv # :nodoc:
  644. end
  645. end
  646. #
  647. # Globalized socket constants
  648. #
  649. SHUT_RDWR = ::Socket::SHUT_RDWR
  650. SHUT_RD = ::Socket::SHUT_RD
  651. SHUT_WR = ::Socket::SHUT_WR