lib/rex/services/local_relay.rb in librex-0.0.68 vs lib/rex/services/local_relay.rb in librex-0.0.70

- old
+ new

@@ -13,410 +13,410 @@ # Rex::IO::Stream interface. # ### class LocalRelay - include Rex::Service + include Rex::Service - ### - # - # This module is used to extend streams such that they can be associated - # with a relay context and the other side of the stream. - # - ### - module Stream + ### + # + # This module is used to extend streams such that they can be associated + # with a relay context and the other side of the stream. + # + ### + module Stream - # - # This method is called when the other side has data that has been read - # in. - # - def on_other_data(data) - if (relay.on_other_data_proc) - relay.on_other_data_proc.call(relay, self, data) - else - put(data) - end - end + # + # This method is called when the other side has data that has been read + # in. + # + def on_other_data(data) + if (relay.on_other_data_proc) + relay.on_other_data_proc.call(relay, self, data) + else + put(data) + end + end - attr_accessor :relay - attr_accessor :other_stream - end + attr_accessor :relay + attr_accessor :other_stream + end - ### - # - # This module is used to extend stream servers such that they can be - # associated with a relay context. - # - ### - module StreamServer + ### + # + # This module is used to extend stream servers such that they can be + # associated with a relay context. + # + ### + module StreamServer - # - # This method is called when the stream server receives a local - # connection such that the remote half can be allocated. The return - # value of the callback should be a Stream instance. - # - def on_local_connection(relay, lfd) - if (relay.on_local_connection_proc) - relay.on_local_connection_proc.call(relay, lfd) - end - end + # + # This method is called when the stream server receives a local + # connection such that the remote half can be allocated. The return + # value of the callback should be a Stream instance. + # + def on_local_connection(relay, lfd) + if (relay.on_local_connection_proc) + relay.on_local_connection_proc.call(relay, lfd) + end + end - attr_accessor :relay - end + attr_accessor :relay + end - ### - # - # This class acts as an instance of a given local relay. - # - ### - class Relay + ### + # + # This class acts as an instance of a given local relay. + # + ### + class Relay - def initialize(name, listener, opts = {}) - self.name = name - self.listener = listener - self.opts = opts - self.on_local_connection_proc = opts['OnLocalConnection'] - self.on_conn_close_proc = opts['OnConnectionClose'] - self.on_other_data_proc = opts['OnOtherData'] - if (not $dispatcher['rex']) - register_log_source('rex', $dispatcher['core'], get_log_level('core')) - end - end + def initialize(name, listener, opts = {}) + self.name = name + self.listener = listener + self.opts = opts + self.on_local_connection_proc = opts['OnLocalConnection'] + self.on_conn_close_proc = opts['OnConnectionClose'] + self.on_other_data_proc = opts['OnOtherData'] + if (not $dispatcher['rex']) + register_log_source('rex', $dispatcher['core'], get_log_level('core')) + end + end - def shutdown - begin - listener.shutdown if (listener) - rescue ::Exception - end - end + def shutdown + begin + listener.shutdown if (listener) + rescue ::Exception + end + end - def close - begin - listener.close if (listener) - rescue ::Exception - end - listener = nil - end + def close + begin + listener.close if (listener) + rescue ::Exception + end + listener = nil + end - attr_reader :name, :listener, :opts - attr_accessor :on_local_connection_proc - attr_accessor :on_conn_close_proc - attr_accessor :on_other_data_proc - protected - attr_writer :name, :listener, :opts + attr_reader :name, :listener, :opts + attr_accessor :on_local_connection_proc + attr_accessor :on_conn_close_proc + attr_accessor :on_other_data_proc + protected + attr_writer :name, :listener, :opts - end + end - # - # Initializes the local tcp relay monitor. - # - def initialize - self.relays = Hash.new - self.rfds = Array.new - self.relay_thread = nil - self.relay_mutex = Mutex.new - end + # + # Initializes the local tcp relay monitor. + # + def initialize + self.relays = Hash.new + self.rfds = Array.new + self.relay_thread = nil + self.relay_mutex = Mutex.new + end - ## - # - # Service interface implementors - # - ## + ## + # + # Service interface implementors + # + ## - # - # Returns the hardcore alias for the local relay service. - # - def self.hardcore_alias(*args) - "__#{args}" - end + # + # Returns the hardcore alias for the local relay service. + # + def self.hardcore_alias(*args) + "__#{args}" + end - # - # Returns the alias for this service. - # - def alias - super || "Local Relay" - end + # + # Returns the alias for this service. + # + def alias + super || "Local Relay" + end - # - # Starts the thread that monitors the local relays. - # - def start - if (!self.relay_thread) - self.relay_thread = Rex::ThreadFactory.spawn("LocalRelay", false) { - begin - monitor_relays - rescue ::Exception - elog("Error in #{self} monitor_relays: #{$!}", 'rex') - end - } - end - end + # + # Starts the thread that monitors the local relays. + # + def start + if (!self.relay_thread) + self.relay_thread = Rex::ThreadFactory.spawn("LocalRelay", false) { + begin + monitor_relays + rescue ::Exception + elog("Error in #{self} monitor_relays: #{$!}", 'rex') + end + } + end + end - # - # Stops the thread that monitors the local relays and destroys all local - # listeners. - # - def stop - if (self.relay_thread) - self.relay_thread.kill - self.relay_thread = nil - end + # + # Stops the thread that monitors the local relays and destroys all local + # listeners. + # + def stop + if (self.relay_thread) + self.relay_thread.kill + self.relay_thread = nil + end - self.relay_mutex.synchronize { - self.relays.delete_if { |k, v| - v.shutdown - v.close - true - } - } + self.relay_mutex.synchronize { + self.relays.delete_if { |k, v| + v.shutdown + v.close + true + } + } - # Flush the relay list and read fd list - self.relays.clear - self.rfds.clear - end + # Flush the relay list and read fd list + self.relays.clear + self.rfds.clear + end - ## - # - # Adding/removing local tcp relays - # - ## + ## + # + # Adding/removing local tcp relays + # + ## - # - # Starts a local TCP relay. - # - def start_tcp_relay(lport, opts = {}) - # Make sure our options are valid - if ((opts['PeerHost'] == nil or opts['PeerPort'] == nil) and (opts['Stream'] != true)) - raise ArgumentError, "Missing peer host or peer port.", caller - end + # + # Starts a local TCP relay. + # + def start_tcp_relay(lport, opts = {}) + # Make sure our options are valid + if ((opts['PeerHost'] == nil or opts['PeerPort'] == nil) and (opts['Stream'] != true)) + raise ArgumentError, "Missing peer host or peer port.", caller + end - listener = Rex::Socket.create_tcp_server( - 'LocalHost' => opts['LocalHost'], - 'LocalPort' => lport) + listener = Rex::Socket.create_tcp_server( + 'LocalHost' => opts['LocalHost'], + 'LocalPort' => lport) - opts['LocalPort'] = lport - opts['__RelayType'] = 'tcp' + opts['LocalPort'] = lport + opts['__RelayType'] = 'tcp' - start_relay(listener, lport.to_s + (opts['LocalHost'] || '0.0.0.0'), opts) - end + start_relay(listener, lport.to_s + (opts['LocalHost'] || '0.0.0.0'), opts) + end - # - # Starts a local relay on the supplied local port. This listener will call - # the supplied callback procedures when various events occur. - # - def start_relay(stream_server, name, opts = {}) - # Create a Relay instance with the local stream and remote stream - relay = Relay.new(name, stream_server, opts) + # + # Starts a local relay on the supplied local port. This listener will call + # the supplied callback procedures when various events occur. + # + def start_relay(stream_server, name, opts = {}) + # Create a Relay instance with the local stream and remote stream + relay = Relay.new(name, stream_server, opts) - # Extend the stream_server so that we can associate it with this relay - stream_server.extend(StreamServer) - stream_server.relay = relay + # Extend the stream_server so that we can associate it with this relay + stream_server.extend(StreamServer) + stream_server.relay = relay - # Add the stream associations the appropriate lists and hashes - self.relay_mutex.synchronize { - self.relays[name] = relay + # Add the stream associations the appropriate lists and hashes + self.relay_mutex.synchronize { + self.relays[name] = relay - self.rfds << stream_server - } - end + self.rfds << stream_server + } + end - # - # Stops relaying on a given local port. - # - def stop_tcp_relay(lport, lhost = nil) - stop_relay(lport.to_s + (lhost || '0.0.0.0')) - end + # + # Stops relaying on a given local port. + # + def stop_tcp_relay(lport, lhost = nil) + stop_relay(lport.to_s + (lhost || '0.0.0.0')) + end - # - # Stops a relay with a given name. - # - def stop_relay(name) - rv = false + # + # Stops a relay with a given name. + # + def stop_relay(name) + rv = false - self.relay_mutex.synchronize { - relay = self.relays[name] + self.relay_mutex.synchronize { + relay = self.relays[name] - if (relay) - close_relay(relay) - rv = true - end - } + if (relay) + close_relay(relay) + rv = true + end + } - rv - end + rv + end - # - # Enumerate each TCP relay - # - def each_tcp_relay(&block) - self.relays.each_pair { |name, relay| - next if (relay.opts['__RelayType'] != 'tcp') + # + # Enumerate each TCP relay + # + def each_tcp_relay(&block) + self.relays.each_pair { |name, relay| + next if (relay.opts['__RelayType'] != 'tcp') - yield( - relay.opts['LocalHost'] || '0.0.0.0', - relay.opts['LocalPort'], - relay.opts['PeerHost'], - relay.opts['PeerPort'], - relay.opts) - } - end + yield( + relay.opts['LocalHost'] || '0.0.0.0', + relay.opts['LocalPort'], + relay.opts['PeerHost'], + relay.opts['PeerPort'], + relay.opts) + } + end protected - attr_accessor :relays, :relay_thread, :relay_mutex - attr_accessor :rfds + attr_accessor :relays, :relay_thread, :relay_mutex + attr_accessor :rfds - # - # Closes an cleans up a specific relay - # - def close_relay(relay) - self.rfds.delete(relay.listener) - self.relays.delete(relay.name) + # + # Closes an cleans up a specific relay + # + def close_relay(relay) + self.rfds.delete(relay.listener) + self.relays.delete(relay.name) - begin - relay.shutdown - relay.close - rescue IOError - end - end + begin + relay.shutdown + relay.close + rescue IOError + end + end - # - # Closes a specific relay connection without tearing down the actual relay - # itself. - # - def close_relay_conn(fd) - relay = fd.relay - ofd = fd.other_stream + # + # Closes a specific relay connection without tearing down the actual relay + # itself. + # + def close_relay_conn(fd) + relay = fd.relay + ofd = fd.other_stream - self.rfds.delete(fd) + self.rfds.delete(fd) - begin - if (relay.on_conn_close_proc) - relay.on_conn_close_proc.call(fd) - end + begin + if (relay.on_conn_close_proc) + relay.on_conn_close_proc.call(fd) + end - fd.shutdown - fd.close - rescue IOError - end + fd.shutdown + fd.close + rescue IOError + end - if (ofd) - self.rfds.delete(ofd) + if (ofd) + self.rfds.delete(ofd) - begin - if (relay.on_conn_close_proc) - relay.on_conn_close_proc.call(ofd) - end + begin + if (relay.on_conn_close_proc) + relay.on_conn_close_proc.call(ofd) + end - ofd.shutdown - ofd.close - rescue IOError - end - end - end + ofd.shutdown + ofd.close + rescue IOError + end + end + end - # - # Accepts a client connection on a local relay. - # - def accept_relay_conn(srvfd) - relay = srvfd.relay + # + # Accepts a client connection on a local relay. + # + def accept_relay_conn(srvfd) + relay = srvfd.relay - begin - dlog("Accepting relay client connection...", 'rex', LEV_3) + begin + dlog("Accepting relay client connection...", 'rex', LEV_3) - # Accept the child connection - lfd = srvfd.accept - dlog("Got left side of relay: #{lfd}", 'rex', LEV_3) + # Accept the child connection + lfd = srvfd.accept + dlog("Got left side of relay: #{lfd}", 'rex', LEV_3) - # Call the relay's on_local_connection method which should return a - # remote connection on success - rfd = srvfd.on_local_connection(relay, lfd) + # Call the relay's on_local_connection method which should return a + # remote connection on success + rfd = srvfd.on_local_connection(relay, lfd) - dlog("Got right side of relay: #{rfd}", 'rex', LEV_3) - rescue - wlog("Failed to get remote half of local connection on relay #{relay.name}: #{$!}", 'rex') - lfd.close - return - end + dlog("Got right side of relay: #{rfd}", 'rex', LEV_3) + rescue + wlog("Failed to get remote half of local connection on relay #{relay.name}: #{$!}", 'rex') + lfd.close + return + end - # If we have both sides, then we rock. Extend the instances, associate - # them with the relay, associate them with each other, and add them to - # the list of polling file descriptors - if (lfd and rfd) - lfd.extend(Stream) - rfd.extend(Stream) + # If we have both sides, then we rock. Extend the instances, associate + # them with the relay, associate them with each other, and add them to + # the list of polling file descriptors + if (lfd and rfd) + lfd.extend(Stream) + rfd.extend(Stream) - lfd.relay = relay - rfd.relay = relay + lfd.relay = relay + rfd.relay = relay - lfd.other_stream = rfd - rfd.other_stream = lfd + lfd.other_stream = rfd + rfd.other_stream = lfd - self.rfds << lfd - self.rfds << rfd + self.rfds << lfd + self.rfds << rfd - # Otherwise, we don't have both sides, we'll close them. - else - close_relay_conn(lfd) - end - end + # Otherwise, we don't have both sides, we'll close them. + else + close_relay_conn(lfd) + end + end - # - # Monitors the relays for data and passes it in both directions. - # - def monitor_relays - begin - # Helps with latency - Thread.current.priority = 2 + # + # Monitors the relays for data and passes it in both directions. + # + def monitor_relays + begin + # Helps with latency + Thread.current.priority = 2 - # Poll all the streams... - begin - socks = Rex::ThreadSafe.select(rfds, nil, nil, 0.25) - rescue StreamClosedError => e - dlog("monitor_relays: closing stream #{e.stream}", 'rex', LEV_3) + # Poll all the streams... + begin + socks = Rex::ThreadSafe.select(rfds, nil, nil, 0.25) + rescue StreamClosedError => e + dlog("monitor_relays: closing stream #{e.stream}", 'rex', LEV_3) - # Close the relay connection that is associated with the stream - # closed error - if (e.stream.kind_of?(Stream)) - close_relay_conn(e.stream) - end + # Close the relay connection that is associated with the stream + # closed error + if (e.stream.kind_of?(Stream)) + close_relay_conn(e.stream) + end - dlog("monitor_relays: closed stream #{e.stream}", 'rex', LEV_3) + dlog("monitor_relays: closed stream #{e.stream}", 'rex', LEV_3) - next - rescue - elog("Error in #{self} monitor_relays select: #{$!.class} #{$!}", 'rex') - return - end + next + rescue + elog("Error in #{self} monitor_relays select: #{$!.class} #{$!}", 'rex') + return + end - # If socks is nil, go again. - next unless socks + # If socks is nil, go again. + next unless socks - # Process read-ready file descriptors, if any. - socks[0].each { |rfd| + # Process read-ready file descriptors, if any. + socks[0].each { |rfd| - # If this file descriptor is a server, accept the connection - if (rfd.kind_of?(StreamServer)) - accept_relay_conn(rfd) - # Otherwise, it's a relay connection, read data from one side - # and write it to the other - else - begin - # Pass the data onto the other fd, most likely writing it. - data = rfd.sysread(65536) - rfd.other_stream.on_other_data(data) - # If we catch an error, close the connection - rescue ::Exception - elog("Error in #{self} monitor_relays read: #{$!}", 'rex') - close_relay_conn(rfd) - end - end + # If this file descriptor is a server, accept the connection + if (rfd.kind_of?(StreamServer)) + accept_relay_conn(rfd) + # Otherwise, it's a relay connection, read data from one side + # and write it to the other + else + begin + # Pass the data onto the other fd, most likely writing it. + data = rfd.sysread(65536) + rfd.other_stream.on_other_data(data) + # If we catch an error, close the connection + rescue ::Exception + elog("Error in #{self} monitor_relays read: #{$!}", 'rex') + close_relay_conn(rfd) + end + end - } if (socks[0]) + } if (socks[0]) - end while true - end + end while true + end end end end