ping

偏向報道

この所、TVで ohtani-san ohtani-san って五月蝿い。世の中の野球選手って彼しかいないのかね? 他の頑張っている選手が可哀想。このパターンは他にもあるな(あったな)。スマイル日向子だったかな。ゴルフのおねーたん。活躍できなくても、盛んに報道してたな。流行か。

移ろいやすいというか、視聴率で露出度を決めているんだろうね。商品ですから。

栄一番宣もひどいな。これぞ、皆様の国民放送を人質にしてのやりたい放題だ。再放送で番組制作費を極力抑える。そして推し番組に金をかけるとな。後はYouTubeでも流しておけ。幾らで買ってるんですかね?

民放は、材料費の安い、お笑い芸人ばかりだしね。後は動物番組ね。ユーチューブから拾ってきた。動画はTVで流すの止めてしまえ。放送時間は、1日3時間ぐらいでいいぞ。そうすれば、見応えのある番組を作れるだろう。

で、ネットは大混雑になって困る。ここで提案です。ネットに流す動画はIPv6だけにしちゃえ。そうすれば、みんな仕方なしに移行するだろう。これで、日本もIPv6後進国を脱却出来るの間違い無し。動画ってYouTubeやらHuluやらZoomやら、色々あるからね。高速道路に追いやってしまう作戦ですよ。

なんか文句ある? Windows11になる時、Intelのお願いをMSは聞き入れて、第7世代より古いCPUは切り捨てた(おいらのは第6世代ですよ)。こういう横暴がまかり通る世の中だから、ISPも一致団結すれば、簡単な事さ。

ああ、オイラーも偏向報道してるな。OpenBSDの発信が主ですから。マイナーですよ、ニッチですよ。

mozc

夏はパソコンを置いている所が蒸し風呂になるので、涼しい所でオペレーション。そして日記書き。それはいいんだけど、Debian機の日本語入力が、mozcだ。これに慣れてしまうと、Windows10のIMEと微妙に違うので、指がオロオロする。

リナでの選択肢はmozcしか選択肢ないので、Windows側もmozcにすることにした。

Windows + Emacs + Mozc + boiled-mozc

こういうのがあったので、設定してみた。

socket

少しソケットの勉強をする

まつもと直伝 プログラミングのオキテ 第16回 ネットワーク・プログラミング(ソケット編)

何でもかんでもSocketを使うな

ネットワークインタフェース

(gdb) p pkt
$2 = {
  hdr = {
    ether_dhost = "\377\377\377\377\377\377",
    ether_shost = "\000\000\000\000\000",
    ether_type = 0
  },
  sync = "\377\377\377\377\377\377",
  dest = "\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\\
f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\
\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\000\f)Y\350\272\00\
0\f)Y\350\272\000\f)", <incomplete sequence \350\272>
}

前回やったarpのWoLパケット送出部。bpfのソケット経由なんだけど、どこで本物のソケットに引き継がれるのだろう? 更に、ここでは未定になってる ether_shost は、何処で埋められるのだろう? 疑問だらけだ。

ping

いわゆる導通試験器ね。昔はよくお世話になった。アナログの針が振れるやつ。会社に入って、デジタル式のものが支給されたけど、なかなか馴染めなかったぞ。針がふらふらしてると電気の息使いがみられてよかった。デジタルだと数値がパラパラしてて、何となく頼りなさげだった。ああ、話が違った。

ob$ ping  -c5 10.0.2.2
PING 10.0.2.2 (10.0.2.2): 56 data bytes
64 bytes from 10.0.2.2: icmp_seq=0 ttl=255 time=71.568 ms
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=2.823 ms
64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=1.796 ms
64 bytes from 10.0.2.2: icmp_seq=3 ttl=255 time=2.086 ms
64 bytes from 10.0.2.2: icmp_seq=4 ttl=255 time=1.768 ms

--- 10.0.2.2 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 1.768/16.008/71.568/27.783 ms

ob$ ping -c5 10.0.2.2
PING 10.0.2.2 (10.0.2.2): 56 data bytes
64 bytes from 10.0.2.2: icmp_seq=0 ttl=255 time=5.319 ms
64 bytes from 10.0.2.2: icmp_seq=1 ttl=255 time=1.903 ms
64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=1.802 ms
64 bytes from 10.0.2.2: icmp_seq=3 ttl=255 time=1.832 ms
64 bytes from 10.0.2.2: icmp_seq=4 ttl=255 time=1.796 ms

--- 10.0.2.2 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 1.796/2.530/5.319/1.395 ms

56byteのパケットを投げて、それがちゃんと戻って来るか。往復時間を計測してる。最後に統計データが出てくる。んだけど、この場合は余り頼りにならない。

上記の2回目の平均が2.5msって、オイラーは納得しないぞ。初回がとても時間がかかってしまっているので、それに引っ張られて平均値が上昇してるんだ。くれぐれも、統計数値に惑わされないように。

この場合なら、中央値ぐらいを取るのが妥当だろう。まあ、算術計算って、非常に処理が簡単だからね。

statistics

OpenBSD 6.6 のソースだと全体行が2000行を超えるけど、目的を持てば簡単に追えるだろう。debianは、ping,ping6用と別れているから、もう少し小ぶりなコードだろう。冒頭から流し読みしてくと、お決まりっぽいのに出会った。

double tmin = 999999999.0;      /* minimum round trip time */
double tmax;                    /* maximum round trip time */
double tsum;                    /* sum of all times, for doing average */
double tsumsq;                  /* sum of all times squared, for std. dev. */

こんなグローバル変数が出てきた。tminだけ初期値を決めていて、他は無指定。こんなんで良いのか? 初期値が有る変数はdataエリアに格納される。宣言だけの変数はbssエリアに場所だけ確保される。プログラムが起動した時、OSはbssエリアをZEROクリアする仕様になってる。だから、これでもOK。

でも、このからくりを知らない人は、煙に巻かれてしまうぞ。多少プログラムサイズが大きくなっても、初期値を書いておいた方が親切かな。 コンパイラーが余計なお世話で、グローバル変数で、初期値にZEROを入れてるのは、bssエリアに追い出してしまったり、するのかな?

適当に使ってる場所を探したら、出力してる部分が出てきた。

if (timinginfo) {
        /* Only display average to microseconds */
        double num = nreceived + nrepeats;
        double avg = tsum / num;
        double dev = sqrt(fmax(0, tsumsq / num - avg * avg));
        printf("round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms \n",
            tmin, avg, tmax, dev);
}

1回パケットを投げる毎に、その場で、最小、最大、合計時間等を算出してる。まあ、普通のやり方だな。

インクリメンタルな分散計算 お前の目は節穴か。ちゃんと見て桶。ボーと生きてんじゃねぇよ。

timespecsub(&ts, &tp, &ts);
triptime = ((double)ts.tv_sec) * 1000.0 +
    ((double)ts.tv_nsec) / 1000000.0;
tsum += triptime;
tsumsq += triptime * triptime;
if (triptime < tmin)
        tmin = triptime;
if (triptime > tmax)
        tmax = triptime;

これを、中央値にしたいとなると、今までの結果を保存しておく必要が出てくる。面倒になるんで止めたんだろうね。後は初回の値を捨てるとかって、エグイ方法があるな。 そんな事は許してよいものか?

年収100万円の100人が住む村に、アマゾンをリタイアした会長が移住してきました。念願の宇宙旅行にも行ったし、後は田舎でのんびりだな。有り余る資産を投資しているんで、ぬれ手で粟で年収1000億。さてこの村の平均年収は?

PINGが1回目だけ失敗する(応答しない)原因

なんてのがあるけど、これは資産を隠しているって事? どんなに金を貯めても墓までは持って行けない。資産が有ると言っても、株だとやたらに売りに出すわけにはいかないみたいだね。絵に書いた餅?

ping for gdb

pingを観光しようと思って作ったやつ

vbox$ ./ping 10.0.2.2
ping: socket: Permission denied

こんなエラーになる。なんでかな? Makefileを見たよ。そしたら一般人も実施出来るようにフラグが立ててあった。手動で立ててみても、権利なし。はて困った。正規の場所でコンパイルすると、

vbox# make
cc -O2 -pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual -Werror-implicit-function-declaration -MD -MP  -c ping.c
cc  -static -pie -o ping ping.o -lm
vbox# make install
install -c -s  -o root -g bin  -m 4555 ping /sbin/ping
install -c -o root -g bin -m 444  ping.8 /usr/share/man/man8/ping.8
/sbin/ping6 -> /sbin/ping

こんなことになってた。installコマンドを使っているのね。注目は ーs でstripしちゃう事。

vbox# export STRIP=/usr/bin/true
vbox# make install
install -c -s  -o root -g bin  -m 4555 ping /sbin/ping
install -c -o root -g bin -m 444  ping.8 /usr/share/man/man8/ping.8
/sbin/ping6 -> /sbin/ping

STRIPコマンドを外部から設定出来るので、無害なものに置き換え。そしてインストール。これで、普通にpingする分には問題無し。gdbから使うと、何故かソケットに権利無しと言われる。gdbから起動するアプリは、権利が剥奪されてるのかな。とりあえずroot権限で実行。

(gdb) up
#2  0x166aaee5 in main (argc=1, argv=0xcf7fc338) at ping.c:923
923                     if (poll(&pfd, 1, timeout) <= 0)
(gdb) l
918                             timeout = INFTIM;
919
920                     pfd.fd = s;
921                     pfd.events = POLLIN;
922
923                     if (poll(&pfd, 1, timeout) <= 0)
924                             continue;
925
926                     if (v6flag) {
927                             m.msg_name = &peer6;

タイマー制御で投げるパケットの時間間隔は正確に制御されてるけど、暇な時間はpollからの連絡待ちになってるのね。

パケットの形

デフォでは、56byteのデータを投げるってなってるけど、中身はどうなってるの? 外観検査してみる。

vbox$ ./pkt-recv -i em0 IP.PROTOCOL==1 >LOG
-- 1 --
TIME: 1625353947.610235 Sun Jul  4 08:12:27 2021
SIZE: 98/98
000000: 52 54 00 12  35 02 08 00  27 20 E8 38  08 00 45 00 : RT..5... ' .8..E.
000010: 00 54 B5 85  00 00 FF 01  EE 12 0A 00  02 0F 0A 00 : .T...... ........
000020: 02 02 08 00  D6 43 1F B6  00 00 04 D0  17 39 91 E0 : .....C.. .....9..
000030: 7C 9B 34 D6  3F 18 5C 72  46 75 CD 75  9B D7 31 2C : |.4.?.\r Fu.u..1,
000040: B3 AE 18 19  1A 1B 1C 1D  1E 1F 20 21  22 23 24 25 : ........ .. !"#$%
000050: 26 27 28 29  2A 2B 2C 2D  2E 2F 30 31  32 33 34 35 : &'()*+,- ./012345
000060: 36 37                                              : 67
==
vbox$ cat LOG | ./pkt-analyze
LINKTYPE: 1 (Ethernet)
-- 1 --
received: 98 bytes    1625353947.610235 Sun Jul  4 08:12:27 2021
Ethernet        08:00:27:20:e8:38 -> 52:54:00:12:35:02  (type: 0x0800)
IP      head/total size : 20 / 84 bytes
        ID/fragment     : 0xb585 / 0x0000
        TTL/protocol    : 255 / 1
        checksum        : 0xee12 (Valid)
        src/dst addr    : 10.0.2.15 / 10.0.2.2
ICMP    total size      : 64 bytes
        type/code       : 8 / 0
        checksum        : 0xd643 (Valid)
==

何やら、適当なデータが使われているみたいですなあ。んな事ない。0x18 からインクリメントされる人工のデータみたいだ。詳しくはソース嫁。

データは下記のように、任意に指定出来たりします。そして -sオプションで、サイズも増量出来るようになってます。

vbox$ ping -c 1 -p deadbeaf 10.0.2.2

-- 1 --
TIME: 1625355967.100441 Sun Jul  4 08:46:07 2021
SIZE: 98/98
000000: 52 54 00 12  35 02 08 00  27 20 E8 38  08 00 45 00 : RT..5... ' .8..E.
000010: 00 54 60 17  00 00 FF 01  43 81 0A 00  02 0F 0A 00 : .T`..... C.......
000020: 02 02 08 00  B2 24 BD B2  00 00 A5 0D  8D 55 8A 64 : .....$.. .....U.d
000030: 94 46 40 CF  04 87 4B FF  D1 5F EA 62  57 2F D8 7E : .F@...K. ._.bW/.~
000040: CF 66 DE AD  BE AF DE AD  BE AF DE AD  BE AF DE AD : .f...... ........
000050: BE AF DE AD  BE AF DE AD  BE AF DE AD  BE AF DE AD : ........ ........
000060: BE AF                                              : ..
==

大きなデータを指定すれば、そのデータが往復するんで、ネットワークや相手方、そして自分自身にも負担を強いる事になります。

ping flood

それを顕著に強調すると、サイバー戦争の武器にする事も出来ます。

debian(pen)が攻める側になり、OpenBSD(ob)が防戦する側として、演習します。

sakae@pen:~$ sudo ping -f -c 100 aa.bb.cc.128
PING aa.bb.cc.128 (aa.bb.cc.128) 56(84) bytes of data.

--- aa.bb.cc.128 ping statistics ---
100 packets transmitted, 100 received, 0% packet loss, time 144ms
rtt min/avg/max/mdev = 0.156/1.021/31.173/3.770 ms, pipe 2, ipg/ewma 1.454/0.61 ms

これ、普通は1秒間隔で送出されるパケットなんですが、洪水を発生させました。100個のパケットなので99秒費やすはずですが、わずか144msの間に集中しました。猛烈な雨です、じゃなくてパケットです。

Pingフラッド って奴。洪水作戦。最近は、線状降水帯の影響で、洪水に岩のおまけが付いて来ると言う、大災害が発生してます。注意しましょう。

どやって? 一番簡単なのは、全部捨て去る作戦。

block in proto icmp

を/etc/pf.confに書けばOk。

sakae@pen:~$ ping -c 5 aa.bb.cc.128
PING aa.bb.cc.128 (aa.bb.cc.128) 56(84) bytes of data.

--- aa.bb.cc.128 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 84ms

完全防水になり、OpenBSD本体にはパケットが侵入できていません。まあ、これでもいいんだけど、礼儀正しく少しはICMPに応答するようにします。

pass in proto icmp max-pkt-rate 50/10

10秒間で50パケットは、普通に通すけど、それ以外は、拒否します。この設定で実行すると

sakae@pen:~$ sudo ping -f -c 200 aa.bb.cc.128
PING aa.bb.cc.128 (aa.bb.cc.128) 56(84) bytes of data.
................................................................................
......................................................................
--- aa.bb.cc.128 ping statistics ---
200 packets transmitted, 50 received, 75% packet loss, time 556ms
rtt min/avg/max/mdev = 0.178/1.617/28.858/4.826 ms, pipe 2, ipg/ewma 12.836/2.539 ms

バリアで一つ思い出した事がある。狂った国から発射されるミサイルを追撃して、撃ち落としてしまいましょって言う盾作戦。一発なら防御出来るかも知れないけど、複数が同時に発射されたらどうなるの?

一発ぐらい見逃されて、何処かに着弾したりして。pf.confみたいに、きれいにはいかないだろうね。まあ、折角開発したんだから買ってくれって、押し売りされて、やっと断る理由を見つけたって所かな。

info

The summary information can also be displayed while ping is running by
sending it a SIGINFO signal (see the status argument of stty(1) for more
information).

pingのマニュアルを見ていると、動作中でも要約を知る事が出来るとな。してその方法は、SIGINFO割り込みをキーボードから発生させれば良いとな。キーバインドはsttyコマンドのstatusに設定せいって事らしい。

vbox$ stty -e
  :
min     quit    reprint start   status  stop    susp    time    werase
1       ^\      ^R      ^Q      <undef> ^S      ^Z      0       ^W

sttyの状況を確認すると、未割り当てになってる。

vbox$ stty status \^p

こんな風に割り当てた(バックスラッシュ、山形文字がCtl相当、そしてp)。

64 bytes from 10.0.2.2: icmp_seq=2 ttl=255 time=0.842 ms
64 bytes from 10.0.2.2: icmp_seq=3 ttl=255 time=1.062 ms   ;; Press Ctl-p
load: 0.24  cmd: ping 1443 [runnable] 0.00u 0.00s 0% 178k

--- 10.0.2.2 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.468/0.970/1.510/0.377 ms
64 bytes from 10.0.2.2: icmp_seq=4 ttl=255 time=0.895 ms
64 bytes from 10.0.2.2: icmp_seq=5 ttl=255 time=0.862 ms

これで、動作中にも、状況を把握出来るようになった。

尚、sttyで各種割り込みキーに普通の文字も割当可能だけど、それをやっちゃうと、壊れたキーボードになっちゃうんで、止めとけ。やっていいのは、生意気な新人をいたぶる時だけです(おい、おい)。

RFC 792

ICMP (Page 14) を見ると、ペイロードに有意義なデータを入れる事になっている。勿論OpenBSDも同様。マニュアルには、

If the data space is at least 24 bytes, ping uses the first sixteen bytes
of this space to include a timestamp which it uses in the computation of
round trip times.  The following 8 bytes store a message authentication
code.  If less than 24 bytes of pad are specified, no round trip times
are given.

こんな事が書かれていた。折角なので確かめてみるか。

struct payload {
        struct tv64     tv64;
        u_int8_t        mac[SIPHASH_DIGEST_LENGTH];
};

OpenBSDの時間の扱いはとっくの昔に64Bit化されます。ダイジェストが8Byteを占めるんで、合わせて24Byteになるとな。

(gdb) bt
#0  pinger (s=3) at ping.c:1160
#1  0x18a1de87 in retransmit (s=3) at ping.c:1081
#2  0x18a1ca66 in main (argc=1, argv=0xcf7f0298) at ping.c:853

pingerの中でパケットを組み立てている。

SipHash24_Init(&ctx, &mac_key);
SipHash24_Update(&ctx, tv64, sizeof(*tv64));
SipHash24_Update(&ctx, &ident, sizeof(ident));
SipHash24_Update(&ctx, &seq, sizeof(seq));
SipHash24_Final(&payload.mac, &ctx);

ここでは、認証確認のためのハッシュを作成

(gdb) p *tv64
$8 = {tv64_sec = 15873237536484556959, tv64_nsec = 7183945255579513247}
(gdb) p ident
$9 = 32566
(gdb) p seq
$10 = 0

その元データ、inentはプロセス番号だな。

ここを抜けると、

                /* compute ICMP checksum here */
=>              icp->icmp_cksum = in_cksum((u_short *)icp, cc);

こんな所にやって来る。ccは64って事で、icmpのペイロードだ。どんなデータになってるか調べてみる。

(gdb) x/64b icp
0x34e8d04c <outpackhdr+20>:     0x08    0x00    0x00    0x00    0x78    0x06    0x00    0x00
0x34e8d054 <outpackhdr+28>:     0x30    0xa7    0xca    0xba    0x04    0x63    0x30    0x1c
0x34e8d05c <outpackhdr+36>:     0x80    0x71    0x25    0x95    0x57    0xd7    0x2f    0x6b
0x34e8d064 <outpackhdr+44>:     0x1c    0xbe    0x97    0x8e    0x81    0xbb    0x8c    0x99
0x34e8d06c <outpackhdr+52>:     0x18    0x19    0x1a    0x1b    0x1c    0x1d    0x1e    0x1f
0x34e8d074 <outpackhdr+60>:     0x20    0x21    0x22    0x23    0x24    0x25    0x26    0x27
0x34e8d07c <outpackhdr+68>:     0x28    0x29    0x2a    0x2b    0x2c    0x2d    0x2e    0x2f
0x34e8d084 <outpackhdr+76>:     0x30    0x31    0x32    0x33    0x34    0x35    0x36    0x37

目を凝らして見れば、outpackhdr+52 の所から、人工データのインクリメントなデータが並んでいるのが見て取れる。

余計な事だろうけど、この人工データは、pingが走り初めた割と最初の方で作られていた。

B         if (!(options & F_PINGFILLED))
                  for (i = ECHOTMLEN; i < datalen; ++i)
  =>                      *datap++ = i;
(gdb) p i
$9 = 24
(gdb) p/x i
$10 = 0x18
(gdb) p datalen
$11 = 56

この0x18って謎の数値は、payload構造体のサイズだった。まあ、それでもいいんだけど、若干遊んでいるな。コード書く人の特権と理解しておこう。


This year's Index

Home