その2:SMB

SMBとCIFSの定義を明確にしておく。CIFSはSMBのダイアレクトの1つであり、SMB1.0とほぼ同義のもの。現在はSMB2.0以降が使用される事が多く、これらはCIFSとは呼ばない。直接関係ないが、NETBUEIとNETBIOSも混同しがちだが、NETBUEIはTCP/IPでは無い時代のWindowsの仕様であり、現在はNBT(NetBios on TCP/IP)に置き換えられている。NetBIOSはプロトコル名ではなく、Windowsのネットワーク機能(API)の名前。

PC1からPC2にSMBで接続し、200MB程度のファイルをダウンロードした通信のパケットキャプチャを採取した。

使用した端末:
PC1 Windows10 SMBクライアント側 192.168.3.8
PC2 Windows8 SMBサーバ側 192.168.3.9

No1のパケットはPC1からPC2へのSYN。Windowサイズ値は8,192になっている。
スケーリングオプションが有効になっており、シフトカウントは8にセットされている。

p2-01

この文章で使う言葉を定義しておく。Windowサイズ値はWindowサイズフィールドの値とし、実際のWindowサイズは計算された値とする。No2のパケットはPC2からPC1へのSYN/ACK。Windowサイズ値は8,192になっている。スケーリングオプションが有効になっており、シフトカウントは8にセットされている。

p2-02

No3のパケットはハンドシェイク最後となるPC1からPC2へのAck。Windowサイズ値は256になっている。

p2-03

No3でWindowサイズ値は256Byte。ただしスケーリングのシフトカウントは8にセットされていたので、256*(2の8乗)=65,536Byteということになる。MSSサイズは1460なので、MSSの約44倍ということになる。実際のデータ転送部分を見てみる。

p2-04

No436-No459まで、MSSの1460Byteでセグメンテーションされた24個のパケット(1460*24=35,040Byte)をPC2からPC1に送信している。No460のAckはAckが200,020から、その前のNo435のAck164,980を減算すると35040。ここまではいいのだが、No435のWindowサイズ値は541Byteなので、138,496Byteまで連続送信できるはずなのに1/4くらいしか送っていないのは何故か、よくわからない。

p2-05

No460のAckはWindow size値が541になっている。

p2-06

最終的にはWindow size値が30,000程度まで上がり、Windowサイズは4,523,008Byteになっている。Windowサイズの最大値は65,535なので、まだまだ上げられるはずだが、この通信ではここまでしか上がっていない。

p2-07

SMBを確認する。

p2-08

No4はクライアントからサーバへのSMB negotiateのrequest。フラグは全部て0。SessionIDも0。Signatureも0。

SMBの前にNetBIOSのヘッダがついている。Message TypeとLengthがセットされている。このLengthにはSMBデータも含まれる。
LARGE MTUは有効になっている。Windows8以降はデフォルトで有効。通信速度に影響するので注意しておく。マルチチャンネルも転送速度に影響するが、この機能が使用されるためには以下のような要件があるため、Windows8以降という要件では、まだ一般的にはあまり使われていないと思われる。
「・少なくとも 2 台のコンピューター上で実行される Windows Server 2012 R2, 、Windows Server 2012, 、または Windows 8 オペレーティング システムが必要です。 その他の機能をインストールする必要がありません: SMB マルチ チャネルが既定で有効にします。
・少なくとも 1 つの次の構成:
・複数のネットワーク アダプター
・Receive Side Scaling (RSS) をサポートする 1 つまたは複数のネットワーク アダプター
・NIC チーミングを使用して構成されている複数のネットワーク アダプターのいずれか
・リモート ダイレクト メモリ アクセス (RDMA) をサポートする 1 つまたは複数のネットワーク アダプター」

ENCRYPTIONは暗号化の要件。

p2-09

Dialectは使用できるSMBのバージョン。バージョンは以下のように対応づけられる。

If a common dialect is found, the server MUST set Connection.Dialect to “2.0.2”, “2.1”, “3.0”, “3.0.2”, or “3.1.1”, and Connection.NegotiateDialect to 0x0202, 0x0210, 0x0300, 0x0302, or 0x0311, accordingly, to reflect the dialect selected.

No5はサーバからクライアントへのSMB negotiateのresponse。

p2-10

NTSTATUSがSTATUS_SUCCESSになっている点とFlagsのResponseのビットが立っている以外はRequestとほぼ変わらない。
NTSTATUSのエラーコードは多くのコードが定義されているが0x00000000は成功を意味する。

次にNegotiate Protocolを確認する。

p2-11

Dialectが0x0302になっている。Requestには0x0311も含まれているが、0x0311はWindows10(ビルド9926)で追加されたので、Windows8.1のサーバ側端末はこれを使えないため、0x0302を応答している。
CapabilitiesはPersistent Handlesのフラグが消えている。

Security Blobのフィールドはセキュリティに関する部分。GSS-APIのOIDに1.3.6.1.5.5.2はSPENGOを使ってネゴシエーションするということで、次のmechTypeで1.3.6.1.4.1.311.2.2.30(NEGOX)と1.3.6.1.4.1.311.2.2.10(NTLM認証)が提示されている。

次のNo6のパケットはAckなので飛ばして、No7のパケットでクライアントがSPENGOの応答としてMechType1.3.6.1.4.1.311.2.2.10(NTLM認証)を選択している。

p2-12

更に続けてNTLMSSPのフィールドがあり、ここからいくつかのパケットで認証のやりとりがあるが、NTLMは機会があれば掘り下げたいが、こういう細かい事をいつも覚えていられるわけではないから、やったことは忘備録を作成しておいたほうがいい。