Не делайте фрагментацию флага для пакетов IPv6 в Linux, используя переполнение стека

Я не могу установить флаг «не фрагментировать» для пакетов 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 заголовок включен и IPV6_DONTFRAG определяется в linux/in6.h, В том числе linux/in6.h в моем исходном коде вызывает эти ошибки переопределения.

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

Среда: Ubuntu 12.10 на VirtualBox 4.26 и GNS3 для виртуальной сети. Виртуальный маршрутизатор Cisco C3660 имеет только базовую конфигурацию: ip, ipv6 address, no shut and set mtu.

РЕДАКТИРОВАТЬ:
Мне нужно, чтобы ядро ​​стека / ОС IPv6 отбрасывало пакеты, превышающие MTU канала, или чтобы сигнализировать «этот пакет нуждается во фрагментации». Как я могу добиться этого поведения?

Я старался setsockopt с IPV6_DONTFRAG (определил это в моем коде #define IPV6_DONTFRAG 62 ), setsockopt с IPV6_MTU_DISCOVER, int on = IPV6_PMTUDISC_DO а также setsockopt с IPV6_RECVPATHMTU,

Но я не получаю PACKET TOO BIG ответить или ancillary data с cmsg_level == IPPROTO_IPV6 а также cmsg_type == IPV6_PATHMTU.

Часть моего кода:

/** 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:
Я реализовал, setsockopt с определенным IPV6_DONTFRAG не работает для меня, но setsockopt с IPV6_MTU_DISCOVER работает для собственного интерфейса. MTU интерфейса eth1 равен 1500 (по умолчанию), и если sendto хочет отправлять пакеты с большим размером, errno установлен в EMSGSIZE, Также через некоторое время я получаю PACKET TOO BIG сообщение для этих не отправлять сообщения из собственное ядро ​​/ ОС.

Моя настоящая проблема в том, что я не получение (Ubuntu 12.10 работает на VirtualBox 4.2.6) PACKET TOO BIG сообщения от виртуального маршрутизатора (Cisco c3660), работающего на GNS3.

3

Решение

и я хочу заставить маршрутизатор отбрасывать пакеты больше, чем MTU

В IPv6 пакеты больше, чем MTU, всегда будут отбрасываться. В отличие от IPv4, маршрутизаторы IPv6 не фрагментируют пакеты. Вместо этого ожидается, что источник будет выполнять PMTU и:

  • Протокол транспортного уровня создает дейтаграммы адекватного размера
  • Фрагмент пакетов в местном масштабе и прикрепить фрагмент расширения

Linux действительно имеет полную поддержку IPV6_DONTFRAG (Я думаю, что это было добавлено в 2.6.35), хотя это влияет только на локальное поведение.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]