Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

自作 ping コマンドで質問です

119 views
Skip to first unread message

かわせ

unread,
Sep 9, 2002, 2:30:17 PM9/9/02
to

かわせです。

Slackware から始めて unix を弄るようになって10年位なのですが、1月程
まえからC言語に興味津々で、毎日遊んでいます。

FreeBSD の ping.c をバラバラにして、添附の icmpecho.c というのを作りま
した。これは1個の ICMP ECHO (RQUEST) を指定したホストに送出して、相手
先からの ECHO REPLY を recvfrom() で受け取ってその内容を画面に表示する、
というものです。

IPヘッダの明細を表示するところまで出来ているのですが、Total Lengthの
値が、tcpdump で見るものと違っています。添附の例ですと、0x30オクテット
を送信/受信しているのですが、自作コマンドの出力は 0x1c となります。送
出する ECHO (REQUEST) のサイズを 0x32 にすると自作コマンドの出力は
0x1e になったりしてそれなりに関連があるのですが、違う値であることには
変わりありません。FreeBSD 4.6.2-REL にてコンパイル/実行をしています。

私のソースが間違っているのだと思うのですが、どこが駄目なのか、お教え頂
けないでしょうか。

PS:
直接関係ないですが、ping.c の解剖を始めたとき、RELENG_4_6 の物を最初に
見ていたのですが、私には大変難しくて、FreeBSD の一番古い ping.c を見て
みたらずっとシンプルで良かったです。386BSD というのが手に入ればもっと
色々シンプルなのではないかと期待したりするのですが、これはもう手に入ら
ないのでしょうか?

--
かわせ

Shigenobu Kimura

unread,
Sep 9, 2002, 10:25:11 PM9/9/02
to
本題ほう方はまだ見てませんが,,,(すみません)

かわせ <j-com...@jcom.home.ne.jp> writes:

> 直接関係ないですが、ping.c の解剖を始めたとき、RELENG_4_6 の物を最初に
> 見ていたのですが、私には大変難しくて、FreeBSD の一番古い ping.c を見て
> みたらずっとシンプルで良かったです。386BSD というのが手に入ればもっと
> 色々シンプルなのではないかと期待したりするのですが、これはもう手に入ら
> ないのでしょうか?

4.4BSDLite (FreeBSDの元ネタ) とか net2 (386BSD の元ネタ(?))
で探すと出てきやすいかも知れません.

あと, 大元の V7 UNIX は novel のサイトから落せたと思います.
TCP/IP のコードはありませんが, UNIX の一つの完成形という点で
参照用に持っておくのもいいかもしれません. URLは失念しました...

V7 のコードを見ると「ええっ?こんなんでいいの?」ってなぐらい
シンプルです.

あと ANSI がお好きなら MINIX か Plan9 という手もあります.

MINIX http://www.cs.vu.nl/~ast/minix.html
Plan9 http://plan9.bell-labs.com/

木村 栄伸

Shigenobu Kimura

unread,
Sep 10, 2002, 12:10:11 AM9/10/02
to
えーっと, 最初にお断りしておきますが, ぼくはネットワークのコードを
書いたことありません. 自分の勉強ついでにマニュアルみながらコメント
します. テキトーなことを書いておけば詳しい人が突っ込みを入れてくれる
かもしれないのでそれに期待です.

かわせさん <j-com...@jcom.home.ne.jp> writes:

> cc = 28;
> datap = &outpack[8 + sizeof(struct timeval)];
> for (i = 8; i < (cc - 8); i++)
> *datap++ = 0xaa; /* filling last portion of outpack */

8 たしてるのは何のため? /usr/include/netinet/ip_icmp.h を
みると datap[1] にたどり着くには 8x8 オクテットぐらい(ちゃんと数えてません)
必要ですが,,,,

> icp = (struct icmp *)outpack;
> icp->icmp_type = ICMP_ECHO;
> // icp->icmp_code = 0; 0 is default
> // icp->icmp_cksum = 0; 0 is default
> icp->icmp_id = 0xaa;
> icp->icmp_seq = 0xbb;
> icp->icmp_cksum = in_cksum((u_short *)icp, cc);
> /* outpack is noew ready */
> sendto(s, (char *)outpack, cc, 0, (struct sockaddr *)&whereto,
> sizeof(struct sockaddr));
> /* ICMP ECHO has sent */

でも, とにかく 48 オクテット送って...

> packlen = 64; /* size of receive buffer ?? */
> packet = (u_char *)malloc((u_int)packlen);
> fromlen = sizeof(from);
> cc = recvfrom(s, (char*)packet, packlen, 0, (struct sockaddr *)&from,
> &fromlen);
> /* caught ICMP ECHOREPLY */

なにかしらもらってきて,

> printf("recieved: %d octet(s)\n", cc);

動かしてみたらここには 48 と表示されました.

> printf("IHL: 0x%x\n", ip->ip_hl);
> printf("Total length: 0x%04x\n", ip->ip_len);

ここは 5 と 0x1c が表示されました.

で ip ヘッダのことは知らないので, 悪魔本の Figure 13.6 を
みると IHL は 4 オクテット単位ではかったヘッダの長さと書いてあるけど,
total length の説明は乗ってませんでした(2分ほど周りをぺらぺらめくっただけですが),
仮にヘッダを除いたデータの長さだとすると

(+ ?\x1c (* 4 5)) -> 48

どんなもんでしょ?

木村 栄伸

Hisao Aoyama

unread,
Sep 10, 2002, 6:04:06 AM9/10/02
to
=?ISO-2022-JP?B?GyRCJCskbyQ7GyhC?= <j-com...@jcom.home.ne.jp> writes:
> IPヘッダの明細を表示するところまで出来ているのですが、Total Lengthの
> 値が、tcpdump で見るものと違っています。添附の例ですと、0x30オクテット
> を送信/受信しているのですが、自作コマンドの出力は 0x1c となります。送
> 出する ECHO (REQUEST) のサイズを 0x32 にすると自作コマンドの出力は
> 0x1e になったりしてそれなりに関連があるのですが、違う値であることには
> 変わりありません。FreeBSD 4.6.2-REL にてコンパイル/実行をしています。

どうも,IP ヘッダーの長さを引いた数字になっているようです.

> 私のソースが間違っているのだと思うのですが、どこが駄目なのか、お教え頂
> けないでしょうか。

かわせさんのソースはあっていると思います.

recvfrom() でデータがわたってくる前に OS のルーチンで,自
分の処理にに都合が良いように変えているらしいです.
昔は ip_recv.c というファイルだったとか (今もその名前かも).

そういわれると,私も見たことがあるような気がします.

一般に

struct ip *ip = buf;

ip->ip_len = ntohs(ip->ip_len);

のようなコードって,結構良く見ますね.

BPF (Berkley Packet Filter) のソースでも見て,本当のraw レ
ベルでやれば,思い通りになるんじゃないでしょうか.
----
Hisao Aoyama 青山 尚夫
ASTEC Products, Inc. (株)アステック・プロダクツ
aoy...@astec.co.jp

かわせ

unread,
Sep 10, 2002, 11:52:39 AM9/10/02
to

かわせです。

木村さん、フォローアップありがとうございます。
わざわざ動かしてためして頂いたようで恐縮です。

At Tue, 10 Sep 2002 04:10:11 GMT,
Shigenobu Kimura wrote:

> > cc = 28;
> > datap = &outpack[8 + sizeof(struct timeval)];
> > for (i = 8; i < (cc - 8); i++)
> > *datap++ = 0xaa; /* filling last portion of outpack */
>
> 8 たしてるのは何のため? /usr/include/netinet/ip_icmp.h を
> みると datap[1] にたどり着くには 8x8 オクテットぐらい(ちゃんと数えてません)
> 必要ですが,,,,

これは、本物の(FreeBSDの)ping だと、outpack の最初の8の部分に、
gettimeofday() で得たその時点の時刻情報を埋めこんでいたようなので、そ
れをなんとなくまねしてあるだけです。で、ECHOREPLY が帰ってきたとききた
ときに帰ってきたパケットの該当部分をみて、round trip time を計算してい
るようです。(そういう仕組とは知らなかったので面白かったです。)


> で ip ヘッダのことは知らないので, 悪魔本の Figure 13.6 を
> みると IHL は 4 オクテット単位ではかったヘッダの長さと書いてあるけど,
> total length の説明は乗ってませんでした(2分ほど周りをぺらぺらめくっただけですが),
> 仮にヘッダを除いたデータの長さだとすると
>
> (+ ?\x1c (* 4 5)) -> 48
>
> どんなもんでしょ?

青山様も別にフォローアップをしてくださっているように、恐らく「IPヘッ
ダの長さを除いたものになっている」というのが正解みたいです。
(+ ?\x1c (* 4 5)) -> 48 というのが何なのか私には分からないのですが・・・

時に、「悪魔本」というのはBSDの事をかいた本のようですが、正式な書名
は何と言うのでしょうか?CプログラムとしてのBSDの事を書いた本なのだっ
たら手に入れてみたいのですが・・・

--
かわせ

かわせ

unread,
Sep 10, 2002, 12:11:39 PM9/10/02
to

かわせです。

青山様、フォローアップありがとうございます。

At 10 Sep 2002 19:04:06 +0900,
Hisao Aoyama wrote:

> どうも,IP ヘッダーの長さを引いた数字になっているようです.

言われてみると確かにそのようですね。
投稿したプログラムの CC の値を幾つかかえてみてもそうなりますね。

> かわせさんのソースはあっていると思います.

すなおに嬉しいです。(笑)

> recvfrom() でデータがわたってくる前に OS のルーチンで,自
> 分の処理にに都合が良いように変えているらしいです.
> 昔は ip_recv.c というファイルだったとか (今もその名前かも).

なんとまぁ身勝手なことを(笑)
<netinet/ip.h> で struct ip を定義している部分は見たのですが、そんなこ
と書いてないです。
ていうか、struct ip の ip_len だったら RFC791 にかいてある Total
Length にしといてもらわないと(笑)

> BPF (Berkley Packet Filter) のソースでも見て,本当のraw レ
> ベルでやれば,思い通りになるんじゃないでしょうか.

tcpdump -x だと RFC とおりの Length ででてくるのだからきっと私のコード
が馬鹿なのだと思って、3分程 tcpdump.c を眺めたら頭蓋にヒビが入ってきた
ので慌てて中止しました。

--
かわせ

Shigenobu Kimura

unread,
Sep 10, 2002, 8:53:12 PM9/10/02
to
かわせ <j-com...@jcom.home.ne.jp> writes:
> これは、本物の(FreeBSDの)ping だと、outpack の最初の8の部分に、
> gettimeofday() で得たその時点の時刻情報を埋めこんでいたようなので、そ
> れをなんとなくまねしてあるだけです。で、ECHOREPLY が帰ってきたとききた
> ときに帰ってきたパケットの該当部分をみて、round trip time を計算してい
> るようです。(そういう仕組とは知らなかったので面白かったです。)

じゃぁ

> cc = 28;
> datap = &outpack[8 + sizeof(struct timeval)];
> for (i = 8; i < (cc - 8); i++)
> *datap++ = 0xaa; /* filling last portion of outpack */
>

じゃなくって

cc = 28;
nhead = XX; /* ICMP のヘッダの大きさ(バイト単位) */
datap = &outpack[nhead + sizeof(struct timeval)];
datalen = cc - nhead - sizeof(struct timeval);
for (i = 0; i < datalen; i++)


*datap++ = 0xaa; /* filling last portion of outpack */

こんな感じ?


> (+ ?\x1c (* 4 5)) -> 48 というのが何なのか私には分からないのですが・・・

ごめんなさい編集ミスです.

0x1c + 4*5 = 48

と良み替えてください.

> 時に、「悪魔本」というのはBSDの事をかいた本のようですが、正式な書名
> は何と言うのでしょうか?CプログラムとしてのBSDの事を書いた本なのだっ
> たら手に入れてみたいのですが・・・

The Design and Implementation of the 4.4 BSD Operating System
Addison-Wesley ISBN 0-201-54979-4

あとは google して下さい (_o_)

きむら

0 new messages