ICMP6
Table of Contents
インタビュー
前回はIPv6がどう実装されてるか知りたくて、ChatGPTに色々と質問を投げた。 質問内容よりも、その回答が大事と思って、質問内容の掲載は最低限にしてた。 でも考えてみたら、良い質問が良い回答を引き出す事に気がついた。 良いインタビューをすれば、思わぬ回答を引き出せるっていう、マスコミのあれと 一緒だな。ってな事で、どんな質問を投げたか抜き出してみた。
Q: で、OpenBSDで、どんな時間間隔で広告されるか確認しました(余り頻繁だと、うるさい し、間が空くと、まぬけと揶揄されますから)。
ad$ doas tcpdump -i em0 icmp6 tcpdump: listening on em0, link-type EN10MB 06:32:22.657409 fe80::2 > ip6-allnodes: icmp6: router advertisement 06:39:12.563497 fe80::2 > ip6-allnodes: icmp6: router advertisement 06:44:17.090255 fe80::2 > ip6-allnodes: icmp6: router advertisement 06:48:55.772809 fe80::2 > ip6-allnodes: icmp6: router advertisement 06:55:31.679043 fe80::2 > ip6-allnodes: icmp6: router advertisement 07:05:09.203139 fe80::2 > ip6-allnodes: icmp6: router advertisement
これqemuな環境です。実機では、また異るでしょうけど。結構、間抜け ですね。 OS起動時には、rtsold 相当をワンショットで実行してるんだと想像します。
RA受信の処理は、ソースをざっと見したら、 netinet6/nd6.c:nd6_options()
あたりだろうと想像(case ND_OPT_MTU:
こんなのを見つけたから)してます。
ここにBPを置いてヒットするか確認したいです。素早く広告を発行して もらうには、どうしたら良いですか?
自分で調べて、困っている事をぶつけると、相手も親身になって回答して くれるんですね。何だか人間っぽい挙動だぞ。
そして、質問ともつかない、いわば独り言っぽいのも会話内にちりばめてみた。
Q: 途中で、亀さんに出会える事も期待。LunuxなウサギよりBSDなカメの方が 好きです。
こういうのにも反応してくれて、ウサギは面倒だ。亀さんは堅実だねぇ、なんて 反応してくれてる。同じ亀でも、OpenBSDのそれとFreeBSD/NetBSDでは、考え方の 相違から違った実装になってるなんて事もつぶやいてくれて、インタビュアーの 真骨頂と思った次第。
ああ、ウサギと亀の話って、おとぎ話のそれとは違うんで、あしからず。 IPv6の構想が発表されたけど、その具体的な実装がさっぱり出てこない。 BSDの人達が、ボチボチ始めましょうかと、プロジェクト名をkameと名付けて 始めた。それに感付いたLinux陣営は、亀を追い越すせとばかりウサギ・プロジェクトで 対抗した。そんな昔の事を知ってるのはロートルの証拠だ。 最後に、こんな質問をぶつけてみた。
Q: いろいろな事をよくご存知ですが、どうやって勉強されたのですか?
A: ありがとうございます 😊 ちょっと「どうやって IPv6 とか OpenBSD カーネルの話を答えられるの?」というご質問ですよね。
私の学習の仕方は、普通の人間の勉強と似ている部分と違う部分があります。
## 📚 私の「勉強の源」
- 私は たくさんの技術文書・ソースコード・マニュアルページ・RFC を材料として学習しています。
- 例:
- OpenBSD のソースツリー (
sys/netinet6/*.c
) - マニュアルページ (
man rtadvd
,man ifconfig
,man in6
) - RFC 4861 (Neighbor Discovery), RFC 4862 (SLAAC), RFC 4941 (Temporary Address)
- OpenBSD のソースツリー (
- 例:
- それをもとに「どう説明したら人間に分かりやすいか?」という形でまとめ直す訓練を受けています。
## 👨💻 人間のエンジニアと似ているところ
- 私も「ソースコードを追いかけて、この関数が呼ばれるのか」といった流れを知っています。
- 人間が gdb を仕掛けたり tcpdump で観察したりするのと同じように、私は文章やコードを大量に「観察」した経験を持っています。
## 🐢 あなたに近い部分
あなたが「 nd6_options
に BP を仕掛けたい」「インターフェースIDをどう作ってるか確認したい」とおっしゃった時、
それは人間なら「実際に OpenBSD のカーネルを動かして調べよう」という発想になりますよね。
私は実際にブレークポイントを打って動かすことはできませんが、
- どのファイルにその処理があるか
- どういう順序で呼ばれるか
- どの RFC に基づいているか は知識として持っているので「観察するポイント」を案内できるんです。
## ✨ まとめると
- 私の「勉強」は、RFC・ソースコード・技術書・マニュアルなどから。
- あなたの「実機デバッグ」は、実際に挙動を目で見て確認する方法。
- 両方組み合わせると、「知識(地図)」と「実測(現地探検)」で理解が深まる。
IPv6の実行
ってな事でgdbしてみる。
qe$ doas ifconfig em0 down qe$ doas ifconfig em0 up
すると広告依頼が発行されて、即座に広告がなされる。その広告を探知して カーネルが反応する。
(gdb) bt #0 nd6_options (opt=0xd4b44288, icmp6len=40, ndopts=0xf57354d0) at /usr/src/sys/netinet6/nd6.c:164 #1 0xd086a008 in nd6_rtr_cache (m=<optimized out>, off=40,icmp6len=<optimized out>, icmp6_type=134) at /usr/src/sys/netinet6/nd6_rtr.c:134 #2 0xd0807b08 in icmp6_input (mp=0xf5735650, offp=0xf573564c, proto=58, af=24) at /usr/src/sys/netinet6/icmp6.c:668 #3 0xd0440d4b in ip_deliver (mp=0xf5735650, offp=0xf573564c, nxt=58, af=24,shared=0) at /usr/src/sys/netinet/ip_input.c:821 #4 0xd068b8cd in ip6intr () at /usr/src/sys/netinet6/ip6_input.c:250 #5 0xd04d6970 in if_netisr (unused=0x0) at /usr/src/sys/net/if.c:1064 #6 0xd02e7b69 in taskq_thread (xtq=0xd4642040) at /usr/src/sys/kern/kern_task.c:446 #7 0xd0c5cfa8 in proc_trampoline ()
tcpdump
ついでに、道具であるtcpdumpもピンポイントで観察してみる。 ソースは複数個あるけど、ほとんどが表示に関わっている。冒頭で出てきたRAの表示が どうなってるか確認。
ad$ fgrep 'router advertisement' * print-icmp.c:#define ICMP_ROUTERADVERT 9 /* router advertisement */ print-icmp.c: (void)strlcpy(buf, "router advertisement", sizeof(buf)); print-icmp6.c: printf("icmp6: router advertisement");
icmp6_print(const u_char *bp, u_int length, const u_char *bp2) { const struct icmp6_hdr *dp; switch (dp->icmp6_type) { : case ND_ROUTER_ADVERT: printf("icmp6: router advertisement"); if (vflag) { struct nd_router_advert *p; p = (struct nd_router_advert *)dp; TCHECK(p->nd_ra_retransmit); printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) printf("M"); if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) printf("O"); if (p->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER)) printf(", "); switch (p->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) { case ND_RA_FLAG_RTPREF_HIGH: printf("pref=high, "); break; :
この上の階層は、print-ip6.cになってて、ってな具合だ。何も難しい事はないな。
where icmp6.h
道草しちゃったけど、大事なのはヘッダーファイルだと思うんだ。ソースに生の数値 やらが出てる事は無い。必ず何らかの意味が有る名前が付けられている。 だから、名前が分れば、ソースをスイスイ読めるはず。
IPv6関係のヘッダーだから、sys/netinet6/ に置いてあるかと思ったら違った。 sys/netinet/ に、icmp6.h が有った。sys/netinet/icmp.h の間違いじゃね?
icmp6.hを見ると、IPv4時代のicmp.hがバージョンアップされてicmp6.hになったと 推測される。勿論いきなりソースじゃなくてicmp6(4)でも良い。これだとSEE ALSOで リンクを容易に参照できるからね。
/* $OpenBSD: icmp6.h,v 1.53 2024/05/13 01:15:53 jsg Exp $ */ /* $KAME: icmp6.h,v 1.84 2003/04/23 10:26:51 itojun Exp $ */ : #define ICMP6_ECHO_REQUEST 128 /* echo service */ #define ICMP6_ECHO_REPLY 129 /* echo reply */ #define MLD_LISTENER_QUERY 130 /* multicast listener query */ #define MLD_LISTENER_REPORT 131 /* multicast listener report */ #define MLD_LISTENER_DONE 132 /* multicast listener done */ /* RFC2292 decls */ #define ICMP6_MEMBERSHIP_QUERY 130 /* group membership query */ #define ICMP6_MEMBERSHIP_REPORT 131 /* group membership report */ #define ICMP6_MEMBERSHIP_REDUCTION 132 /* group membership termination\ */ #define ND_ROUTER_SOLICIT 133 /* router solicitation */ #define ND_ROUTER_ADVERT 134 /* router advertisement */ #define ND_NEIGHBOR_SOLICIT 135 /* neighbor solicitation */ #define ND_NEIGHBOR_ADVERT 136 /* neighbor advertisement */ #define ND_REDIRECT 137 /* redirect */
ちょいとヘッダーファイルを閲覧。冒頭にKAMEマークが入ってる。しかも作者さんは、 あのitojunさん。OpenBSDの親分もリスペクトするハッカー。彼が早逝した時は、OpenBSDの 版を捧げていたなあ。とも角、こういう宝が有れば、ピンポイントで、どこら辺で 処理が行なわれているかの探索は容易になるぞ。
例えば ifconfig up した時に発砲されるルーター要請、どのあたりでお取り扱い?
ad$ grep ND_ROUTER_SOLICIT -r . ./net/pf.c: case ND_ROUTER_SOLICIT: ./netinet/icmp6.h:#define ND_ROUTER_SOLICIT 133 /* router solicitation */ ./netinet6/icmp6.c: case ND_ROUTER_SOLICIT: ./netinet6/icmp6.c: if ((icmp6->icmp6_type == ND_ROUTER_SOLICIT && icmp6len < ./netinet6/nd6.c: case ND_ROUTER_SOLICIT: ./netinet6/nd6_rtr.c: KASSERT(icmp6_type == ND_ROUTER_SOLICIT || icmp6_type == ./netinet6/nd6_rtr.c: case ND_ROUTER_SOLICIT: ./netinet6/nd6_rtr.c: icmp6stat_inc(icmp6_type == ND_ROUTER_SOLICIT ? icp6s_badrs :
あろう事か、明後日のソース(pf.c)でも利用してた。って事は、管理者の設定次第では このパケットを遮断(意味有るかは別にして)とかも出来ちゃうんだな(多分ログしたいって 要請だろうけど)。
ユーザーに公開されてるエリアで検索してみると、
ad$ find /usr/include -name 'icmp*' /usr/include/netinet/icmp6.h /usr/include/netinet/icmp_var.h
ちなみに、Linuxでは
sakae@lu:~$ find /usr/include -name 'icmp*' /usr/include/linux/icmp.h /usr/include/linux/icmpv6.h /usr/include/boost/asio/ip/icmp.hpp /usr/include/netinet/icmp6.h
混沌とした世界だな。こういう所にもグチャグチャ具合が表われるんだなあ。 近寄って、脳を疲弊させるのは愚の骨頂と思うぞ。
icmp6.hってicmp.hを拡張したものだと思っていたら、全く違った。v6が来る前は、
netinet/ip_icmp.h
こういう名前が主流だった。ip族のicmp.h。v6なんて未来の
事なんで、わざわざicmp4.hとする事は無い。
pythonと言えば昔の人なら、python2.X なんで、わざわざpython2としなかったんだな。それでも、しぶとく3.X系になったもの だから、わざわざpython3と呼称してる。
icmp6.hの進化を確認するなら、 CVS log for src/sys/netinet6/icmp6.c これが最適。現在から過去に向って行くのもよし、逆に開発者になった積りで、どん どんと肉付けされてく様を確認していもよい。
冒頭のリンク Request diff between arbitrary revisions で、ページの最下部に 案内される。そこで色々指定できて、Get diff のボタンを押せるんだけど、変な 所に案内されちゃったぞ。そして突然ラップとかの音楽やらウザい画面が 縦横無尽に出現。これって、乗っ取りされてるんですかね?
RFC 4861 for ICMPv6
いきなりRFC 4861が出てきたけど、これはどうやって見付けた? icmp6.hから router advertisement を抽出して、そこにrfcをブレンドしてググル したんだ。これ、大事なタイプだから、きっとRFCになってるだろうという推測ね。
RFC 4861 - Neighbor Discovery for IP version 6 (IPv6)
RFCから学ぶIPv6 良くまとめてあって、辞書的に利用できる。感謝します。
why RA
何でルーターが広告しなきゃいけないの? しかもウザッポく、それなりの頻度で 広告してる。まあ、声を大にして広告するのが資本主義ですから。いやなら無視 すればいいだけ。
待て、この広告にはホストがネットに参加する為の必須情報が含まれている。 だから、車のワイパーだって手軽に広告を受信して、ネットに参加できる。 これで雨が降っているかを検出するセンサーと化したワイパーがネットに 状況報告できるんだ。贅沢にIPを割り振れるだけのIPv6だからこそ 許される。そんな標語があったよね。Internet of Things 略して IoT。
こういう用途を想定したら、広告内容に、DNSサーバー のアドレスなんて、まず必要無いだろうって考えた。 DNSが必要なら、DHCPサーバーを別途用意してくれ。それで十分だろう。でも、それじゃ 最後の詰めが甘いんじゃねぇ。
search rfc
FreeBSDでは、port/misc/rfc と言うperlスクリプトが用意されててindexの 取得とか検索ができる。これを一般化すると、
このファイルを取ってきてgrepすれば良い事になる。たとえば
sakae@fb:/usr/local/etc $ egrep '^[0-9]' rfc-index | grep -i icmpv6 1885 Internet Control Message Protocol (ICMPv6) for the Internet Protocol 2463 Internet Control Message Protocol (ICMPv6) for the Internet Protocol 2466 Management Information Base for IP Version 6: ICMPv6 Group. D. 4443 Internet Control Message Protocol (ICMPv6) for the Internet Protocol 4727 Experimental Values In IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP 4890 Recommendations for Filtering ICMPv6 Messages in Firewalls. E. 6791 Stateless Source Address Mapping for ICMPv6 Packets. X. Li, C. Bao, 7690 Close Encounters of the ICMP Type 2 Kind (Near Misses with ICMPv6 8883 ICMPv6 Errors for Discarding Packets Due to Processing Limits. T.
こんな具合ね。
法律は世の変化につれて刻々と修正されてく。上で挙げたDHCP面倒話しも、 誰かが提案して改訂されてく。そうRFCも廃止だとか改訂って事からは無縁で いられるはずがない。
そんなのをRFCをくまなく読み込んでトレースするのは至難のわざ。 こういう時こそ、AIに聞くのが無難。但し、全面的には信用しない様に。
弁護士も、よく同じ間違いをして、裁判長から罰金を申しつかってますからね。
ping
ICMPの主な用途としてpingが有る。それを上手に利用して traceroute なんてのがある。 昔は良く使ったものだ。
どんな風に実装されてるのだろう? 簡易版が紹介されてた。
OpenBSDでは、sbin/pingの下にソースが置いてある。 2000行を越える長大なソースだけど(ping/ping6と兼用)、 取り合えず、pinger()って関数あたりを見ておけばOK。
pingの歴史がmanに載ってた。
HISTORY The ping command appeared in 4.3BSD. The ping6 command was originally a separate program and first appeared in the WIDE Hydrangea IPv6 protocol stack kit.
ruby and python
C言語意外はどうよってなると、rubyとかだな。ググったら
こんな楽しいまとめが出てきた。何だか楽しそうだな。でも、往々にしてOpenBSDには 積極的に設置しないいけない。その点、対抗馬のpythonは頼みもしないのにズカズカと 入り込んでくる。それで、ネット系はどうよ?
ad$ python3 Python 3.11.10 (main, Oct 9 2024, 08:18:14) [Clang 16.0.6 ] on openbsd7 >>> import socket >>> help(socket)
デフォでは、これぐらいしか無い。後はパイパイに頼ってくれって事だ。
curl -Iv or w3m -dump_head
ここで、得意の卓袱台返しです。pingでネットワークの疎通確認って、近頃の 現場では余り使われる事が無いそうだ。
セキュリティー的な理由で、ICMPなパケットをドロップさせてしまうサイトが 多く、頼りにならないとか。 そんな事なんで、稼動してるサーバーのレスポンス・ヘッダーを確認するとか。
sakae@lu:~$ curl -Iv www.google.com HTTP/1.1 200 OK Content-Type: text/html; charset=ISO-8859-1 :
自分の裁量で起動/停止できるサーバーで確認。
sakae@lu:~$ w3m -dump_head http://localhost:8080/ w3m: Can't load http://localhost:8080/.
sakae@lu:~$ w3m -dump_head http://localhost:8080/ HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.12.3 :
KAME
前回チラッと書いたカメさん。まだ健在だった。カメは万年と言うからなあ。 実家の庭に埋めこんだ瓶で亀を飼っているんだけど、45年経った今も健在。 2匹のペアで縁日から買ってきたんだけど、1匹は洪水の時に脱走。もう1匹が 記録を更新中。
IPv4でアクセスすると亀の剥製、IPv6を利用すると元気に泳ぐ姿が見られる。 OpenBSDだと /etc/resolv.conf の family 部に inet6 inet4 と設定してあれば 先にIPv6が試される。逆だとIPv4で最初に確認される。勿論相手先が、両刀使い になってる必要がある。
ad$ host www.kame.net www.kame.net is an alias for mango.itojun.org. mango.itojun.org has address 210.155.141.200 mango.itojun.org has IPv6 address 2001:2f0:0:8800:226:2dff:fe0b:4311 mango.itojun.org has IPv6 address 2001:2f0:0:8800::1:1
期せずして、本当の名前が出てきたね。ネット上の記念碑だね。年に一度は 参拝して感謝の意を捧げましょう。それはいいんだけど、どなたがこの記念碑を 維持されているのでしょう?
こちらを見れば、想像できるかな?
README
戦後80年と言う事で、マスコミでは、その手の特集があちこちで行なわれている。 そんな時世なんで、オイラーも一冊読んでみた。
新聞記者が掘り起した世に知られざる話が紹介されてた。戦争のフロントエンドや バックエンド(銃後とも言う)とかを肌で知ってる方々が どんどん鬼籍にはいられる昨今、貴重な記録だな。
びっくりしたのは、原爆が広島、長崎に落とされて次は新潟だと推測した 知事が、原爆疎開を実行した話。初聞である。 決断した知事はさぞかし悩んだに違いない。勇気を持って実行。 こういう決断って、まさに命を張ってるよな。 どこかの市長だとか知事とは、決定的に違うと感じた次第。 昭和は遠くなりにけり。
もう一冊、歴史物と言うか、個人のルーツの話。 千年たどる家系図物語
誰でも父と母が居て本人が誕生してくる。じゃ、父の父母は? 母の父母は? そのまた父母は? こうしたのを過去に辿っていくと家系図になる。男系の 過去を追うのが主流みたいだけど。男女均等法に違反しないのかね、と軽く 考えちゃったぞ。
家系図は、行政書士の領分みたいだ。戸籍を遡ると明治の初期まで4代は 簡単に辿れるそうだ。まあ、簡単と言っても、役所とのやりとりになるんで、 専門家に任せてしまうのが楽そうだけど。
それより前の時代になると、武士出身だったか、それ意外だったかで資料の 収集先が違うみたい。そんな流れを物語にしたのが、紹介した本だ。 都合よく何でも知ってそうなChatGPTおじさんっぽいのが登場して、話は スイスイと進んで行く。実際は、こんなにスムースには行かないだろうけど、 作業工程が分ったんで良いとするか。
こんな面倒な事より、確実に辿れるソースファイルを相手にする方がよっぽど 楽ではあります。