4

I can not set the "don't fragment" flag for the IPv6/ICMPv6 packets. I am doing PMTUD and I want to force the router to drop packets bigger then the MTU. Using setsockopt with IPV6_MTU_DISCOVER is not working.

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

result: wireshark

I also can not use setosckopt with IPV6_DONTFRAG as described in Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming because I have the netinet/in6.h header included and IPV6_DONTFRAG is defined in linux/in6.h. Including linux/in6.h in my source code causes these redefinition errors.

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

Environment: Ubuntu 12.10 on VirtualBox 4.26 and GNS3 for the virtual network. The virtual Cisco C3660 router has just basic configuration: ip, ipv6 address, no shut and set mtu.

EDIT: I need the IPv6 stack/OS kernel to drop packets that are bigger than the link MTU or to signalize "this packet needs fragmentation". How can I achieve this behavior?

I tried setsockopt with IPV6_DONTFRAG (defined it in my code #define IPV6_DONTFRAG 62 ), setsockopt with IPV6_MTU_DISCOVER, int on = IPV6_PMTUDISC_DO and setsockopt with IPV6_RECVPATHMTU.

But I am not getting the PACKET TOO BIG reply or ancillary data with cmsg_level == IPPROTO_IPV6 and cmsg_type == IPV6_PATHMTU.

Part of my code:

/** 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: I realized, setsockopt with defined IPV6_DONTFRAG is not working for me, but setsockopt with IPV6_MTU_DISCOVER is working for the own interface. The eth1 interface MTU is 1500 (default) and if sendto wants to send packets with bigger size, errno is set to EMSGSIZE. Also after some time I get PACKET TOO BIG message for these not send messages fom the own kernel/OS.

My real problem is, I am not getting (Ubuntu 12.10 running on VirtualBox 4.2.6) PACKET TOO BIG messages from the virtual router (Cisco c3660) running on GNS3.

1 Answers1

5

and I want to force the router to drop packets bigger then the MTU

In IPv6 packets bigger than the MTU will always be dropped. Unlike in IPv4, IPv6 routers don't fragment packets. Instead, the source is expected to perform PMTU and:

  • Have the transport layer protocol produce adequate-sized datagrams
  • Fragment packets locally and attach a fragment extension

Linux does indeed have full support for IPV6_DONTFRAG (I think it was added in 2.6.35) although it only affects local behavior.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • Why is Wireshark showing me a fragmented packet from the router to the PC? Is it a "bug"? and why is the source **and** destination address of the "Packet too big" packet my PC? Shouldn't it be the router? – Matej Koleják Jan 06 '13 at 20:53
  • @MatejKoleják I can only *speculate* if you provide a portion of the trace. Why don't you show more of it ? Perhaps give us the full pcap. – cnicutar Jan 06 '13 at 20:59
  • @MatejKoleják And you obtained this with a simple `ping6` ? – cnicutar Jan 06 '13 at 21:30
  • no, it's my program, that is sending IPv6 packet with ICMv6 header and data. – Matej Koleják Jan 06 '13 at 22:27
  • @MatejKoleják And you used the IPV6_DONTFRAG ? Are you sending only one packet ? – cnicutar Jan 07 '13 at 06:11
  • I used the "IPV6_MTU_DISCOVER" with "IPV6_PMTUDISC_DO" because I can not use IPV6_DONTFRAG as described in OP. I am trying to send more packets, but for the other i get "Packet too big" replys. I still think I am doing the PMTUD for IPv6 wrong. – Matej Koleják Jan 07 '13 at 16:57
  • OK. I think I know what is causing my problems. _By default, the IPv6 stack will fragment outgoing packets to the path MTU. An application such as traceroute may not want this automatic fragmentation, to discover the path MTU on its own._ Source: Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming. I don't want the IPv6 stack to automatically fragment outgoing packets. How can I achieve this without using setsockopt with "IPV6_DONTFRAG"? Because I can not use "linux/in6.h". – Matej Koleják Jan 07 '13 at 18:25
  • I marked cnicutars answer as accepted because it's the correct answer for the original post. But my problem remains. I'm not getting ICMPv6 "packet too big" messages from the virtual router. – Matej Koleják Jan 12 '13 at 15:50
  • @MatejKoleják I'll compile your code tomorrow to see what happens. If need be I'll fire up my old dynamips to reproduce it. – cnicutar Jan 12 '13 at 19:48
  • That would be great. Its not complete, if you need also the socket, ICMPv6 creation etc. tell me. – Matej Koleják Jan 13 '13 at 23:07