2

I strace a curl command:

strace -s 2000 -f curl google.com

and see 2 DNS queries

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

Then, I see a connect() syscall to 142.250.179.238 which is a Google's IP.

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

I believe one of the 2 recvfrom calls contains the IP "142.250.179.238", otherwise curl can't know the IP to connect to.

My question: What is the format of the 2 recvfrom strings? And how to parse it to get the IP address?

"\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
  • Maybe using the -e read=1 option will simplify your task, (you may need to use a different number than 1). from man systrace searching for hex. (Perform a full hexadecimal and ASCII dump of all the data read from file descriptors) (My experience with systrace is decades old, so please tell me if I should delete this comment (-;!) ... Good luck.
    – shellter
    Dec 3, 2023 at 16:49

1 Answer 1

8

recvfrom(2) is documented like this (using a Linux man page below):

  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);

or more simply with a POSIX definition:

  ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
      int flags, struct sockaddr *restrict address,
      socklen_t *restrict address_len);

To understand the output of strace, one should read the man page for each syscall.

Buf/buffer is the space where received data will be provided once the syscall succeeded, and its content is displayed back by strace in a C-like fashion.

The buffer space is displayed as a serie of bytes encoded like in C language, as any buffer or string displayed by strace. The \ followed by 3 digits means it's an octal number represents a byte value not displayable as a simple ASCII character or any predefined special preferred display form (for some special character such as \n used below in the second printf command) as defined by the C language. See for example wikipedia's reference about this:

\nnn The byte whose numerical value is given by nnn interpreted as an octal number

Here since we know what we're looking for (octal):

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

which is visible at the end of the 2nd recvfrom() data.

Of course it's not about a syscall anymore, but about the DNS protocol. To know more about the DNS reply, read the RFC(s) documenting this, especially RFC 1035: DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION section 4.1.3. Resource record format:

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                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

each part is described in this RFC (here RDLENGTH = 4 and RDATA holds the 4 bytes IPv4 address).

FWIW, the first reception is the reply for IPv6. Where \034 is 28 which stands for an AAAA IPv6 record (RFC 3596 - 2.1 AAAA record type) instead of 1 for an A IPv4 record.

3
  • 1
    A brilliant answer. Thank you!
    – Rocherlee
    Dec 3, 2023 at 21:25
  • 2
    On a general note, in a case like this it can make sense to use Wireshark, trace the network, and find the corresponding packet. This will allow you to interactively match the packet structure with the packet bytes. Dec 4, 2023 at 7:52
  • @GuntramBlohm right using a network capture and wireshark would be way easier.
    – A.B
    Dec 4, 2023 at 8:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .