Вопрос

Я пытаюсь установить DF (флаг не фрагментировать) для отправки пакетов с использованием UDP.

Рассматривая книгу Ричарда Стивена Том 1 Сетевое программирование в 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:

Я пока нигде не нахожу в своей программе, где установлен "флаг force DF" tcpdump предполагает, что это так.Есть ли какой-нибудь другой способ, которым это можно было бы установить?

С этой замечательной страницы здесь:

IP_MTU_DISCOVER: Устанавливает или получает параметр обнаружения MTU пути для сокета.Когда этот параметр включен, Linux выполнит обнаружение MTU пути, как определено в RFC 1191, для этого сокета.Флаг "Не фрагментировать" установлен для всех исходящих дейтаграмм.Общесистемное значение по умолчанию контролируется ip_no_pmtu_disc sysctl для SOCK_STREAM сокеты и отключены на всех остальных.Для не SOCK_STREAM сокеты пользователь несет ответственность за упаковку данных в блоки размером MTU и повторную передачу, если это необходимо.Ядро отклонит пакеты, размер которых превышает MTU известного пути, если этот флаг установлен (с EMSGSIZE).

Мне кажется, что вы можете установить общесистемное значение по умолчанию, используя sysctl:

sysctl ip_no_pmtu_disc

ВОЗВРАТ "error: "ip_no_pmtu_disc" is an unknown key" в моей системе, но он может быть установлен и в вашей.Кроме этого, я не знаю ни о чем другом (кроме setsockopt() как упоминалось ранее), которые могут повлиять на настройку.

Другие советы

Если вы работаете в пользовательской среде с намерением обойти сетевой стек ядра и, таким образом, создаете свои собственные пакеты и заголовки и передаете их пользовательскому модулю ядра, есть вариант получше, чем setsockopt().

На самом деле вы можете установить флаг DF точно так же, как и любое другое поле struct iphdr определенный в linux/ip.h.3-разрядные IP-флаги фактически являются частью frag_off (Смещение фрагмента) элемент структуры.

Когда вы думаете об этом, имеет смысл сгруппировать эти две вещи, поскольку флаги связаны с фрагментацией.В соответствии с RFC-791, в разделе, описывающем структуру IP-заголовка, указано, что смещение фрагмента имеет длину 13 бит и имеется три 1-битных флага.В frag_off член имеет тип __be16, который может содержать 13 + 3 бита.

Короче говоря, вот решение:

struct iphdr ip;
ip.frag_off |= ntohs(IP_DF);

Здесь мы точно устанавливаем бит DF, используя разработанный для этой конкретной цели IP_DF маска.

IP_DF определяется в net/ip.h (заголовки ядра, конечно), тогда как struct iphdr определяется в linux/ip.h.

Я согласен с ответом paxdiablo's.

  • setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &значение, sizeof(значение))

где 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top