tracerouteの出力を42生が調べたら
はじめに
こんにちは、42tokyo Advent Calendar 2021の25日目を担当する、在校生のhiroinです。
この文書は「tracerouteの出力を42生が調べたら」と題しまして、
(1) 42生が日頃どのように疑問を解決しているのかの雰囲気を味わって頂く
(2) 42で、ある程度課題をこなした学生は、一次情報をあたって調べることができることをアピールする
ための文書です。
42生は分からないことがあった場合「ぐぐって最初にヒットした文書を読んで、はい終わり!」ではなく、マニュアルであったり、ソースコードを読んで理解を深めていく傾向があります。
具体的にどのようにマニュアルやソースコードをあたっていくのかを示します。
それでは、はじまりはじまり~
tracerouteの出力を42生が調べたら
ある日、借用しているGMOクラウド専用サーバーにpingが飛ばないことに気がつきました。
SSHやHTTPによるアクセスは可能なので、何かがpingを拒否しているに違いないと思って、一時時にnftablesを無効化したりfirewalldを無効化したりするもNG。
さて、なんでだろう…と他のサーバー(CentOS8)からtracerouteをしました。
以下が出力です。
$ traceroute 180.222.XXX.XX
traceroute to 180.222.XXX.XX (180.222.XXX.XX), 30 hops max, 60 byte packets
1 153.127.XXX.XXX (153.127.XXX.XXX) 0.358 ms 0.363 ms 0.356 ms
(中略)
12 180.222.XXX.XXX (180.222.XXX.XXX) 18.539 ms example.com (180.222.XXX.XXX) 20.333 ms !X 180.222.XXX.XXX (180.222.XXX.XXX) 18.645 ms
結論から書くと「サーバーセキュリィティの一環として、外部からのICMPパケットを遮断する仕組となっておりますのでpingの疎通や、トレースルートの確認は行えません。」とのことでした。
※そういえばサーバーを構築したときにpingが飛ばないから死活監視のサービスを申し込んだなあ…と思いました…
さて、tracerouteの最後の出力に「!X」という見たことがない文字があります。
12 180.222.XXX.XXX (180.222.XXX.XXX) 18.539 ms example.com (180.222.XXX.XXX) 20.333 ms !X 180.222.XXX.XXX (180.222.XXX.XXX) 18.645 ms
とりあえず「traceroute !X」でぐぐると以下の文書が見つかりました。
【Linux】traceroute の結果(!X, !H, *アスタリスク)の原因/理由,利用ポートについて~
!X の意味
!X は [Type=3/Code=13] Communication Administratively Prohibited が返ってきたことを意味します。これは主に、途中の NW 機器が ACL によりその通信を拒否していることが多いです。!X が表示されている行の IP がアサインされている NW 機器の設定を調べましょう。
なるほど、おそらく、サーバーの手前のNW機器がpingを拒否しているのだなあ…と思いました。
次に、tracerouteのマニュアルを見てみます。
$ man traceroute
(中略)
After the trip time, some additional annotation can be printed: !H, !N, or !P (host, network or protocol unreach‐able), !S (source route failed), !F (fragmentation needed), !X (communication administratively prohibited), !V (host precedence violation), !C (precedence cutoff in effect), or !<num> (ICMP unreachable code <num>). If almost all the probes result in some kind of unreachable, traceroute will give up and exit.
(中略)
!X (communication administratively prohibited)、管理上禁止されている通信とのことです。
次に、tracerouteが、どのような場合に「!X」を出力するか見てみます。
CentOS8のtracerouteコマンドが入っているrpmは、traceroute-2.1.0-6.el8.x86_64.rpmです。このWebページのHomepageにhttp://traceroute.sourceforge.netとあるので、こちらにアクセスします。
「ダウンロード」をクリックして、https://sourceforge.net/projects/traceroute/files/に遷移し「Download Latest Version」をクリックしてtraceroutのソースをダウンロードします。
traceroute-2.1.0.tar.gzを解凍して、traceroute.cを「!X」で検索します。検索した結果が以下のとおりです。
case ICMP_UNREACH_NET_PROHIB:
case ICMP_UNREACH_HOST_PROHIB:
case ICMP_UNREACH_FILTER_PROHIB:
str = "!X";
break;
なるほど、ICMP_UNREACH_NET_PROHIB、ICMP_UNREACH_HOST_PROHIB、ICMP_UNREACH_FILTER_PROHIBの場合に、!Xと表示されることが分かりました。
次に、上記3つがなんなのかを調べます。
とりあえず「ICMP_UNREACH_NET_PROHIB」でぐぐると、Source to netinet/ip_icmp.hが一番上にきますので、netinet/ip_icmp.hに定義が書いてあると分かります。
先程みたtraceroute-2.1.0-6.el8.x86_64.rpmのRequiresを見ると
libc.so.6(GLIBC_2.14)(64bit)
libm.so.6()(64bit)
rtld(GNU_HASH)
の3つがあります。GLIBCにnetinet/ip_icmp.hがありそうだなあ…と思うので、glibc-2.28-164.el8.x86_64.rpmのHomepageに書いてあるhttp://www.gnu.org/software/glibc/にアクセスしてSourceタブをクリックします。
Sourceを手に入れるためには、
git clone https://sourceware.org/git/glibc.git
cd glibc
git checkout release/2.34/master
と書いてあるので、実行しまして、netinet/ip_icmp.hを探します。
\sysdeps\gnuにnetinet\ip_icmp.hにいるのが確認されたので、中身を見ます。
/* UNREACH codes */
#define ICMP_UNREACH_NET 0 /* bad net */
#define ICMP_UNREACH_HOST 1 /* bad host */
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
#define ICMP_UNREACH_PORT 3 /* bad port */
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
#define ICMP_UNREACH_NET_PROHIB 9 /* net denied */
#define ICMP_UNREACH_HOST_PROHIB 10 /* host denied */
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */
#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */
#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */
UNREACH codesというカテゴリで、
ICMP_UNREACH_NET_PROHIBは9
ICMP_UNREACH_HOST_PROHIBは10
ICMP_UNREACH_FILTER_PROHIBは13
と定義されています。
※いつもはめんどいので…、どなたかがforkしたものがGithubにあるので、それを見ます、たとえば「ICMP_UNREACH_HOST_UNKNOWN glibc」でぐぐると
https://github.com/lattera/glibc/blob/master/sysdeps/gnu/netinet/ip_icmp.h
がひっかかるので、その中身を見ます。
tracerouteはICMPを使っているので、RFCでUNREACH codesの9と10と13の定義を確認します。
RFCは読むのが大変なので…、まず「ICMP RFC」でぐぐります。
するとInternet Control Message Protocol - Wikipediaが3番目にヒットするので読みます。
UNREACH codesはWikipediaのDestination Unreachable Message(宛先到達不可能通知)の部分に書いてありまして、9と10と13について書いてあるのは以下の部分です。
RFC 1122において、以下のコードが追加されている。
6 - 宛先ネットワーク不明
7 - 宛先ホスト不明
8 - 発信元ホストが孤立している
9 - 宛先ネットワークとの通信が管理上禁止
10 - 宛先ホストとの通信が管理上禁止
11 - Type of Serviceに対してネットワーク到達不能
12 - Type of Serviceに対してホスト到達不能
さらにRFC 1812では、以下のコードが追加されている。
13 - 通信が管理上禁止
14 - ホスト優先度違反
15 - 優先度が低すぎる
コード9および10は特殊な用途のために定義されており、通常のルーターは13を発生させるよう求めている。
RFCの1122とRFC1812に、9と10と13について書いてあることが分かりましたのでRFCを探して読みます。
RFC1122
9 = communication with destination network administratively prohibited
10 = communication with destination host administratively prohibited
9=相手先ネットワークとの通信が管理上禁止されている
10 = 送信先ホストとの通信が管理上禁止されている
RFC1812
13 = Communication Administratively Prohibited - generated if a router cannot forward a packet due to administrative filtering;
13 = 管理上禁止されている通信 - 管理上のフィルタリングにより、ルータがパケットを転送できない場合に生成されます。
NOTE:
[INTRO:2] also defined Code 9 for communication with destination network administratively prohibited and Code 10 for communication with destination host administratively prohibited.
These codes were intended for use by end-to-end encryption devices used by U.S military agencies. Routers SHOULD use the newly defined Code 13 (Communication Administratively Prohibited) if they administratively filter packets.
また、[INTRO:2]では、コード9を「宛先ネットワークとの通信が管理上禁止されている」、コード10を「宛先ホストとの通信が管理上禁止されている」と定義しています。
これらのコードは、米国の軍事機関で使用されるエンドツーエンドの暗号化装置での使用を意図したものです。 ルータは、パケットを管理的にフィルタリングする場合、新たに定義されたコード13(Communication Administratively Prohibited)を使用すべきである。
以上から、tracerouteして、!Xが返ってきた場合は、RFCどおりに実装されたNW機器であれば、コードに13をセットして返しているんだろうなあ…と思いました。
おわりに
42の課題にはlibcの再実装、printfの再実装、Bashの再実装、STLコンテナのvectorとmapとstackの再実装、NginxのようなWebサーバーの実装、があります。
これらの課題をこなすには、マニュアルを読み込み、実際のソースコードを読み込み、RFCを読み込む必要があります。
42生は、一次情報をあたって調べることができることをアピールできたことを願いまして、本文書を締めくくります。
著者
42 Tokyoの第一期生(2020年2月のPiscineに参加、2020年6月下旬からカリキュラム開始)