首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不要使用IPv6为Linux中的C++数据包设置碎片标志

不要使用IPv6为Linux中的C++数据包设置碎片标志
EN

Stack Overflow用户
提问于 2013-01-06 18:58:13
回答 1查看 2.1K关注 0票数 4

我不能为IPv6 6/ICMPv6 6数据包设置“不要碎片”标志。我正在做PMTUD,我想迫使路由器丢包比MTU更大。在IPV6_MTU_DISCOVER中使用setsockopt不起作用。

代码语言:javascript
复制
int on = IPV6_PMTUDISC_DO; // tried also IPV6_PMTUDISC_PROBE
setsockopt(socket, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on));

结果:

我也不能像中描述的那样,在IPV6_DONTFRAG中使用setosckopt,因为我包含了netinet/in6.h头,而IPV6_DONTFRAG是在linux/in6.h中定义的。在我的源代码中包括linux/in6.h会导致这些重新定义错误。

代码语言:javascript
复制
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

环境: VirtualBox 4.26上的Ubuntu12.10和虚拟网络的GNS3。虚拟思科C3660路由器只有基本的配置: ip,ipv6地址,没有关闭和设置mtu。

编辑:--我需要IPv6堆栈/OS内核来丢弃大于链接MTU的数据包,或者表示“此数据包需要碎片”。我怎样才能达到这种行为呢?

我尝试了setsockoptIPV6_DONTFRAG (在代码#define IPV6_DONTFRAG 62中定义了它)、setsockoptIPV6_MTU_DISCOVERint on = IPV6_PMTUDISC_DOsetsockoptIPV6_RECVPATHMTU

但是我没有收到PACKET TOO BIG的回复,也没有收到cmsg_level == IPPROTO_IPV6cmsg_type == IPV6_PATHMTU.ancillary data

我的代码之一是:

代码语言:javascript
复制
/** 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;

                }
            }
        }

EDIT2: --我意识到,带有定义IPV6_DONTFRAGsetsockopt并不适合我,但是setsockoptIPV6_MTU_DISCOVER一起使用的是自己的接口。eth1接口MTU是1500 (默认的),如果sendto想要发送更大的数据包,则errno设置为EMSGSIZE。另外,过了一段时间,我得到了PACKET TOO BIG消息,因为这些消息不是针对自己的内核/OS发送的。

我真正的问题是,我是而不是not(运行在VirtualBox 4.2.6上的Ubuntu12.10)来自运行在GNS3上的虚拟路由器(Ciscoc3660)的PACKET TOO BIG消息。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-06 19:02:24

我想强迫路由器丢弃比MTU大的数据包

在IPv6中,大于MTU的数据包将始终被丢弃。与IPv4不同的是,IPv6路由器不对数据包进行分段。相反,预计源将执行PMTU,并:

  • 传输层协议是否产生足够大小的数据报?
  • 片段包本地并附加片段扩展

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14185610

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档