Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/iax2/client.rb
Views: 11704
# -*- coding: binary -*-12require 'rex/socket'3require 'thread'4require 'digest/md5'5require 'timeout'67module Rex8module Proto9module IAX210class Client1112attr_accessor :caller_number, :caller_name, :server_host, :server_port13attr_accessor :username, :password14attr_accessor :sock, :monitor15attr_accessor :src_call_idx16attr_accessor :debugging17attr_accessor :calls1819def initialize(uopts={})20opts = {21:caller_number => '15555555555',22:caller_name => '',23:server_port => Constants::IAX2_DEFAULT_PORT,24:context => { }25}.merge(uopts)2627self.caller_name = opts[:caller_name]28self.caller_number = opts[:caller_number]29self.server_host = opts[:server_host]30self.server_port = opts[:server_port]31self.username = opts[:username]32self.password = opts[:password]33self.debugging = opts[:debugging]3435self.sock = Rex::Socket::Udp.create(36'PeerHost' => self.server_host,37'PeerPort' => self.server_port,38'Context' => opts[:context]39)4041self.monitor = ::Thread.new { monitor_socket }4243self.src_call_idx = 044self.calls = {}4546end4748def shutdown49self.monitor.kill rescue nil50end5152def create_call53cid = allocate_call_id()54self.calls[ cid ] = IAX2::Call.new(self, cid)55end5657#58# Transport59#6061def monitor_socket62while true63begin64pkt, src = self.sock.recvfrom(65535)65next if not pkt6667# Find the matching call object68mcall = matching_call(pkt)69next if not mcall7071if (pkt[0,1].unpack("C")[0] & 0x80) != 072mcall.handle_control(pkt)73else74# Dispatch the buffer via the call handler75mcall.handle_audio(pkt)76end77rescue ::Exception => e78dprint("monitor_socket: #{e.class} #{e} #{e.backtrace}")79break80end81end82self.sock.close rescue nil83end8485def matching_call(pkt)86src_call = pkt[0,2].unpack('n')[0]87dst_call = nil8889if (src_call & 0x8000 != 0)90dst_call = pkt[2,2].unpack('n')[0]91dst_call ^= 0x8000 if (dst_call & 0x8000 != 0)92end9394src_call ^= 0x8000 if (src_call & 0x8000 != 0)9596# Find a matching call in our list97mcall = self.calls.values.select {|x| x.dcall == src_call or (dst_call and x.scall == dst_call) }.first98if not mcall99dprint("Packet received for non-existent call #{[src_call, dst_call].inspect} vs #{self.calls.values.map{|x| [x.dcall, x.scall]}.inspect}")100return101end102mcall103end104105def allocate_call_id106res = ( self.src_call_idx += 1 )107if ( res > 0x8000 )108self.src_call_idx = 1109res = 1110end111res112end113114def dprint(msg)115return if not self.debugging116$stderr.puts "[#{::Time.now.to_s}] #{msg}"117end118119def send_data(call, data, inc_seq = true )120r = self.sock.sendto(data, self.server_host, self.server_port, 0)121if inc_seq122call.oseq = (call.oseq + 1) & 0xff123end124r125end126127def send_ack(call)128data = [ Constants::IAX_SUBTYPE_ACK ].pack('C')129send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ), false )130end131132def send_pong(call, stamp)133data = [ Constants::IAX_SUBTYPE_PONG ].pack('C')134send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )135end136137def send_lagrp(call, stamp)138data = [ Constants::IAX_SUBTYPE_LAGRP ].pack('C')139send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )140end141142143def send_invalid(call)144data = [ Constants::IAX_SUBTYPE_INVAL ].pack('C')145send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )146end147148def send_hangup(call)149data = [ Constants::IAX_SUBTYPE_HANGUP ].pack('C')150send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )151end152153def send_new(call, number)154data = [ Constants::IAX_SUBTYPE_NEW ].pack('C')155156cid = call.caller_number || self.caller_number157cid = number if cid == 'SELF'158159data << create_ie(Constants::IAX_IE_CALLING_NUMBER, cid )160data << create_ie(Constants::IAX_IE_CALLING_NAME, call.caller_name || self.caller_name)161data << create_ie(Constants::IAX_IE_DESIRED_CODEC, [Constants::IAX_SUPPORTED_CODECS].pack("N") )162data << create_ie(Constants::IAX_IE_ACTUAL_CODECS, [Constants::IAX_SUPPORTED_CODECS].pack("N") )163data << create_ie(Constants::IAX_IE_USERNAME, self.username) if self.username164data << create_ie(Constants::IAX_IE_CALLED_NUMBER, number)165data << create_ie(Constants::IAX_IE_ORIGINAL_DID, number)166167send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )168end169170def send_authrep_chall_response(call, chall)171data =172[ Constants::IAX_SUBTYPE_AUTHREP ].pack('C') +173create_ie(Constants::IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password ))174175send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )176end177178def send_regreq(call)179data = [ Constants::IAX_SUBTYPE_REGREQ ].pack('C')180data << create_ie(Constants::IAX_IE_USERNAME, self.username) if self.username181data << create_ie(Constants::IAX_IE_REG_REFRESH, [Constants::IAX_DEFAULT_REG_REFRESH].pack('n'))182183send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )184end185186def send_regreq_chall_response(call, chall)187data =188[ Constants::IAX_SUBTYPE_REGREQ ].pack('C') +189create_ie(Constants::IAX_IE_USERNAME, self.username) +190create_ie(Constants::IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password )) +191create_ie(Constants::IAX_IE_REG_REFRESH, [Constants::IAX_DEFAULT_REG_REFRESH].pack('n'))192193send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, Constants::IAX_TYPE_IAX, data ) )194end195196def create_ie(ie_type, ie_data)197[ie_type, ie_data.length].pack('CC') + ie_data198end199200def create_pkt(src_call, dst_call, tstamp, out_seq, inp_seq, itype, data)201[202src_call | 0x8000, # High bit indicates a full packet203dst_call,204tstamp,205out_seq & 0xff, # Sequence numbers wrap at 8-bits206inp_seq & 0xff, # Sequence numbers wrap at 8-bits207itype208].pack('nnNCCC') + data209end210211end212end213end214end215216217218