Telefonanlage mit Asterisk 13 und PJSIP

In diesem Artikel habe ich das große Ganze zu meiner Heiminstallation mit Asterisk 13 und auf Raspberry Pi-Basis erläutert.
Es war nicht ganz leicht, PJSIP zu konfigurieren, da es im Internet kaum Einrichtungsbeispiele für PJSIP-Installationen gibt (zumindest deutlich weniger als für chan_sip), insbesondere gab es nichts, was auf die Spezialitäten für den Telekom AllIP-Anschluss eingeht und über die Verwendung von pjsip_wizard.conf konnte ich in diesem Zusammenhang garnichts finden.
Daher stelle ich in diesem Artikel die Konfiguration meines Asterisk vor und gehe auf ein paar Herausforderungen ein, die sich durch die Umstellung von chan_sip ergeben haben.

Mein Dank geht an Jürgen Büssert und Dr. Martin Rother, die ebenfalls Einblick in die Dokumentation ihrer „Asteriskse“ geben.

pjsip_wizard.conf

Bei pjsip.conf wird ein grundlegend anderes Konzept der Konfiguration verfolgt als bei sip.conf.
Bei sip.conf gibt es pro Peer eine Section, in der alle Optionen aufgeführt werden.
PJSIP führt ein Konzept starker Trennung ein, indem die verschiedenen Aspekte, die für einen Peer relevant sind (Authentifikationsdaten, Erreichbarkeit im sinne von IP-Adresse(n), etc.) jeweils eigene Sections bekommen. Das führt m. E. nach zu einer sehr großen und unübersichtlichen Konfigurationsdatei – und birgt Fehler, denn die Verknüpfung dieser Teilsections muss man händisch durch jeweils zusätzliche Parameter in den Sections vornehmen. Vertippt man sich oder vergisst mal eine Zuordnung, kann das schnell zu Problemen führen.
So richtig verstanden habe ich die Argumentation auf der Asterisk-Seite ehrlich gesagt nicht, denn schon in der sip.conf gibt es mittels Templates die Möglichkeit, Tipparbeit zu sparen.

Abhilfe schaffen soll jedenfalls der PJSIP Wizard, der über die pjsip_wizard.conf konfiguriert wird. Hier gibt es den übergeordneten Section-Typ wizard, den man einerseits mit Templates verwenden kann, andererseits hat man hier aber wieder eine etwas zentralere Sicht auf die Optionen und kann Daten für einzelne Section-Typen, die zu einem Peer gehören sollen, für die entsprechenden Sections definieren. Die resultierenden Sections werden zur Laufzeit vom Wizard erstellt, der dann auch für die passenden Verknüpfungen sorgt und noch einige „übliche“ Optionen automatisch mit erzeugt.

Die auf diese Weise erzeugte Konfiguration lässt sich über das CLI übrigens mit dem Kommando pjsip export config_wizard primitives to, gefolgt von einem Dateinamen inkl. vollständigem Pfad, ausgeben.

Mir half diese Seite im Asterisk-Wiki, die Konfiguration besser zu verstehen. Noch mehr geholfen hat mir allerdings ein in den Kommentaren zu der Seite verlinktes Diagramm, das ein Nutzer erstellt hat. Das ist hier zu finden. Der Nutzer warnt ausdrücklich davor, es sei vermutlich weder vollständig noch 100%ig richtig, aber bei meiner Konfiguration war es dennoch eine große Hilfe und mir sind keine groben Fehler aufgefallen.

Zum Nachschlagen und besseren Verständnis einzelner Konfigurationsschalter gibt es die kommentierten Versionen der PJSIP-Konfigurationsdateien auch online: pjsip.conf und pjsip_wizard.conf.

Asterisk am Telekom AllIP-Anschluss

Sehen wir uns also den Abschnitt der pjsip_wizard.conf an, wie er bei mir im Einsatz ist. Im Wesentlichen basiert er auf meiner sip.conf, die bereits jahrelang stabil lief, sowie den Erkenntnissen von Jürgen Büssert und Dr. Martin Rother.

Falls sich jemand die Inhalte für sein eigenes Asterisk kopieren möchte: am Ende des Abschnitts gibt es alles nochmal im Zusammenhang.

Starten wir also mit dem Kopf der Section:

[telekom-template](!)
type = wizard
transport = transport-udp

Relativ unspannend. Es wird ein Template definiert. Der transport muss weiterhin in der pjsip.conf definiert werden.

sends_auth = yes
sends_registrations = yes
remote_hosts = tel.t-online.de

Dies sind Optionen direkt für den wizard. Aus der ersten Option folgt, dass wir abgehend telefonieren können wollen (und zwar mit Authentifiziereung), die zweite ist notwendig, um dafür zu sorgen, dass Asterisk sich bei der Telekom registriert, um einen Kontext offen zu halten, damit wir auch ankommende Gespräche empfangen können. Da sends_registrations gesetzt ist, muss auch diese Option angegeben werden.

Definieren wir nun den Endpoint. Die Optionen mit Schrägstrich sind Optionen, die an zu bildende Sections weitergereicht werden. Aus den Optionen mit endpoint/ wird also eine Section vom Typ endpoint, die durch den Wizard passend mit den anderen Sections für diesen Wizard-Eintrag verknüpft wird.

endpoint/allow=!all,g722,alaw,ulaw,g729,gsm
endpoint/context=ankommend
endpoint/from_domain=tel.t-online.de
endpoint/dtmf_mode=rfc4733
endpoint/direct_media=no

Zunächst wird eine Liste der erlaubten Sprachcodes definiert. Eigentlich sollten G.722 und A-Law reichen (weswegen sie die höchste Priorität bekommen). Wie auch schon zu chan_sip-Zeiten, löscht !all zunächst einmal eventuell bereits vorgegebene Codecs.
Mit context wird, wie in der sip.conf, der Kontext des Dialplans definiert, der bei ankommenden Rufen abgearbeitet werden soll.
Wenn Asterisk selbst Anfragen an diesen Endpoint stellt, soll es sich nicht mit seiner eigenen, internen Domain ausgeben, sondern natürlich mit tel.t-online.de.
Der DTMF-Modus ist derjenige, den die Telekom unterstützt.
Die direct_media-Option wird für NAT-Betrieb empfohlen.
Es folgen zusätzliche Optionen für NAT:

;endpoint/force_rport=yes
endpoint/rewrite_contact=yes
endpoint/rtp_symmetric=yes

chan_sip bot im Wesentlichen nur den Schalter nat, bei PJSIP kann man die Mechanismen, die bei Rechnern hinter NAT helfen sollen, feingranularer steuern. force_rport ist nicht aktiviert, ist aber auch per Default eingeschaltet, daher hier als Gedächtnisstütze.

Die „Address of Record“-Optionen und die für die Registrierung sehen wie folgt aus:

aor/qualify_frequency = 60
aor/contact=sip:tel.t-online.de
aor/default_expiration=585


registration/retry_interval = 60
registration/server_uri=sip:tel.t-online.de
registration/forbidden_retry_interval=120
registration/expiration=480

Die Zeiten sind ein wenig Erfahrungswerte. Wichtig bei der Serverangabe ist das sip:, damit der DNS SRV-Eintrag für SIP abgefragt und die richtigen Server kontaktiert werden.

Damit hätten wir das Template für den Telekom-Anschluss schon geschafft, hier nochmal in Gänze:


[telekom-template](!)
type = wizard
transport = transport-udp

sends_auth = yes
sends_registrations = yes
remote_hosts = tel.t-online.de

endpoint/allow=!all,g722,alaw,ulaw,g729,gsm
endpoint/context=ankommend
endpoint/from_domain=tel.t-online.de
endpoint/dtmf_mode=rfc4733
endpoint/direct_media=no

aor/qualify_frequency = 60
aor/contact=sip:tel.t-online.de
aor/default_expiration=585

registration/retry_interval = 60
registration/server_uri=sip:tel.t-online.de
registration/forbidden_retry_interval=120
registration/expiration=480

;endpoint/force_rport=yes
endpoint/rewrite_contact=yes
endpoint/rtp_symmetric=yes

Um nun eine tatsächliche Rufnummer anzulegen, muss das Template natürlich pro Rufnummer noch instanziiert werden, zum Beispiel so:

[hh1982](telekom-template)
outbound_auth/username = 0401982
outbound_auth/password = meinsuperpasswort
registration/client_uri=sip:+49401982@tel.t-online.de
registration/contact_user=hh1982
endpoint/from_user=0401982

Durch das Template ist schon alles generische vorgegeben, sodass hier nur noch die Rufnummernspezifischen Einträge gemacht werden müssen.
mit outbound_auth Nutzername und Passwort. Die Registrierung wird um die Quell-URI mit Rufnummer erweitert.
Mit der Option registration/contact_user kann die Extension angegeben werden, die bei ankommenden Anrufen aufgerufen werden soll. So kann man verschiedene Rufnummern innerhalb eines Kontextes im Dialplan auswerten.

Kommen wir nun zur einer „Spezialität“ im Zusammenhang mit Telekom-Anschlüssen. Die Telekom hat ja nun ein paar mehr Teilnehmer und damit auch SIP-Server. Das drückt sich darin aus, dass es wiederum eine Anzahl von Loadbalancern gibt, die jeweils eine Anzahl von SIP-Servern ausgeben. Das äußert sich darin, dass die IP-Adressen für DNS SRV-Einträge, die man erhält, immer wieder wechseln.
Leider ist es so, dass beim Start von Asterisk ein mal eine Auflösung erfolgt und die (in diesem Falle) drei IP-Adressen genutzt werden, um daraus identify-Sections zu erzeugen.
In der Praxis merkt man, dass man in diese Falle getappt ist, wenn das ganze Asterisk-Setup gut läuft, aber nach 1-2 Tagen plötzlich keine ankommenden Anrufe mehr möglich sind, genau genommen zwar SIP INVITEs kommen, Asterisk diese aber frech mit einem 401 Unauthorized beantwortet 🙂

Der IP-Adress-Block, zu dem tel.t-online.de liegt, ist 217.0.0.0/13.
Im einfachsten Fall definiert man sich in der pjsip.conf nochmal händisch einen identify-Block, der diesen IP-Adressbereich definiert. In unserem Beispiel wäre das also:

[hh1982-identify]
type=identify
endpoint=hh1982
match=217.0.0.0/13

Geliebte ISDN-Leistungsmerkmale: CLIR und CCBS

Nicht nur die „nackte Telefonie“ sondern auch Netz-Leistungsmerkmale interessieren mich, die ich zu ISDN-Zeiten des öfteren genutzt habe.
Falls jemand bis hierhin Hoffnungen hatte: Rückruf bei Besetzt ist nach meinem Kenntnisstand im Telekom-Netz nicht möglich. Im RFC 6910 wird zwar eine mögliche Umsetzung beschrieben, aber die Telekom hat sich dazu entschieden, diese Funktion komplett auf der Basis von Sprachansagen zu realisieren.

Was dafür allerdings funktioniert, ist die Rufnummernunterdrückung. Am Telekom-Anschluss ist das über den Header Privacy geregelt, der den Wert id bekommt.

Diese Variante wird auch von den SIP-Endgeräten, die bei mir im Einsatz sind, unterstützt. Somit brauche ich bei einem abgehenden Telefonat nur zu schauen, ob der Header für das abgehende Gespräch reproduziert werden muss. Hier gibt es etwas größere Unterschiede zu chan_sip. Zu chan_sip gibt es die Application SIPAddHeader, die es bei PJSIP in der Form nicht gibt; dafür gibt es die Function PJSIP_HEADER, die hier als Handler aufgerufen werden muss. Hier ist der Ausschnitt aus dem Dialplan:

same => n,ExecIf($["${PJSIP_HEADER(read,Privacy)}"="id"] ?Dial(PJSIP/${EXTEN}@hh1982,,b(clirhandler^addheader^1)): Dial(PJSIP/${EXTEN}@hh1982)

Der Handler sieht wie folgt aus:

[clirhandler]
exten => addheader,1,Set(PJSIP_HEADER(add,Privacy)=id)
same => n,Return()

Nun gibt es in Sachen CLIR noch eine Spezialität, die bei mir im Zusammenhang mit Snom-Telefonen auftritt: Schaltet man dort die Rufnummernunterdrückung ein, wird nicht nur der Privacy-Header gesetzt, sondern der From-Header auf anonymous@anonymous.invalid gesetzt. chan_sip hat in diesem Fall offenbar von sich aus auch andere Informationen zurate gezogen, um das INVITE zu identifizieren. PJSIP verlässt sich grundsätzlich erstmal ausschließlich auf den From-Header und gerät so natürlich ins Stocken.

Lösen lässt sich das Problem, indem man in der pjsip.conf einen identify-Eintrag anlegt, um das Endgerät anhand seiner IP-Adresse identifizieren zu können:

[hh-arbeitszimmer-ep]
type=identify
endpoint=arbeitszimmer
match=192.168.178.123

Zu guter letzt: Es traten Probleme auf, wenn dieselbe IP-Adresse sowohl für Endpoints als Endgeräte als auch für Telefonleitungen genutzt wird, wie das z. B. bei einer Fritzbox der Fall ist. Das lässt sich beheben, indem man in der pjsip.conf die Reihenfolge verändert, in der versucht werden soll, einen Endpoint zu identifizieren. Normalerweise steht die IP-Adresse an erster Stelle.

[global]
type=global
endpoint_identifier_order=auth_username,username,ip,anonymous

Vielleicht hilft jemandem diesem Artikel – zumindest, um Zeit zu sparen. Meines Wissens nach gibt es bisher keine Dokumentation zur Verwendung von pjsip_wizard.conf im Zusammenhang mit Telekom AllIP. Über Kommentare und Erfolgsmeldungen freut sich auch dieser Artikel.
Übrigens: An dieser Stelle möchte ich nochmal Werbung für meinen jetzt Artikel zum Thema Upcycling klassischer Telefonanlagen machen. Ich suche immer noch Mitstreiter für diese Idee 🙂

Ein Gedanke zu „Telefonanlage mit Asterisk 13 und PJSIP

  1. Pingback: Heim-Server auf Raspberry Pi mit Asterisk, fhem, LDAP und davical | Technikgedöns

Schreibe einen Kommentar