#!/usr/bin/perl # RTP-Proxy 0.1 # Receive announcments of redirected RTP-sessions from sip-redirectrtp, receive # the packets, wiretap or do anything with them and forward them to the real # targets. # # Copyright (C) 2005 Thomas Skora # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # Changelog: # 0.1: first version, proof of concept, just forwards packets. # # TODO: # - Add daemon mode. # - Add wiretapping etc. # - forward RTCP. use Getopt::Std; use NetPacket::IP; use NetPacket::UDP; #use Net::RawIP; use Socket; use IO::Socket; use IO::Select; $sigport = 64120; $rtpport = 64121; $udp_maxlength = 1400; $udp_inittimeout = 0.5; $udp_maxretries = 5; sub HELP_MESSAGE { print < Set signalisation port different to 64120. -r Set RTP port different to 64121. EOH } sub verbose { if ($opt_v) { print $_[0]; } } sub incoming_sig { # process incoming signalisation datagram my $addr = $sig->recv(my $msg, $udp_maxlength); my ($port, $ip) = sockaddr_in($addr); $ip = inet_ntoa($ip); # print "$msg\n"; if ($msg =~ /^REGISTER/) { # registration request (no really registration is done, just the RTP port is sent) verbose "Registration request from $ip:$port.\n"; my $reply = <send($reply,0,$addr); } elsif ($msg =~ /^ANNOUNCE/) { # RTP session announcment my ($callid) = ($msg =~ /^callid=(.*)$/m); # parse session description my ($fromip, $fromport) = ($msg =~ /from=([0-9\.]+):([0-9]+)/m); my ($toip, $toport) = ($msg =~ /to=([0-9\.]+):([0-9]+)/m); verbose "Session announcement for $callid from $ip:$port. $fromip:$fromport <-> $toip:$toport\n"; # send reply my $reply = <send($reply,0,$addr); # add session to session description hash $session{$callid} = { fromip => $fromip, fromport => $fromport, toip => $toip, toport => $toport }; # additional build from-to-hashes to making forwarding of RTP packets fast. $fromto{"$fromip:$fromport"} = { ip => $toip, port => $toport }; $fromto{"$toip:$toport"} = { # same for the opposite direction ip => $fromip, port => $fromport }; } elsif ($msg =~ /^DISCARD/) { # signalisation of ending RTP session my ($callid) = ($msg =~ /^callid=(.*)$/m); verbose "Discarding session $callid from $ip:$port.\n"; undef $fromto{"$session{$callid}{fromip}:$session{$callid}{fromport}"}; undef $fromto{"$session{$callid}{toip}:$session{$callid}{toport}"}; undef $session{$callid}; my $reply = <send($reply,0,$addr); } } sub incoming_rtp { # receive RTP packet, process and forward it to real destination my $addr = $rtp->recv(my $msg, $udp_maxlength); my ($port, $ip) = sockaddr_in($addr); $ip = inet_ntoa($ip); # first forward incoming packet to real destination to keep latency low defined $fromto{"$ip:$port"} or return; # ignore packets from unknown sources my ($toip, $toport) = (inet_aton($fromto{"$ip:$port"}{ip}), $fromto{"$ip:$port"}{port}); my $toaddr = pack_sockaddr_in($toport, $toip); $rtp->send($msg, 0, $toaddr); } sub waitevent { # wait with select for incoming packets and process them. @ready = $sel->can_read(); # wait for incoming packet # print "Event!\n"; foreach my $sock (@ready) { if ($sock == $sig) { # something on the signalisation port incoming_sig; } elsif ($sock == $rtp) { # something on rtp port incoming_rtp; } } } $Getopt::Std::STANDARD_HELP_VERSION = 1; getopts('vs:r:'); !defined $opt_s or $sigport = $opt_s; !defined $opt_r or $rtpport = $opt_r; # create signalisation and RTP sockets $sig = IO::Socket::INET->new( Proto => "udp", LocalPort => "$sigport" ) or die "Cannot create UDP socket: $@"; $rtp = IO::Socket::INET->new( Proto => "udp", LocalPort => "$rtpport" ) or die "Cannot create UDP socket: $@"; $sel = IO::Select->new($sig, $rtp); verbose "Signalisation port: $sigport, RTP port: $rtpport\n"; while (1) { waitevent(); }