From 1de2dac652073498d7d06f667fd6fcd4fd1ab119 Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Thu, 2 Jun 2005 07:52:17 +0000 Subject: [PATCH] unfinished shiznit git-svn-id: file:///home/svn/incoming/trunk@2544 4d416f70-5f16-0410-b530-b9f4589650da --- lib/rex/io/stream.rb | 7 +- lib/rex/socket.rb | 77 +++++++++++++++++++++ lib/rex/socket/comm/local.rb | 56 +++++++++++++++ lib/rex/socket/parameters.rb | 128 +++++++++++++++++++++++++++++++++++ lib/rex/socket/tcp.rb | 61 +++++++++++++++++ 5 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 lib/rex/socket.rb create mode 100644 lib/rex/socket/comm/local.rb create mode 100644 lib/rex/socket/parameters.rb create mode 100644 lib/rex/socket/tcp.rb diff --git a/lib/rex/io/stream.rb b/lib/rex/io/stream.rb index ca1b532279..a705a0ded9 100644 --- a/lib/rex/io/stream.rb +++ b/lib/rex/io/stream.rb @@ -59,7 +59,12 @@ module Stream # otherwise nil is returned. # def poll_read(timeout = nil) - return nil + end + + # + # Returns the file descriptor that can be polled via select, if any. + # + def poll_fd end ## diff --git a/lib/rex/socket.rb b/lib/rex/socket.rb new file mode 100644 index 0000000000..291a6d2595 --- /dev/null +++ b/lib/rex/socket.rb @@ -0,0 +1,77 @@ +require 'socket' +require 'resolv' +require 'Rex/Socket/Parameters' + +module Rex + +### +# +# Socket +# ------ +# +# Base class for all sockets. +# +### +class Socket + + ## + # + # Factory methods + # + ## + + def self.create(opts) + return create_param(Rex::Socket::Parameters.from_hash(opts)) + end + + def self.create_param(param) + return param.comm.create(param) + end + + def self.create_tcp(opts) + return create_tcp_param(Rex::Socket::Parameters.from_hash(opts)) + end + + def self.create_tcp_param(param) + param.proto = 'tcp' + + return create_param(param) + end + + ## + # + # Serialization + # + ## + + # + # Create a sockaddr structure using the supplied IP address, port, and + # address family + # + def self.to_sockaddr(ip, port, af = ::Socket::AF_INET) + ip = "0.0.0.0" unless ip + ip = Resolv.getaddress(ip) + data = [ af, port.to_i ] + ip.split('.').collect { |o| o.to_i } + [ "" ] + + return data.pack('snCCCCa8') + end + + ## + # + # Class initialization + # + ## + + def initialize(sock) + self.sock = sock + end + + attr_reader :sock + +protected + + attr_writer :sock + +end + +end diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb new file mode 100644 index 0000000000..3d62f0b1d1 --- /dev/null +++ b/lib/rex/socket/comm/local.rb @@ -0,0 +1,56 @@ +require 'Rex/Socket' +require 'Rex/Socket/Tcp' +require 'Rex/Socket/TcpServer' + +### +# +# Local +# ----- +# +# Local communication class factory. +# +### +class Rex::Socket::Comm::Local + + # + # Creates an instance of a socket using the supplied parameters. + # + def self.create(param) + case param.proto + when 'tcp' + return create_tcp(param) + else + raise RuntimeError, "Unsupported protocol: #{param.proto}", caller # FIXME EXCEPTION + end + end + + # + # Creates a TCP socket + # + def self.create_tcp(param) + # Create the raw TCP socket + sock = ::Socket.new(::Socket::AF_INET, 'tcp', 0) + + # Bind to a given local address and/or port if they are supplied + if (param.localhost || param.localport) + sock.bind(to_sockaddr(param.localhost, param.localport)) + end + + # If a server TCP instance is being created... + if (param.server?) + sock.listen(32) + + return sock if (param.bare?) + + return Rex::Socket::TcpServer.new(sock) + # Otherwise, if we're creating a client... + else + sock.connect(to_sockaddr(param.peerhost, param.peerport)) + + return sock if (param.bare?) + + return Rex::Socket::Tcp.new(sock) + end + end + +end diff --git a/lib/rex/socket/parameters.rb b/lib/rex/socket/parameters.rb new file mode 100644 index 0000000000..ef5163172e --- /dev/null +++ b/lib/rex/socket/parameters.rb @@ -0,0 +1,128 @@ +require 'Rex/Socket' +require 'Rex/Socket/Comm/Local' + +### +# +# Parameters +# ---------- +# +# This class represents the set of parameters that are used to create +# a socket, whether it be a server or client socket. +# +### +class Rex::Socket::Parameters + + ## + # + # Factory + # + ## + + def Parameters.from_hash(hash) + return Parameters.new(hash) + end + + ## + # + # Constructor + # + ## + + # Initializes the attributes from the supplied hash + def initialize(hash) + if (hash['PeerHost']) + self.peerhost = hash['PeerHost'] + elsif (hash['PeerAddr']) + self.peerhost = hash['PeerHost'] + else + self.peerhost = nil + end + + if (hash['LocalHost']) + self.localhost = hash['LocalHost'] + elsif (hash['LocalAddr']) + self.localhost = hash['LocalAddr'] + else + self.localhost = '0.0.0.0' + end + + if (hash['PeerPort']) + self.peerport = hash['PeerPort'].to_i + else + self.peerport = 0 + end + + if (hash['LocalPort']) + self.localport = hash['LocalPort'].to_i + else + self.localport = 0 + end + + if (hash['Bare']) + self.bare = true + else + self.bare = false + end + + # The protocol this socket will be using + self.proto = hash['Proto'].downcase || 'tcp' + + # Whether or not the socket should be a server + self.server = hash['Server'] || false + + # The communication subsystem to use to create the socket + self.comm = hash['Comm'] || Rex::Socket::Comm::Local; + + # The number of connection retries to make (client only) + self.retries = hash['Retries'] || 0 + end + + ## + # + # Conditionals + # + ## + + def server? + return (server == true) + end + + def client? + return (server == false) + end + + def tcp? + return proto == 'tcp' + end + + def udp? + return proto == 'udp' + end + + def bare? + return (bare == true) + end + + ## + # + # Attributes + # + ## + + attr_accessor :peerhost, :peerport + attr_accessor :localhost, :localport + attr_accessor :proto, :server, :comm + attr_accessor :retries, :bare + + ## + # + # Synonyms + # + ## + + alias peeraddr peerhost + alias localaddr localhost + +end + +end; end diff --git a/lib/rex/socket/tcp.rb b/lib/rex/socket/tcp.rb new file mode 100644 index 0000000000..e695eeb0c1 --- /dev/null +++ b/lib/rex/socket/tcp.rb @@ -0,0 +1,61 @@ +require 'Rex/Socket' +require 'Rex/IO/Stream' + +class Rex::Socket::Tcp < Rex::Socket + include Rex::IO::Stream + + ## + # + # Class initialization + # + ## + + def initialize(sock) + super + end + + ## + # + # Stream mixin implementations + # + ## + + def blocking=(tf) + return tf # FIXME + end + + def blocking + return true # FIXME + end + + def write(buf, opts = {}) + return sock.syswrite(buf) + end + + def read(length = nil, opts = {}) + length = 16384 unless length + + begin + return sock.sysread(length) + rescue EOFError + return nil + end + end + + def shutdown(how = SW_BOTH) + return sock.shutdown(how) + end + + def close + sock.close + end + + def poll_read(timeout = nil) + return select([ sock ], nil, nil, timeout) + end + + def poll_fd + return sock + end + +end