了解 mDNS 响应记录指针的工作原理

Understanding how the pointers of mDNS response records works

需要帮助了解指针如何在 mDNS 数据包的十六进制转储上工作。

这是我发出的原始 "hex" 转储:

const ptrRecord = "0b5f676f6f676c6563617374045f746370056c6f63616c00000c000100000078"+domainSize+"2b"+domainName.toString('hex')+"c00c"
const txtRecord = "c02e"+"0010800100001194"+txtResponseLength+txtResponse
const srvRecord = "c02e"+"0021800100000078"+targetSize+"000000001f4924"+target.toString('hex')+"c01d"
const aRecord   = "c127"+"00018001000000780004"+ip

const msg = "000084000000000100000003"+ptrRecord+txtRecord+srvRecord+aRecord

在这里您可以看到 4 条记录。它们在 Wireshak 中包含的数据比此处多得多。他们似乎遗漏了很多数据。

但实际上他们指向某个地方以获取该数据以使包裹更小。

第一个在第一个包(最后)上有一个指针 "c00c" 以某种方式指向包的开头。获取表示 (._googlecast._tcp.local).

的 12 个字节的数据

后两个有 "c02e" 以某种方式从 ptr 记录中获取代表 "Chromecast-._googlecast._tcp.local"

的最后数据

最后一个 "c127" 以某种方式从 srv 记录的 "target".

获取数据

在此处查看最后一条 A 记录的图像:

有人知道指针的工作原理吗?如果我改变例如txtResponse 的值不再起作用。如果我添加字母,我必须通过将 27 值更改为更高的值来修改 aRecord 的指针,如果我删除,则更改为更低的值。

所以有一些逻辑,我就是找不到!

答案似乎在 RFC 1035 4.1.4 中。消息压缩

可以找到 RFC here

这里引用4.1.4供以后参考:

4.1.4. Message compression

In order to reduce the size of messages, the domain system utilizes a
compression scheme which eliminates the repetition of domain names in a
message.  In this scheme, an entire domain name or a list of labels at
the end of a domain name is replaced with a pointer to a prior occurance
of the same name.

The pointer takes the form of a two octet sequence:

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    | 1  1|                OFFSET                   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

The first two bits are ones.  This allows a pointer to be distinguished
from a label, since the label must begin with two zero bits because
labels are restricted to 63 octets or less.  (The 10 and 01 combinations
are reserved for future use.)  The OFFSET field specifies an offset from
the start of the message (i.e., the first octet of the ID field in the
domain header).  A zero offset specifies the first byte of the ID field,
etc.

The compression scheme allows a domain name in a message to be
represented as either:

   - a sequence of labels ending in a zero octet

   - a pointer

   - a sequence of labels ending with a pointer

Pointers can only be used for occurances of a domain name where the
format is not class specific.  If this were not the case, a name server
or resolver would be required to know the format of all RRs it handled.
As yet, there are no such cases, but they may occur in future RDATA
formats.

If a domain name is contained in a part of the message subject to a
length field (such as the RDATA section of an RR), and compression is used, the length of the compressed name is used in the length
calculation, rather than the length of the expanded name.

Programs are free to avoid using pointers in messages they generate,
although this will reduce datagram capacity, and may cause truncation.
However all programs are required to understand arriving messages that
contain pointers.

For example, a datagram might need to use the domain names F.ISI.ARPA,
FOO.F.ISI.ARPA, ARPA, and the root.  Ignoring the other fields of the
message, these domain names might be represented as:

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    20 |           1           |           F           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    22 |           3           |           I           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    24 |           S           |           I           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    26 |           4           |           A           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    28 |           R           |           P           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    30 |           A           |           0           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    40 |           3           |           F           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    42 |           O           |           O           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    44 | 1  1|                20                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    64 | 1  1|                26                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    92 |           0           |                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

The domain name for F.ISI.ARPA is shown at offset 20.  The domain name
FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
concatenate a label for FOO to the previously defined F.ISI.ARPA.  The
domain name ARPA is defined at offset 64 using a pointer to the ARPA
component of the name F.ISI.ARPA at 20; note that this pointer relies on
ARPA being the last label in the string at 20.  The root domain name is defined by a single octet of zeros at 92; the root domain name has no
labels.