不要使用C ++在Linux中分割IPv6数据包的标志

时间:2013-01-06 18:58:13

标签: c++ ipv6 icmp

我无法设置"不要片段" IPv6 / ICMPv6数据包的标志。我正在做PMTUD,我想强制路由器丢弃比MTU更大的数据包。使用setsockopt和IPV6_MTU_DISCOVER不起作用。

int on = IPV6_PMTUDISC_DO; // tried also IPV6_PMTUDISC_PROBE
setsockopt(socket, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on));

结果: wireshark

我也不能将setosckopt与IPV6_DONTFRAG一起使用,如 Unix-Linux Addison-Wesley - Stevens2003 - Unix网络编程中所述,因为我有netinet/in6.h标题和{ {1}}在IPV6_DONTFRAG中定义。在我的源代码中包含linux/in6.h会导致这些重新定义错误。

linux/in6.h

环境:VirtualBox 4.26上的Ubuntu 12.10和虚拟网络的GNS3。虚拟Cisco C3660路由器只有基本配置:ip,ipv6地址,无关闭和设置mtu。

修改 我需要IPv6堆栈/操作系统内核丢弃大于链路MTU的数据包或发信号通知"这个数据包需要分段"。我怎样才能实现这种行为?

我尝试In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:30:8: error: redefinition of ‘struct in6_addr’ In file included from /usr/include/netdb.h:28:0, from mypmtud.cc:23: /usr/include/netinet/in.h:198:8: error: previous definition of ‘struct in6_addr’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:46:8: error: redefinition of ‘struct sockaddr_in6’ In file included from /usr/include/netdb.h:28:0, from mypmtud.cc:23: /usr/include/netinet/in.h:239:8: error: previous definition of ‘struct sockaddr_in6’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:54:8: error: redefinition of ‘struct ipv6_mreq’ In file included from /usr/include/netdb.h:28:0, from mypmtud.cc:23: /usr/include/netinet/in.h:275:8: error: previous definition of ‘struct ipv6_mreq’ make: *** [mypmtud] Error 1 setsockopt(在我的代码IPV6_DONTFRAG中定义),#define IPV6_DONTFRAG 62 setsockoptIPV6_MTU_DISCOVER和{{1}与int on = IPV6_PMTUDISC_DO

但我没有收到setsockopt回复或IPV6_RECVPATHMTU PACKET TOO BIGancillary data

我的部分代码:

cmsg_level == IPPROTO_IPV6

EDIT2: 我意识到,定义cmsg_type == IPV6_PATHMTU.的{​​{1}}对我不起作用,但/** sending ICMP packet*/ if (((length = sendto(mysocket, packet, lengthBuff, 0, result->ai_addr, result->ai_addrlen)) < 0) && (errno == EMSGSIZE)){ // works for IPv4, doesn't work with IPv6 cout << "changing maxBuff and lengthBuff size" << endl; maxBuff = lengthBuff; lengthBuff = (minBuff + maxBuff) / 2; if (packet) { delete(packet); packet = NULL; } } else if (length < 0){ cerr << "Error: sending data." << endl; freeaddrinfo(result); close(mysocket); if (packet) { delete(packet); packet = NULL; } exit(1); } else if(((recvmsg(mysocket, &msg, 0)) != -1) && (errno != EINTR)) { // reading ancillary dada as described in *Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming, page 736* cmsgh = CMSG_FIRSTHDR(&msg); if(cmsgh != NULL) { cout << "getting msg " << endl; cout << "msg len " << msg.msg_controllen << endl; if(cmsgh->cmsg_level == IPPROTO_ICMPV6 && cmsgh->cmsg_type == IPV6_PATHMTU) { cout << "CMSGHEADER - GOOD" << endl; //mtustruct = CMSG_DATA(&msg); maxBuff = lengthBuff; lengthBuff = (minBuff + maxBuff) / 2; if (packet) { delete(packet); packet = NULL; } } else{ cout << "different ancillary data. " << endl; cout << " level " << cmsgh->cmsg_level << " type " << cmsgh->cmsg_type << endl; } } } else { cout << "no ERROR with sendto and no RESCVMSG" << endl; } /** receiving ICMP data */ tv.tv_sec = 3; tv.tv_usec = 0; int retval; // select FD_ZERO(&mySet); FD_SET(mysocket, &mySet); retval = select(mysocket + 1, &mySet, NULL, NULL, &tv); if (retval == -1) { cerr << "select failed" << endl; //break; exit(1); } else if (retval) { if ((length = recvfrom(mysocket, buffer, MAX, 0, result->ai_addr, &(result->ai_addrlen))) == -1) { cerr << "Error: receiving data." << endl; } else { icmpRec = (struct icmp6_hdr*) buffer; if((icmpRec->icmp6_type == ICMP6_PACKET_TOO_BIG)) { cout << "next hop MTU: " << ntohl(icmpRec->icmp6_mtu) << endl; maxBuff = ntohl(icmpRec->icmp6_mtu); } else if ((icmpRec->icmp6_type == ICMP6_ECHO_REPLY) && (ntohs(icmpRec->icmp6_id) == pid) && (ntohs(icmpRec->icmp6_seq) == (seq - 1))) { cout << "code " << ntohs(icmpRec->icmp6_code) << endl; cout << "ICMP ECHO REPLY" << endl; minBuff = lengthBuff; } } } setsockopt正在为自己的界面工作。 eth1接口MTU为1500(默认),如果IPV6_DONTFRAG想要发送更大的数据包,setsockopt设置为IPV6_MTU_DISCOVER。一段时间后,我收到sendto消息,因为这些消息不是从自己的内核/操作系统发送消息。

我真正的问题是,我 获取(在VirtualBox 4.2.6上运行Ubuntu 12.10)来自在GNS3上运行的虚拟路由器(Cisco c3660)的errno消息。

1 个答案:

答案 0 :(得分:5)

  

我想强制路由器丢弃大于MTU的数据包

在IPv6中,大于MTU的数据包将始终被丢弃。与IPv4不同,IPv6路由器不会对数据包进行分片。相反,源应该执行PMTU和:

  • 让传输层协议生成足够大小的数据报
  • 将数据包本地分段并附加片段扩展名

Linux确实完全支持IPV6_DONTFRAG(我认为它是在2.6.35中添加的),尽管它只会影响本地行为。