Raw DNS

Raw DNS

最近想用 raw socket 发送 DNS 请求. 遇到了一些问题. 纪录在这里.

sendto

raw socket 最后发送数据的时候, 使用 sendto. sendto 要传入对方的地址, 那么这里可以不写吗? 因为我们已经自己构造了 IP 包. 实际是要写的,
因为 raw socket 是构造的 ip 层以下的内容, 那链路层的信息是怎么生成的呢? 就是通过传给 sendto 的参数. 如果在内网里请求外网的地址, 那么你给 sendto 的地址也是外网的,
那怕是和你 ip 层的地址不同, 也是可以正常送达的, 因为都是可以正常送给路由器的.

UDP checksum

UDP 的 checksum 的计算是居然是另外构造了一个结构体进行计算的, 这让我很意外. 以前也没有特别关注过这个问题.

struct pseudo_header
{
    u_int32_t source_address;
    u_int32_t dest_address;
    u_int8_t placeholder;
    u_int8_t protocol;
    u_int16_t udp_length;
};

这个结构体之后再加上 UDP 的报头还有 payload 进行checksum 计算.

checksum offload

这个是占用了我最多时间的, 因为我先构造了一个 dns 报文, 使用正常的 UDP socket 进行发送了. 发现 UDP 的 checksum 是一个不正确的值, 我以为自己计算有问题, 就直接使用了这个值.
但是我的报文怎么也发送不成功. 在这个上面浪费了大量的时候, 比较我构造的包与使用 UDP socket 包的区别.

最后, 看着 wireshark 提示的 “UDP checksum offload” 知道了. 这里, UDP socket 在 checksum 的时候, 实际没有进行 checksum 计算, 而是利用了网卡的 offload 功能, 让网卡进行计算的.
我得到的包的时候, 还没有进入网卡, 所以我看到 checksum 的值并不正确.

代码

 github 


发表评论

邮箱地址不会被公开。 必填项已用*标注