このプログラムのほとんどの処理はこの関数でおこなわれる バケットを読み込むたびに情報を表示する また、統計情報のためにデータの保存もおこなう 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
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
に発行される。 トを受け取ると、受け取ったサーバーはかならすそのパ ケットに対する返答を送らなければならないと決められ ・ 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
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
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
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
/ * 待ち時間ごとにバケットを送り出すルーチンを設定 * / #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
[ 赭文献 ] [ 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
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
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