ICMP - みる会図書館


検索対象: UNIX MAGAZINE 1996年8月号
11件見つかりました。

1. UNIX MAGAZINE 1996年8月号

このプログラムのほとんどの処理はこの関数でおこなわれる バケットを読み込むたびに情報を表示する また、統計情報のためにデータの保存もおこなう void reCV 144 —packet ( ) struct int int U_Char struct int struct struct double sockaddr_in len; from; buf [IP_MAXPACKET] ; IP 1 ; 1 cmp timeval t ; *ipp = (struct ip*)buf ; *icmpp ; tv; / * この関数を終了することはない * / for ( ; / * 無限ループ * / len = sizeof (from) ; / * 変更されているかもしれない * / if ( ( Ⅱ recvfrom(fd, buf , sizeof (buf) , 0 , (struct sockaddr *)&from, &len)) く 0 ) { = EINTR) { / * 割り込まれたなら正常。再度受信を試みる * / contlnue ; perror ("recvfrom" ) ; exit(l); } else { gettimeofday(&tv, (struct timezone * ) 0 ) ; hl = ipp->ip—hl くく 2 ; icmpp = (struct icmp * ) (buf + (l) ; if (icmpp—>icmp—id ! = ident) continue ; / * 到着時刻 * / / * 工 P ヘッダのサイズを取得 * / / * ICMP ヘッダを指す * / / * 自分が送ったバケット以外の返答は無視する * / if (icmpp—>icmp—type ! = ICMP—ECHOREPLY) { / * ICMP_ECHOREPLY 以外を受け取った場合の処理 * / fprintf (stderr , " ICMP-TYPE = %d\n" , icmpp—>icmp_type) ; こでバケットの内容を出力したほうがよいだろう * / continue , nrecv 十十 ; / * 受信バケット数をインクリメント * / / * 受信パイト数、発信元アドレス、 seq 番号、 TTL 値を出力 * / printf("%d bytes from %s: Ⅱー hl, inet-ntoa(ipp—>ip—src)) ; printf ("icmp—seq=%d ttl=%d" , icmpp->icmp—seq, ipp—>ip_ttl) ; / * データの大きさを見て時刻情報が含まれるかを判断 * / if ( Ⅱー hl ICMP_HSIZE(icmpp) > = sizeof (struct timeval) ) { / * 時刻情報が含まれる場合 * / t = diff—timeval (icmpp—>icmp—data, &tv) ; ncount 十十・ / * RTT を出力する * / printf(" time=%. 3f ms", t) ; if (tmin > t) tmin = t ; if (tmax く t) tmax = t ; tsum 十 = t ; / * 重複したバケットかを検査 * / if (FD_ISSET(icmpp—>icmp-seq % FD_SETSIZE, &seqs) ) { / * 重複していればその旨を表示し、受信バケット数から削除 * / UNIX MAGAZINE 1996.8

2. UNIX MAGAZINE 1996年8月号

LJN Ⅸ流プログラミング 70 icmp—seq=O ttl = 255 time=O. 645 ms icmp—seq=l ttl = 255 time=O. 638 ms icmp—seq=2 ttl = 255 time=O. 65 ms 64 bytes from 127.0.0.1 : 64 bytes from 127.0.0.1 : 64 bytes from 127.0.0.1 : PING 10Ca1 五 ost ( 127.0.0.1 ) : 56 data bytes % ping 10Ca1 ost 図 1 ping の出力 10Ca1 五 OSt ping statistics 3 packets transmitted, 3 packets received , 0 % packet IOSS round—trip min/avg/max = 0.638 / 0.644 / 0.65 ms ・データがあまり速く到達したために処理しきれなくな った場合に、送り側にしばらくのあいだデータの送信 を中止するように知らせる。 ・宛先ホストまで到達できないことが分かったときに それを送り側に知らせる。 ・送り側か利用しているゲートウェイよりも、より宛先 に近いゲートウェイが存在するときに、近いゲートウ ェイを利用するように知らせる。 ・リモートホストが IP の処理ができるかどうかを検査 する。 ICMP により送受される情報は、 ICMP のプロトコ ルヘッダとデータ部分に分けることができます。 ICMP のプロトコルヘッダ部分は、 netinet/ip-icmp. h という ヘッダファイルで定義されている icmp 構造体で表現 されます。この構造体は共用体が数多く用いられている ので複雑にみえますが、注目してはしいのは、共用体に なっていない部分の次の 3 つのフィールドです。 u—short icmp—cksum ・ u—char icmp—code ; u—char icmp—type ; UNIX MAGAZINE 1996.8 ICMP-UNREACH-HOST がそれぞれ格納されます。 NET が、宛先ホストへ到達できないことが判明すると 到達できないことが判明すると ICMP-UNREACH- REACH が格納されている場合、宛先ネットワークへ かな種別を表すわけです。 icmp-type に ICMP-UN- 種類を大まかに規定し、この icmp-code の値がより細 値が変わります。つまり、 icmp-type を用いて情報の 次の icmp-code は、 icmp-type により格納される れています。 トでは、 ここに ICMP-UNREACH という値かオ各納さ きないことが分かったときに生成される ICMP バケッ 定数かオ各納されます。たとえば、宛先のホストに到達で 最初の icmp-type には、バケットの種類を示す記号 もう 1 つの値の icmp-cksum には、ヘッダとデー タのチェックサムかオ褓内されます。ここにオ褓内される値 は、ヘッダ中の icmp-cksum フィールドを除くすべての フィールドと、すべてのデータから計算されます。チェ ックサムの値は、対象となるすべての値を 2 バイトす つに切り分け、そのそれぞれの値を合計し、オー ノヾーフ ローしたときにはそれを 1 として加えて計算します。 の値が間違っていると、バケットを送出しようとしても できないので、注意してください。チェックサムを計算 するためには、 icmp-cksum フィールドを 0 に設定しま す。こうすれば、あらかじめ icmp-cksum フィールド を除外してから計算するのと同し結果が得られるので、 ・ ICMP-UNREACH の簡単な意味を紹介しておきましよう。 まず、 ICMP2S ケットの型として用いられる値と、そ ICMP-ECHO と ICMP-ECHOREPLY 処理か簡単になります。 TTL が 0 になって相手先に到達できない場合に、ゲ ・ ICMP-TIMXCEED イやホストから発行される。 い ( つまり、相手が存在しない ) 場合に、ゲートウェ 宛先ネットワーク、ホスト、ポートなどに到達できな ・ ICMP-SOURCEQUENCH トウェイやホストから発行される。 IP オプションの値カ墹違っている場合などに、ゲー ・ ICMP-PARAMPROB ートウェイから発行される。 ゲートウェイやホストが、バケットを処理しきれない ゲートウェイがより近いゲートウェイを紹介するとき ・ ICMP-REDIRECT ときに発行する。 135

3. UNIX MAGAZINE 1996年8月号

に発行される。 トを受け取ると、受け取ったサーバーはかならすそのパ ケットに対する返答を送らなければならないと決められ ・ ICMP-ECHO ェコー要求。 ています。つまり、このバケットを送れ ( 訂寉実に返事が 戻ってくるはすです。相手にバケットが届けばかならす ・ ICMP-ECHOREPLY ICMP-ECHO への応答で、渡された情報がそのまま 返答か得られるのですから、この ping コマンドの目的 格納される。 である「相手が通信可能な状態かどうかを検査する」た めに利用できます。 ・ ICMP-TSTAMP タイムスタンプを問い合わせるときに、発イ訓寺刻を入 一方、 ICMP-ECHO ノヾケットを受けたマシンでは、 れて発行する。 ICMP-ECHOREPLY バケットを生成します。これを ・ ICMP-TSTAMPREPLY ICMP-ECHO'S ケットを送り出したマシンに送り返す ICMP-TSTAMP への応答で、バケットの受イ訓刻 ことにより、自分自身か稼動中で、 IP のデータを処理 と返イ訓刻が加えられる。 できる状態にあることを示します。 ・ ICMP-IREQ ICMP バケットの送信 IP アドレスの指定が不要な引数のないエコー要求。 ・ ICMP-IREQREPLY ICMP-IREQ への応答。 次に、 ICMP のバケットを送信する方法についてお ・ ICMP-MASKREQ 舌ししましよう。 サプネットマスクの間合せ。 ICMP は、 TCP/IP のプロトコル群に含まれてはい ・ ICMP-MASKREPLY ますが、 TCP (SOCK-STREAM) や UDP (SOCK- ICMP-MASKREQ への応答。 DGRAM ) のように専用のソケット・インターフェイ ・ ICMP-ROUTERADVERT スをもっているわけではありません。その代わりに 自分がゲートウェイであることを示すために、ゲート SOCK-RAW という記号定数を用いて RAW ソケット ウェイが発行する。 をオープンして利用します。このとき、 socket システム ・ ICMP-ROUTERSOLICIT コールの 3 番目の引数として ICMP を示すプロトコル ICMP-ROUTERADVERT を要求するために、ホ 番号を指定すれば、 ICMP を利用できるソケットを作成 ストから発行される。 することができます。その際の処理は図 2 のようになり ます。 ここに挙げた順番は、それぞれの記号定数がもつ値と 最初の getprotobyname 関数は、プロトコルを示す は無関係です。また、旧い OS では、最後の 4 つが定義 文字列を引数としてとり、そのプロトコルに関する情 されていないこともあります。 報を返します。この関数により返される値は、 netdb. h ICMP-TSTAMP と ICMP-TSTAMPREPLY は、 ヘッダファイルで定義されている protoent 構造体へ 2 つのホストのあいだで時刻を同期させるために使うこ のポインタです。この構造体には、 p-proto フィール ともできます。しかし、実際にはネットワークの通過時 ドとしてプロトコルを示す番号かオ褓内されています。そ 間はバケットごとに異なるため、正確な時刻の取得は困 れを socket システムコールの引数に用います。この 難です。そこで、この目的のために ntp などのプロトコ socket システムコールの戻り値として得られるソケッ ルが開発されて利用されています。また、 ICMP-IREQ トは、 ICMP のバケットが送り出せる RAW ソケット と ICMP-IREQREPLY は、現在では使われていませ です。 ん。このバケットは、ホストが起重加に自分自身の IP アドレスを取得するために準備されたものですが、現在 ただし、 TCP や UDP の場合とは異なり、たんに ではやはり新たに開発された rarp や dhcp などのプロ write や sendto システムコールを用いて送りたいデー トコルか利用されています。 タだけを送り出すことはできません。 RAW と付くくら これらの値のなかで、今回の p ⅲ g プログラムで用い いですから、、、生の " ソケットなのです。 RAW ソケット るのは ICMP-ECHO 型のノヾケットです。このバケッ を使う場合は、自分自身でバケットのタイフ。やそのチェ UNIX MAGAZINE 1996.8 一三ロ 136

4. UNIX MAGAZINE 1996年8月号

IJN Ⅸ流プログラミング 70 図 2 ICMP を利用できるソケットの入手 if ( (proto = getprotobyname ( ” icmp" ) ) = = NULL) { fprintf(stderr, "unknovn protocol icmp\n") ; exit(l); if ((fd = socket (AF—INET, SOCK—RAW, proto—>p—proto)) く 0 ) { perror ( "socket " ) ; exit(l); ックサムを計算する必要があります。 ICMP バケット は IP バケットにオ絲タされて通信されますが、 ICMP'S ケットとしての型さえ整っていればよく、 IP バケット としての型まで整える必要はありません。 ICMP'S ケッ トは、いくっかのフィールドとそれに続くデータ部分だ けを管理すれは意外と簡単に作れます。 今回用いる ICMP-ECHO バケットでは、さきはど 紹介した 3 つのフィールドに加え、 n—short icmp—id , n—short icmp—seq; という 2 つのフィールドを利用します。 icmp-id は、 TCP や UDP のポートと同しような目 的で、つまり、クライアントを認識するために用いるこ とができます。 ICMP-ECHO バケットに自分自身を示 す値をオ内し、返された ICMP-ECHOREPLY バケッ トのなかから自分が送ったバケットの icmp-id と同一 の値をもつものだけを処理することで、ほかのクライア ントが生成した ICMP-ECHO に対する応答に反応す ることがなくなります。この値がネットワーク上を流れ ることを考えれば、型名 (nshort) が示すとおりネット ワーク・バイトオーダーで指定すべきでしようが、実際 に処理をおこなうのは自分自身だけなので、とくに気に する必要はありません。これは次の icmp-seq に関して も同様です。 icmpseq には、やはりクライアント側で自由な値を 設疋することができます。今回は、クライアントのなか でバケットを認識するための数字を格納することにしま しよう。具イ勺には、バケットを送るたびにインクリメ ントしていき、どのバケットに対する返答なのかが分か るようにします。 ちなみに、 icmp-type には ICMP-ECHO を指定し ます。これはすぐに分かるでしよう。 ICMP-ECHO の 場合には icmp-code を利用しないので、このフィール ドは 0 にしておきます。 icmp-cksum は、最初は 0 に しておいて、チェックサムを計算した後で値を入れるの UNIX MAGAZINE 1996.8 は、前述のとおりです。 これらの ICMP ヘッダの後ろには任意の長さのデー タを付けることができます。しかし、 IP のバケット長の 制限もあり、どんなに長いバケットでも受け付けられる わけではありません。 TCP や UDP の場合は、とくに この点には注意を払っていませんでした。これは、シス テムが勝手にバケットを分割してくれていたからです。 しかし、 ICMP を用いる場合は、この点に関してもあ る程度自分で作業する必要があります。 IP バケットと して許される大きさは、 netinet/ip. h ヘッダファイル に IP-MAXPACKET として定義されています。デー タを含めたすべての大きさがこの値を超えないように注 意しなけれはいけません。しかし、この大きさを守った からといって、かならすバケットが送受信できるわけで はありません。ちょっと試してみたところでは、 8 , 000 バイトを超えたあたりでプログラムの挙動がおかしくな り、あまり長いバケットだと送信の際にエラーとなって しまいます。 このようにしてバケットを準備したら、あとは UDP の場合と同様に sendto システムコールを使ってノヾケッ トを送出することができます。 簡易 ping プログラムの作成 簡易 ping プログラムを作成してみることにしましょ う ( リスト 1 ) 。このプログラムのオプションは 2 つで、 s オプションではデータサイズを、 -i オプションではパ ケットの送出間隔を指定します。引数には、かならすホ スト ( ドットで区切られた数字の並びかホスト名 ) を指 定しなければなりません。 このプログラムでは、 ICMP-ECHO バケットを指 定された宛先に定期的に送出し、そこから返される ICMP-ECHOREPLY バケットの様子を調べて出力し ます。また、バケットを送り出すときにデータとしてパ ケット送出時刻を含め、バケットを受け取ったときには 137

5. UNIX MAGAZINE 1996年8月号

IJN Ⅸ流プログラ FD_CLR(nsend % FD—SETSIZE , &seqs) ; / * 決まっている情報を埋め込む * / pack—>icmp-type = ICMP—ECHO ; pack—>icmp—code = pack—>icmp—id = ident ; pack—>icmp—seq = nsend 十十 ; pack—>icmp—cksum = 0 ; / * 工コー 要求バケット * / / * チェックサムの計算時には 0 にしておく / * チェックサムの計算が楽になるようによけいに 0 を書き込んでおく * / if (len & 1 ) { buf [len] = / * データサイズが timeval 構造体以上であれば送出時刻をデータに加える * / if (dsize > = sizeof (struct timeval) ) { if (gettimeofday ( (struct timeval *)pack—>icmp_data, (struct timezone * ) 0 ) perror ( "gettimeofday" ) ; exit(l); / * バケットのチェックサムを計算する * / pack—>icmp-cksum = calc—cksum( (u—short *)pack, / * バケットの送出。Ⅱは len と等しくなるはず * / Ⅱ = sendto(fd, (char *)pack, len, 0 , len) ; if (n ! = len) (struct sockaddr*)&to , sizeof (struct sockaddr—in) ) ; / * 正しく送出できなかった場合の処理 * / perror ( "sendto" ) ; ICMP'< ケットのチェックサムを計算する チェックサムは、データの 16 パイトずつをそれぞれ加算し キャリーが出た場合にはそれも加える データが奇数の場合には呼出し側で工夫する int u—short *p ; calc—cksum (p , Ⅱ ) int sum = 0 ; long / * 2 パイトよりも長い 4 パイトを使う * / / * 2 バイトずつ加算してしまう サイズが奇数でも、呼出し側で後ろに 0 を置いているため問題ない * / バケット送出先ホストから返されるバケットを読み出す return C(sum + ( 皿 > > 16 ) ) & Oxffff) ; 1 の補数をとり 2 パイトに丸める * / / * この処理でもキャリーが出る可能性があるのでさらにキャリーを加え、 sum = ( & Oxffff) + (sum > > 16 ) ; / * この時点でのキャリーを加える * / sum 十 = * p 十十 ; / * short は 2 パイトと仮定している * / vhile (n > 0 ) { UNIX MAGAZINE 1996.8 ミング 70 143

6. UNIX MAGAZINE 1996年8月号

printf(" (DUP! ) " ) ; —nre CV ; / * 最初のデータなら重複バケット検査用にフラグを立てる これをクリアするのはバケット送出時点 * / FD_SET (icmpp—>icmp—seq % FD_SETSIZE, &seqs) ; putchar( '\n' ) ; / * 無限ループ * / } else { 引数として与えられた 2 つの timeval 構造体の指す時刻の差を計算 timeval 構造体の時刻の差を計算する / * NOTREACHED * / 戻り値はミリ秒単位の d 。 uble 値 ret ; *tl, *t2; t2) struct t imeval diff—timeval(tl, double double / * tv ーⅡ sec はマイクロ秒単位 * / ret + = (t2—>tv—usec ー tl—>tv—usec) / 1000.0 ; / * tv-sec は秒単位 * / ret (t2—>tv—sec ー tl—>tv—sec) * 1000.0 ; LJN Ⅸ流プログラ nrecv) ; void info void intr return ret ; —handler() バケットに関する統計情報を出力する ホスト名、送出バケット数、受信バケット数、バケットの消失率を出力 バケットに時刻が含まれている場合には RTT の最小値、 RTT の平均値、 RTT の最大値も出力 %s ping statistics ー \ Ⅱ " , hostname) ; pr int f ( " \ Ⅱー printf ("%d packets transmitted, %d packets received, printf ("%d%% packet loss\n" , ((nsend ー nrecv) * 100 ) if (ncount > 0 ) { printf ("round-trip min/avg/max = %. 3f/%.3f/%.3f ms\n" tmin, tsum / ncount , tmax) ; —handler() info—handler ( ) ; exit(O) ; 終了用のシグナルハンドラ 統計情報を出力してプログラムを正常終了する / nsend) ; nsend , UNIX MAGAZINE 1996.8 ミング 70 145

7. UNIX MAGAZINE 1996年8月号

/ * 待ち時間ごとにバケットを送り出すルーチンを設定 * / #endif / * SIGINFO * / signa1(SIGINFO, info—handler) ; / * SIGINFO シグナルがあれば統計情報表示用のルーチンを設定 * / #ifdef SIGINFO signa1(SIGINT, intr-handler) ; / * シグナルによる終了用のルーチンを設定 * / signal (SIGALRM, alarm—handler) ; / * 処理の開始にあたり情報を表示 * / FD_ZERO(&seqs) ; / * バケットの重複を調べるための変数を初期化する 繰り返しシグナルが送られるようにしている 自分自身で再度 alarm 関数を呼び出すことにより、 待ち時間ごとにバケットを送り出すためのルーチン exit ( 0 ) ; info—handler ( ) ; プログラムの変更に対応するために最後の出力関数を呼び出す * / バケット数を指定するオプションを付け加えるなど こに制御が到達することはないが、 recv—packet ( ) ; ほかの処理は、すべてシグナルハンドラとして実行される * / / * この後、プログラムの制御はバケットの受信に移る alarm—handler ( ) ; 最初はシグナルハンドラを直接呼び出す * / / * バケットを送出し SIGALRM を待ち時間ごとに発生するために 待ち時間も表示する * / / * 普通の ping プログラムでは表示しないが、 hostname , inet—ntoa(to. sin_addr) , dsize , printf ("PING %s (%s) : %d data bytes, %d sec interval\n" void 可能であればバケット送出時刻をデータ内に組み込む ICMP'< ケットの体裁を整え、 バケットを送り出すルーチン return ・ alarm(wait_time) ; send—packet ( ) ; alarm—handler ( ) void S end 142 -packet ( ) static struct int int u_char ICmp buf [ I P_MAXPACKET] ; *pack = (struct icmp *)buf ; len = dsize + ICMP—HSIZE(pack) ; / * バケットの長さ ( ICMP ヘッダを含む ) * / / * 重複バケット検査用のデータを修正 * / wait—time) ; UNIX MAGAZINE 1996.8

8. UNIX MAGAZINE 1996年8月号

[ 赭文献 ] [ 1 ] J. Postel, "lnternet ControI Message Protocol ” RFC792, Sep. 1981 リスト 1 簡易 ping プログラムのソースコード sages ” RFC1256 , Sep. 1991 [ 4 ] S. Deering (ed. ), "ICMP Router Discovery Mes- RFC1191 , Nov. 1990 [ 3 ] J. Mogul and S. Deering, "Path MTU Discovery ting Procedure ” RFC950, Aug. 1985 [ 2 ] J. Mogul and J. Postel, "lnternet Standard Subnet- 簡易 ping プログラム / * ヘッダファイル一覧 * / IJN Ⅸ流プログラミング 70 [ 5 ] Douglas Comer 著、オ耕純・楠本博之訳 CTCP/IP に よるネットワーク構築第 2 版』 Vol. I 、共立出版、 1993 年 [ 6 ] Craig Hunt 著、村井純監訳 CTCP/IP ネットワーク管 理」、インターナショナル・トムソン・バブリッシング・ ジャノヾン、 1994 年 [ 7 ] Richard W. Stevens 著、篠田ド一訳 CUNIX ネットワー クプログラミング』、トッパン、 1992 年 # inc lude # include #include #include #include #include #include #include #include #include #include #include #include # include # inc lude #include #include く stdio . > く unistd. > く stdl 土 b . > く string. h> く signal . h> く sys/types ・ h> く sys/socket . h> く netinet/in—systm. h> く netinet/in. h> く netinet/ip. h> く netinet/ip—icmp. 五 > く sys/param. h> く errno . h> く sys/time. h> く time . 五 > く netdb. h> く arpa/inet . > void void void int void double void void / * マクロー覧 * / #ifdef #de f ine #else #define ICMP_HSIZE(p) ICMP_HSIZE(p) _STDC_ #define DEF_DSIZE #de f ine DEF_WTIME int r—handler ( ) ; info—handler ( ) ; diff—timeval ( ) ; recv—packet ( ) ; calc—cksum() ; send—packet ( ) ; UNIX MAGAZINE 1996.8 *myname ; char / * 外部変数一覧 * / #endif / * ——STDC / * このファイルで作成した関数の一覧 ( main を除く ) * / alarm handler ( ) ; usage() ; 1 56 / * デフォルトの待ち時間 * / / * デフォルトのデータサイズ * / ((void *)p—>icmp-data ー (void *)p) / * ICMP'€ケットのヘッダサイズを計算するためのマクロ * / ( 8 ) / * うまく動作しないマシンでは 8 とすればよい * / / * Usage 出力に使う自分の名前 * / 139

9. UNIX MAGAZINE 1996年8月号

case default : IJN Ⅸ流プログラ 十十 ; if (dsize く 1 ) dsize = DEF—DSIZE; break ; strtol(* + + av, NULL, 10 ) ; / * ー i オプションは待ち時間を指定 * / wait_time break ; if (wait—time く 1 ) vait—time = DEF—WTIME; / * これ以外のオプションは受け付けられない * / / * 大きすぎるバケットサイズは受け入れられない * / if (dsize > IP—MAXPACKET ー sizeof (struct ip) usage() ; sizeof (struct icmp) ) if ( ( to. sin—addr. s-addr = inet—addr(host) ) / * とりあえす aaa. bbb. cc c. ddd 形式になっていると仮定 * / to. sin—family = AF—INET ; bzero( (char *)&to, sizeof (to)) ; / * バケット送出先ホストの情報を得る * / host / * バケット送出先ホストが必要 * / if ()c ! = 1 ) usage(); dsize = DEF_DSIZE; この形式でないのならホスト名と仮定する * / if ( ()p = gethostbyname (host) ) = = NULL) { / * これも失敗した場合はエラー * / fprintf (stderr , "%s : Unknown host %s\n' exit(l); t0 . sin—family = hp—>h-addrtype ; / * アドレスは u ー long ( 4 パイト ) と仮定している * / myna.me , host) ; tO. sin—addr. s—addr = **(u—long (*)hp—>h—addr—list ; / * アドレスからホスト名を得る * / ( ()p = gethostbyaddr ( (char * ) &t0. sin—addr. s-addr , 4 , AF-INET) ) ! = NULL) { host = hp—>h—name ; もし得られない場合にはアドレスをそのまま使う * / } else { if strcpy(hostname , host) ; ident = getpid() & Oxffff ; / * icmp のプロトコル番号の取得 * / / * 別の関数からも使えるようにコビー * / / * このクライアントを識別する値を プロセス ID から生成 ( sh 。 rt 値 ) * / if ( (proto = getprotobyname ( " icmp" ) ) = = NULL) { fprintf (stderr , "unknown protocol icmp\n" ) ; exit(l); / * RAW ソケットのオープン * / if ((fd = socket(AF—INET, SOCK—RAW, proto—>p—proto)) く 0 ) { perror ( " socket" ) ; / * このソケットは root てないとオープンできない * / if (errno = = EACCES) { fprintf (stderr , "This program has to run SUID t0 ROOT. \ Ⅱ " ) ; UNIX MAGAZINE 1996.8 exit(l); ミング 70 141

10. UNIX MAGAZINE 1996年8月号

DZ—X 流プログラミング ping プログラム ping は、あるホストが正しくネットワークに接続さ れているかどうかを調べるためによく用いられるコマン ドです。使い方は、 ping ホスト名 と簡単です。 Su Ⅱで実行すると、引数として指定したホ ストがネットワークに接続し、動作している場合には、 ホスト名 is alive と出力され、ネットワークに接続されていなかったり、 重川乍していないと、 no answer from ホスト名 と出力されます。 Sun の ping コマンドに - s オプションを付けたり、 ほかのマシンの ping コマンドを使った場合には、図 1 のようなより詳細な情報が出力されます。 この場合、 ping コマンドは自動的には終了しないた め、 ControI-C などの割込み文字を使ってプログラム を強制終了する必要があります。こちらの形式の場合、 ただたんに対象とするホストがネットワークに接続さ れて動作していることが分かるだけでなく、バケットの TTL (Time To Live)1 や、バケットを送受信したとき の RTT (Round Trip Time)2 も出力されます。さらに 強制終了したときには、これまで送ったバケット数や受 信したバケット数、消失したバケットの割合、 RTT の 最小 / 平均 / 最大値なども出力されます。 今回は、図 1 のような情報を表示する ping プログラ ムを作成してみることにします。 前回は、 UDP を用いたソケットの例として、簡単な クライアントとサーバー、 inetd 経由て起動するサーバ ICMP 、 wait 形式のサーバーで nowait 形式のようなサービ スを提供する方法、ソケット・オプションを設定してプ プログラムには、 ICMP と呼ばれるプロトコルを利用 ロードキャスト通信をおこなうガ去などについて紹介し します。このプロトコルは、ゲートウェイやホストとの ました。これで、 TCP と UDP のそれぞれについての あいだで制律情報をやりとりするためのプロトコルで、 解説が一段落したことになります。 たとえば次のような目的で使われます。 しつをいうと、今回からはネットワークやシステムコ ールとは離れた別の話題を始めようと思っていたのです 1 ゲートウェイを越えるたびに 1 すっ減らされて、 0 になるとバケット が、考え直して、もうすこしネットワーク関連の話を続 カ皸棄される。 2 ping コマンドを実行したホストから対象のホストまでバケットが到 けることにしました。今回は ping プログラムをとりあ 達し、そこからさらに元のホス日ンヾケットカ唳ってくるまでの日乢 げます。 70 今泉貴史 134 UNIX MAGAZINE 1996.8