Request-URI vs. To-Header-URI beim eingehenden Routing in SIP

Da einige SIP-Provider bei kommenden Anrufen die Zielrufnummer in der To-Header-URI statt in der Request-URI des INVITE-Requests im SIP-Protokoll übermitteln habe ich hier eine technische Betrachtung dieser Vorgehensweise zusammengestellt.

Inhalt:

Definitionen aus dem SIP-RFC

Ein eingehendes INVITE sieht normalerweise etwa so aus (vereinfacht):

INVITE sip:bob@pbx;transport=udp SIP/2.0
To: "Bob" <sip:bob@pbx>
...

Sowohl die Request-URI (R-URI) als auch die URI im To-Header sind hier sip:bob@pbx.

RFC 3261 §7.1 - Requests:

      Request-URI: The Request-URI is a SIP or SIPS URI as described in
           Section 19.1 or a general URI (RFC 2396 [5]).  It indicates
           the user or service to which this request is being addressed.

RFC 3261 §8.1.1.1 - Request-URI:

   The initial Request-URI of the message SHOULD be set to the value of
   the URI in the To field.

RFC 3261 §8.1.1.2 - To:

   The To header field first and foremost specifies the desired
   "logical" recipient of the request, or the address-of-record of the
   user or resource that is the target of this request.

RFC 3261 §20.39 - To:

   The To header field specifies the logical recipient of the request.

RFC 3261 §8.2.2.1 - To and Request-URI:

   The To header field identifies the original recipient of the request
   designated by the user identified in the From field.  The original
   recipient may or may not be the UAS processing the request, due to
   call forwarding or other proxy operations.
   However, the Request-URI identifies the UAS that is to process the
   request

RFC 3261 §26.5 - Privacy:

   In some cases, users may want to conceal personal information in
   header fields that convey identity.  This can apply not only to the
   From and related headers representing the originator of the request,
   but also the To - it may not be appropriate to convey to the final
   destination a speed-dialing nickname, or an unexpanded identifier for
   a group of targets, either of which would be removed from the
   Request-URI as the request is routed, but not changed in the To
   header field if the two were initially identical.  Thus it MAY be
   desirable for privacy reasons to create a To header field that
   differs from the Request-URI.

Was bedeutet das?

Im To-Header eines eingehenden INVITE-Requests steht normalerweise die vom Anrufer gewählte Nummer. Das kann auch eine Kurzwahl o.ä. sein die von der Telefonanlage des Anrufers zu einer Request-URI aufgelöst wird.

Die To-Header-URI ist also sowas ähnliches wie DNIS/DNID, also die gewählte Nummer; nicht zwangsläufig die Zielrufnummer auf der Seite des Angerufenen.

Im To-Header kann sogar eine andere Telefonanlage (Domain) stehen als in der Request-URI. Beispiel:
A ruft B an. B steht in der Request-URI und sehr wahrscheinlich auch im To-Header. B leitet an C (auf unserer Telefonanlage) weiter. Jetzt steht C (wir) in der Request-URI. Im To-Header kann aber immer noch B stehen.

D.h. die To-URI hat auf der Telefonanlage des Angerufenen keine Relevanz bei der Entscheidung an welchen eigenen Benutzer der Anruf gerichtet ist.

Soviel zur Theorie.

Problem: SIP-Trunks bei SIP-Providern

SIP-Provider senden in der Request-URI normalerweise nicht die tatsächlich angerufene Nummer sondern den Account-Namen (manchmal SIP-ID genannt, meist alphanumerisch oder die Kopfnummer unseres Rufnummernblocks) unseres Trunks. Beispiel:

INVITE sip:accountname@host;transport=udp SIP/2.0
To: <sip:012377777555@pbx>
...

oder

INVITE sip:0123777770@host;transport=udp SIP/2.0
To: <sip:012377777555@pbx>
...

Dies ist laut SIP-RFC korrekt. Daß in der Request-URI nicht die tatsächlich angerufene Nummer steht sondern der Account-Name beim Provider ist nach dem SIP-Standard so vorgesehen.

Die Problematik entsteht schon bei der SIP-Registrierung (REGISTER, RFC 3261 §10.2 - Constructing the REGISTER Request). Durch die SIP-Registrierung wird dem SIP-Registrar mitgeteilt unter welcher IP-Adresse ein Benutzer-Account aktuell für kommende Anrufe erreichbar ist. REGISTER ist aber immer nur auf einzelne Benutzer ausgelegt, nicht auf Rufnummernblöcke (Trunks). Von einer Telefonanlage mit einem Rufnummernblock mit 4-stelligen Durchwahlen (xxxx) für jede dieser Durchwahlen (10.000!) eine Registrierung zu senden ist keine gute Lösung.

Dieses Problem hat also weder etwas mit Asterisk zu tun noch mit Gemeinschaft. Das ist eher ein allgemeines SIP-Problem, denn SIP-Provider oder Trunks sind in keinem der SIP-RFCs vorgesehen.

Asterisk (und damit erstmal auch Gemeinschaft) nimmt die angerufene Nummer (in den o.g. Beispielen accountname bzw. 0123777770) RFC-konform aus der Request-URI (INVITE sip:accountname@... bzw. INVITE sip:0123777770@...). Blöderweise sagt das in solchen Fällen dann nichts über die angerufene Durchwahl aus.

Woher bekommen wir die Zielrufnummer?

Kurze Antwort: Gar nicht. SIP-Trunks sind im SIP-Standard nicht vorgesehen.

Man könnte zwar die angerufene Nummer aus dem To-Header nehmen, das wäre aber nicht RFC-konform und funktioniert auch nicht immer, z.B. nicht wenn vorher schon Weiterleitungen stattgefunden haben. Evtl. mag zwar ein Provider dafür sorgen daß bei ihm der To-Header immer stimmt, also die bei uns anzurufende Nummer enthält, aber das kann Asterisk / Gemeinschaft ja nicht wissen, ist also keine allgemeingültige Lösung.

Workaround in Gemeinschaft

Wenn man trotzdem (nicht RFC-konform) anhand der To-Headers-URI eingehend routen will, so ist dies in Gemeinschaft / Asterisk durch einen manuellen Workaround möglich.

Vorab sei aber gesagt daß durch den Begriff Workaround kein Fehler in Gemeinschaft impliziert wird und daß weder die Amooma GmbH noch ich Unzulänglichkeiten im SIP-Protokoll supporten können. Die folgenden Änderungen sind nur etwas für erfahrene Benutzer und erfolgen auf eigene Gefahr.

In der Datei /opt/gemeinschaft/etc/asterisk/e-gategroups-in.ael.php gibt es folgenden auskommentierten Code:

    /*
    # hack for Sipgate.de {
    if (preg_match('/\bsipgate\b/i', $name)) {
        echo "\t\t\t", "\n";
        echo "\t\t\t", 'Set(did_full=${SIP_HEADER(To)});' ,"\n";
        echo "\t\t\t", 'Set(did_full=${CUT(did_full,@,1)});' ,"\n";
        echo "\t\t\t", 'Set(did_full=${did_full:5});' ,"\n";
        echo "\t\t\t", 'Verbose(1,### Inbound call from Sipgate to ${did_full});' ,"\n";
        echo "\t\t\t", "\n";
    }
    # hack for Sipgate.de }
    */

Diesen Code könnte man reinnehmen (also die Kommentarzeichen /* */ entfernen) um anhand des To-Headers zu routen. Etwa so:

    # hack for routing based on To header URI {
    echo 'if ("${CHANNEL(channeltype)}" = "SIP") {' ,"\n";
    echo '    Set(did_full=${SIP_HEADER(To)});' ,"\n";
    //                    "Bob" <sip:012377777555@host>
    echo '    Set(did_full=${CUT(did_full,@,1)});' ,"\n";
    //                    "Bob" <sip:012377777555
    echo '    if ("${CUT(did_full,<,2)}" != "") {' ,"\n";
    echo '        Set(did_full=${CUT(did_full,<,2)});' ,"\n";
    echo '    }' ,"\n";
    //                           sip:012377777555
    echo '    if ("${CUT(did_full,:,2)}" != "") {' ,"\n";
    echo '        Set(did_full=${CUT(did_full,:,2)});' ,"\n";
    echo '    }' ,"\n";
    //                               012377777555
    echo '    Verbose(1,### DNID by To header: ${did_full});' ,"\n";
    echo '}' ,"\n";
    # hack for routing based on To header URI }

Dann Asterisk neu starten:
/etc/init.d/asterisk restart

Es versteht sich von selbst daß man sich danach mit dem Asterisk-CLI verbindet (asterisk -r) und mit Verbosity 1 (core set verbose 1) und ggf. auch 3 (core set verbose 3) genau beobachtet ob der Code korrekt funktioniert bzw. diesen ggf. anpaßt.

Von der kompletten angerufenen Nummer (z.B. 012377777555) läßt sich dann ganz normal in der Web-Oberfläche von Gemeinschaft (als Benutzer mit Admin-Rechten) unter Routen → Gateway-Gruppen bei Eingehende Durchwahl mit einem Suchen-/Ersetzen-Muster eine eventuelle Ortsvorwahl und Kopfnummer (z.B. 012377777) abschneiden, sodaß nur die reine Durchwahl (z.B. 555, bei einem Anlagenanschluss oder hier SIP-Trunk) bzw. MSN (z.B. 555555, bei einem Mehrgeräte-Basisanschluß oder Analog-Anschluß) übrigbleibt. Dies funktioniert also genauso wie beim eingehenden Routing anhand der Request-URI. Auch das eingehende Routing von Durchwahlen zu Nebenstellen unter Routen → Routen eingehend funktioniert ganz genauso.

Weitere technische Diskussionen zum Thema

Manchmal sieht man Remote-Party-ID mit ;party=called, aber Remote-Party-ID (RPID) ist nur ein alter Draft der es nicht in ein RFC geschafft hat, und ;party=called war da nie angesprochen.

Daneben gibt es auch P-Called-Party-ID (RFC 3455 §4.2, §5.2). Dieser Header würde sich gut eignen, allerdings kommt er bei kaum einem Provider zum Einsatz.

Manche SIP-Provider senden einen proprietären X-irgendwas-Header (z.B. X-Original-DDI-URI). Das ist natürlich erst recht keine allgemeingültige Lösung.

Wieder andere Provider senden gar keinen zusätzlichen SIP-Header sondern sagen ihren Kunden sie sollen die angerufene Nummer aus dem To-Header nehmen. Dies ist wahrscheinlich die schlechteste aller Varianten, denn der To-Header ist bereits anders definiert.


Klaus Darilion in asterisk-dev:

A Workaround is to put the originally called number in the To header - 
but this is ugly as To based routing it is against all RFCs.

in asterisk-dev:

Using To: you assume that the To header contains the originally called 
number. But that depends on the setup of the trunking provider.

in asterisk-dev:

Found it: http://www.ietf.org/rfc/rfc3455.txt
P-Called-Party-ID (there is is good documentation why other workarounds 
are not good).

This remembers me on another approach - differentiate between routing 
and retargeting. Please read 
http://tools.ietf.org/html/draft-rosenberg-sip-ua-loose-route-02 which 
also addresses these problems. As this is logically not retargeting but 
routing, the trunking provider could send the called number in the RURI, 
and the registered contact is sent as Route header. Thus, Asterisk could 
match the registered contact against the topmost Route header and the 
RURI contains the dialed number.

Probably, as there are multiple solutions, we should ask on the
SIP implementors list.

Thread signaling DID on a SIP trunk auf der sip-implementors-Mailingliste:
https://lists.cs.columbia.edu/pipermail/sip-implementors/2009-January/thread.html#21508

Olle E. Johansson in https://lists.cs.columbia.edu/pipermail/sip-implementors/2009-January/021536.html:

Right now there's too many ways for service providers to solve
this problem, including home-brewed headers. That doesn't
help anyone.

Theo Zourzouvillys in http://wiki.voip.co.uk/sip/matching_using_to_header:

the To and From header fields are end to end header fields populated by the originating UA, and not modified by the network. A UA is free to place whatever it likes in this field, as it is not used in any routing or targeting decisions.

So, the request that proxy.voip.co.uk will forward now looks like this:

INVITE sip:056854@87.127.89.138:5060 SIP/2.0
From: Alice <sip:alice@voip.co.uk>
To: Bob <sip:bob@voip.co.uk>

Note that the From and To headers have NOT been modified by the proxy, as RFC 3261 (the SIP standard) makes clear on page 162/163 in Table 2: Summary of header fields:

      Header field          where   proxy ACK BYE CAN INV OPT REG
      ___________________________________________________________
      From                    c       r    m   m   m   m   m   m
      To                      c(1)    r    m   m   m   m   m   m

   The "proxy" column describes the operations a proxy may perform on a
   header field:

      r: A proxy must be able to read the header field, and thus this
           header field cannot be encrypted.

So, as you can see, a SIP proxy is NOT allowed to modify the To or From headers, only read them.

In short, you can not use the To header for matching, and doign so is totally incorrect.

There is currently work going on in the IETF to provide a mechanism to work out what (logical) address a request was initially targeted to, as there is no correct way to pass this information yet (although we try and send with P-Called-Party-ID where possible). Current ideas include a new 'Target' header or using loose routing and not modifying the R-URI at all.


Fazit: Es gibt für dieses Problem leider noch keinen verbindlichen Standard in SIP der sich durchgesetzt hat.

IETF-Draft Delivery of Request-URI Targets to User Agents (draft-rosenberg-sipcore-target-uri-delivery) (zuvor auch bekannt als draft-rosenberg-sip-target-uri-delivery, draft-holmberg-sip-target-uri-delivery

IETF-Draft Applying Loose Routing to Session Initiation Protocol (SIP) User Agents (UA) (draft-rosenberg-sip-ua-loose-route)

History-Info-Header (RFC 4244)

SIP Forum: SIPconnect,
SIPconnect Technical Recommendation v. 1.0 (PDF)


Rechtliches | (c) Philipp Kempgen