TCP/IP とデータ通信

第 6 章 TCP/IP の障害追跡

この章では、TCP/IP ネットワークの一般的な障害追跡の方法と、そのために使用できるツール (pingifconfignetstatroute など) について説明します。

一般的な障害追跡方法

ネットワーク上での問題を示す最初の徴候は、1 つまたはいくつかのホストでの通信の消滅です。あるホストを初めてネットワークに追加したときに、そのホストがまったく動作しない場合は、構成ファイルのどれか、またはネットワークインタフェースに問題があることが考えられます。1 つのホストに突然問題が生じた場合は、ネットワークインタフェースに原因があると考えられます。ネットワーク上のホスト相互間の通信はできるが、他のネットワークとの通信ができないという場合は、ルーターに問題があるか、または他のネットワークに問題があることが考えられます。

ifconfig プログラムを使用すればネットワークインタフェースに関する情報を入手でき、netstat を使用すればルーティングテーブルとプロトコル統計を表示できます。サードパーティのネットワーク診断プログラムから、さまざまな障害追跡ユーティリティが提供されています。詳細は、サードパーティのマニュアルを参照してください。

比較的明らかになりにくいのは、ネットワーク上でのパフォーマンス低下の原因です。たとえば、ping のようなツールを使用することで、ホストでのパケットの消失など、問題の原因を突き止めることができます。

ソフトウェア検査の実行

ネットワークに障害が生じた場合は、以下のような処置によって、ソフトウェア関連の問題を診断し修正することができます。

  1. netstat コマンドを使ってネットワーク情報を表示します。

  2. hosts データベースを検査して、個々のエントリが適正で最新であるかどうかを確認します。

  3. RARP を実行している場合は、 ethers データベース内のイーサネットアドレスを検査して、個々のエントリが適正で最新であるかどうかを確認します。

  4. telnet によりローカルホストに接続してみます。

  5. ネットワークデーモン inetd が実行中であることを確認します。そのためには、スーパーユーザーとしてログインし、次のように入力します。

    # ps -ef | grep inetd

inetd デーモンが実行中であれば、次の例に示すような出力が表示されます。


root 57   1    0 Apr 04   ?     3:19 /usr/sbin/inetd -s
root 4218 4198 0 17:57:23 pts/3 0:00 grep inetd 

ping コマンド

ping コマンドは、特定のホストとの IP 接続が存在しているかどうかを確認するために使用します。基本構文は次のとおりです。

/usr/sbin/ping host [timeout]

host は問題のマシンのホスト名を示します。オプションの timeout 引数は、ping がそのマシンに到達しようと試みる秒数を示し、デフォルトは 20 秒です。詳しい構文とオプションについては、ping(1M) のマニュアルページを参照してください。

ping を実行すると、ICMP プロトコルは、指定されたホストにデータグラムを送って、応答を求めます (ICMP は、TCP/IP ネットワーク上のエラー処理を担当するプロトコルです。詳細は、「ICMP プロトコル」を参照してください)。

次のように入力したとします。


$ ping elvis

ホスト elvis が動作していれば、次のメッセージが表示されます。


elvis is alive

これは、elvis が ICMP の要求に応答したことを示します。しかし、elvis がダウン状態にあるかまたは ICMP パケットを受け取れなかった場合は、ping から次の応答が返されます。


no answer from elvis

マシンが動作状態にあるのにパケットが失われている疑いがある場合は、pings オプションを使用して、問題を追求することができます。たとえば次のように入力します。


$ ping -s elvis 

ping は、ユーザーが割り込み文字を送るかまたはタイムアウトが生じるまで、elvis にパケットを送り続けます。画面上には、次のように出力されます。


PING elvis: 56 data bytes
64 bytes from 129.144.50.21: icmp_seq=0. time=80. ms
64 bytes from 129.144.50.21: icmp_seq=1. time=0. ms
64 bytes from 129.144.50.21: icmp_seq=2. time=0. ms
64 bytes from 129.144.50.21: icmp_seq=3. time=0. ms
.
.
.
----elvis PING Statistics----
4 packets transmitted, 4 packets received, 0% packet loss
round-trip (ms) min/avg/max = 0/20/80   

パケットロスの統計値は、ホストがパケットを失ったかどうかを示します。

ping が失敗した場合は、ifconfignetstat が報告するネットワーク状態を調べます。これについては、次の ifconfig コマンド」と、netstat コマンド」を参照してくだい。

ifconfig コマンド

ifconfig コマンドは、指定したインタフェースの構成に関する情報を表示します。詳細は、ifconfig(1M) のマニュアルページを参照してください。ifconfig の構文は次のとおりです。

ifconfig interface-name [protocol_family]

特定のインタフェース、たとえば le0 に関する情報を表示したい場合は、次のように入力します。


$ ifconfig le0

le0 インタフェースの場合は、出力は次のようになります。


le0: flags=863<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
 	inet 129.144.44.140 netmask ffffff00 broadcast 129.144.44.255
ether 8:0:20:8:el:fd

上記の flags セクションは、インタフェースが "up" として構成されていて、ブロードキャストの能力があり、"trailer" リンクレベルのカプセル化を使用していないことを示しています。mtu フィールドは、このインタフェースの最大転送速度が 1500 であることを示しています。2 行目には、使用しているホストの IP アドレス、現在使用されているネットマスク、インタフェースの IP ブロードキャストアドレスの情報が含まれています。3 行目は、ホストのマシンアドレス (この場合はイーサネット) です。

ifconfig の便利なオプションの 1 つに -a があります。これを使用すると、ネットワーク上のすべてのインタフェースに関する情報が提供されます。たとえば、ifconfig -a と入力したとします。


le0:  flags=49<UP,LOOPBACK,RUNNING> mtu 8232
     inet 127.144.44.140 netmask ff000000 
le0:flags=863<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
     inet 129.144.44.140 netmask ffffff00 broadcast 129.144.44.255
ether 8:0:20:8:el:fd


注 -

特権 (root) ユーザーが ifconfig コマンドを発行した場合は、上記のようにマシンのアドレスが出力に表示されます。


実行されていないインタフェースがあることが出力に示されている場合は、そのインタフェースに問題があると考えられます。その場合は、ifconfig(1M) のマニュアルページを参照してください。

netstat コマンド

netstat コマンドは、ネットワーク状態とプロトコル統計を表示します。TCP と UDP のエンドポイントの状態 (テーブル形式)、ルーティングテーブルの情報、インタフェースの情報を表示できます。

netstat は、選択したコマンド行オプションに応じて、さまざまな種類のデータを表示します。この表示は、特にシステム管理に役立ちます。このコマンドの構文は次のとおりです。

netstat [-m] [-n] [-s] [-i | -r] [-f address_family]

ネットワーク状態の判別のために最もよく使われるオプションは、 sri です。オプションの説明については、netstat(1M) のマニュアルページを参照してください。

プロトコル別統計の表示

netstat -s オプションは、UDP、TCP、ICMP、IP プロトコルについて、プロトコル別の統計を表示します。結果は、下に示す出力例のように表示されます (出力の一部は省略してあります)。この情報には、プロトコルに問題のある箇所が示されることがあります。たとえば ICMP からの統計情報は、このプロトコルがどこにエラーを検出したかを示します。

UDP

      udpInDatagrams      =  39228     udpOutDatagrams     =  2455
      udpInErrors         =     0

TCP

      tcpRtoAlgorithm     =     4      tcpMaxConn          =    -1
      tcpRtoMax           = 60000      tcpPassiveOpens     =     2
      tcpActiveOpens      =     4      tcpEstabResets      =     1
      tcpAttemptFails     =     3      tcpOutSegs          =   315
      tcpCurrEstab        =     1      tcpOutDataBytes     = 10547
      tcpOutDataSegs      =   288      tcpRetransBytes     =  8376
      tcpRetransSegs      =    29      tcpOutAckDelayed    =    23
      tcpOutAck           =    27      tcpOutWinUpdate     =     2
      tcpOutUrg           =     2      tcpOutControl       =     8
      tcpOutWinProbe      =     0      tcpOutFastRetrans   =     1
      tcpOutRsts          =     0
      tcpInSegs           =   563      tcpInAckBytes       = 10549
      tcpInAckSegs        =   289      tcpInAckUnsent      =     0
      tcpInDupAck         =    27      tcpInInorderBytes   =   673
      tcpInInorderSegs    =   254      tcpInInorderBytes   =   673
      tcpInUnorderSegs    =     0      tcpInUnorderBytes   =     0
      tcpInDupSegs        =     0      tcpInDupBytes       =     0
      tcpInPartDupSegs    =     0      tcpInPartDupBytes   =     0
      tcpInPastWinSegs    =     0      tcpInPastWinBytes   =     0
      tcpInWinProbe       =     0      tcpInWinUpdate      =   237
      tcpInClosed         =     0      tcpRttNoUpdate      =    21
      tcpRttUpdate        =   266      tcpTimRetrans       =    26
      tcpTimRetransDrop   =     0      tcpTimKeepalive     =     0
      tcpTimKeepaliveProbe=     0      tcpTimKeepaliveDrop =     0

IP
 
      ipForwarding        =     2      ipDefaultTTL        =   255
      ipInReceives        =  4518      ipInHdrErrors       =     0
      ipInAddrErrors      =     0      ipInCksumErrs       =     0
      ipForwDatagrams     =     0      ipForwProhibits     =     0
      ipInUnknownProtos   =     0      ipInDiscards        =     0
      ipInDelivers        =  4486      ipOutRequests       =  2805
      ipOutDiscards       =     5      ipOutNoRoutes       =     0
      ipReasmTimeout      =    60      ipReasmReqds        =     2
      ipReasmOKs          =     2      ipReasmReqds        =     2
      ipReasmDuplicates   =     0      ipReasmFails        =     0
      ipFragOKs           =    20      ipReasmPartDups     =     0
      ipFragCreates       =   116      ipFragFails         =     0
      tcpInErrs           =     0      ipRoutingDiscards   =     0
      udpInCksumErrs      =     0      udpNoPorts          =    33
      rawipInOverflows    =     0      udpInOverflows      =     6

ICMP

      icmpInMsgs          =     0      icmpInErrors        =     0
      icmpInCksumErrs     =     0      icmpInUnknowns      =     0
      icmpInDestUnreachs  =     0      icmpInTimeExcds     =     0
      icmpInParmProbs     =     0      icmpInSrcQuenchs    =     0
      icmpInRedirects     =     0      icmpInBadRedirects  =     0
      icmpInEchos         =     0      icmpInEchoReps      =     0
      icmpInTimestamps    =     0      icmpInTimestampReps =     0
      icmpInAddrMasks     =     0      icmpInAddrMaskReps  =     0
      icmpInFragNeeded    =     0      icmpOutMsgs         =     7
      icmpOutDestUnreachs =     1      icmpOutErrors       =     0
      icmpOutDrops        =     5      icmpOutTimeExcds    =     0
      icmpOutParmProbs    =     0      icmpOutSrcQuenchs   =     6
      icmpOutRedirects    =     0      icmpOutEchos        =     0
      icmpOutEchoReps     =     0      icmpOutTimestamps   =     0
      icmpOutTimestampReps=     0      icmpOutAddrMasks    =     0
      icmpOutAddrMaskReps =     0      icmpOutFragNeeded   =     0
      icmpInOverflows     =     0


IGMP:
 
0 messages received
0 messages received with too few bytes
0 messages received with bad checksum
0 membership queries received
0 membership queries received with invalid field(s)
0 membership reports received
0 membership reports received with invalid field(s)
0 membership reports received for groups to which we belong
0 membership reports sent

ネットワークインタフェースの状態の表示

netstati オプションは、このコマンドを実行したマシンで構成されているネットワークインタフェースの状態を示します。次に示すのは、netstat -i による出力結果の例です。

Name Mtu  Net/Dest     Address   Ipkts    Ierrs Opkts    Oerrs  Collis  Queue
le0  1500 b5-spd-2f-cm tatra     14093893 8492  10174659 1119   2314178   0
lo0  8232 loopback     localhost 92997622 5442  12451748 0      775125    0

この表示から、各ネットワークについてマシンが送信し受信したとみなしているパケットの数が分かります。たとえば、サーバーについて表示される入力パケットカウント (Ipkts) はクライアントがブートを試みるたびに増加しているのに、出力パケットカウント (Opkts) が変化しないことがあります。これは、サーバーがクライアントからのブート要求パケットを見ているが、それを応答すべきものとして認識していないことを示しています。この原因としては、hosts データベースまたは ethers データベース内に誤ったアドレスがあることが考えられます。

逆に、入力パケットカウントが長時間にわたり変化しないとすれば、それは、マシンがパケットをまったく見ていないことを意味します。この原因としては、上記の場合と違って、ハードウェアの問題の可能性が高くなります。

ルーティングテーブルの状態の表示

netstat-r オプションは、IP ルーティングテーブルを表示します。次に示すのは、マシン tenere で実行した netstat -r の出力結果の例です。

Routing tables
Destination   Gateway Flags Refcnt Use   Interface
temp8milptp   elvis   UGH   0      0	
irmcpeb1-ptp0 elvis   UGH   0      0	
route93-ptp0  speed   UGH   0      0	
mtvb9-ptp0    speed   UGH   0      0	
	              .
mtnside       speed   UG    1      567	
ray-net       speed   UG    0      0	
mtnside-eng   speed   UG    0      36	
mtnside-eng   speed   UG    0      558	
mtnside-eng   tenere	 U     33     190248  le0

最初の列は宛先ネットワーク、2 番目の列はパケットを転送するルーターを示しています。U フラグは送信経路が up 状態であること、G フラグは送信経路がゲートウェイへのものであることを示します。H フラグは、宛先がネットワークではなく、完全指定のホストアドレスであることを示します。

Refcnt 列は 1 送信経路当たりの有効ユーザーの数、Use 列は 1 送信経路当たりの送信パケット数を示します。最後の Interface 列は、送信経路で使用されているネットワークインタフェースを示します。

ネットワークの問題の記録

ルーティングデーモンについて誤動作の疑いがある場合は、すべてのパケット転送も含めてそのデーモンの動作をログに記録することができます。ルーティングデーモンの動作のログファイルを作成するには、routed デーモンを起動するときにファイル名を指定します。たとえば次のように入力します。


# /usr/sbin/in.routed /var/routerlog


注意 - 注意 -

ビジー状態のネットワークでは、ほとんど絶え間なく出力が生じることがあります。


パケットの内容表示

snoop を使用すると、ネットワークパケットを取得して内容を表示できます。取得したパケットについては、そのまま表示することも、ファイルに保存することも可能です。snoop が中間ファイルに書き込む場合、トレースのビジー状態でパケットロスはほとんど発生しません。その後、snoop 自体はファイルの解釈に使用されます。詳細は、snoop(1M) のマニュアルページを参照してください。

snoop コマンドは必ず root(#) になって実行してください。プロミスキュアス (promiscuous) モードでデフォルトのインタフェースとやりとりするパケットを取得できます。最上位のプロトコルに関連するデータのみが一覧形式で表示されます。たとえば NFS パケットでは、NFS 情報のみが表示されます。RPC、UDP、IP、および Ethernet のフレーム情報は抑止されますが、verbose (詳細表示) オプションのいずれかを選択してあれば表示できます。

snoop が取得するファイルの形式は、RFC 1761 で説明しています。これを参照するには、Web ブラウザで http://ds.internic.net/rfc/rfc1761.txt にアクセスしてください。

snoop server client rpc rstatd は、クライアント/サーバー間のすべての RPC トラフィックを収集し、rstatd に対するフィルタをかけます。

システムから全パケットを確認する方法

  1. netstat -i と入力し、システムに接続されたインタフェースを検索します。

    通常、snoop では最初の非ループバックデバイス (le0) が使用されます。

  2. root になって snoop と入力します。

    Ctrl -C でプロセスを停止します。

    # snoop
    Using device /dev/le (promiscuous mode)
         maupiti -> atlantic-82  NFS C GETATTR FH=0343
     atlantic-82 -> maupiti      NFS R GETATTR OK
         maupiti -> atlantic-82  NFS C GETATTR FH=D360
     atlantic-82 -> maupiti      NFS R GETATTR OK
         maupiti -> atlantic-82  NFS C GETATTR FH=1A18
     atlantic-82 -> maupiti      NFS R GETATTR OK
         maupiti -> (broadcast)  ARP C Who is 129.146.82.36, npmpk17a-82 ?
  3. 結果を解釈します。

    上記の例では、クライアント maupiti からサーバー atlantic-82 への転送には NFS ファイルハンドル 0343 が使用され、atlantic-82 は OK と応答しています。who is 129.146.82.36? と問い合わせる ARP 要求が maupiti から伝送されるまで、会話は継続します。

    この例は、snoop の形式を説明しています。次の手順では、snoop にフィルタをかけてファイルにパケットを取り込みます。

    取り込んだファイルを解釈するには、RFC 1761 に記述された説明を使用します。これを参照するには、Web ブラウザで http://ds.internic.net/rfc/rfc1761.txt にアクセスします。

snoop の結果をファイルに取り込む方法

  1. root になって snoop -o filename の形式で入力します。たとえば、次のように入力します。


    # snoop -o /tmp/cap
    Using device /dev/le (promiscuous mode)
    30 snoop: 30 packets captured

    これによって、ファイル /tmp/cap に 30 個のパケットが取り込まれました。ディスク容量が十分にあれば、ファイルはどこにでも格納できます。取り込んだパケットの数はコマンド行に表示され、Ctrl-C を押せばいつでも終了できます。

    snoop 自体によってホストマシン上にネットワーク負荷がかかるので、結果に誤差が生じる場合があります。正確な状態を確認するには、第 3 のシステム (クライアントまたはサーバーに接続されているハブのいずれかを外したシステム) から snoop を実行してください (次の節を参照)。

  2. snoop -i filename の形式で入力し、ファイルを検査します。

    # snoop -i /tmp/cap
    
    1  0.00000 frmpk17b-082 -> 224.0.0.2   IP  D=224.0.0.2 S=129.146.82.1 LEN=32, ID=0
    2  0.56104        scout -> (broadcast) ARP C Who is 129.146.82.63, grail ?
    3  0.16742  atlantic-82 -> (broadcast) ARP C Who is 129.146.82.76, honeybea ?
    4  0.77247        scout -> (broadcast) ARP C Who is 129.146.82.63, grail ?
    5  0.80532 frmpk17b-082 -> (broadcast) ARP C Who is 129.146.82.92, holmes ?
    6  0.13462        scout -> (broadcast) ARP C Who is 129.146.82.63, grail ?
    7  0.94003        scout -> (broadcast) ARP C Who is 129.146.82.63, grail ?
    8  0.93992        scout -> (broadcast) ARP C Who is 129.146.82.63, grail ?
    9  0.60887        towel -> (broadcast) ARP C Who is 129.146.82.35, udmpk17b-82 ?
    10 0.86691  nimpk17a-82 -> 129.146.82.255 RIP R (1 destinations)

    ARP、IP、RIP その他の詳細な分析と推奨されるパラメータについては、特定のプロトコルのマニュアルを参照してください。RFC の確認には、Webを検索することをお奨めします。

サーバー/クライアント間のパケットを確認する方法

  1. snoop を実行するシステムから、クライアントまたはサーバーに接続されたハブのいずれかを外します。

    この第 3 のシステム (snoop システム) はすべてのトラフィックを監視するので、snoop のトレースには実際のネットワーク上の状態が反映されます。

  2. root になって snoop をオプション付きで実行し、結果をファイルに保存します。

  3. 結果の検査と解釈を行います。

    snoop 取り込みファイルの詳細については、RFC 1761 を参照してください。これを参照するには、Web ブラウザで http://ds.internic.net/rfc/rfc1761.txt にアクセスします。

頻繁かつ定期的に snoop を使用して、システムが正常に動作している場合の状態を把握してください。最近の白書や RFC を参照したり、NFS や YP といった特定分野の専門家からアドバイスを受けるのも、パケットの分析に役立ちます。snoop とそのオプションの使用法についての詳細は、snoop(1M) のマニュアルページを参照してください。

ルーティング情報の表示

traceroute ユーティリティは、IP パケットが特定のインターネットホストに至るまでのルートを追跡する際に使用します。traceroute ユーティリティは、IP プロトコルの ttl (time to live) フィールドを利用して、経路に沿った各ゲートウェイからの ICMP TIME_EXCEEDED 応答と、宛先ホストからの応答 PORT_UNREACHABLE (または、ECHO_REPLY) の受信を試みます。traceroute ユーティリティは、ttl を 1 にしてプローブの送信を開始し、プローブが目的のホストに到達するか、最大数の中間ホストを通過するまで ttl を 1 ずつ増加します。

traceroute ユーティリティは、ルーティングの誤設定やルーティング経路の障害を判定する場合に特に役立ちます。特定のホストが到達不可能な場合には、traceroute ユーティリティ を使用して、パケットがどの経路をたどって目的のホストに到達し、どこで障害が起きる可能性があるかを調べることができます。

また、traceroute ユーティリティは、経路に沿った各ゲートウェイの宛先ホストとの間の往復時間も表示します。この情報は、2 つのホスト間のどこでトラフィックが遅くなっているかを分析する際に利用することができます。

traceroute ユーティリティの実行方法

以下のコマンドを入力するのが、traceroute ユーティリティを実行する最も簡単な方法です。


traceroute hostname
上記の hostname は、宛先ホストの名前を示します。

以下の traceroute コマンドの例では、パケットがホスト istanbul から ホスト sanfrancisco までにたどる 7 つの経路と、パケットが各経路を通過する時間が表示されています。


istanbul% traceroute sanfrancisco
	traceroute: Warning: Multiple interfaces found; using 172.31.86.247 @ le0
	traceroute to sanfrancisco (172.29.64.39), 30 hops max, 40 byte packets
	 1  frbldg7c-86 (172.31.86.1)  1.516 ms  1.283 ms  1.362 ms
	 2  bldg1a-001 (172.31.1.211)  2.277 ms  1.773 ms  2.186 ms
	 3  bldg4-bldg1 (172.30.4.42)  1.978 ms  1.986 ms  13.996 ms
	 4  bldg6-bldg4 (172.30.4.49)  2.655 ms  3.042 ms  2.344 ms
	 5  ferbldg11a-001 (172.29.1.236)  2.636 ms  3.432 ms  3.830 ms
	 6  frbldg12b-153 (172.29.153.72)  3.452 ms  3.146 ms  2.962 ms
	 7  sanfrancisco (172.29.64.39)  3.430 ms  3.312 ms  3.451 ms

traceroute ユーティリティについての詳細は、traceroute(1M) のマニュアルページを参照してください。