13

我正在尝试设置 DF(不要分段标志)以使用 UDP 发送数据包。

查看 Richard Steven 的书 Volume 1 Unix Network Programming;Sockets Networking API,我找不到如何设置它。

我怀疑我会用 setsockopt() 来做,但在第 193 页的表格中找不到它。

请建议这是如何完成的。

4

3 回答 3

27

通过使用以下选项,您可以通过setsockopt()调用来执行此操作:IP_DONTFRAG

int val = 1;
setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));

这是一个更详细地解释这一点的页面。

对于 Linux,您似乎必须使用IP_MTU_DISCOVER带有值的选项IP_PMTUDISC_DO(或IP_PMTUDISC_DONT将其关闭):

int val = IP_PMTUDISC_DO;
setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));

我没有对此进行测试,只是查看了头文件和一些网络搜索,因此您需要对其进行测试。

至于是否可以设置 DF 标志的另一种方式:

我在我的程序中找不到设置“强制 DF 标志”的地方,但tcpdump暗示它是。还有其他方法可以设置吗?

从这里的这个优秀页面:

IP_MTU_DISCOVER: 设置或接收套接字的路径 MTU 发现设置。启用后,Linux 将在此套接字上执行 RFC 1191 中定义的路径 MTU 发现。在所有传出数据报上都设置了不分段标志。系统范围的默认值由ip_no_pmtu_disc sysctlforSOCK_STREAM套接字控制,并在所有其他套接字上禁用。对于非SOCK_STREAM套接字,用户有责任将数据打包成 MTU 大小的块,并在必要时进行重传。EMSGSIZE如果设置了此标志(使用),内核将拒绝大于已知路径 MTU 的数据包。

在我看来,您可以使用以下命令设置系统范围的默认值sysctl

    sysctl ip_no_pmtu_disc

返回"error: "ip_no_pmtu_disc" is an unknown key"我的系统,但它可能设置在你的系统上。除此之外,我不知道有任何其他(除了setsockopt()前面提到的)会影响设置。

于 2009-06-10T02:34:43.990 回答
5

我同意paxdiablo的回答。

  • setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))

其中val之一是:

#define IP_PMTUDISC_DONT   0    /* Never send DF frames.  */
#define IP_PMTUDISC_WANT   1    /* Use per route hints.  */
#define IP_PMTUDISC_DO     2    /* Always DF.  */
#define IP_PMTUDISC_PROBE  3    /* Ignore dst pmtu.  */
  • ip_no_pmtu_disc在内核源代码中:
if (ipv4_config.no_pmtu_disc)
    inet->pmtudisc = IP_PMTUDISC_DONT;
else
    inet->pmtudisc = IP_PMTUDISC_WANT;
于 2013-12-26T06:49:23.310 回答
4

如果您在 Userland 中工作并打算绕过内核网络堆栈,从而构建您自己的数据包和标头并将它们交给自定义内核模块,那么有比setsockopt().

您实际上可以设置 DF 标志,就像在 中struct iphdr定义的任何其他字段一样linux/ip.h。3 位 IP 标志实际上是结构的frag_off (片段偏移)成员的一部分。

当您考虑它时,将这两件事分组是有意义的,因为标志与碎片相关。根据RFC-791,描述 IP 标头结构的部分指出片段偏移量为 13 位长,并且有三个 1 位标志。 frag_off成员类型为,__be16可容纳 13 + 3 位。

长话短说,这里有一个解决方案:

struct iphdr ip;
ip.frag_off |= ntohs(IP_DF);

我们在这里使用专门设计的IP_DF掩码准确设置 DF 位。

IP_DFnet/ip.h(当然是内核头文件)struct iphdr中定义,而在linux/ip.h.

于 2012-02-01T05:50:32.380 回答