はじめに
前回は、ネットワーク技術の標準化・SIP・IMSについて解説しました。本パートではIMSを横断するVoIPサービスの設計について触れ、より詳細なプロトコル解説を行いたいと思います!
Inter-IMS
複数の通信事業者のIMSが接続し、より広範囲でVoIPサービスが利用できるような状態のことをInter-IMSと呼びます。Inter-IMSを設計する際には、前回パートで述べたように、IMS間でプロトコルに整合性がとれていなければ、正常なVoIPサービスを運用することができません。したがってInter-IMSでのプロトコル設計を標準化する必要があります。そのための文書がTTCのJJ-90.30です。
JJ-90.30では、IMSとIMSの間のインターフェースであるII-NNI(Inter-IMS Network to Network Interface)でのSIP関連メッセージの標準を定めています。この規格に則りSIPメッセージを設計、または変換することで、各IMS間のプロトコルの違いを吸収し、Inter-IMSでのVoIPサービスを運用することができます。
II-NNIは以下のイメージです。
Session Border Controller
では、Inter-IMSのためにSIPメッセージの設計を見直しましょう!といってもそんなに簡単な話ではありません。というのも、IMS内ではすでにSIPを用いたVoIPサービスを運用してしまっています。つまり、SIPメッセージをまるっきり変更してしまうと、これまで運用していたVoIPサービスが正常に動かなくなってしまう恐れがあるのです。このような場合、今運用しているVoIPサービスで用いるSIPメッセージには変更を加えず、IMSをまたぐ際はSIPメッセージを変換するような機器を導入する必要があります。このような役割を担う機器がSession Border Controller (SBC)です。SBCはメッセージ変換のほかにもFWのような境界防御、NW外部から自身のIMSのネットワーク構成を隠すトポロジ隠蔽の役割があります。前回のパートで詳細を割愛したInter-connection Border Control Function (IBCF) はまさにSBCです。
SBCが実際に行いうるメッセージ変換の例を以下に示します。
この例では、INVITEリクエストのAllowヘッダから「MESSAGE」の値を削除しています。この意味についてはすぐに後述しますが、とりあえずこのようなメッセージの変換を行うことによってInter-IMS用のSIPメッセージを作成できるということになります。
SIP INVITEの詳細
ここから本格的にII-NNI用のSIP標準化を見ていきますが、そのためにはまずSIPメッセージの詳細な規約を知る必要があります。まずは、INVITEメッセージの規定や主要なヘッダの詳細を理解していきましょう!
Request-URIとTo
Request-URIは、SIPメッセージを着信先のsip端末までしっかり届けるための要素、Toヘッダは着信先のユーザを示すためのヘッダです。どちらも、「着信先」を表すためのsipヘッダですが、その目的が異なります。
Request-URIは、sipメッセージを「届ける」ことに重点を置いており、Toヘッダは着信先が「誰であるか」に重点を置いています。そのため、Request-URIの値は最初に設定されるAoRからContactアドレスに変わる場合も想定されていますが、Toヘッダは最初に設定されるAoRから値が変わるべきではありません。図に表すと以下のようになります。
また、RFC3261では、REGISTER以外の初期のRequest-URIとToヘッダは等しく設定されるべきだと書かれています。これは、SIPのメディアセッションがユーザ中心の設計になっているためであり、呼び出したいのは「ユーザ」であるからだと考えられます(つまり、まずユーザを指定して、そのあとに複数ありうるsip端末から正しい端末が特定されるという流れになるわけです)。
from
fromヘッダは発信したユーザを示すためのヘッダです。「ユーザ」を示すためAoRが設定され、物理的な位置や端末を示すIPアドレスやIPアドレスと直接紐づいたFQDNが設定されるべきではありません。技術的には物理的なアドレスを指定することも可能ですが、設計上は美しくないです。
基本的に、SIPメッセージで設定される値は論理的な「ユーザアドレス」(AoR)を示し、実際の端末に到達するためのURI(Contact)への解決やルーティングはLocation Serviceに任せる設計となっています。
Call-ID
Call-IDヘッダは、関連する一連のSIPメッセージを識別するための識別子です。少しあいまいな書き方にしたのは、SIPメッセージによって意味合いが多少異なるためです。INVITEの場合は同一の通話に関連するSIPメッセージ、REGISTERの場合は同一のsip端末に関連するSIPメッセージを識別する役割があります。
特にRFCでは、同一ダイアログ内のSIPリクエスト/レスポンスには同一のCall-IDを設定しなければならないと書かれています。一方で、Call-IDが同一のリクエスト/レスポンスは同一ダイアログであるとは限りません。これはForkingによって、1つのINVITEがコピーされて、複数のsip端末に届きうる場合が想定されるためです。
例えば上の図について、発信側端末とB@ua3の間でダイアログが確立した時(ua1からua3までの3つの端末が同時に鳴り始めたが、Bさんがua3で応答したようなとき)のことを考えます。この場合にCall-IDでSIPメッセージをトレースすると、発信側端末とB@ua3の間のダイアログ内SIPメッセージのほかに、B@ua1、B@ua2のINVITEメッセージも含まれることになります。これは、Call-IDが同一通話に関連する一連のSIPメッセージを識別するという設計であるため、forkingされてもIDを引き継ぐためです。そして、トレースされたua1とua2のメッセージは発信側端末-B@ua3間ダイアログ外のSIPメッセージであるため、Call-IDが同一のリクエスト/レスポンスであっても、同一ダイアログであるとは限らないということになります。
このように、Call-IDは同一通話に関連する広い範囲のSIPメッセージを識別するためのIDとして設計されているため注意が必要です。もしも、ヘッダでダイアログを識別したい場合には、Call-IDに加えてFrom-TagとTo-Tagを用いる必要があります。
UDP上でダイアログを管理する
Call-ID、from Tag、To Tagによってダイアログを識別できることは、sipにとってかなり重要です。なぜなら、sipはUDP上のメッセージにもかかわらず、リクエストに対するレスポンスを返したり、メッセージの種類やヘッダを読み取ってUAの制御をしたりと、まるでTCP上のメッセージのようにふるまわなくてはならないからです。UDP上のsipによってダイアログのフローを正常に動くようにするためには、トランザクションやダイアログの識別、順序制御、再送などを行わなければいけません。そのために、Call-IDやCSeq、branchパラメータなどのTCPっぽいヘッダやパラメータが規定されています。
Via
Viaヘッダは、あるsipリクエストが送信先に届くまでに通った経路を示すためのヘッダです。より具体的には、経路中の各UAがSIPメッセージを送信するときに用いたインターフェースのアドレスを設定したものです。これにより、sipレスポンスは、リクエストのViaの経路を逆順にたどることで送信元まで届けることができます。このように、リクエストと対応するレスポンスに同じ経路を用いることで、経路中のプロキシの状態管理やforking、NAT越えが正常に行なわれます。
VoIPでは、発着sip端末の間に複数のSIP Proxyが存在しうるため、Viaヘッダで経路を示すことは重要となります。
途中でNAT越えする場合
ここで、以下のように途中でNAT越えを挟むようなトポロジーを考えてみます。
まずUACがINVITEを送信すると、NATによりアドレス変換(10.1.0.15:5060→200.20.2.1:5070)されます。しかし、NATでアドレス変換されるのはIPレイヤだけであるため、アプリケーションレイヤのViaヘッダの中身は書き換えられません。そのまま、UASまでINVITEが送信され、今度はレスポンスをViaヘッダ記載のアドレスに向けて転送することを考えます。するとSIP Proxy2はNATサーバに宛先IP 200.20.2.1:5070 でレスポンスを送らなければいけないのにも関わらず、Viaヘッダ記載のアドレス「10.1.0.15:5060」にレスポンス返送してしまいます。結果として、INVITEフローは途中で途切れてしまい、ダイアログは確立されません。
以上より、トポロジー上にNAT越えを含む場合は、Viaヘッダ記載の通りにパケット転送するとダイアログはうまく確立されないことがわかります。
このような現象の対応策として、Viaヘッダにはreceived/rportパラメータを付与することができます。
SIP Proxyは実際のViaに記載のアドレスとパケットを受け取ったときの実際のアドレスを比較し、異なっている場合はreceivedパラメータとrportパラメータを付与することができます。ProxyがUASからINVITEレスポンスを受け取り再度転送する際は、これらのパラメータの値を参照し、宛先IPに指定することで、正常にNAT越えを行うことができます。
トランザクション
ここで、SIPのトランザクションについて少し解説を行います。SIPにおけるトランザクションとは、あるリクエストとそれに対応する最終応答までのフローのことです。重要なのは、「100 Trying」や「180 Ringing」などの暫定応答では、トランザクションは終了しないということです。「200 OK」や「503 Service Unavailable」等の最終応答を待ってトランザクションが終了することになります。
トランザクションの識別のためにはViaヘッダのbranchパラメータが用いられます。具体的な値はmagic cookie 「z9hG4bK」を接頭とするランダムな文字列が設定されます。つまり以下のようなViaヘッダが付与される音になります。
Via: SIP/2.0/UDP b.example.com:5060;branch=z9hG4bK87asdks7
上述したようにSIPメッセージフローはUDP上で実装されつつも、状態管理や再送等TCPのような機能を持たせる必要があるため、トランザクションを管理できることは重要となります。
Allow
Allowヘッダは、UA自身が受け取って正常に処理できるMethodの一覧を示します。INVITEリクエストでは、ダイアログ内で処理できるメソッド一覧を示すこととなります。
例えば以下のような形式です。
Allow: INVITE, ACK, OPTIONS, CANCEL, BYE
INVITEリクエスト内で上記のようなAllowを送った場合、UAはそのダイアログ内で、再度INVITE(セッション更新用)、ACK、OPTIONS、CANCEL、BYEを受け取り、処理できることを示します。
Supported/Require
Supportedヘッダでは、UA自身が持つSIP拡張機能を示すことができます。SIP拡張機能である100relやtimerについては、次回以降のパートで解説します。
例えば以下のように記載します。
Supported: timer, 100rel
Requireヘッダでは、相手のUAにサポートしてほしいSIP拡張機能を示すことができます。以下のように記載します。
Require: 100rel
通信相手がRequireヘッダに書かれた拡張をサポートしていれば通信続行、サポートしていなければそのことを記載した420 Bad Extensionレスポンスが返されます。
終わりに
INVITEの解説が長くなったので、いったんここでパートを切ります。次回はearly dialog周りについて扱いたいと思います!








