Mostreremo di seguito come configurare un trunk MessageNet ed un interno telefonico, operando tra essi in diverse condizioni e scenari, ovvero: deviazione chiamata con mantenimento del numero originario, selezione passante in ingresso ed uscita, nonché la gestione del FAX tramite protocollo T38.
- Configurazione con stack PJSIP
- Configurazione (pjsip.conf)
- Dialplan (extensions.conf)
- Interni multipli (medesimo interno registrato su due dispositivi)
- Selezione Passante in ingresso
- Selezione Passante in uscita – Header P-Preferred-Identity o Remote-Party-ID
- Deviazione pilotata dal PBX con mantenimento del numero chiamante
- NAT traversal
- Invio e Ricezione FAX in T38
Configurazione con stack PJSIP
pjsip è la nuova tecnologia SIP per Asterisk che sostituisce e migliora le feature disponibili con chan_sip; è pertanto consigliabile migrare a questa soluzione ove non già presente.
Configurazione (pjsip.conf)
Come esempio, consideriamo una configurazione aperta generica sul realm di MessageNet con trasporto UDP, che abilita i codec standard ST-769, sotto NAT, dove il context inbound è inbound_context, ed un Account VoIP 5xxxxxx con password yyyyyyy per tramite di un auth, un endpoint ed un AoR. Il parametro contact_user sostituisce l’estensione di registrazione nella register fatta con chan_sip. Configureremo inoltre un interno 244 per esemplificare una configurazione funzionante e trattare alcuni esempi, anche qui per tramite di un auth, un endpoint ed un AoR opportuno (il quale in questo caso accetterà due location distinte).
; Default UDP transport [transport-udp] type=transport protocol=udp bind=0.0.0.0:5060
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Register to receive incoming calls [messagenet-5XXXXX] type=registration transport=transport-udp outbound_auth=messagenet-5XXXXX server_uri=sip:sip.messagenet.it client_uri=sip:5XXXXX@sip.messagenet.it contact_user=5XXXXX ; this is the dialplan extension expiration=300 line=yes endpoint=messagenet-5XXXXX
; Authentication credentials for Messagenet (userpass) [messagenet-5XXXXX] type=auth auth_type=userpass username=5XXXXX password=yyyyyyy realm=sip.messagenet.it
; Endpoint to call PSTN using Messagenet [messagenet-5XXXXX] type=endpoint transport=transport-udp context=from-messagenet disallow=all ;allow=g729,alaw ; commented: you need g729 license allow=alaw outbound_auth=messagenet-5XXXXX from_user=5XXXXX aors=messagenet
; AoR to reach Messagenet [messagenet] type=aor contact=sip:sip.messagenet.it:5060
; Sample internal phone with related auth and AoR [244] type=endpoint transport=transport-udp context=from-internal disallow=all ;allow=g729,alaw ; commented: you need g729 license allow=alaw auth=244 aors=244<em> callerid=Pinco Pallino
[244] ; authentication: this is the “from” user type=auth auth_type=userpass username=244 ; authentication: this is the “auth” username password=ciaociao
[244] type=aor max_contacts=2
Dialplan (extensions.conf)
Seguendo l’esempio, definiamo due contesti:
- from_messagenet per l’ingresso (che inoltra quanto ricevuto da Messagenet all’interno)
- from-internal per l’uscita (che inoltra via Messagenet la chiamata, se effettuata verso un numero fisso/mobile nazionale o nel formato e164).
[globals] PSTN_ENDPOINT=messagenet-5XXXXX ; PSTN via Messagenet -> Asterisk [from-messagenet] exten => 5XXXXX,1,NoOp() same => n,Ringing() same => n,Wait(1) same => n,Answer() same => n,Dial(PJSIP/244) same => n,Hangup() ; Internal -> Asterisk -> PSTN via Messagenet [from-internal] exten => _00Z.,1,Goto(+${EXTEN:2},1) exten => _X.,1,Goto(+39${EXTEN},1) exten => _+Z.,1,Dial(PJSIP/${EXTEN}@${PSTN_ENDPOINT}) exten => i,1,Hangup()
Interni multipli (medesimo interno registrato su due dispositivi)
Con pjsip è possibile accettare più location distinte per un singolo AoR: in altre parole possiamo utilizzare un medesimo interno su più apparati i quali potranno essere invocati contemporaneamedialplannte o selettivamente tramite le funzioni stesse di pjsip: Nell’esempio sopra indicato abbiamo definito l’interno 244 per accettare 2 location (max_contacts) e possiamo attenderci di registrarle entrambe su due dispositivi diversi e contattarle assieme; occorrerà modificare la Dial() nel nostro esempio precedente in questo modo:
[...] same => n,Dial(${PJSIP_DIAL_CONTACTS(244)}) [...]
Selezione Passante in ingresso
Si faccia riferimento all’articolo Un solo Account VoIP con più numeri geografici su Helpcenter MessageNet. Come esempio, si ipotizzi di aver abilitato il numero 021234567 e lo 061234567 sulla medesima utenza 5xxxxxx e di voler distinguere le chiamate sulla base del numero chiamato. Il file pjsip.conf non subisce modifiche sostanziali rispetto a quanto già documentato (vedi sezione Configurazione), la logica sarà invece definita nel fil extensions.conf dove dovremo fare uso di una funzione per la lettura dell’header richiesto e basarsi poi sul suo valore (salvato in una variabile di esempio CALLED) per procedere a dialplan secondo le Un solo Account VoIP con più numeri geograficicondizioni volute (vedi contesti successivi):
[from-internal] [...] same => n,Set(CALLED=${CUT(CUT(PJSIP_HEADER(read,To),@,1),:,2)}) [...] same => n,GotoIf($["${CALLED}" == "0612345678"]?to-rome,s,1) same => n,GotoIf($["${CALLED}" == "0212345678"]?to-milan,s,1) same => n,GotoIf($["${CALLED}" == "5312345"]?to-internal,s,1) [to-rome] exten => s,1,Verbose(Chiamata per Roma) exten => s,n,Dial(SIP/201) ; inoltro chiamata al peer 201 exten => s,n,Hangup() [to-milan] exten => s_,1,Verbose(Chiamata per Milano) exten => s,n,Dial(SIP/202) ; inoltro chiamata al peer 202 exten => s,n,Hangup() [to-internal] exten => s,1,Verbose(Chiamata per Numero Interno Messagenet - URI) exten => s,n,Dial(SIP/203) ; inoltro chiamata al peer 203 exten => s,n,Hangup() [to-other]exten => s,1,Verbose(Chiamata per numero non configurato) exten => s,n,Playback(pbx-invalid) exten => s,n,Hangup()
Selezione Passante in uscita – Header P-Preferred-Identity o Remote-Party-ID
Si faccia riferimento all’articolo Un solo Account VoIP con più numeri geografici su Helpcenter MessageNet: in breve, la feature è disponibile tramite diversi header, ma deve essere abilitata specificamente sull’URI in questione.
Non ci occuperemo in questo esempio della logica di associazione e retrieve del numero da impiegare nel caso voluto.
Si ipotizzi di aver abilitato il numero 021234567 e lo 061234567 sulla medesima utenza 5xxxxxx e di voler chiamare il numero 3212345678 (EXTEN, nel nostro esempio: vedi Configurazione) percorrendo l’estensione ext nel dialplan: exten => _+Z.,n,Dial(PJSIP/${EXTEN}@${PSTN_ENDPOINT}) [...]
Si vuole scegliere quale dei due numeri mostrare al chiamato e per questo fine dovremo fare impiego di un hook pre-dial poiché la funzione PJSIP_HEADER() dovrà essere applicata necessariamente sul channel PJSIP uscente:
[...] exten => _+Z.,n,Dial(PJSIP/${EXTEN}@${PSTN_ENDPOINT},30,b(set-cli^021234567^1)) [...]
Procediamo quindi nella definizione di un ulteriore contesto set-cli che useremo per la nostra subroutine (vedi documentazione dell’app Dial()):
[...]; subroutine context to set CLI [set-cli]
exten => _X.,1,Set(PJSIP_HEADER(add,P-Preferred-Identity)=<sip:+39${EXTEN}@sip.messagenet.it>) exten => _X.,n,Return()
Con questo setup la chiamata andrà su rete telefonica con CLI 021234567.
Deviazione pilotata dal PBX con mantenimento del numero chiamante
Si faccia riferimento all'articolo Deviazione di Chiamata tramite apparato esterno: in breve, la feature è realizzata riproponendo nella chiamata in uscita l’header X-Mnet-InLeg atto a screening.
Dovremo fare impiego di un hook pre-dial poiché la funzione PJSIP_HEADER() dovrà essere applicata necessariamente sul channel PJSIP uscente. La Dial() sarà quindi modificata per leggere il nostro header e passarlo come estensione nella subroutine del nostro hook:
[...] same => n,Playback(beep) same => n,Dial(PJSIP/3212345678,30,b(x-mnet-handler^${PJSIP_HEADER(read,X-Mnet-InLeg)}^1)) [...]
Procediamo quindi nella definizione di un ulteriore contesto x-mnet-handler che useremo per la nostra subroutine (vedi documentazione dell’app Dial()):
[...]; subroutine context to set CLI [x-mnet-handler] exten => _X.,1,Set(PJSIP_HEADER(add,X-Mnet-InLeg)=${EXTEN})</span></font></font></font></em></pre> exten => _X.,n,Return()
N.B.: nell’esempio sopra abbiamo preposto alla Dial() una Playback() atta sostanzialmente a rilasciare dell’RTP verso il chiamato, non necessariamente con audio udibile (potrebbe essere un file di silenzio); tale soluzione viene utilizzata per sollecitare la sessione NAT necessaria all’RTP in una condizione dove il PBX non emette RTP fino a che non ne riceve dalla destinazione chiamata.
NAT traversal
In generale, non è mai necessario configurare DMZ o port-forwarding statici (che si baserebbero per altro su situazioni di NAT della porta simmetriche o predicibili, e non sempre è così): si consiglia pertanto di mantenere dietro NAT il PBX demandando alle funzionalità di NATP dinamico dell’apparato di rete la definzione delle sessioni necessarie alla comunicazione.
Per mantenere funzionale questa configurazione, è utile tenere in considerazione che a seconda del trasporto scelto, dall’intervallo di ri-registrazione al servizio od al keep-alive impostato, derivano caratteristiche della NAT diverse (tipicamente su TCP avremo masquerading della porta) o conseguenze operative (chiusura della sessione anzitempo) che devono essere tenute in considerazione ed ottimizzate.
Tenendo quindi in considerazione la configurazione esemplificata in precedenza, in caso di problemi nella registrazione al servizio o nella gestione della comunicazione SIP, è opportuno verificare se l’impiego di TCP quale trasporto possa risolvere tali problematiche (tipicamente legate alla sessione NAT od alla frammentazione IP): vedi Cojfigurazione, già ottimizzato per molti aspetti.
Si ribadisce che qui sono in gioco due flussi: da un lato c’è la registrazione al servizio, dall’altra l’endpoint chiamante: questi due oggetti possono essere configurati diversamente e sono, appunto, distinti.
Nel momento in cui il problema si presenta come indisponibilità randomica, senza errori nella registrazione al servizio, la comunicazione avviene correttamente, ma la sessione NAT dura troppo poco: nei nostri template abbiamo sempre indicato un lease di registrazione basso (300 secondi) con keep-alive attivo. Si può ottimizzare riducendo questi valore od incrementando la durata della sessione NAT sul router.
Per il trasporto TCP, sarà necessario definire un transport nel nostro pjsip.conf ed impiegarlo sia per la registrazione al trunk che per l’endpoint chiamante.
; Custom TCP transport [transport-tcp] type=transport protocol=tcp bind=0.0.0.0:5060 [...] ; Register to receive incoming calls [messagenet-5XXXXX] type=registration transport=transport-tcp [...]
Invio e Ricezione FAX in T38
Asterisk consente di inviare e ricevere FAX tramite un opportuno DSP (fisico o virtuale) e l’estensione T38 del protocollo SIP.
Procederemo impiegando span_dsp come risorsa per la ricezione e l’invio del fax (tramite immagini TIFF) e configureremo il T38 in modo tale da utilizzare redundancy quale EC mode.
ttps://www.soft-switch.org/ (viene distribuito assieme al PBX stesso)
... t38_udptl=yes t38_udptl_ec=redundancy t38_udptl_maxdatagram=0 fax_detect=yes fax_detect_timeout=30 t38_udptl_nat=yes
Nel momento in cui la risorsa è correttamente caricata e configurata, possiamo definire a dialplan opportuni contesti per la ricezione e l’invio, come da esempio a seguire:
;;;; INVIO ;;;; ; definiamo un contesto SendFax dove, ; alla stregua degli esempi originali, ; il nostro URI instaura una chiamata ; e tramite un hook post-dial andrà ad ; invocare l’app SendFax su
ll’estensione `s` [SendFax] exten => _X!,1,Dial(PJSIP/${EXTEN}@${PSTN_ENDPOINT},,TWG(s^1),) exten => s,1,HangUp() exten => s,n,NoOp("TESTFAX starts") exten => s,n,SendFax(/tmp/${FAXFILE}.tif,dfzs) exten => s,n,NoOp(FAXstatus ${FAXOPT(status)})
;;;; RICEZIONE ;;;; ; salviamo nella directory /tmp il file ricevuto, ; nominandolo in base alla data ed ora di ricezione ; `fax` è il nome dell’estensione usata in caso di ; tono CNG o re-INVITE in udptl (vedi sip.conf) ; NOTE: the channel must be answered in order to switch here! [inbound_context] exten => fax,1,NoOp("Incoming FAX Transmission") exten => fax,n,Set(NAME=/tmp/fax_${STRFTIME(,,%C%y%m%d%H%M)}.tif) exten => fax,n,ReceiveFax(${NAME},dfs)