Ir para conteúdo

MTU & fragmentação de pacotes IP e a sua análise com python


Visitante gnoo

Posts Recomendados

Saudações,

há uns tempos atrás andei a bater com a cabeça no tema de fragmentação de pacotes e MTU, andei a mexer com python também para tentar observar esse todo esse processo, e percebi que este assunto tem alguma importância quando estamos a aprender redes e normalmente não prestamos muita atenção. Decidi fazer uma pequena introdução para aqueles mais distraídos, e também para aqueles que querem um dia mexer com gestão de redes e que precisam de movimentar grandes quantidades de  dados seja em backups ou outras coisas, este tópico é de extrema importância.

Tal como eu disse este tópico é apenas uma introdução e é imprescindível ler sobre este conteúdo num livro sobre a especialidade,  alguma informação que aqui deixo foi retirada deste livro:

2081715649_Capturadeecr_2019-04-27_21-49-34.thumb.png.fc0120ba4f540b4690242669aff3c800.png

 

MTU significa Unidade Máxima de Transmissão, determina o tamanho máximo de um Frame/Pacote recebido ou enviado a partir de um interface de rede, o valor do tamanho máximo é determinado pela tecnologia que estamos a utilizar para enviar informação entre dois dispositivos.

Vamos dar o exemplo da Ethernet, um frame Ethernet normal carrega 1500 bytes, todos os datagramas /pacotes IP com tamanho superior a 1500 bytes serão fragmentados.

Para ver o valor do MTU configurado na nossa placa de rede, quem tem o pacote iproute2 instalado no seu sistema, pode ver com o comando, ip addr, para aqueles que ainda usam o net-tools, podem ver com o comando ifconfig.

mtu.png.2c6fd0e61cb97e3bea8c9b37993e6a92.png

 

O valor do MTU pode ser configurado tanto na nossa máquina como no dispositivo que está a fazer o roteamento de pacotes, atenção cada plca de rede tem um valor mínimo e máximo para o valor do MTU.

Como a imagem que segue nos mostra se o valor da nossa configuração for 3,300, e o valor do MTU do dispositivo que faz o roteameneto dos pacotes for 1,300, ao passar no router esses pacotes vão fragmentados uma vez que o MTU do router, é menor que o MTU do emissor do pacote.

1943026457_Capturadeecr_2019-04-27_18-45-54.png.b5f141b044702b7eef3193e64a47a61e.png

No header de um datagrama IP temos 5 campos importantes de entender quando falamos de fragmentação de pacotes IP.

header.png.ca370050b0aaf44a1a45fa96b9dfe6e3.png

 

Identification – O valor deste campo é utilizado após a fragmentação do lado do recetor na altura de reagrupar os pacotes fragmentados.

Total Length – Diz-nos o tamanho de cada pacote / fragmento em bytes.

Flags :

X -Reservada não utilizada

DF ( don’t Fragment ) - Quando o valor desta flag é 1, diz que o pacote não deve ser fragmentado

MF ( more fragments ) - Os valores desta flag podem variar mediante o número de fragmentos caso seja o ultimo fragmento, o valor é zero porque é o último fragmento. O valor zero também pode querer dizer que não existem fragmentos para além desse pacote.

Fragment Offset – Este valor indica ao recetor dos fragmentos em que posição e sequência cada fragmento de estar para reconstruir o pacote fragmentado pelo emissor do pacote.

Header Checksum – Ao enviar o pacote cálculo é feito ao header, a cada hop ( cada passagem num router ), é feito um novo cálculo ao header pelo dispositivo que recebe o pacote, se o valor não corresponder ao anterior, o pacote é tido como corrompido e descartado.

 

Script Com python:

#coding:utf-8  
#!/usr/bin/env python3

from socket import *
import struct
import binascii

def ethernet_frame(raw_dados):
    
    mac_destino, mac_fonte, protocolo = struct.unpack('! 6s 6s H', raw_dados[:14])

    return byte_to_hex_mac(mac_destino), byte_to_hex_mac(mac_fonte), htons(protocolo), raw_dados[14:]

def byte_to_hex_mac(mac_em_bytes):
    endereco = binascii.hexlify(mac_em_bytes).decode("ascii")
    return ":".join([endereco[i:i+2] for i in range(0,12,2)])


def dados_pacote_ipv4(carga):
    tupla_dados_ipv4 = struct.unpack("!BBHHHBBH4s4s", carga[:20])
    tamanho_total_pacote = tupla_dados_ipv4[2]
    identificacao = tupla_dados_ipv4[3]
    flags_offset_fragmento = tupla_dados_ipv4[4]
    checksum_cabecalho = tupla_dados_ipv4[7]
    ip_origem = inet_ntoa(tupla_dados_ipv4[8])
    ip_destino = inet_ntoa(tupla_dados_ipv4[9])
    fragmento = (flags_offset_fragmento << 3) & 1

    #Flags
    flag_RES = (flags_offset_fragmento >> 15) & 1
    flag_DF  = (flags_offset_fragmento >> 14) & 1
    flag_MF  = (flags_offset_fragmento >> 13) & 1

    return tamanho_total_pacote, identificacao, fragmento, checksum_cabecalho, ip_origem, ip_destino, flag_RES, flag_DF, flag_MF 


sock = socket(AF_PACKET, SOCK_RAW, ntohs(0x0003))    

while True:
    raw_dados, addr = sock.recvfrom(65536)
    mac_destino, mac_fonte, tipo_ethernet, payload = ethernet_frame(raw_dados)

    # tipo_ethernet
    # Se for 8 vem ai pacote IP \0/
    if tipo_ethernet == 8:
        tamanho_total_pacote, identificacao, fragmento, checksum_cabecalho, ip_origem, ip_destino, flag_RES, flag_DF, flag_MF = dados_pacote_ipv4(payload)
        print("##### IPv4 HEADER #####")
        print("Tamanho pacote em bytes {}".format(tamanho_total_pacote))
        print("Identificação do Fragmento {}".format(identificacao))
        print("Fragmento {}".format(fragmento))
        print("Checksum cabeçalho {}".format(checksum_cabecalho))
        print("IP Origem {}".format(ip_origem))
        print("IP Destino {}".format(ip_destino))
        print("----FLAGS---")
        print("Reservado : {}".format(flag_RES))
        print("Sem Fragmento : {}".format(flag_DF))
        print("Mais Fragmentos : {}".format(flag_MF))
        
        

Abraço.

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...