カールコマンドを追跡しました。
strace -s 2000 -f curl google.com
2つのDNSクエリを参照してください。
recvfrom(3, "\302\325\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\34\0\1\6google\3com\0\0\34\0\1\0\0\0\362\0\20*\0\24P@\t\10\v\0\0\0\0\0\0 \16", 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.65.7")}, [28->16]) = 66
recvfrom(3, "X\320\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\1\0\1\6google\3com\0\0\1\0\1\0\0\1)\0\4\216\372\263\356", 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.65.7")}, [28->16]) = 54
次に、GoogleのIPである142.250.179.238へのconnect()システムコールを表示します。
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("142.250.179.238")}, 16) = 0
私は2つのrecvfrom呼び出しのうちの1つにIP "142.250.179.238"が含まれていると思います。それ以外の場合、カールはどのIPに接続するかを知ることができません。
私の質問:2つのrecvfrom文字列の形式は何ですか?そして、IPアドレスを取得するためにこれを解析する方法は?
"\302\325\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\34\0\1\6google\3com\0\0\34\0\1\0\0\0\362\0\20*\0\24P@\t\10\v\0\0\0\0\0\0 \16"
"X\320\201\200\0\1\0\1\0\0\0\0\6google\3com\0\0\1\0\1\6google\3com\0\0\1\0\1\0\0\1)\0\4\216\372\263\356"
答え1
recvfrom(2)
次のように文書化されています(以下のLinuxのマニュアルページを使用)。
ssize_t recvfrom(int sockfd, void buf[restrict .len], size_t len, int flags, struct sockaddr *_Nullable restrict src_addr, socklen_t *_Nullable restrict addrlen);
またはもっと簡単にPOSIX定義:
ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
出力を理解するには、strace
各システムコールのマニュアルページを読んでください。
バッファ/バッファは、システムコールの成功後に受信したデータを提供する空間で、strace
Cと同様の方法でその内容を再表示します。
バッファスペースは、Cのようにエンコードされたバイトシーケンスで表され、で表示されるバッファまたは文字列と同じですstrace
。その後に\
3桁の数字が来ると8進数数値は、単純なASCII文字またはC言語で定義されている事前定義された特殊デフォルト表示形式(\n
以下の2番目のコマンドで使用されるような特殊文字の一部)では表示できないバイト値を表します。printf
例を見るウィキペディアリファレンスこれで:
\nnn
その値はnnn
与えられたバイトとして解釈されます。8進数
私たちが探しているものが何であるかを知っているので(8進数):
$ printf '\\%o' 142 250 179 238; printf '\n'
\216\372\263\356
これは2番目のデータの終わりにありますrecvfrom()
。
もちろん、これはもはやシステムコールに関するものではなく、DNSプロトコルに関するものです。 DNS応答の詳細については、特にこれについて説明するRFCをお読みください。RFC 1035:ドメイン名 - 実装と仕様セクション4.1.3。リソースレコード形式:
Each resource record has the following format: 1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / / / NAME / | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | CLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TTL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RDLENGTH | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| / RDATA / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
各部分はこのRFCで説明されています(ここではRDLENGTH = 4で、RDATAは4バイトのIPv4アドレスを保持しています)。
FWIW、受信した最初の応答はIPv6応答です。ここで\034
、28はAAAA
IPv6レコード(RFC 3596 - 2.1 AAAAレコードタイプA
)IPv4レコードの場合1の代わりに。