我正在尝试使用UDP发送数据包时设置DF(不分段标志)。
查看Richard Steven的书籍《Unix网络编程》第一卷:套接字网络API,我无法找到如何设置此标志。
我认为可以使用setsockopt()函数来实现,但在第193页的表格中找不到它。
请建议如何完成此操作。
您可以使用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
表明它已经被设置了。还有其他方法可以设置吗?
根据这个优秀的页面here:
IP_MTU_DISCOVER:
设置或接收套接字的路径MTU发现设置。启用时,Linux将在此套接字上执行RFC 1191中定义的Path MTU Discovery。所有传出数据报文都设置了“不分段”标志。系统范围内的默认值由ip_no_pmtu_disc
sysctl
控制,适用于SOCK_STREAM
套接字,并对所有其他套接字禁用。对于非SOCK_STREAM
套接字,用户有责任将数据分段为MTU大小的块,并在必要时执行重传。如果设置了此标志(使用EMSGSIZE
),内核将拒绝大于所知路径MTU的数据包。
在我看来,您可以使用sysctl
设置系统范围内的默认值:
sysctl ip_no_pmtu_disc
在我的系统上返回"error: "ip_no_pmtu_disc" is an unknown key"
,但是它可能在您的系统上设置过。除此之外,我不知道其他任何影响设置的东西(除了之前提到的setsockopt()
)。
struct iphdr
字段一样设置DF标志,该结构定义在linux/ip.h
中。 3位IP标志实际上是结构体中的frag_off
(片段偏移)成员的一部分。frag_off
成员的类型为__be16
,可以容纳13 + 3位。struct iphdr ip;
ip.frag_off |= ntohs(IP_DF);
IP_DF
掩码来精确设置DF位。
IP_DF
在net/ip.h
(当然是内核头文件)中定义,而struct iphdr
则在linux/ip.h
中定义。我同意paxdiablo的答案。
其中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;
IP_PMTUDISC_DO
的意思是始终不分段吗? - pellucidcoder
IP_DONTFRAG
选项在哪里设置?我正在使用Ubuntu,我认为这是一个文件中的参数。我不知道文件在哪里。 - Sablefoste