Outgoing packets interception
André Guimarães, 2012-01-31
Switzernet
The aim of this document is to describe how to intercept outgoing traffic from asterisk to a phone to modify its content. The changed packets should be to the same IP and port they were originally intended to. The objective is to solve transparently the problem some customers have after their server’s migration made during December. The issue is described in:
http://ftp.switzernet.com/3/public/120106-dnatproblem/
An Astrad with the following software installed:
- ngrep – for verifying the traffic,
- iptables – for redirecting the traffic,
- netcat - for generating the packets to be filtered (this can be done also with perl),
- perl (for changing the packets)
The tests bellow where made in an Astrad v11 machine.
To intercept the traffic IPTABLES will be used. Before the procedure this is the iptables status (fail2ban DROP rules where filtered out in the output):
Default UDP connections track values are:
To verify if the traffic is redirected after inserting the rule, a netcat command is set to send packets each second to an IP and port of our choosing:
watch -n1 'echo -ne "hello world:`date`\r\n" | nc -u -p5090 -w 1 212.147.8.99 5091'
and run a ngrep on port 5090 to verify if the above command is sending traffic to the specified IP address and port:
ngrep port 5090 –d any
In the connection tracking file the following information appears:
astrad:~# cat /proc/net/ip_conntrack|grep udp|grep 5090
udp 17 27 src=91.121.122.64 dst=212.147.8.99 sport=5090 dport=5091 [UNREPLIED] src=212.147.8.99 dst=91.121.122.64 sport=5091 dport=5090 mark=0 use=2
The result above can be obtained with the command:
cat /proc/net/ip_conntrack|grep udp|grep 5090
We then add the IPTABLES rule to forward the traffic to another local port:
iptables -t nat -I OUTPUT --src 91.121.122.64 --dst 212.147.8.99 -p udp --sport 5090 -m string --string ":" --algo bm -j DNAT --to-destination 91.121.122.64:5070
IPTABLES rules list after insertion of rule above:
Watching ngrep we can see nothing happens. This is because rules appear to be applied only to new udp streams/connections. To clean the cache we issue an:
echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream
echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
Verifying again the connection tracking file we get no results and in ngrep we see the IPTABLES rule started to work and traffic is being redirected from port 5091 to 5070:
After the redirection the default values can be restored using the following commands. As we are allowing all incoming UDP traffic in the firewall at the moment it does not matter if the timeout is set or not after the rules are applied.
echo 180 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream
echo 30 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
After changing the timeout, the connection appears again in the connection track file:
astrad:~# cat /proc/net/ip_conntrack|grep udp|grep 5090
udp 17 29 src=91.121.122.64 dst=212.147.8.99 sport=5090 dport=5091 [UNREPLIED] src=91.121.122.64 dst=91.121.122.64 sport=5070 dport=5090 mark=0 use=2
Here is the screenshot of the above commands and their results:
To test if the iptables rule is matching by string (:) a new netcat command is issued but this time sending a string without ‘:’:
watch -n1 'echo -ne "hello world->`date +"%Y-%m-%d %H.%M.%S"`\r\n" | nc -u -p5090 -w 1 212.147.8.99 5091'
The corresponding result is no redirection has expected:
To test the behavior of cache a new command is issued sending each time a message with ‘:’ and afterwards another one without it. Before running this command the connection track file should not have an entry for this connection (cache should be empty):
watch -n1 'echo -ne "hello world->`date +"%Y-%m-%d %H.%M.%S"`\r\n" | nc -u -p5090 -w 1 212.147.8.99 5091; echo -ne "hello world:`date +"%Y-%m-%d %H.%M.%S"`\r\n" | nc -u -p5090 -w 1 212.147.8.99 5091'
The result with the default udp ipv4 timeouts is always the same. The packet is redirected or not depending on the first packet sent. If the first packet doesn’t have the ‘:’ all packets go to the original port. If the first packet has ‘:’ all following packets are redirected. Result obtained when sending first the packet with the ‘:’:
If the timeout is reseted again and left at 0 we obtain the desired result:
echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream
echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
So to be able to do realtime redirection the above two variables should be 0. The difference between the ip_conntrack_udp_timeout_stream and ip_conntrack_udp_timeout is that the latter is used for exporadic connections (new connections or connections with little traffic). After several UDP exchanges using the same IP and port addresses, without it timing out, the connection is upgraded to stream.
To change the content of the packet a Perl script is used. The script creates an UDP socket listening in the port where the traffic is being redirected. Everything that is sent to that socket is printed and the content after the first ‘:’ is removed. Notice that in the second socket which is used to send traffic back to the original destination the flag Reuse is set. This enables the socket to use a port already used by another program that might be listening to that port.
perl -e '
use IO::Socket::INET;
$socket = new IO::Socket::INET (
LocalPort => '5070',
Proto => 'udp'
);
while(1){
$socket->recv($s,1024);
print "Original\n".$s;
$s=~s/^[^:]+:(.*)/$1/;
print "Changed:\n".$s;
$c2=new IO::Socket::INET (
PeerHost => "212.147.8.99:5091",
LocalPort => '5090',
Proto => 'udp',
Reuse => 1) or print "ERR\r\n";
print $c2 $s;
$c2->close();
}'
Results ngrep:
#
U 91.121.122.64:5090 -> 212.147.8.99:5091 <-P1
hello world->2012-02-01 09.57.41..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070 <-P2
hello world:2012-02-01 09.57.43..
#
U 91.121.122.64:5090 -> 212.147.8.99:5091 <-P2 Changed
2012-02-01 09.57.43..
#
U 91.121.122.64:5090 -> 212.147.8.99:5091 <-P3
hello world->2012-02-01 09.57.46..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070 <-P4
hello world:2012-02-01 09.57.48..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070 <-P4 Changed
2012-02-01 09.57.48..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070 <-P4 Changed retransmission back to script
2012-02-01 09.57.48..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070 <-P4 Changed retransmission back to script
2012-02-01 09.57.48..
…
#
U 91.121.122.64:5090 -> 91.121.122.64: 5091 <-P4 Changed retransmission to correct address
2012-02-01 09.57.48..
Script result for the above messages:
Original
hello world:2012-02-01 09.57.43 <-P2
Changed:
2012-02-01 09.57.43 <-P2 Changed
Original
hello world:2012-02-01 09.57.48 <-P4
Changed:
2012-02-01 09.57.48 <-P4 Changed
Changed:
2012-02-01 09.57.48 <-P4 Changed
…
In front of each packet in both results the packet number is showed in black to allow easier comparison.
Several times the same message is rerouted again back to the script even though the ‘:’ does not exist anymore, until the packet is finally delivered in the correct destination
Script output for the aforementioned issue:
Original
hello world:2012-02-01 10.07.32
Changed:
2012-02-01 10.07.32
Original
2012-02-01 10.07.32
Changed:
2012-02-01 10.07.32
… Above 4 lines repeated several times …
Original
2012-02-01 10.07.32
Changed:
2012-02-01 10.07.32
Ngrep output for the same messages:
#
U 91.121.122.64:5090 -> 91.121.122.64:5070
hello world:2012-02-01 10.07.32..
#
U 91.121.122.64:5090 -> 91.121.122.64:5070
2012-02-01 10.07.32..
… Above 3 lines repeated several times …
#
U 91.121.122.64:5090 -> 91.121.122.64:5070
2012-02-01 10.07.32..
#
U 91.121.122.64:5090 -> 212.147.8.99:5091
2012-02-01 10.07.32..
Introducing a micro sleep before sending the packet solves the problem. With values lesser than 4000 microseconds the message is still retransmitted back to the perl script. Using the changed script bellow it was not detected any retransmission. Lines added in bold:
perl -e '
use IO::Socket::INET;
use Time::HiRes qw(usleep nanosleep);
$socket = new IO::Socket::INET (
LocalPort => '5070',
Proto => 'udp'
);
while(1){
$socket->recv($s,1024);
print "Original\n".$s;
$s=~s/^[^:]+:(.*)/$1/;
usleep(4000);
print "Changed:\n".$s;
$c2=new IO::Socket::INET (
PeerHost => "212.147.8.99:5091",
LocalPort => '5090',
Proto => 'udp',
Reuse => 1) or print "ERR\r\n";
print $c2 $s;
$c2->close();
}'
To solve the incompatibility between Netgear’s WNR routers with the field Contact sent by asterisk which includes the called number, it is needed to remove that string from the contact field in the SIP packet.
For these tests the NAT table will be cleaned again and a new set of rules will be added. All outgoing messages from asterisk to a phone behind a problematic router should be redirected to a Perl script running on port 5080. This script will then remove field the number from the contact header, add a new header called X-Astrad-Parsed and then resend the message to the phone. Iptables should not redirect again this packet to the script, although it has the same source and destination, due to the new header. In the final implementation it is important to limit the string match only to the relevant part of the message.
iptables -t nat -F
iptables -t nat -X
iptables -t nat -N nat_output_udp
iptables -t nat -N nat_output_router_correction
iptables -t nat -A OUTPUT -p udp -j nat_output_udp
iptables -t nat -A nat_output_udp --src 91.121.122.64 --dst 212.147.8.99 -p udp --sport 5060 -j nat_output_router_correction
iptables -t nat -A nat_output_router_correction -m string --string "X-Astrad-Parsed" --algo bm -j RETURN
iptables -t nat -A nat_output_router_correction -p udp -j DNAT --to-destination 91.121.122.64:5080
The following script should be running on the redirect local port to change and redirect the packages to the phone.
/etc/astrad/script/ast-routerfix.pl:
#!/usr/bin/perl
##########################################################################
# #
# Perl Script that makes SIP signalling compatible with some routers #
# #
# Switzernet(c)2012 #
# #
##########################################################################
# my modules
use IO::Socket::INET;
use Time::HiRes qw(usleep nanosleep);
my $asteriskip = '91.121.122.64';
my $asteriskport = 5060;
my $scriptport = 5080;
my $s,$temp = ('','');
my $socket = new IO::Socket::INET (
LocalPort => $scriptport,
Proto => 'udp');
CYCLE1: while(1){
$socket->recv($s,2048);
# print "\n\n==============================\nOriginal\n".$s;
if ($s !~ m/^X-Astrad-Parsed/m) {
$s =~ s/From:/X-Astrad-Parsed: 1\r\nFrom:/m;
}
#get source ip and port where the message should be sent from Via
my $iptosend = '';
my $porttosend = '';
if ($s =~ m/SIP\/2.0 (.*)/) {
print "Reply message ";
$s =~ m/received=([rport0-9.=;]+)/;
$temp = $1;
$temp =~ m/^([0-9.]+)/;
$iptosend = $1 if ($1 ne '');
$temp =~ m/rport=([0-9]+)/;
$porttosend = $1 if ($1 ne '');
$s=~s/^(Contact: <sip:)[^@]*\@/$1/m;
} else {
print "Error: Method message unimplemented. Discarding message\n";
next CYCLE1;
}
$porttosend = 5060 if ($porttosend eq '');
if ($iptosend eq '') {
print "Error: Could not obtain IP and port. Discarding message\n";
next CYCLE1;
}
print "to $iptosend:$porttosend\n";
print "Changed:\n".$s;
usleep(10000);
my $c2=new IO::Socket::INET (
PeerHost => "$iptosend:$porttosend",
LocalPort => $asteriskport,
Proto => 'udp',
Reuse => 1) or next CYCLE1;
print $c2 $s;
$c2->close();
}
Using the above IPTABLES rules it was noticed that sometimes outgoing registration replies to the phones where sometimes delivered directly to the phone and sometimes delivered in the local script. Even removing all the above rules and replacing them for an explicit redirect we achieved the same result: not every reply was redirected. However every message with a SIP Method originated by asterisk respected the rule.
Without solving this problem this solution cannot be used as almost 50% of messages are not changed creating retransmission problems.
This solution solves the problem of calls to customers. During the tests it was noticed that when Asterisk sent any Method the message didn’t arrive to the phone. It was blocked by the routers firewall. Porta-SIP’s Kamailio worked. Comparing the two messages one of the differences was that Kamailio sends the messages with 2 Via fields, while Asterisk sends only one. With the tests described here it was noticed that by adding an additional Via field in asterisk the call arrived to the phone and the phone replied, but then asterisk dropped the message due to the additional Via. Another solution was thought: replace the Via by a custom field with the same format of Via.
To insert this additional header two solutions were thought:
- add the header in asterisk
- use a script to insert it
Asterisk inserts this message only in the Method message. This insertion is achieved by adding in /etc/asterisk/extensions.conf the following line before the Dial command:
exten => _[*0-9]!,n,SIPAddHeader(X-Via: SIP/2.0/UDP 91.121.122.64)
As the phone removes the field when replying, all replies to these messages are dropped by the router. This means that when sending an Invite, the 1XX replies are received and the 200 OK is also received when the call is answered. However the ACK to the 200 OK never arrives to the phone because the router blocks it due to the missing via and the call is dropped after 30 seconds.
To intercept the communication between Asterisk and the telephone without using IPTABLES, Asterisk should call directly the script. The script should then add a second Via with the machines IP and the script port and relay the packet to the phone. The phone should reply to the script again to the port where the script is listening instead of replying directly to Asterisk. The script should then remove the Via that it added and deliver the packet to Asterisk. It is needed also to enable NAT for this call despite being on the same machine, to prevent Asterisk from sending the messages to any internal IP address that appears in the packet.
The following script was used to insert this header in all outgoing messages. In black the Via header added. The destination IP and port (in red) should be replaced by the IP and port where the phone is registered. This information can be obtained from table sippeer2 or sipdevices2, but for the tests was inserted manually.
#!/usr/bin/perl
##########################################################################
# #
# Perl Script that makes SIP signalling compatible with some routers #
# #
# Switzernet(c)2012 #
# #
##########################################################################
# my modules
use IO::Socket::INET;
#TODO Read from configuration file
my $asteriskip = '91.121.122.64';
my $asteriskport = 5060;
my $scriptport = 5080;
my $sendfromport = '';
my $s,$temp,$branch = ('','','z9hG4bK000000');
my $socket = new IO::Socket::INET (
LocalPort => $scriptport,
Proto => 'udp',
Reuse=>1);
CYCLE1: while(1){
$socket->recv($s,2048);
my $iptosend = '';
my $porttosend = '';
my $peer_address = $socket->peerhost();
my $peer_port = $socket->peerport();
print "\n\n==============================\n";
# print "Original\n".$s;
if ($peer_address eq $asteriskip) {
print "Message to customer\n";
$s=~s/^(Contact: <sip:)[^@]*\@/$1/m;
if ($s =~ m/SIP\/2.0 (.*)/) {
print "Reply message ";
} else {
print "Method message\n";
}
$s =~ s/(^Via:.*$)/Via: SIP\/2\.0\/UDP $asteriskip:$scriptport;branch=$branch\r\n$1/m;
#TODO Autodetect to each IP and port the message should be sent
$iptosend = '212.147.8.99';
$porttosend = 63917;
$sendfromport = $asteriskport;
} else {
print "Message to asterisk\n";
if ($s =~ m/SIP\/2.0 (.*)/) {
print "Reply message ";
} else {
print "Method message\n";
}
$iptosend = $asteriskip;
$porttosend = $asteriskport;
$sendfromport = $scriptport;
$s =~ s/Via:.*Via/Via/ims;
}
print "to $iptosend:$porttosend\n";
print "Changed:\n".$s;
my $socketerror=0;
my $c2=new IO::Socket::INET (
PeerHost => "$iptosend:$porttosend",
LocalAddr => "$asteriskip:$sendfromport",
Proto => 'udp',
Reuse => 1) or $socketerror=1;
if ($socketerror == 1){
print "ERROR in Socket Creation : $!\n";
next CYCLE1;
}
print $c2 $s;
$c2->close();
}
In the asterisk database a new entry was added to create a fictional location for the phone. The table used should be sipppers2 for Astrad v<11 and sipdevices2 for AstradV11. This is required to enable NAT for the communication with the script:
insert into sipdevices2 (name,host,port,context,fullcontact,ipaddr,type,nat) values ('UB1','91.121.122.64','5080','forbidden','','91.121.122.64','peer','yes');
The IP and port used are the local IP and port where the script is listening.
To enable NAT for the local IP the following change is required in /etc/asterisk/sip.conf general‘s context:
localnet=127.0.0.1/32
For the test the dial in /etc/asterisk/extensions.conf should be modified to call the UB1 device that was added to the database, replacing the dial in routing context:
exten => _[*0-9]!,n,Dial(SIP/41215502419@UB1,120)
With these changes in place the call is made successfully if at least one ACK arrives to the phone. However many are loss. The ACK to the 200 OK sent by asterisk is lost several times (is not read by /do not arrive to the Perl script). Due to this there are several retransmissions of the 200 OK from the telephone side.
On the image bellow, the selected 200 OK arrives to the perl script, is retransmitted to asterisk which answers with an ACK. This ACK appears to be delivered to the Perl script, but it doesn’t appear in its debug. All traces are from the same call.
Wireshark trace server side [pcap]:
Wireshark phone side [pcap]:
Perl script debug resume [Full debug in Perl script]:
Message to customer
Method message "INVITE sip" to 212.147.8.99:63917
==============================
Message to asterisk
Reply message "100 Trying" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "180 Ringing" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
==============================
Message to customer
Method message "ACK sip" to 212.147.8.99:63917
==============================
Message to customer
Method message "BYE sip" to 212.147.8.99:63917
==============================
Message to asterisk
Reply message "200 OK" to 91.121.122.64:5060
The lost message appears to be received by the second socket before it is closed. A modified script that tries to read before closing the second socket does not suffer from the same problem for the initial handshake. It has as a disadvantage an one second timeout while it waits for asterisk to send something. Also, with this script a problem with disconnection was detected. This was caused by the use of a fixed Via-branch. As it is always the same branch, the phone ignores the BYE message until it sends a REGISTRATION. This message apparently resets the internal control of the last branch received and the phone immediately accepts the BYE afterwards. From the SIP RFC:
The branch parameter value MUST be unique across space and time for
all requests sent by the UA. The exceptions to this rule are CANCEL
and ACK for non-2xx responses. As discussed below, a CANCEL request
will have the same value of the branch parameter as the request it
cancels. As discussed in Section 17.1.1.3, an ACK for a non-2xx
response will also have the same branch ID as the INVITE whose
response it acknowledges.
This means that the script should use a unique branch for each message sent except when ACK a 2XX message. In that case should use the same branch used in the Method message. I.E. the branch in the ACK to a 200 OK sent by a phone, should be the same as the one in the INVITE.
/etc/astrad/script/ast-routerfix_v0.4.pl :
#!/usr/bin/perl
##########################################################################
# #
# Perl Script that makes SIP signalling compatible with some routers #
# #
# Switzernet(c)2012 #
# #
##########################################################################
# my modules
use IO::Socket::INET;
use Class::Struct;
#TODO Read from configuration file
my $timeo = pack("qq", 1, 0);
my $asteriskip = '91.121.122.64';
my $asteriskport = 5060;
my $scriptport = 5080;
my $read = 1;
my $sendfromport = '';
my $s,$temp,$branch = ('','','z9hG4bK000000');
my $socket = new IO::Socket::INET (
LocalPort => $scriptport,
Proto => 'udp',
Reuse=>1);
my $iptosend = '';
my $porttosend = '';
my $peer_address = '';
my $peer_port = '';
my $fromasterisk = 0;
CYCLE1: while(1){
print "Length".length($s)."\n";
if ($read == 1 || length($s) == 0) {
$socket->recv($s,2048);
$iptosend = '';
$porttosend = '';
$peer_address = $socket->peerhost();
$peer_port = $socket->peerport();
if ($peer_address eq $asteriskip) {
$fromasterisk=1;
} else {
$fromasterisk=0;
}
} else {
$read = 1;
$fromasterisk=1;
}
if (length($s) == 0) {
next CYCLE1;
}
print "\n\n==============================\n";
print "Original\n".$s;
if ($fromasterisk) {
print "Message to customer\n";
$s=~s/^(Contact: <sip:)[^@]*\@/$1/m;
if ($s =~ m/SIP\/2.0 (.*)/) {
print "Reply message ";
} else {
print "Method message ";
}
$s =~ s/(^Via:.*$)/Via: SIP\/2\.0\/UDP $asteriskip:$scriptport;branch=$branch\r\n$1/m;
#TODO Connect to BD to get IP port based on the numero
$iptosend = '212.147.8.99';
$porttosend = 63917;
$sendfromport = $asteriskport;
} else {
print "Message to asterisk\n";
if ($s =~ m/SIP\/2.0 (.*)/) {
print "Reply message ";
} else {
print "Method message\n";
}
$read = 0;
$iptosend = $asteriskip;
$porttosend = $asteriskport;
$sendfromport = $scriptport;
$s =~ s/Via:.*Via/Via/ims;
}
$s =~ m/^(SIP\/2\.0 )?([0-9|A-Z|a-z| ]+)/;
print ' "'.$2.'" ';
print "to $iptosend:$porttosend\n";
print "Changed:\n".$s;
my $socketerror=0;
my $c2=new IO::Socket::INET (
PeerHost => "$iptosend:$porttosend",
LocalAddr => "$asteriskip:$sendfromport",
Proto => 'udp',
Reuse => 1) or $socketerror=1;
if ($socketerror == 1){
print "ERROR in Socket Creation : $!\n";
next CYCLE1;
}
$c2->sockopt(SO_RCVTIMEO, $timeo) if ($read == 0);
print $c2 $s;
$c2->recv($s,2048) if ($read == 0);
$c2->close();
}
The following script corrects the branch problem and also solves the reading problem from the socket in a different way. It never closes the socket to asterisk and has an additional socket to listen for incoming connections. When sending messages to the phone it immediately closes the socket. There is however a small probability that any following message that doesn’t use the added Via (par example a REGISTER) reaches the script before we close the socket. That is way the script discards all REGISTER packets.
/etc/astrad/script/ast-routerfix_v0.5.pl :
#!/usr/bin/perl
##########################################################################
# #
# Perl Script that makes SIP signalling compatible with some routers #
# #
# Switzernet(c)2012 #
# #
##########################################################################
# my modules
use strict;
use warnings;
use IO::Socket::INET;
use Class::Struct;
use IO::Select;
use POSIX;
use Config::IniFiles;
use Switch;
use DBI;
use Getopt::Long;
#Enable debug
use constant DEBUG => 3;
#TODO Read conf from file
my $asteriskport = 5060;
my $scriptport1 = 5080;
my $scriptport2 = 5081;
my $config_file = '/etc/astrad/config/switzer.conf';
my ($DBUser,$DBPass,$DBName,$asteriskip);
my ($s,$peer_address,$peer_port,$temp,$callid)
= ('','','','','');
my %callids;
##########################################################################
sub load_config {
my $conf=Config::IniFiles->new(-file => $config_file);
return 0 if !defined $conf ;
$DBUser = $conf->val('ASTER_DB','DB_USER');
$DBPass = $conf->val('ASTER_DB','DB_PASS');
$DBName = $conf->val('ASTER_DB','DB_NAME');
$asteriskip = $conf->val('GLOBAL','NAS_IP');
return 1;
}
sub getcontact {
my $number = shift;
my $query="select CONCAT(ipaddr,':',port) as contact from sipdevices2 where name = '".$number."'";
my @execsystem = `mysql -u$DBUser -p$DBPass $DBName -e \"$query\"`;
return $execsystem[1] if (defined $execsystem[1]);
return '';
}
#########################################################################
#Main
load_config();
#Socket creation
my $socketast = new IO::Socket::INET (
PeerHost => "$asteriskip:$asteriskport",
LocalAddr => "$asteriskip:$scriptport1",
Proto => 'udp',
Reuse=>1);
my $socketlisten = new IO::Socket::INET (
LocalAddr => "$asteriskip:$scriptport2",
Proto => 'udp',
Reuse=>1);
#Defines default sockets to read
my $readable_handles = new IO::Select();
$readable_handles->add($socketast);
$readable_handles->add($socketlisten);
#Main Cycle
CYCLE1: while (1) {
my @new_readable = $readable_handles->can_read;
CYCLE2: foreach my $sock (@new_readable) {
my $sockswitch = 2;
$sockswitch = 0 if ($sock == $socketast);
$sockswitch = 1 if ($sock == $socketlisten);
switch ($sockswitch) {
case 0 {
print "\n==============================\nIncoming message from Asterisk\n" if DEBUG > 0;
$sock->recv($s,2048);
$peer_address = $sock->peerhost();
$peer_port = $sock->peerport();
if ( $s ) {
$s =~ m/^(SIP\/2\.0 )?([0-9|A-Z|a-z| |:|@|\/]+)/i;
my $header = $2;
my $msgtype;
if ( $1 ) {
print "Reply message \"".$2."\" from $peer_address:$peer_port\n" if ( DEBUG > 0 );
$msgtype = 1;
} else {
print "Method message \"".$2."\" from $peer_address:$peer_port\n" if ( DEBUG > 0 );
$msgtype = 0;
}
my $sendfromport = $asteriskport;
$s =~ m/z9hG4bK([a-z|A-Z|0-9|\-]+)/;
my $branch = 'z9hG4bK-'.$1.'123';
$s =~ m/^Call-ID: (.*)$/mi;
$callid = $1;
print "Call-ID: ".$callid."\n" if DEBUG > 1;
print "Via-Branch: ".$branch."\n" if DEBUG > 1;
my ($iptosend,$porttosend) = ('','');
if (defined ($callids{$callid})) {
print "Known CallID. " if DEBUG > 1;
} else {
if ( $msgtype == 0 ) {
$s =~ m/To: <sip:(.*)@/i;
if (!defined ($1)) {
print "ERROR: Unable to detect number\n";
next CYCLE2;
}
my $callednumber = $1;
print "Calling ".$callednumber."\n" if DEBUG > 1;
#TODO Limit the number of active callids in the hash
$callids{$callid} = getcontact($callednumber);
} else {
print "ERROR: Unimplemented\n";
next CYCLE2;
}
print "Unknown CallID. " if DEBUG > 1;
}
$callids{$callid} =~ m/([0-9.]*):([0-9]*)/;
$iptosend = $1;
$porttosend = $2;
print "Sending message to ".$iptosend.":".$porttosend."\n" if DEBUG > 1;
print "Original Message: $s\n" if DEBUG > 2;
$s =~ s/^(Contact: <sip:)[^@]*\@/$1/mi;
$s =~ s/(^Via:.*$)/Via: SIP\/2\.0\/UDP $asteriskip:$scriptport2;branch=$branch\r\n$1/mi;
print "Changed Message: $s\n" if DEBUG > 2;
my $socketerror=0;
my $c2=new IO::Socket::INET (
PeerHost => "$iptosend:$porttosend",
LocalAddr => "$asteriskip:$sendfromport",
Proto => 'udp',
Reuse => 1) or $socketerror=1;
if ( $socketerror == 1 ) {
print "ERROR in Socket Creation : $!\n";
next CYCLE2;
}
print $c2 $s;
$c2->close();
}
} else {
print "\n==============================\nIncoming message from customer\n" if DEBUG > 0;
$sock->recv($s,2048);
next CYCLE2 if (length $s == 0);
$peer_address = $sock->peerhost();
$peer_port = $sock->peerport();
if ( $s ) {
if ( DEBUG > 0 ) {
$s =~ m/^(SIP\/2\.0 )?([0-9|A-Z|a-z| |:|@|\/]+)/i;
if ( $1 ) {
print "Reply message \"".$2."\" from $peer_address:$peer_port\n";
} else {
print "Method message \"".$2."\" from $peer_address:$peer_port\n";
next CYCLE2 if ($2 =~ m/^REG/i); #Drop incoming Registrations
}
}
print "Original Message: $s\n" if DEBUG > 2;
$s =~ s/Via:.*Via/Via/mis;
print "Changed Message: $s\n" if DEBUG > 2;
print $socketast $s;
}
}
}
}
}
The script above finds the number in the INVITE packet and searches the phone’s location (IP Address and port) in Asterisk’s registration table. It then sends the packet to that address. It also keeps in its memory an array which matches the Call-ID with the phone’s location. It uses the Via-branch sent by asterisk and appends a fixed string. For each following transaction, if the Call-id is known it uses the location in its memory. The module SELECT is used to read from multiple sockets at the same time.
Wireshark trace server side [pcap]:
Wireshark trace router side:
Perl script debug resume [Full debug in Perl script]:
==============================
Incoming message from Asterisk
Method message "INVITE sip:41215502419@91" from 91.121.122.64:5060
Call-ID: 0617a84713638f3e55b744bd6c65eca0@91.121.122.64:5060
Via-Branch: z9hG4bK-0c7b49e8123
Calling 41215502419
Unknown CallID. Sending message to 212.147.8.99:62721
==============================
Incoming message from customer
Reply message "180 Ringing" from 212.147.8.99:62721
==============================
Incoming message from customer
Reply message "200 OK" from 212.147.8.99:62721
Original Message: SIP/2.0 200 OK
==============================
Incoming message from Asterisk
Method message "ACK sip:41215502419@10" from 91.121.122.64:5060
Call-ID: 0617a84713638f3e55b744bd6c65eca0@91.121.122.64:5060
Via-Branch: z9hG4bK-37f4e977123
Known CallID. Sending message to 212.147.8.99:62721
==============================
Incoming message from Asterisk
Method message "BYE sip:41215502419@10" from 91.121.122.64:5060
Call-ID: 0617a84713638f3e55b744bd6c65eca0@91.121.122.64:5060
Via-Branch: z9hG4bK-2fe6d9cd123
Known CallID. Sending message to 212.147.8.99:62721
==============================
Incoming message from customer
Reply message "200 OK" from 212.147.8.99:62721
Original Message: SIP/2.0 200 OK
In this trace, the call flow is normal and there are now retransmissions. There is sound both ways and the call ends when the calling side hangs up.
The next trace shows the result of INFO DTMFs. The phone behind the router sends digits. Those digits go directly to Asterisk.
Wireshark trace server side [pcap]:
Perl script debug resume [Full debug in Perl script]:
==============================
Incoming message from Asterisk
Method message "INVITE sip:41215500331@91" from 91.121.122.64:5060
Call-ID: 23ded76572a6a2e11dd2a24d31b2b7fd@91.121.122.64:5060
Via-Branch: z9hG4bK-45dc2ffa123
Calling 41215500331
Unknown CallID. Sending message to 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "100 Trying" from 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "180 Ringing" from 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "200 OK" from 212.147.8.99:64087
==============================
Incoming message from Asterisk
Method message "ACK sip:41215500331@10" from 91.121.122.64:5060
Call-ID: 23ded76572a6a2e11dd2a24d31b2b7fd@91.121.122.64:5060
Via-Branch: z9hG4bK-36ebfbbe123
Known CallID. Sending message to 212.147.8.99:64087
The next test shows call cancellation. The call flow is the expected.
Wireshark trace server side [pcap]:
Perl script debug resume [Full debug in Perl script]:
==============================
Incoming message from Asterisk
Method message "INVITE sip:41215500331@91" from 91.121.122.64:5060
Call-ID: 7fcf49d92d4d83fe408815df48ddedcc@91.121.122.64:5060
Via-Branch: z9hG4bK-63b8c5ad123
Calling 41215500331
Unknown CallID. Sending message to 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "100 Trying" from 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "180 Ringing" from 212.147.8.99:64087
==============================
Incoming message from Asterisk
Method message "CANCEL sip:41215500331@91" from 91.121.122.64:5060
Call-ID: 7fcf49d92d4d83fe408815df48ddedcc@91.121.122.64:5060
Via-Branch: z9hG4bK-63b8c5ad123
Known CallID. Sending message to 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "487 Request Terminated" from 212.147.8.99:64087
==============================
Incoming message from Asterisk
Method message "ACK sip:41215500331@91" from 91.121.122.64:5060
Call-ID: 7fcf49d92d4d83fe408815df48ddedcc@91.121.122.64:5060
Via-Branch: z9hG4bK-63b8c5ad123
Known CallID. Sending message to 212.147.8.99:64087
==============================
Incoming message from customer
Reply message "200 OK" from 212.147.8.99:64087
The registration of a telephone should be sent directly to Asterisk. The following trace shows a normal registration. Nothing arrives to the Perl script. However if the registration immediately follows a message sent by the Perl script for the phone the script might intercept the incoming REGISTER message. It disregards it and the phone should retransmit another request that will arrive to asterisk.
Wireshark trace server side [pcap]
It is possible to tell the phone to use another phone when it starts to make a call using asterisk’s dialplan command Transfer.
Unfortunately the command appears to ignore everything after a ‘:’ so it is not possible to redirect to a location with a port which is not 5060.
In /etc/asterisk/extensions.conf:
[fromaccountwithalgproblem]
exten => _[#+*0-9]!,1,Set(ACCOUNTNUMBER=${CUT(CUT(CHANNEL,-,1),/,2)})
same => n,NoOP(${ACCOUNTNUMBER})
same => n,ExecIf($[ "${ACCOUNTNUMBER}" != "41215504126" & "${ACCOUNTNUMBER}" != "41215502419" & "${ACCOUNTNUMBER}" != "41215500331" ]?Return)
same => n,Set(Transferto_IP_Address=dk1.youroute.net)
same => n,Transfer(SIP/${EXTEN}@${Transferto_IP_Address})
same => n,NoOp(After Transfer: ${TRANSFERSTATUS})
same => n,Hangup()
[fromaccount]
exten => _[#+*0-9]!,1,NoOp(-- SIP Authentication --)
same => n,Set(CDR(CustomerType)=SipAuth)
same => n,Set(CDR(accountcode)=${SIP_Username})
same => n,Gosub(h323-id,${EXTEN},1)
same => n,Set(SIP_Authorization=${SIP_HEADER(Proxy-Authorization)})
same => n,Execif($[ "${SIP_Authorization}" = "" ]?Set(SIP_Authorization=${SIP_HEADER(Authorization)}))
same => n,GoSub(fromaccountwithalgproblem,${EXTEN},1)
…
When a call is made by one of the phones listed in fromaccountwithalgproblem, the call is successfully transferred to a Porta-SIP. The following trace shows the full SIP transaction on the Astrad server, all other SIP messages are sent to the PortaSIP. The relevant part of the redirection message is marked bellow in black. The UA is a Linksys SPA921.
U 212.147.8.99:64087 -> 91.121.122.64:5060
INVITE sip:0215504122@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:5060;branch=z9hG4bK-93d59df7
From: "41215500331" <sip:41215500331@astrad.switzernet.com>;tag=cc26b87c73e7c5eo0
To: <sip:0215504122@astrad.switzernet.com>
Call-ID: 66e457b-94e94afa@10.0.0.3
CSeq: 102 INVITE
Max-Forwards: 70
Authorization: Digest username="41215500331",realm="switzernet",nonce="7b8f39df",uri="sip:0215504122@astrad.switzernet.com",algorithm=MD5,response="915f149490211d776db3c8fa737b1c41"
Contact: "41215500331" <sip:41215500331@192.168.1.132:5060>
Expires: 240
User-Agent: Linksys/SPA921-5.1.8
Content-Length: 401
Allow: ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, REFER
Supported: replaces
Content-Type: application/sdp
v=0
o=- 26449850 26449850 IN IP4 192.168.1.132
s=-
c=IN IP4 192.168.1.132
t=0 0
m=audio 16478 RTP/AVP 0 2 4 8 18 96 97 98 101
a=rtpmap:0 PCMU/8000
a=rtpmap:2 G726-32/8000
a=rtpmap:4 G723/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:18 G729a/8000
a=rtpmap:96 G726-40/8000
a=rtpmap:97 G726-24/8000
a=rtpmap:98 G726-16/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=ptime:30
a=sendrecv
#
U 91.121.122.64:5060 -> 212.147.8.99:64087
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.132:5060;branch=z9hG4bK-93d59df7;received=212.147.8.99;rport=64087
From: "41215500331" <sip:41215500331@astrad.switzernet.com>;tag=cc26b87c73e7c5eo0
To: <sip:0215504122@astrad.switzernet.com>
Call-ID: 66e457b-94e94afa@10.0.0.3
CSeq: 102 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: <sip:0215504122@91.121.122.64:5060>
Content-Length: 0
#
U 91.121.122.64:5060 -> 212.147.8.99:64087
SIP/2.0 302 Moved Temporarily
Via: SIP/2.0/UDP 192.168.1.132:5060;branch=z9hG4bK-93d59df7;received=212.147.8.99;rport=64087
From: "41215500331" <sip:41215500331@astrad.switzernet.com>;tag=cc26b87c73e7c5eo0
To: <sip:0215504122@astrad.switzernet.com>;tag=as271b88bc
Call-ID: 66e457b-94e94afa@10.0.0.3
CSeq: 102 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: Transfer <sip:0215504122@dk1.youroute.net>
Content-Length: 0
#
U 212.147.8.99:64087 -> 91.121.122.64:5060
ACK sip:0215504122@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:5060;branch=z9hG4bK-93d59df7
From: "41215500331" <sip:41215500331@astrad.switzernet.com>;tag=cc26b87c73e7c5eo0
To: <sip:0215504122@astrad.switzernet.com>;tag=as271b88bc
Call-ID: 66e457b-94e94afa@10.0.0.3
CSeq: 102 ACK
Max-Forwards: 70
Authorization: Digest username="41215500331",realm="switzernet",nonce="7b8f39df",uri="sip:0215504122@astrad.switzernet.com",algorithm=MD5,response="915f149490211d776db3c8fa737b1c41"
Contact: "41215500331" <sip:41215500331@192.168.1.132:5060>
User-Agent: Linksys/SPA921-5.1.8
Content-Length: 0
The result for the same test is shown bellow, but using X-Lite (same result for a Siemens Gigaset C450 or C470). The phone ignores the redirect request and resends the INVITE to the same machine. X-Lite problem reported here. Using an IP address instead of a domain has the same result. Wireshark traces for each of these tests: [pcap1] [pcap2] [pcap3]
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
INVITE sip:0215504124@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-28d68a655cc5e829-1---d8754z-;rport
Max-Forwards: 70
Contact: <sip:41215502419@192.168.1.132:12452>
To: <sip:0215504124@astrad.switzernet.com>
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
Supported: replaces
User-Agent: X-Lite 4 release 4.1 stamp 63214
Content-Length: 617
v=0
o=- 12973095769921875 1 IN IP4 192.168.1.132
s=CounterPath X-Lite 4.1
c=INIP4 192.168.1.132
t=0 0
a=ice-ufrag:94c547
a=ice-pwd:80948503b7a999679947a34ac5de62d1
m=audio 62434 RTP/AVP 119 107 100 106 6 0 97 105 98 8 102 3 5 101
a=rtpmap:119 BV32-FEC/16000
a=rtpmap:107 BV32/16000
a=rtpmap:100 SPEEX/16000
a=rtpmap:106 SPEEX-FEC/16000
a=rtpmap:97 SPEEX/8000
a=rtpmap:105 SPEEX-FEC/8000
a=rtpmap:98 iLBC/8000
a=rtpmap:102 L16/16000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=candidate:1 1 UDP 659136 10.0.0.2 62434 typ host
a=candidate:1 2 UDP 659134 10.0.0.2 62435 typ host
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-28d68a655cc5e829-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>;tag=as0a01f7a5
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 1INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=MD5, realm="switzernet", nonce="6c8be0a0"
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
ACK sip:0215504124@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-28d68a655cc5e829-1---d8754z-;rport
Max-Forwards: 70
To: <sip:0215504124@astrad.switzernet.com>;tag=as0a01f7a5
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 1 ACK
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
INVITE sip:0215504124@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-cbcf04950fa8f03f-1---d8754z-;rport
Max-Forwards: 70
Contact: <sip:41215502419@192.168.1.132:12452>
To: <sip:0215504124@astrad.switzernet.com>
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 2 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
Supported: replaces
User-Agent: X-Lite 4 release 4.1 stamp 63214
Authorization: Digest username="41215502419",realm="switzernet",nonce="6c8be0a0",uri="sip:0215504124@astrad.switzernet.com",response="41cb69bf6e8e296753c6ac8c9bc1ab00",algorithm=MD5
Content-Length: 617
v=0
o=- 12973095769921875 1 IN IP4 192.168.1.132
s=CounterPath X-Lite 4.1
c=IN IP4 192.168.1.132
t=0 0
a=ice-ufrag:94c547
a=ice-pwd:80948503b7a999679947a34ac5de62d1
m=audio 62434 RTP/AVP 119 107 100 106 6 0 97 105 98 8 102 3 5 101
a=rtpmap:119 BV32-FEC/16000
a=rtpmap:107 BV32/16000
a=rtpmap:100 SPEEX/16000
a=rtpmap:106 SPEEX-FEC/16000
a=rtpmap:97 SPEEX/8000
a=rtpmap:105 SPEEX-FEC/8000
a=rtpmap:98 iLBC/8000
a=rtpmap:102 L16/16000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=candidate:1 1 UDP 659136 10.0.0.2 62434 typ host
a=candidate:1 2 UDP 659134 10.0.0.2 62435 typ host
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-cbcf04950fa8f03f-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 2 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: <sip:0215504124@91.121.122.64:5060>
Content-Length: 0
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 302 Moved Temporarily
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-cbcf04950fa8f03f-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>;tag=as28874337
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 2 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: Transfer <sip:0215504124@db.switzernet.com>
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
ACK sip:0215504124@astrad.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-cbcf04950fa8f03f-1---d8754z-;rport
Max-Forwards: 70
To: <sip:0215504124@astrad.switzernet.com>;tag=as28874337
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 2 ACK
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
INVITE sip:0215504124@db.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-df3430b3e1e8f1df-1---d8754z-;rport
Max-Forwards: 70
Contact: <sip:41215502419@192.168.1.132:12452>
To: <sip:0215504124@astrad.switzernet.com>
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 3 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
Supported: replaces
User-Agent: X-Lite 4 release 4.1 stamp 63214
Authorization: Digest username="41215502419",realm="switzernet",nonce="6c8be0a0",uri="sip:0215504124@db.switzernet.com",response="669ea0150f6bb6797d6d7f90d843a072",algorithm=MD5
Content-Length: 617
v=0
o=- 12973095769921875 1 IN IP4 192.168.1.132
s=CounterPath X-Lite 4.1
c=IN IP4 192.168.1.132
t=0 0
a=ice-ufrag:94c547
a=ice-pwd:80948503b7a999679947a34ac5de62d1
m=audio 62434 RTP/AVP 119 107 100 106 6 0 97 105 98 8 102 3 5 101
a=rtpmap:119 BV32-FEC/16000
a=rtpmap:107 BV32/16000
a=rtpmap:100 SPEEX/16000
a=rtpmap:106 SPEEX-FEC/16000
a=rtpmap:97 SPEEX/8000
a=rtpmap:105 SPEEX-FEC/8000
a=rtpmap:98 iLBC/8000
a=rtpmap:102 L16/16000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=candidate:1 1 UDP 659136 10.0.0.2 62434 typ host
a=candidate:1 2 UDP 659134 10.0.0.2 62435 typ host
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-df3430b3e1e8f1df-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>;tag=as1981ea53
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 3INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=MD5, realm="switzernet", nonce="2f0569ae"
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
ACK sip:0215504124@db.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-df3430b3e1e8f1df-1---d8754z-;rport
Max-Forwards: 70
To: <sip:0215504124@astrad.switzernet.com>;tag=as1981ea53
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 3 ACK
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
INVITE sip:0215504124@db.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-782e242500bef3a8-1---d8754z-;rport
Max-Forwards: 70
Contact: <sip:41215502419@192.168.1.132:12452>
To: <sip:0215504124@astrad.switzernet.com>
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 4 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Type: application/sdp
Supported: replaces
User-Agent: X-Lite 4 release 4.1 stamp 63214
Authorization: Digest username="41215502419",realm="switzernet",nonce="2f0569ae",uri="sip:0215504124@db.switzernet.com",response="9ae7265b69ffd2ee777e16ede43b26b3",algorithm=MD5
Content-Length: 617
v=0
o=- 12973095769921875 1 IN IP4 192.168.1.132
s=CounterPath X-Lite 4.1
c=IN IP4 192.168.1.132
t=0 0
a=ice-ufrag:94c547
a=ice-pwd:80948503b7a999679947a34ac5de62d1
m=audio 62434 RTP/AVP 119 107 100 106 6 0 97 105 98 8 102 3 5 101
a=rtpmap:119 BV32-FEC/16000
a=rtpmap:107 BV32/16000
a=rtpmap:100 SPEEX/16000
a=rtpmap:106 SPEEX-FEC/16000
a=rtpmap:97 SPEEX/8000
a=rtpmap:105 SPEEX-FEC/8000
a=rtpmap:98 iLBC/8000
a=rtpmap:102 L16/16000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=candidate:1 1 UDP 659136 10.0.0.2 62434 typ host
a=candidate:1 2 UDP 659134 10.0.0.2 62435 typ host
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-782e242500bef3a8-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 4 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: <sip:0215504124@91.121.122.64:5060>
Content-Length: 0
#
U 91.121.122.64:5060 -> 212.147.8.99:59449
SIP/2.0 302 Moved Temporarily
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-782e242500bef3a8-1---d8754z-;received=212.147.8.99;rport=59449
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
To: <sip:0215504124@astrad.switzernet.com>;tag=as29ea7eb6
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 4 INVITE
Server: Astradv11
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH
Supported: replaces, timer
Contact: Transfer <sip:0215504124@db.switzernet.com>
Content-Length: 0
#
U 212.147.8.99:59449 -> 91.121.122.64:5060
ACK sip:0215504124@db.switzernet.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.132:12452;branch=z9hG4bK-d8754z-782e242500bef3a8-1---d8754z-;rport
Max-Forwards: 70
To: <sip:0215504124@astrad.switzernet.com>;tag=as29ea7eb6
From: "41215502419"<sip:41215502419@astrad.switzernet.com>;tag=8b2baaf4
Call-ID: MzI2NzIyOTYyMGUwNGRmY2NlMzcyMDRmMzZiNjU4YjE
CSeq: 4 ACK
Content-Length: 0
It is possible to redirect and change the packet content with IPTables but some issues have been found. To enable real time filtering it is needed to set the UDP timeout to 0 or else the IPTABLES rule will match or not depending only on the content of the first packet. The following packets will use the same IP and port destination disregarding the IPTABLES rules set. Also it appears that even if the UDP timeout is 0 there’s a time period after the redirect where the changed packets do not match the string rule and are still redirected to the script. This is solved by waiting before sending another packet.
For calls initiated by the server an alternative solution was found calling directly the script from Asterisk. A script adds a new Via to the port it is using and most phones reply to that port. However Siemens Gigaset ignore the Via and send the traffic to where the message came from (port 5060 instead of 5081).
For calls initiated from the customer side it is possible to redirect the call to another server which does not send contact messages with the number. A new Kamailio server can be installed to receive the redirected calls and return them to the original Astrad, modifying all replies to the phone to the needed format (remove the number from Via).
Iptables
http://linux.die.net/man/8/iptables
http://www.inetdoc.net/guides/iptables-tutorial/traversingoftables.html
http://www.rigacci.org/wiki/lib/exe/fetch.php/doc/appunti/linux/sa/iptables/conntrack.html
DNAT problem description
http://ftp.switzernet.com/3/public/120106-dnatproblem/
Asterisk Source Code
http://www.asterisk.org/doxygen/trunk/chan__sip_8c.html#083b016992c4b3dfbb6f5e17112c1a52
http://www.asterisk.org/doxygen/trunk/app__transfer_8c.html#ee25cb42107a6b1b608f57f6068a7ecf
302 Redirect Problems
http://forums.counterpath.com/viewtopic.php?f=1&t=13227