1 MB - Garr

Transcript

1 MB - Garr
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
PROGETTO V.O.C.I.
H O W T O
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
N O M E
D A T A
F I L E
S T A T O
SER_supporto_IPv6
13/10/2009
:
:
A T T I V I T À
U R L
:
:
:
A U T O R E
/
I
:
Gruppo VoIP
ABSTRACT:
Il presente documento include le informazioni per la configurazione di SER 0.9.X per supportare
IPv6.
SER_SUPPORTO_IPV6
1/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
INDICE
INTRODUZIONE ......................................................................................................................3
1. CONFIGURAZIONE DI SER PER SUPPORTARE IPV6 ......................................................4
1.1. ABILITAZIONE DEL SUPPORTO IPV6 .....................................................................................4
1.2. COMUNICAZIONE TRA SIP UA IPV4 ED IPV6 ........................................................................8
1.3. CASISTICHE POSSIBILI .......................................................................................................18
SER_SUPPORTO_IPV6
2/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
INTRODUZIONE
Il presente documento include le informazioni per la configurazione del SIP server SER (versione
0.9.X) per supportare IPv6. In particolare è descritta la soluzione adottata per permettere la
comunicazione tra SIP UA che utilizzano differenti versioni del protocollo IP e basata sul software
indipendente RTPproxy. RTPproxy è un media relay, tipicamente utilizzato per permettere la
comunicazione da e verso SIP client dietro NAT ma che di recente include anche la funzione di
bridging tra reti IPv4 ed IPv6. La comunicazione tra SER ed RTPproxy è resa possibile grazie al
modulo nathelper di SER.
SER_SUPPORTO_IPV6
3/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
1. CONFIGURAZIONE DI SER PER SUPPORTARE IPV6
1.1. Abilitazione del supporto IPv6
Per abilitare in SER 0.9.x il supporto IPv6 è sufficiente inserire nel file di configurazione ser.cfg la
direttiva:
…
listen=[2001:760::212:79ff:fe67:6935]
….
Tabella 1 Direttiva listen in ser.cfg per abilitare il supporto IPv6
La direttiva in Tabella 1 sarebbe sufficiente per consentire la comunicazione tra gli UA SIP nel caso in
cui IPv6 sia l’unica versione del protocollo IP supportata nella rete. Se invece è richiesta la modalità di
funzionamento dual-stack per supportare la coesistenza nella rete delle versioni IPv4 ed IPv6 è
necessario configurare SER per smettersi in ascolto su IPv4 ed IPv6 contemporaneamente:
…
listen=193.206.158.109
listen=[2001:760::212:79ff:fe67:6935]
….
Tabella 2 Direttive listen in ser.cfg per abilitare la modalità dual-stack
Configurare SER in modalità dual-stack non è tuttavia sufficiente a garantire la comunicazione tra SIP
UA con Address Family differente. In tutti i casi in cui un UA IPv4 voglia comunicare con un UA
IPv6 è necessario un elemento che faccia da ponte tra le due reti, a meno che anche gli stessi UA non
operino in dual-stack. SER gestisce infatti soltanto la segnalazione SIP, permettendo l’instaurazione
della chiamata facendo da ponte tra le reti IPv4 ed IPv6. Il relativo flusso multimediale invece deve
essere scambiato direttamente tra i due UA. È evidente che se uno utilizza IPv6 e l’altro IPv4, tale
flusso non potrà mai essere recapitato a destinazione, come evidenziato in Figura 1.
Figura 1 Mancata comunicazione tra SIP UA con Address Family differente
SER_SUPPORTO_IPV6
4/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Si riportano di seguito alcune osservazioni sul funzionamento del supporto IPv6 per SER:
o Se il SIP server SER è configurato per supportare gli UA dietro NAT mediante RTPproxy o
Mediaproxy, tutte le richieste SIP destinate agli UA IPv6 non possono essere consegnate
correttamente. Infatti i controlli effettuati dalle funzioni client_nat_test del modulo mediaproxy e
nat_uac_test di nathelper durante la registrazione di un SIP UA si aspettano un indirizzo IPv4
nella segnalazione SIP; quando la richiesta di registrazione proviene da un client che utilizza
IPv6 le due funzioni non sono in grado di gestire correttamente questo tipo di indirizzo IP e
stabiliscono erroneamente che l’UA in esame si trova dietro un NAT. Questo comporta
l’inserimento nel campo received della tabella location del database MySQL di SER della stringa
“sip:indirizzo_IP:porta”, come riportato in Figura 2. Ogni volta che il SIP server SER riceve
una chiamata destinata all’utente registratosi con un UA IPv6, sostituirà le informazioni di
contatto nella segnalazione SIP con la coppia “indirizzo_IP:porta”, senza inserire l’indirizzo
IPv6 all’interno di parentesi quadre per separarlo dalla porta. Questo determina il fallimento
dell’invio della richiesta SIP, in quanto il SIP server non è in grado di decifrare l’informazione
presente nella domain-part della R-URI. In Tabella 3 è riportato il log di SER con i messaggi
d’errore nell’invio della SIP request. Una soluzione può essere quella di creare un apposito
script per effettuare il lookup del contact-address, sostituendo di fatto la funzione
lookup(“location”) di SER. Ad esempio, lo script usrloc-handle.pl riportato in Tabella 4 ricava con
una query SQL i valori dei campi contact e received della tabella location e relativi all’UA
dell’utente interno desiderato. Se il campo received non è vuoto, si controlla se l’indirizzo IP
qui riportato è IPv4 e solo in tal caso lo si utilizzato per riscrivere la domain-part della RequestURI, altrimenti è semplicemente ignorato. Questo script deve essere invocato in ser.cfg
tramite la funzione exec_dset del modulo exec ogni qualvolta è necessario risalire al contactaddress di un utente registrato, come riportato in Tabella 5.
…
4(11812) ERROR: parse_uri: bad char ':' in state 2 parsed: <sip:2001:760>
<sip:2001:760:0:0:212:79FF:FE67:67BC:5080> (40)
4(11812) ERROR: uri2proxy: bad_uri: sip:2001:760:0:0:212:79FF:FE67:67BC:5080
4(11812) ERROR: t_forward_nonack: failure to add branches
4(11812) ERROR:tm:t_relay_to: t_forward_nonack returned error
….
(12)
Tabella 3 Log di SER con errore nell’invio della richiesta SIP ad un UA registrato con IPv6
SER_SUPPORTO_IPV6
5/23
/
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Figura 2 Inserimento della coppia “indirizzo IPv6:porta” nel campo received tabella location
#! /usr/bin/perl -w
# usrloc-handle.pl
# Author: Pierpaolo Culurciello
use DBI;
use DBD::mysql;
# MYSQL CONFIG VARIABLES
$host = "localhost";
$database = "ser";
$tablename = "location";
$user = "ser";
$pw = "xxxxxxx";
$uri=$ARGV[0];
# EXTRACT USERNAME PART OF RURI
$temp_username = substr $uri, 0, index($uri, '@');
$username = substr $temp_username, 4;
# CONNECT TO DB
$dbh = "dbi:mysql:$database:$host";
$connect = DBI->connect($dbh, $user, $pw);
$query1 = "SELECT contact, received FROM $tablename WHERE username='$username'";
SER_SUPPORTO_IPV6
6/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
# PREPARE QUERY
$sqlQuery1 = $connect->prepare($query1);
# EXECUTE QUERY
$sqlQuery1->execute or die "can't execute the query: $sqlQuery1->errstr";
$usrloc = "";
($contact, $received) = undef;
$ipv4 = undef;
# FETCH QUERY OUTPUT
while (my @results = $sqlQuery1->fetchrow_array()) {
($contact, $received) = @results;
# si riscrive l'host-part della R-URI con l'indirizzo IP in received solo se è IPv4.
if (defined $received) {
if ($received =~ m/^sip:((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}
(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(:([1-5]\d{4}|6[0-4]\d{3}|
65[0-4]\d{2}|655[0-2]\d|6553[0-5]|[1-9]\d{0,3}))?$/) {
$nat_sock = substr $received, 4;
$usrloc = $usrloc."sip:".$username."@".$nat_sock."\n";
} else {
$usrloc = $usrloc.$contact."\n";
}
} else {
$usrloc = $usrloc.$contact."\n";
}
if ($contact =~ m/^sip:.*\@((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}
(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(:([1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|
655[0-2]\d|6553[0-5]|[1-9]\d{0,3}))?.*/) {
$ipv4 = 1;
} else {
$ipv4 = 0;
}
}
if($ipv4) {
$query2 = "SELECT username,attribute,value FROM usr_preferences WHERE
username = '$username' AND attribute = 'IPv4'";
$sqlQuery2 = $connect->prepare($query2);
$sqlQuery2->execute or die "can't execute the query: $sqlQuery2->errstr";
if ($sqlQuery2->rows == 0) {
$query3 = "INSERT INTO usr_preferences (username,attribute,value)
VALUES('$username','IPv4',1)";
$sqlQuery3 = $connect->prepare($query3);
$sqlQuery3->execute or die "can't execute the query: $sqlQuery3->errstr";
SER_SUPPORTO_IPV6
7/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
}
}
print $usrloc;
exit(0);
Tabella 4 Script usrloc-handle.pl in sostituzione del lookup(“location”) di SER
…
exec_dset("/usr/local/bin/usrloc-handle.pl");
….
Tabella 5 Sostituzione del lookup(“location”) con un apposito script
o SER effettua sempre prima una query A quando deve risolvere un hostname presente nella
domain-part di una R-URI. Solo nel caso in cui questa non ritorni alcun indirizzo IPv4 viene
effettuata anche la query AAAA per lo stesso hostname. Di conseguenza:
1. Se il SER che deve inoltrare una richiesta SIP utilizza soltanto IPv6 e la query A per il
next-hop ha successo, la transazione fallisce perché il proxy non è in grado di
inoltrare il messaggio in IPv4.
2. L’inoltro fallisce anche se il SER utilizza solo IPv4 ed il next-hop solo IPv6 (in tal
caso nel DNS dovrebbe essere presente solo il record AAAA ed il SER in esame
dovrebbe operare in dual-stack).
1.2. Comunicazione tra SIP UA IPv4 ed IPv6
L’unico modo per permettere quindi ad UA IPv4 di comunicare con UA IPv6 quando SER opera in
modalità dual-stack è di utilizzare un media relay in grado di mettere in comunicazione le due reti.
Esattamente come il SIP server, anche questa entità opererà in modalità dual-stack in modo da
inoltrare agli UA IPv6 i flussi RTP che riceve dagli UA IPv4 e viceversa. Un relay RTP in grado di
operare in dual-stack è l’RTPproxy che tipicamente viene utilizzato per risolvere il problema del NAT
. Nel caso in esame, è sufficiente indicare all’RTPproxy di tradurre i flussi multimediali non più tra
una rete IPv4 privata ed una pubblica, ma tra una rete con indirizzamento IPv4 ed una con
indirizzamento IPv6. Si assume cioè che l’interfaccia “interna” sia quella con indirizzo IPv4, quella
esterna con IPv6. Il relay RTP dovrà quindi essere attivato da SER ogni volta che viene rilevata una
richiesta di comunicazione tra entità appartenenti a reti con differenti versioni IP. Di seguito è riportata
una possibile configurazione di SER 0.9.x per supportare IPv6 in dual-stack e permettere la
comunicazione tra UA IPv4 ed IPv6 sia nel caso di chiamate uscenti (generate da UA interno a SER e
all’RTPproxy) sia di chiamate entranti (generate da UA appartenenti a domini esterni a quello gestito
dal SIP server SER in esame). Il comando per avviare l’RTPproxy in questa configurazione è:
# rtpproxy -l /193.206.158.109 -6 2001:760::212:79ff:fe67:6935
Tabella 6 Comando per avviare l’RTPproxy in bridging mode tra IPv4 ed IPv6
SER_SUPPORTO_IPV6
8/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Infatti, come riporta il manuale del comando rtpproxy (si veda la sottostante Tabella 7), l’istanza di
rtpproxy può essere avviata in bridging mode specificando due interfacce su cui mettersi in ascolto. In
tal modo può inoltrare i pacchetti in ingresso su
un’interfaccia attraverso l’altra interfaccia.
…
When two listen interfaces have been specified using the command line parameters described below then
rtpproxy will enter so called bridging mode. In briding mode rtpproxy forwards RTP packets received on
one interface to the other interface and vice versa. This mode can be used to forward RTP packets
between networks without direct network level connectivity (provided that the host running rtpproxy has
one interface in both of them). One particular application of bridging mode is IPv4/IPv6 traversal of
RTP packets
….
Tabella 7 Estratto del manuale del comando rtpproxy
In particolare, il carattere “/” davanti all’indirizzo IPv4 specifica che la rete IPv4 è considerata interna,
mentre la rete IPv6 è esterna. La funzione force_rtp_proxy([flags [, ip_address]]) esportata dal
modulo nathelper di SER segnala al RTPproxy con opportuni flags (si veda la Tabella 8) che tipo di
traslazione deve essere effettuata, se da IPv4 ad IPv6 o viceversa. La Figura 3 illustra il flusso della
segnalazione SIP e del traffico RTP successivo all’attivazione dell’RTPproxy per SER:
Figura 3 Comunicazione mediante RTPproxy tra SIP UA con Address Family differente
In Tabella 8 è invece riportata la route appositamente inserita in ser.cfg per l’attivazione del RTPproxy
in tutti i casi di comunicazione tra SIP UA con diversa Address Family.
SER_SUPPORTO_IPV6
9/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
route[4] {
# ----------------------------------------------------------------# IPv4-IPv6 Traversal Section
# ----------------------------------------------------------------if (isflagset(14)) {
## INBOUND CALLS
resetflag(14);
# il flag(14) è impostato nella route(3), non appena è verificato che la
# chiamata in ingresso è destinata ad un utente interno registrato; inoltre,
# lo script usrloc-handle.pl (invocato sempre nella route(3)) scrive nella
# tabella usr_preferences un AVP che contiene l'Address Family dell'UA
# interno (IPv4 o IPv6)
if (avp_db_load("$ruri/username", "s:IPv4/usr_preferences")) {
xdbg("************ IPv4 LOCAL USER *********\n");
avp_db_delete("$ruri/username", "s:IPv4/usr_preferences");
# IPv4 LOCAL USER
if (af == inet6) {
xdbg("******** Int/Ext IPv6 -> Int IPv4 ********\n");
if (force_rtp_proxy("FAIE")) {
t_on_reply("1");
break;
};
} else {
xdbg("******** Int/Ext IPv4 -> Int IPv4 ********\n");
# le righe sotto non sono strettamente necessarie;
# decommentarle solo se si desidera che tutto il traffico
# RTP attraversi l’RTPproxy
#if (force_rtp_proxy("FAII")) {
#
t_on_reply("1");
#
break;
#}
};
} else {
# IPv6 LOCAL USER
if (af == inet) {
xdbg("******* Int/Ext IPv4 -> Int IPv6 ********\n");
if (force_rtp_proxy("FAEI")) {
t_on_reply("1");
break;
};
} else {
xdbg("****** Int/Ext IPv6 -> Int IPv6 *********\n");
# le righe sotto non sono strettamente necessarie;
SER_SUPPORTO_IPV6
10/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
# decommentarle solo se si desidera che tutto il traffico
# RTP attraversi l’RTPproxy
#if (force_rtp_proxy("FAEE")) {
#
t_on_reply("1");
#
break;
#};
};
};
} else {
## OUTBOUND CALLS
exec_dset("/usr/local/bin/sip_IPv4_IPv6_relay.pl");
if (avp_db_load("$ruri", "s:addr_family/usr_preferences")) {
if (avp_check("s:addr_family", "eq/s:IPv4/i")) {
avp_db_delete("$ruri", "s:addr_family/usr_preferences");
# IPv4 EXTERNAL DESTINATION
if (af == inet6) {
xdbg("********* Int IPv6 -> Ext IPv4 *********\n");
if (force_rtp_proxy("FAIE")) {
t_on_reply("1");
break;
};
} else {
xdbg("******* Int IPv4 -> Ext IPv4 *******\n");
# le righe sotto non sono strettamente necessarie;
# decommentarle solo se si desidera che tutto il
# traffico RTP attraversi l’RTPproxy
#if (force_rtp_proxy("FAII")) {
#
t_on_reply("1");
#
break;
#}
};
} else if (avp_check("s:addr_family", "eq/s:IPv6/i")) {
avp_db_delete("$ruri", "s:addr_family/usr_preferences");
# IPv6 EXTERNAL DESTINATION
if (af == inet) {
xdbg("******** Int IPv4 -> Ext IPv6 **********\n");
if (force_rtp_proxy("FAEI")) {
t_on_reply("1");
break;
};
} else {
xdbg("******* Int IPv6 -> Ext IPv6 *******\n");
# le righe sotto non sono strettamente necessarie;
# decommentarle solo se si desidera che tutto il
# traffico RTP attraversi l’RTPproxy
#if (force_rtp_proxy("FAEE")) {
SER_SUPPORTO_IPV6
11/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
#
#
#};
t_on_reply("1");
break;
};
} else {
sl_send_reply("487", "Unresolvable Destination");
break;
};
};
};
}
Tabella 8 Route(4) per la gestione dei flussi RTP con SER in modalità dual-stack
Lo schema di funzionamento della route[4] riportata sopra è il seguente:
1. si verifica se si tratta di una chiamata in ingresso o in uscita controllando il valore del
flag 14. Questo flag è attivato nella route[3] (che gestisce gli INVITE) non appena si
rileva che la chiamata è appunto indirizzata ad un utente interno attualmente registrato.
In Tabella 10 è riportato un estratto della route[3] che mostra l’utilizzo della route[4]
per la gestione delle chiamate tra UA IPv4 ed UA IPv6 sia nel caso di chiamate uscenti
che entranti. Nel primo caso è riportato l’esempio di una chiamata in cui l’host-part della
R-URI è un numero E.164, per cui si tenta la risoluzione tramite ENUM. Nel secondo
è mostrato l’utilizzo della funzione usrloc-handle.pl, riportata in Tabella 4 e is-userregistered.pl riportata invece in Tabella 9 per la gestione delle chiamate entranti.
2. se la chiamata è in ingresso, si verifica se esiste nella tabella usr_preferences l’AVP con
attributo “IPv4” e valore “1” per l’utente interno chiamato: questo è impostato dalla
funzione usrloc-handle.pl (si veda la Tabella 4) qualora si rilevi che l’utente chiamato è
registrato con un UA IPv4. Come già accennato in precedenza, questa funzione è
invocata nella route[3] e di fatto sostituisce il lookup(“location”) in quanto restituisce il
contact-address dell’utente chiamato.
3. se l’utente locale utilizza IPv4, si verifica se l’INVITE è stato ricevuto dal SIP proxy in
IPv6 o in IPv4 controllando il valore assunto dal parametro af (Address Family) che
indica appunto se il messaggio è stato ricevuto in IPv4 (INET) o in IPv6 (INET6); nel
caso in cui in le due versioni siano differenti, si contatta l’RTPproxy con la funzione
force_rtp_proxy() del modulo nathelper.
4. se invece si tratta di una chiamata in uscita, è necessario stabilire quale Address Family
(se IPv4 o IPv6) verrà utilizzata per inoltrare il messaggio al next-hop. La funzione
sip_IPv4_IPv6_relay.pl riportata in Tabella 11 verifica appunto quanto appena descritto
nel modo seguente:
SER_SUPPORTO_IPV6
12/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
a. si controlla innanzitutto se nella domain-part della R-URI c’è già un indirizzo
IPv4 o IPv6, in quanto in tal caso non è necessario proseguire.
b. se il controllo precedente fallisce, la domain-part è composta da un hostname o
un dominio SIP: si effettua quindi una query SRV utilizzandola come chiave di
ricerca; se la query ha successo, il valore ritornato è assegnato alla variabile
“proxy”.
c. si controlla se il risultato della query SRV è gia un indirizzo IPv4 o IPv6: in tal
caso non sono necessarie ulteriori query (A o AAAA).
d. se invece è necessario effettuare anche una query A o AAAA, se almeno una
delle due ha successo la funzione termina con un valore positivo, altrimenti
l’uscita avverrà con valore negativo.
5. dopo aver ottenuto l’Address Family in uscita, si controllerà quella del messaggio SIP in
ingresso e in caso non coincidano, si attiverà l’RTPproxy esattamente come fatto per le
chiamate destinate agli utenti interni.
#! /usr/bin/perl -w
# is-user-registered.pl
use DBI;
use DBD::mysql;
# MYSQL CONFIG VARIABLES
$host = "localhost";
$database = "ser";
$tablename = "location";
$user = "ser";
$pw = "xxxxxxxx";
$uri=$ARGV[0];
# EXTRACT USERNAME PART OF RURI
$exit_status = 1;
$temp_username = substr $uri, 0, index($uri, '@');
$username = substr $temp_username, 4;
# connect to db
$dbh = "dbi:mysql:$database:$host";
$connect = DBI->connect($dbh, $user, $pw);
# DEFINE MySQL QUERY
$query = "SELECT COUNT(*) FROM $tablename WHERE username='$username'";
# prepare and execute the query
SER_SUPPORTO_IPV6
13/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
$sqlQuery = $connect->prepare($query);
$sqlQuery->execute or die "can't execute the query: $sqlQuery->errstr";
# GET COUNT VALUE
$count = $sqlQuery->fetchrow_array();
if ($count > 0) {
$exit_status = 0;
} else {
$exit_status =1;
}
print $uri;
exit($exit_status);
Tabella 9 Script is-user-registered.pl per la gestione delle registrazioni presso SER
…
route[3] {
# ----------------------------------------------------------------# INVITE Message Handler
# ----------------------------------------------------------------….
# se la R-URI conitenre un numero in formato E.164, si tenta la risoluzione ENUM
if (uri=~"^sip:\+[0-9]+\*?[0-9]+@") {
if (enum_query("nrenum.net.")) {
route(4);
route(1);
break;
};
…
# se tutti i precedenti conrolli falliscono, allora o la chiamata è destinata ad
# un utente interno, oppure ad un’estensione non gestita dal SIP server locale
if (!exec_dset("/usr/local/bin/is-user-registered.pl")) {
sl_send_reply("404", "Not Found");
break;
} else {
exec_dset("/usr/local/bin/usrloc-handle.pl");
setflag(14);
route(4);
route(1);
};
}
….
Tabella 10 Estratto della route[3] in ser.cfg che sostituisce la funzione lookup(“location”)
SER_SUPPORTO_IPV6
14/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
#! /usr/bin/perl -w
# sip_IPv4_IPv6_relay.pl
# Author: Pierpaolo Culurciello
use Net::DNS;
use DBI;
use DBD::mysql;
# MYSQL CONFIG VARIABLES
$host = "localhost";
$database = "ser";
$tablename = "usr_preferences";
$user = "ser";
$pw = "xxxxxxx";
my $ruri = $ARGV[0];
my $res = Net::DNS::Resolver->new;
my $SRV_query = undef;
my @answer = undef;
my $A_query = undef;
my $AAAA_query = undef;
my $addr_family = undef;
my $exit_value = undef;
# EXTRACT USERNAME PART OF RURI
$temp_username = substr $ruri, 0, index($ruri, '@');
$username = substr $temp_username, 4;
# EXTRACT DOMAIN PART OF RURI
my $domain_part = substr $ruri, index($ruri, '@') + 1;
# IPv4 check
if ($domain_part =~ m/^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|
2[0-4]\d|25[0-5])(:([1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|
6553[0-5]|[1-9]\d{0,3}))?.*/) {
$addr_family = "IPv4";
$exit_value = 0;
}
# IPv6 check
if (!defined($addr_family)) {
my $ipv6_addr = undef;
if ($domain_part =~ m/^\[.*\](:([1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|
655[0-2]\d|6553[0-5]|[1-9]\d{0,3}))?.*/) {
$ipv6_addr = substr $domain_part, 1, index($domain_part, ']') - 1;
SER_SUPPORTO_IPV6
15/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
} else {
$ipv6_addr = $domain_part;
}
if (&is_ipv6($ipv6_addr)) {
$addr_family = "IPv6";
$exit_value = 0;
}
}
# se $addr_family è undef allora la domain-part è un dominio SIP o un hostname e si deve proseguire
if (!defined($addr_family)) {
if (index($domain_part, ':') ne '-1') {
$domain_part = substr $domain_part, 0, index($domain_part, ':');
}
$SRV_query = $res->query('_sip._udp.'.$domain_part, 'SRV');
if ($SRV_query) {
@answer = $SRV_query->answer;
my $priority = $answer[0]->priority;
$proxy = $answer[0]->target;
foreach my $rr (grep { $_->type eq 'SRV' } @answer) {
if ($rr->priority < $priority) {
$proxy = $rr->target;
$priority = $rr->priority;
}
}
} else {
$proxy = $domain_part;
}
# si controlla se il risultato della query SRV è un indirizzo IPv4 o IPv6;
# in tal caso le query A o AAAA non sono necessarie
if($proxy =~ m/^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}
(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])/) {
$addr_family = "IPv4";
$exit_value = 0;
} else if (&is_ipv6($proxy)) {
$addr_family = "IPv6";
$exit_value = 0;
} else {
$A_query = $res->query($proxy, 'A');
$AAAA_query = $res->query($proxy, 'AAAA');
if ($A_query) {
$addr_family = "IPv4";
$exit_value = 0;
} elsif ($AAAA_query) {
$addr_family = "IPv6";
$exit_value = 0;
SER_SUPPORTO_IPV6
16/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
} else {
$exit_value = 1;
}
}
}
if (defined($addr_family)) {
$dbh = "dbi:mysql:$database:$host";
$connect = DBI->connect($dbh, $user, $pw);
$query1 = "SELECT username,attribute,value FROM usr_preferences
WHERE username = '$username' AND domain = '$domain_part'
AND attribute = 'addr_family'";
$sqlQuery1 = $connect->prepare($query1);
$sqlQuery1->execute or die "can't execute the query: $sqlQuery1->errstr";
if ($sqlQuery1->rows == 0) {
$query2 = "INSERT INTO $tablename (username, domain, attribute, value)
VALUES ('$username', '$domain_part', 'addr_family', '$addr_family')";
$sqlQuery2 = $connect->prepare($query2);
$sqlQuery2->execute or die "can't execute the query: $sqlQuery2->errstr";
}
}
print $ruri;
exit($exit_value);
sub is_ipv6 {
my($addr) = @_;
return $addr =~ /^\s*((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}
(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|
(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[04]\d|
[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|
((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}
((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)
|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Faf]{1,4}){0,2}
((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)
|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}
((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)
|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4}){0,4}
((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d
{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4})
{0,5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d
{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(((25[0-5]|2[0-4]\d|
[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?\s*$/;
}
Tabella 11 Script sip_IPv4_IPv6_relay.pl per il controllo delle chiamate in uscita
SER_SUPPORTO_IPV6
17/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
La Figura 3 illustra il flusso della segnalazione SIP e del traffico RTP per una comunicazione tra due
UA sotto lo stesso dominio. Nel caso in cui la comunicazione debba avvenire tra due UA appartenenti
a domini SIP diversi o che semplicemente utilizzano outbound proxy differenti, affinché tutte le
possibili tipologie di chiamate possano avere successo è necessario che anche il proxy responsabile del
dominio dell’UA destinatario della comunicazione utilizzi un RTPproxy. Il paragrafo seguente riporta
un elenco di tutte le casistiche possibili con i dettagli sul flusso della segnalazione SIP e del traffico
RTP.
1.3. Casistiche possibili
In tabella sono riportati tutti i possibili casi di chiamate tra UA che utilizzano IPv4 o IPv6 ed
appartenenti allo stesso dominio SIP o a domini differenti.
CASO
CHIAMANTE
CHAIMATO
TIPO CHIAMATA
FIGURA
1
IPv6 interno
IPv4 interno
ingresso
Figura 4
2
IPv6 esterno
IPv4 interno
ingresso
Figura 5
3
IPv4 interno
IPv4 interno
ingresso
Figura 6
4
IPv4 esterno
IPv4 interno
ingresso
Figura 7
5
IPv4 interno
IPv6 interno
ingresso
Figura 8
6
IPv4 esterno
IPv6 interno
ingresso
Figura 9
7
IPv6 interno
IPv6 interno
ingresso
Figura 10
8
IPv6 esterno
IPv6 interno
ingresso
Figura 11
9
IPv6 interno
IPv4 esterno
uscita
Figura 12
10
IPv4 interno
IPv4 esterno
uscita
Figura 13
11
IPv6 interno
IPv6 esterno
uscita
Figura 14
12
IPv4 interno
IPv6 esterno
uscita
Figura 15
Tabella 12 Possibili casi di chiamate tra UA in infrastrutture di rete dual-stack IPv4-IPv6
Le figure seguenti illustrano graficamente il flusso della segnalazione SIP e del traffico RTP per tutte
le casistiche riportate in Tabella 12. Alcune precisazioni sullo scenario utilizzato per i test:
1. gli UA definiti come “interni” sono quelli registrati presso il SIP proxy SER sull’host
sipsrv1.dir.garr.it ed appartenenti all’omonimo dominio SIP.
2. gli UA definiti come “esterni” sono quelli registrati presso il SIP proxy SER sull’host
sipsrv2.dir.garr.it ed appartenenti all’omonimo dominio SIP.
3. le estensioni interne al dominio sipsv1.dir.garr.it sono tutte del tipo 32XX, mentre
quelle relative al dominio sipsrv2.dir.garr.it sono 62XX; in ciascuno dei due proxy è
stata definita una regola (statica) che riscrive la domain-part della R-URI quando il
numero richiesto appartiene all’altro dominio SIP. In Tabella 13 è mostrato l’estratto di
ser.cfg che consente agli UA del dominio sipsrv1.dir.garr.it di contattare quelli
appartenenti a sipsrv2.dir.garr.it semplicemente tramite numero breve 62XX.
SER_SUPPORTO_IPV6
18/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
4. quando SER deve risolvere un hostname in un indirizzo IPv6 effettua prima una query
DNS di tipo A (cerca cioè dapprima l’indirizzo IPv4 associato all’hostname in
questione); solo nel caso in cui questa query non dia risultato viene effettuata anche la
query AAAA. Al fine di poter simulare una chiamata in uscita dal dominio
sipsrv1.dir.garr.it con protocollo IPv6 è stato perciò necessario configurare nel DNS
solo il record AAAA per l’host sipsrv2.dir.garr.it.
…
route[3] {
…
if (uri=~"^sip:62[0-9]{2}@") {
rewritehost("sipsrv2.dir.garr.it");
route(4);
route(1);
break;
};
…
)
…
Tabella 13 Estratto da ser.cfg su sipsrv1.dir.garr.it per l’inoltro delle chiamate a sipsrv2.dir.garr.it
Figura 4 Scenario 1: chiamata da UA interno in IPv6 ad UA interno in IPv4
SER_SUPPORTO_IPV6
19/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Figura 5 Scenario 2: chiamata da UA esterno in IPv6 ad UA interno in IPv4
Figura 6 Scenario 3: chiamata da UA interno in IPv4 ad UA interno in IPv4
Figura 7 Scenario 4: chiamata da UA esterno in IPv4 ad UA interno in IPv4
SER_SUPPORTO_IPV6
20/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Figura 8 Scenario 5: chiamata da UA interno in IPv4 ad UA interno in IPv6
Figura 9 Scenario 6: chiamata da UA esterno in IPv4 ad UA interno in IPv6
Figura 10 Scenario 7: chiamata da UA interno in IPv6 ad UA interno in IPv6
SER_SUPPORTO_IPV6
21/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Figura 11 Scenario 8: chiamata da UA esterno in IPv6 ad UA interno in IPv6
Figura 12 Scenario 9: chiamata da UA interno in IPv6 ad UA esterno in IPv4
Figura 13 Scenario 10: chiamata da UA interno in IPv4 ad UA esterno in IPv4
SER_SUPPORTO_IPV6
22/23
“CONFIGURAZIONE DEL SUPPORTO IPV6 PER SER 0.9.X”
Figura 14 Scenario 11: chiamata da UA interno in IPv6 ad UA esterno in IPv6
Figura 15 Scenario 12: chiamata da UA interno in IPv4 ad UA esterno in IPv6
SER_SUPPORTO_IPV6
23/23