如何从系统调用解析 strace recv?

如何从系统调用解析 strace recv?

我跟踪了一个curl命令:

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

然后,我看到对 142.250.179.238 的 connect() 系统调用,这是 Google 的 IP。

connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("142.250.179.238")}, 16) = 0

我相信2个recvfrom调用之一包含IP“142.250.179.238”,否则curl无法知道要连接的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,应该阅读每个系统调用的手册页。

Buf/buffer 是系统调用成功后将提供接收到的数据的空间,并且其内容以strace类似于 C 的方式显示回来。

缓冲区空间显示为一系列字节编码,就像 C 语言中一样,与 . 显示的任何缓冲区或字符串一样strace。后面\跟3位数字表示是八进制number 表示不能显示为简单 ASCII 字符或C 语言定义的任何预定义特殊首选显示形式(对于某些特殊字符,例如\n下面第二个命令中使用的字符)的字节值。printf参见示例维基百科的参考对这个:

\nnn 其数值由nnn解释为给出的字节八进制数

因为我们知道我们要寻找什么(八进制):

$ printf '\\%o' 142 250 179 238; printf '\n'
\216\372\263\356

这在第二个数据的末尾可见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 的回复。其中\03428 代表AAAAIPv6 记录(RFC 3596 - 2.1 AAAA 记录类型) 而不是AIPv4 记录的 1。

相关内容