class Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::UdpChannel
Public Class Methods
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 27 def cls return CHANNEL_CLASS_DATAGRAM end
Simply initialize this instance.
Rex::Post::Meterpreter::Channel::new
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 66 def initialize(client, cid, type, flags) super(client, cid, type, flags) # the instance variable that holds all incoming datagrams. @datagrams = [] end
Open a new UDP channel on the remote end. The local host/port are optional, if none are specified the remote end will bind to INADDR_ANY with a random port number. The peer host/port are also optional, if specified all default send(), write() call will sendto the specified peer. If no peer host/port is specified you must use sendto() and specify the remote peer you wish to send to. This effectivly lets us create bound/unbound and connected/unconnected UDP sockets with ease.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 39 def UdpChannel.open(client, params) c = Channel.create(client, 'stdapi_net_udp_client', self, CHANNEL_FLAG_SYNCHRONOUS, [ { 'type' => TLV_TYPE_LOCAL_HOST, 'value' => params.localhost }, { 'type' => TLV_TYPE_LOCAL_PORT, 'value' => params.localport }, { 'type' => TLV_TYPE_PEER_HOST, 'value' => params.peerhost }, { 'type' => TLV_TYPE_PEER_PORT, 'value' => params.peerport } ] ) c.params = params c end
Public Instance Methods
Wrap the _write() call in order to catch some common, but harmless Windows exceptions
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 193 def _write(*args) begin super(*args) rescue ::Rex::Post::Meterpreter::RequestError => e case e.code when 10000 .. 10100 raise ::Rex::ConnectionError.new end end end
The channels direct io write handler for any incoming data from the remote end of the channel. We extract the data and peer host/port, and save this to a queue of incoming datagrams which are passed out via calls to self.recvfrom()
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 177 def dio_write_handler( packet, data ) peerhost = packet.get_tlv_value( TLV_TYPE_PEER_HOST ) peerport = packet.get_tlv_value( TLV_TYPE_PEER_PORT ) if( peerhost and peerport ) @datagrams << [ data, peerhost, peerport ] return true end return false end
We overwrite Rex::Socket::Udp.recvfrom
in order to correctly hand out the datagrams which the remote end of this channel has received and are in the queue.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 102 def recvfrom( length=65535, timeout=def_read_timeout ) result = nil # force a timeout on the wait for an incoming datagram begin Timeout.timeout( timeout ) { while( true ) # wait untill we have at least one datagram in the queue if( @datagrams.empty? ) Rex::ThreadSafe.sleep( 0.2 ) next end # grab the oldest datagram we have received... result = @datagrams.shift # break as we have a result... break end } rescue Timeout::Error result = nil end # if no result return nothing if( result == nil ) return [ '', nil, nil ] end # get the data from this datagram data = result[0] # if its only a partial read of this datagram, slice it, loosing the remainder. result[0] = data[0,length-1] if data.length > length # return the result in the form [ data, host, port ] return result end
This function is called by Rex::Socket::Udp.sendto
and writes data to a specified remote peer host/port via the remote end of the channel.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 155 def send( buf, flags, saddr ) af, peerhost, peerport = Rex::Socket.from_sockaddr( saddr ) addends = [ { 'type' => TLV_TYPE_PEER_HOST, 'value' => peerhost }, { 'type' => TLV_TYPE_PEER_PORT, 'value' => peerport } ] return _write( buf, buf.length, addends ) end
Overwrite the low level sysread to read data off our datagram queue. Calls to read() will end up calling this.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 138 def sysread( length ) result = self.recvfrom( length ) return result[0] end
Overwrite the low level syswrite to write data to the remote end of the channel. Calls to write() will end up calling this.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 147 def syswrite( buf ) return _write( buf ) end
We overwrite Rex::Socket::Udp.timed_read
in order to avoid the call to Kernel.select which wont be of use as we are not a natively backed ::Socket or ::IO instance.
# File lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb, line 76 def timed_read( length=65535, timeout=def_read_timeout ) result = '' begin Timeout.timeout( timeout ) { while( true ) if( @datagrams.empty? ) Rex::ThreadSafe.sleep( 0.2 ) next end result = self.read( length ) break end } rescue Timeout::Error result = '' end return result end