Pergunta

Eu estou tentando definir o DF (não fragmento bandeira) para o envio de pacotes usando UDP.

Olhando para o livro Volume Programação 1 Unix rede do Richard Steven; A API Sockets Networking, eu sou incapaz de encontrar como configurar isso.

Eu suspeito que eu faria isso com setsockopt (), mas não pode encontrá-lo na tabela na página 193.

Por favor, sugerem como isso é feito.

Foi útil?

Solução

Você faz isso com a chamada setsockopt(), usando a opção IP_DONTFRAG ::

int val = 1;
setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));

Aqui está uma página explicando isso em mais detalhes.

Para Linux, parece que você tem que usar a opção IP_MTU_DISCOVER com o valor IP_PMTUDISC_DO (ou IP_PMTUDISC_DONT para desligá-lo):

int val = IP_PMTUDISC_DO;
setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));

Eu não testei isso, apenas olhou nos arquivos de cabeçalho e um pouco de uma pesquisa na web para que você vai precisar para testá-lo.

Quanto a saber se há outra maneira a bandeira DF poderia ser definido:

I encontrar nada em meu programa onde a "força DF bandeira" está definido, mas tcpdump sugere que é. Existe alguma outra maneira este conjunto poderia começar?

A partir deste excelente página aqui :

Conjuntos IP_MTU_DISCOVER: ou recebe a configuração Path MTU Discovery para um socket. Quando ativado, o Linux realiza o Path MTU Discovery conforme definido na RFC 1191 sobre este socket. A não sinalizem fragmento é definido em todos os datagramas de saída. O padrão de todo o sistema é controlado pelo ip_no_pmtu_disc sysctl para sockets SOCK_STREAM e desativado em todos os outros. Para sockets não SOCK_STREAM é de responsabilidade do usuário empacotar os dados em MTU tamanho pedaços e fazer a retransmissão, se necessário. O kernel irá rejeitar pacotes que são maiores que o MTU caminho sabe se este sinalizador é definido (com EMSGSIZE).

Isso parece-me que você pode definir o padrão usando sysctl de todo o sistema:

sysctl ip_no_pmtu_disc

retornos "error: "ip_no_pmtu_disc" is an unknown key" no meu sistema, mas pode ser definido no seu. Fora isso, eu não estou ciente de qualquer outra coisa (que não seja setsockopt() como mencionado anteriormente) que podem afetar a configuração.

Outras dicas

Se você estiver trabalhando em Userland com a intenção de ignorar a pilha de rede Kernel e construindo assim seus próprios pacotes e cabeçalhos e entregá-los a um módulo kernel personalizado, há uma opção melhor do que setsockopt().

Você pode realmente definir o sinalizador DF como qualquer outro campo da struct iphdr definido no linux/ip.h. As bandeiras IP 3 bits são na verdade parte do frag_off (Fragmento Offset) membro da estrutura.

Quando você pensa sobre isso, faz sentido agrupar essas duas coisas como as bandeiras são a fragmentação relacionados. De acordo com o RFC-791 , na secção que descreve os estados estrutura de cabeçalho IP que Fragmento deslocamento é 13-bit de comprimento e há três bandeiras de 1 bit. O membro frag_off é do tipo __be16, que pode conter 13 + 3 bits.

Para encurtar a história, aqui está uma solução:

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

Estamos aqui exatamente definir o DF bit usando o projetado-para-que-especial-purpose máscara IP_DF.

IP_DF é definido em net/ip.h (cabeçalhos do kernel, é claro), ao passo que struct iphdr é definido em linux/ip.h.

Eu concordo com a resposta da paxdiablo.

  • setsockopt (sockfd, IPPROTO_IP, IP_MTU_DISCOVER, & val, sizeof (val))

onde val é um dos seguintes:

#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 no fonte do kernel:
if (ipv4_config.no_pmtu_disc)
    inet->pmtudisc = IP_PMTUDISC_DONT;
else
    inet->pmtudisc = IP_PMTUDISC_WANT;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top