Trabalho 10: Simulação de Roteador IPv6 Redes de Computadores 1 Descrição Este trabalho pode ser feito por até três acadêmicos. Neste trabalho vocês implementarão dois programas, de forma similar ao trabalho 09. Você pode reutilizar o código de qualquer um do seu grupo do trabalho 09. O primeiro programa criará um pacote ping IPv6 (echo request) e enviará para o segundo programa. Seu segundo programa encaminhará o pacote de acordo com a tabela de roteamento, tanto descartando ele ou encaminhando para outro roteador (outra instância do mesmo programa). Seu programa roteador deve também imprimir o que acontece com cada programa recebido, ex.: encaminhado ou descartado. Como no trabalho 09, as tabelas de roteamento deste trabalho são estáticas e fornecidas como argumento por linha de comando, logo, você não precisa implementar nenhum protocolo de roteamento ou mesmo uma tabela de roteamento. 2 Criando um pacote ping ICMPv6 Escreva um programa em C, pinggen6, para criar e enviar um pacote ICMPv6 válido de echo request. Esse pacote começa com um cabeçalho IPv6 válido assim como no trabalho 09, seguido por um byte 128 (echo request), três bytes zero (isso envia o checksum como zero). Os próximos dois bytes são um identificador selecionado pelo seu programa (o ID do processo retornado por getpid é o suficiente). Os próximos dois bytes são o número de sequência (incrementado de 0). Isso pode ser, opcionalmente, seguido por 8 bytes do horário obtido por gettimeofday. O pinggen6 recebe quatro argumentos por linha de comando: um número de porta local e remoto e dois endereços IPv6. Ele então cria um socket, conecta=o ao número de porta local, cria um pacote como descrito acima e envia-o para ::1 (localhost) e o número de porta UDP remoto fornecido por linha de comando. Ou seja, você está enviando um pacote IPv6 (consistindo de um cabeçalho IPv6 e conteúdo ICMPv6) sobre IPv6 e UDP para o seu programa router6 descrito a seguir. Depois de enviar o pacote, pinggen6 lê do socket e imprime qualquer pacote que for recebido. Por exemplo, $./pinggen6 9876 12345 1:2:3::4 5:6:7:8:9:a:b:c 1
cria um pacote com cabeçalho IPv6 com endereço de origem 1:2:3::4 (que é o mesmo que 1:2:3:0:0:0:0:4) e endereço de destino 5:6:7:8:9:a:b:c e uma carga (payload) ICMP com echo request como descrito acima. Ele envia o pacote para o endereço IPv6 de localhost (::1) da porta UDP 9876 para a porta UDP 12345, e então escuta por qualquer mensagens que cheguem na porta UDP 9876. 2.1 Testando o pinggen6 O programa pinggen6 pode ser testado com ele mesmo. Para isso você precisa de duas janelas e executar os seguintes comandos, um em cada janela: Janela 1: $./pinggen6 9876 12345 1:2:3::4 9:8:7::6 Janela 2: $./pinggen6 12345 9876 9:8:7::6 1:2:3::4 Se o seu comando pinggen6 funcionar corretamente, a segunda chamada (na Janela 2) deve enviar um pacote para o programa rodando na outra janela (Janela 1). 3 Roteamento e Encaminhamento Neste trabalho, como no trabalho 09, a tabela de roteamento é uma série de argumentos por linha de comando, cada um deles no formato: destino/gateway/máscara/interface Cada um dos argumentos é usado para criar uma entrada na tabela de roteamento, na ordem fornecida na linha de comando. Argumentos de linha de comando também são usados para especificar os endereços IP das interfaces do roteador: +interface/local-ipv6/máscara/minha-porta-udp/porta-udp-do-par Essa definição de interface começa sempre com o caractere + e inclui: 1. o nome da interface (usada quando pacotes são encaminhados deve casar com o nome da interface de uma rota específica e deve ter no máximo 100 caracteres) 2. o endereço IPv6 configurado nessa interface 2
3. a máscara de rede correspondente, um número entre 0 e 128 inclusive 4. uma porta UDP local que a interface irá escutar por pacotes chegando 5. uma porta remota UDP em ::1 no qual essa interface enviará pacotes Os dois tipos de argumentos podem ser fornecidos em qualquer ordem na linha de comando. Somente a ordem de entrada para a tabela de roteamento é significante. Para escutar em diferentes interfaces (ex.: receber diferentes conexões por sockets em diferentes portas UDP), seu programa deve trabalhar tanto com múltiplas threads (recomendado, mas um pouco mais difícil) ou múltiplos processos (bem mais simples de implementar). Multiplas threads são criadas com pthread_create e múltiplos processos com fork. Se você usar pthreads, você precisará passar o parâmetro -lpthread ao gcc para fazer o link com o seu código, ex.: $ gcc -o router6 router6.c -lpthread 4 Exemplo Eu vou simular uma topologia de rede simples com dois hosts e dois roteadores (Figura 1). Cada roteador tem duas interfaces, uma conectada a um host e outra ao outro roteador. Essa rede simples precisa de três números em redes IPv6. Eu vou usar 2001:2:3:4::/64, 2002:3:4:5::/64 e 2003:4:5:6::/64. Figura 1: Topologia ligando dois roteadores e dois hosts usando endereços IPv6 e portas UDP. 3
Para rodar os quatro programas a seguir ao mesmo tempo, eu abrirei 4 janelas de terminal diferentes e executar cada comando em uma janela: $./router6 +eth0/2001:2:3:4::1/64/12345/9876 2001:2:3:4::/2001:2:3:4::2/64/eth0 +eth1/2002:3:4:5::1/64/12346/12347 2002:3:4:5::/2002:3:4:5::2/64/eth1 2003:4:5:6::/2002:3:4:5::2/64/eth1 $./router6 +eth0/2002:3:4:5::2/64/12347/12346 2002:3:4:5::/2002:3:4:5::1/64/eth0 +eth1/2003:4:5:6::1/64/12348/9875 2003:4:5:6::/2003:4:5:6::2/64/eth1 2001:2:3:4::/2002:3:4:5::1/64/eth0 $./pinggen6 9876 12345 2001:2:3:4::2 2003:4:5:6::2 $./pinggen6 9875 12348 2003:4:5:6::2 2001:2:3:4::2 Com esses comandos, o pacote do primeiro pinggen deve iniciar e ser entregue ao primeiro roteador e depois para o segundo roteador e finalmente ao segundo host. Se o segundo host não estiver em executação ainda, o pacote será descartado pelo UDP. Quando o segundo host for iniciado, o ping deve viajar todo o caminho até o primeiro host, onde será ignorado (a não ser que você tenha um tempo extra e queira trabalhar um pouco mais, nesse caso, seu código deve responder ao echo request com o echo reply correspondente). Note que o número da porta UDP correspondente a cada interface simulada deve ser único, uma vez que o socket deve ser vinculado com uma porta. Depois de receber cada pacote, seu roteador deve imprimir exatamente uma linha, começando com: forwarding 2001:2:3:4::2 to next hop 2002:3:4:5::1 on eth0 ou dropping 2001:2:3:4::5 Cada mensagem deve ser seguida de detalhes adicionais como no route ou (opcionalmente) Hop Limit zero. 5 Resultados Por favor siga os exemplos anteriores e relate os resultados do seu analisador de tabelas de roteamento (e faça um pequeno texto explicativo, README). Escreva seu código fonte para pinggen6.c e router6.c (e quaisquer outros códigos ou arquivos de cabeçalho), coloque tudo em um único arquivo.zip e envie. 4
6 Opcional Se você tiver um pouco de tempo extra, você é bem vindo para implementar pacotes de echo reply ICMPv6 válidos em resposta aos pacotes echo request. Veja a RFC4443 1 para detalhes. Se você incluir o tempo (os 8 bytes adicionais de gettimeofday) no seu echo request, enquanto, quando você receber o echo reply poderá imprimir o tempo resultante do round-trip time. Neste trabalho, o echo reply deve ter o mesmo payload que o echo request, ou seja, o sistema que vai gerar o echo reply deve copiar o payload que veio no echo request. Você também é bem vindo para decrementar o número limite de hop s quando encaminhar um pacote até que ele chegue a zero. Se você for fazer isso, você precisará dar suporte a um quinto campo opcional no pinggen6, especificando o limite de hop s (se não for especificado, use 64). Se você decrementar o hop limite e discartar pacotes, você também precisará enviar a origem um pacote de destino inalcançável. Isso permitirá que você implemente a funcionalidade do traceroute. Você é bem vindo para implementar checksums. Veja a Seção 8.1 da RFC 2460 2 para mais detalhes. 1 https://tools.ietf.org/html/rfc4443 2 https://tools.ietf.org/html/rfc2460#section-8.1 5