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