Monday, November 10, 2008

SIP and Perl

I have been working with SIP(Session Initiation Protocol) and VoIP in general on and off for many years now. And I have been using perl whenever I could to automate stuff like testing, generate testcases, during performance testing and for recreating scenarios and fixing issues that occur at interops or at remote sites by analyzing the logs.

And uptill now, I had used some very primitive level coding involving string manipulation, sockets and some quick and dirty hard coded stuff in the code to achieve the required functionality asap. I loved this approach because it gave me immense power to simulate any scenario and simulate any proprietary implementations of vendors.

Here is a sample crude perl code I used to use earlier for simulating a SIP UA. Of course on the other end would be a SIP UA we are testing, or some other entity under test. This SIP UA registers with a registrar and waits for an incoming call and establish a call/session. Don't even ask me why this script waits for 2 responses for REGISTER, I don't even remember.


#!/usr/bin/perl -w
use IO::Socket;

#--------------------------------------------------------

$numArgs = $#ARGV + 1;
print "thanks, you gave me $numArgs command-line arguments.\n";

#-------------------------------------------------------

my $sock = new IO::Socket::INET (
LocalPort => 8888,
PeerAddr => '10.232.14.112',
PeerPort => '5060',
Proto => 'udp',
);
die "Could not create socket: $!\n" unless $sock;

#-------------------------------------------------------

my $sip_request="";
my $response = "";

# register
$sip_request = "REGISTER sip:10.232.14.112:5060 SIP/2.0\r\nFrom: 1550 ;tag=hrs7fes6\r\n";
$sip_request = $sip_request."To: 1550 \r\nCall-ID: ft36633sdffff7a21111111z7\r\n";
$sip_request = $sip_request."CSeq: 1 REGISTER\r\nContact: 1550 ;q=0.9;expires=3600\r\n";
$sip_request = $sip_request."Via: SIP/2.0/UDP 10.232.15.31:8888;branch=z9hG4bK548s97i77d555458fs\r\n";
$sip_request = $sip_request."Max-Forwards: 70\r\n\r\n";

print "Request to be sent: \n$sip_request\n";

print $sock $sip_request;
#
$sock->recv($sip_request, 5000);
print "Response received: \n$sip_request\n";

$sock->recv($sip_request, 5000);
print "Response received: \n$sip_request\n";

#-------------------------------------------------------

$sip_request = "";
$response = "";


while (TRUE) {

$sock->recv($sip_request, 5000);
print "Response received: $sip_request\n";

@sip_headers = split(/\r\n/, $sip_request);

print "Number of headers in received message: $#sip_headers\n\n";

print "\n\n-------------------------------------------------\n\n";


#-------------------------------------------------------------

#send 100 Trying
$response = "SIP/2.0 100 Trying\r\n";

foreach $header (@sip_headers) {
if (($header =~ "^From") or ($header =~ "^To") or ($header =~ "^Call-ID") or ($header =~ "^CSeq") or ($header =~ "^Via")) {
$response = $response.$header."\r\n";
}
}

$response = $response."\r\n";

print "Response to be sent: $response\n";

print $sock $response;

#-----------------------------------------------------------

#send 180 Ringing
$response = "SIP/2.0 180 Ringing\r\n";

foreach $header (@sip_headers) {
if (($header =~ "^From") or ($header =~ "^To") or
($header =~ "^Call-ID") or ($header =~ "^CSeq") or
($header =~ "^Via")) {

if ($header =~ "^To") {
$header = $header.";tag=rfsdf677566577";
}
$response = $response.$header."\r\n";
}
}

$response = $response."Contact: ; isfocus\r\nContent-Length:0\r\n";
$response = $response."Record-Route: ,,\r\n";
$response = $response."Require: 100rel\r\nRSeq: 1\r\n";
$response = $response."Content-Type: application/sdp\r\n";

$response = $response."\r\n";

print "Response to be sent: $response\n";

print $sock $response;

#---------------------------------------------------------------
# wait for PRACK

$sock->recv($sip_request, 5000);
print "Response received: $sip_request\n";

@sip_headers = split(/\r\n/, $sip_request);

print "Number of headers in received message: $#sip_headers\n\n";

print "\n\n-------------------------------------------------\n\n";

#-----------------------------------------------------------------

#send 200 OK
$response = "SIP/2.0 200 OK\r\n";

foreach $header (@sip_headers) {
if (($header =~ "^From") or ($header =~ "^To") or
($header =~ "^Call-ID") or ($header =~ "^CSeq") or
($header =~ "^Via")
) {
$response = $response.$header."\r\n";
}
}

$response = $response."Contact: ; isfocus\r\nContent-Length:189\r\n";
$response = $response."Content-Type: application/sdp\r\n";

$response = $response."\r\n";

$response = $response."v=0"."\r\n"."o=RV-MCU 2021970 2021970 IN IP4 10.232.15.31"."\r\n"."s=RV MCU Session\r\n"."c=IN IP4 10.232.15.31"."\r\n"."b=CT:64"."\r\n"."t=0 0"."\r\n"."m=audio 6028 RTP/AVP 8"."\r\n"."c=IN IP4 10.232.15.31"."\r\n"."a=rtpmap:8 PCMA/8000"."\r\n"."a=sendrecv"."\r\n";

print "Response to be sent: $response\n";

print $sock $response;

#---------------------------------------------------------------

#Wait for ACK
$sip_request = "";
@sip_headers = "";

$sock->recv($sip_request, 5000);
print "Response received: $sip_request\n";

@sip_headers = split(/\r\n/, $sip_request);

print "Number of headers in received message: $#sip_headers\n\n";

print "\n\n-------------------------------------------------\n\n";

print "CALL SETUP\n";
sleep 100;

#----------------------------------------------------------------

}

close $sock;
Of course, I am bringing this up in this post because I have found Net::SIP module for perl. That reminded me of my earlier days and this dirty code I used to write. I don't know how I didn't discover this module earlier. However, my experiments with Net::SIP will be part of another post.

2 comments:

Unknown said...

Its a dam cool example,i got a job by showing the code,so please refer it.Thanks to this blog.

Unknown said...

interesting article sir, i'm looking for perl program that mitigate inviteflood attack. We are university students from sri lanka, currently undergoing with VoIP security project. Can you help us out sir? I will honor to contact you sir. Looking forward from you sir