【问题标题】:Sending structs over a C socket通过 C 套接字发送结构
【发布时间】:2016-06-06 04:10:29
【问题描述】:

我正在编写一个 DNS 查询客户端,但无法理解我的数据是如何发送的以及如何使其正常工作。

在 Wireshark 中,我收到大量带有错误数据包警告的随机数据,并且我正在测试的 DNS 服务器没有响应。 (目前谷歌的DNS...8.8.8.8)

一个sn-p...

typedef struct DNS_HEADER {

    // id to identify the request
    int16_t id;

    // query or response flag; default is 0
    uint8_t qr :1;

    // type of query; default is 0
    uint8_t opcode :4;

    // authoritative answer
    uint8_t aa :1;

    // message was truncated
    uint8_t tc :1;

    // recursion desired; default is yes
    uint8_t rd :1;

    // recursion available
    uint8_t ra :1;

    // unused
    uint8_t z :1;

    // response code
    uint8_t rcode :4;

    // entries in the question section; default is 1
    uint16_t qdcount;

    // resource records
    uint16_t ancount;

    // server resource records (in the authority section)
    uint16_t nscount;

    // resource records (in addl. section)
    uint16_t arcount;

} dns_h;

header->qr = 0;
header->opcode = 0;
...
header->qdcount = htons(1);
...

还有我的发件人...

char buffer[sizeof(*header) * sizeof(*question) * 2];
int offset = 0;
memcpy(buffer, header, sizeof(*header));
offset += sizeof(*header);
memcpy(buffer + offset, question, sizeof(*question)); 

ssize_t sent = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)addr, sizeof(*addr));

我做错了什么?这是通过套接字发送结构的推荐方法吗?我已将标题中的大多数字段设置为 0,而我设置为 1 的任何内容都使用了 htons

【问题讨论】:

  • 嗯,首先,您发送的数据量是预期的两倍,而后半部分是未初始化的垃圾。
  • 另外,你有 14 位的位域,所以编译器会插入额外的填充位,这可能不是你所期望的。

标签: c sockets struct dns


【解决方案1】:

您的标头结构有两个问题:

  • z 字段是 3 位,而不是 1。因此,rcode 字段在它应该在的位置的左侧两位。
  • 事实上,您使用的是位域。要做到这一点,您需要在编译时知道字节顺序,并且没有可移植的方法来做到这一点。您最好为所有内容声明一个 16 位字段(或 2 个 8 位字段)并进行位移以读取/写入正确的值。

您不会在创建标头的位置显示代码,但请确保在设置字段时使用htons,以便值按网络字节顺序排列。

另外,在 Wireshark 中仔细查看数据包中的二进制数据。将其与您输入的值进行比较,看看有什么不合适的地方。

【讨论】:

  • 谢谢@dbush - 绝对有帮助。您将如何在 DNS 问题包中指定域名?我已经声明了一个char qname[50],只是为了测试并不断从 DNS 服务器获取“未找到域”。我需要做一些不同的事情吗?
  • DNS 有线格式比简单的 C 数据结构复杂得多。例如,名称被编码为一系列标签,其中每个标签是一个字节,其中两个高位是标志,低六位是构成标签内容的后续字节的字节数(整个名称以带有零长度标签)。但这只能让您编码一个简单的名称,如果您想阅读答案,您必须知道如何处理不同的 RR 类型和 DNS 名称压缩。
猜你喜欢
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 2010-11-22
  • 2015-01-02
  • 2013-07-22
相关资源
最近更新 更多