FPing: utilitário mult-ping

Saudações. Vou apresentar a ferramenta FPing, um utilitário em linha de comando para monitoramento usando ICMP.

Pré-requisitos (constam em outros artigos aqui do blog):

  • Instalação do Linux (Debian);
  • Internet no servidor;

1 – Sobre o FPing

Normalmente usamos o comando “ping” ou “ping6” para testar se um determinado IP responde ao testes básico de conectividade IP + ICMP (echo-request – echo-reply).

Em casos onde precisamos dar ping em muitos IPs, incorremos na montagem de scripts que podem demorar muito a rodar e apresentar resultados difíceis de conciliar.

O FPing reune os recursos para testar vários IPs com agilidade e resultados claros.

Instalando

Bash
# Instalar FPing:
    apt -y install fping;

# Consultar ajuda do comando:
    fping --help;

Ajuda e argumentos: comando fping –help

fping help
Probing options:
   -4, --ipv4         only ping IPv4 addresses
   -6, --ipv6         only ping IPv6 addresses
   -b, --size=BYTES   amount of ping data to send, in bytes (default: 56)
   -B, --backoff=N    set exponential backoff factor to N (default: 1.5)
   -c, --count=N      count mode: send N pings to each target
   -f, --file=FILE    read list of targets from a file ( - means stdin)
   -g, --generate     generate target list (only if no -f specified)
                      (give start and end IP in the target list, or a CIDR address)
                      (ex. fping -g 192.168.1.0 192.168.1.255 or
                           fping -g 192.168.1.0/24)

   -H, --ttl=N        set the IP TTL value (Time To Live hops)
   -I, --iface=IFACE  bind to a particular interface
   -l, --loop         loop mode: send pings forever
   -m, --all          use all IPs of provided hostnames (e.g. IPv4 and IPv6),
                      use with -A

   -M, --dontfrag     set the Don't Fragment flag
   -O, --tos=N        set the type of service (tos) flag on the ICMP packets
   -p, --period=MSEC  interval between ping packets to one target (in ms)
                      (in loop and count modes, default: 1000 ms)
   -r, --retry=N      number of retries (default: 3)
   -R, --random       random packet data (to foil link data compression)
   -S, --src=IP       set source address
   -t, --timeout=MSEC individual target initial timeout (default: 500 ms,
                      except with -l/-c/-C, where it's the -p period up to 2000 ms)

Output options:
   -a, --alive        show targets that are alive
   -A, --addr         show targets by address
   -C, --vcount=N     same as -c, report results in verbose format
   -D, --timestamp    print timestamp before each output line
   -e, --elapsed      show elapsed time on return packets
   -i, --interval=MSEC  interval between sending ping packets (default: 10 ms)
   -n, --name         show targets by name (-d is equivalent)
   -N, --netdata      output compatible for netdata (-l -Q are required)
   -o, --outage       show the accumulated outage time
                      (lost packets * packet interval)
   -q, --quiet        quiet (don't show per-target/per-ping results)
   -Q, --squiet=SECS  same as -q, but show summary every n seconds
   -s, --stats        print final stats
   -u, --unreach      show targets that are unreachable
   -v, --version      show version
   -x, --reachable=N  shows if >=N hosts are reachable or not

2 – Ping e MTU

Testes de MTU: o tamanho do pacote informado nos comandos fping, ping e ping6 no Linux considera o PAYLOAD ICMP e não o tamanho do pacote IP.

O retorno do ping mostra apenas o SEGMENTO ICMP (Payload ICMP + Cabeçalho ICMP de 8 bytes).

Deve-se contabilizar o overhead:

  • Cabeçalho ICMP: +8 bytes;
  • Cabeçalho IP:
    • IPv4: +20 bytes;
    • IPv6: +40 bytes;

Vou fazer os testes usando o site registro.br:

  • IPv4: 200.160.2.3
  • IPv6: 2001:12ff:0:2::3

O argumento “-M” impede a fragmentação no caminho (dont-fragment).

Testando MTU IPv4:

Bash
# Ping IPv4 com 64 bytes de payload ICMP:
# - Payload.......: 64 bytes (-b 64)
# - Cabecalho ICMP: 8 bytes
# - Segmento ICMP.: 64 + 8 = 72 bytes
#
# - Cabecalho IPv4: 20 bytes
# - Tamanho total do pacote IP: 72 + 20 = 92 bytes
#
fping -C 4 -M -b 64 200.160.2.3;
    # 200.160.2.3 : [0], 72 bytes, 0.835 ms (0.835 avg, 0% loss)
    # 200.160.2.3 : [1], 72 bytes, 0.791 ms (0.813 avg, 0% loss)
    # 200.160.2.3 : [2], 72 bytes, 0.848 ms (0.824 avg, 0% loss)
    # 200.160.2.3 : [3], 72 bytes, 0.811 ms (0.821 avg, 0% loss)
    # 200.160.2.3 : 0.835 0.791 0.848 0.811

# Ping IPv4 com 1472 bytes de payload ICMP:
# - Payload.......: 1472 bytes (-b 1472)
# - Cabecalho ICMP: 8 bytes
# - Segmento ICMP.: 1472 + 8 = 1480 bytes
#
# - Cabecalho IPv4: 20 bytes
# - Tamanho total do pacote IP: 1480 + 20 = 1500 bytes
#
fping -C 4 -M -b 1472 200.160.2.3;
    # 200.160.2.3 : [0], 1480 bytes, 0.762 ms (0.762 avg, 0% loss)
    # 200.160.2.3 : [1], 1480 bytes, 0.794 ms (0.778 avg, 0% loss)
    # 200.160.2.3 : [2], 1480 bytes, 0.836 ms (0.797 avg, 0% loss)
    # 200.160.2.3 : [3], 1480 bytes, 0.792 ms (0.796 avg, 0% loss)
    # 200.160.2.3 : 0.762 0.794 0.836 0.792

Testando MTU IPv6:

Bash
# Ping IPv6 com 64 bytes de payload ICMP:
# - Payload.......: 64 bytes (-b 64)
# - Cabecalho ICMP: 8 bytes
# - Segmento ICMP.: 64 + 8 = 72 bytes
#
# - Cabecalho IPv6: 40 bytes
# - Tamanho total do pacote IP: 72 + 40 = 112 bytes
#
fping -C 4 -M -b 64 2001:12ff:0:2::3;
    # 2001:12ff:0:2::3 : [0], 72 bytes, 1.03 ms (1.03 avg, 0% loss)
    # 2001:12ff:0:2::3 : [1], 72 bytes, 1.09 ms (1.06 avg, 0% loss)
    # 2001:12ff:0:2::3 : [2], 72 bytes, 1.08 ms (1.07 avg, 0% loss)
    # 2001:12ff:0:2::3 : [3], 72 bytes, 1.07 ms (1.07 avg, 0% loss)
    # 2001:12ff:0:2::3 : 1.03 1.09 1.08 1.07

# Ping IPv6 com 1452 bytes de payload ICMP:
# - Payload.......: 1452 bytes (-b 1452)
# - Cabecalho ICMP: 8 bytes
# - Segmento ICMP.: 1452 + 8 = 1460 bytes
#
# - Cabecalho IPv6: 40 bytes
# - Tamanho total do pacote IP: 1460 + 40 = 1500 bytes
#
fping -C 4 -M -b 1452 2001:12ff:0:2::3;
    # 2001:12ff:0:2::3 : [0], 1460 bytes, 1.02 ms (1.02 avg, 0% loss)
    # 2001:12ff:0:2::3 : [1], 1460 bytes, 1.10 ms (1.06 avg, 0% loss)
    # 2001:12ff:0:2::3 : [2], 1460 bytes, 1.33 ms (1.15 avg, 0% loss)
    # 2001:12ff:0:2::3 : [3], 1460 bytes, 1.19 ms (1.16 avg, 0% loss)
    # 2001:12ff:0:2::3 : 1.02 1.10 1.33 1.19

Tamanho de payload baseado no MTU do caminho:

  • IPOE/Ethernet: 1500 bytes
    • Ping IPv4 Payload ICMP 1472;
    • Ping IPv6 Payload ICMP 1452;
  • PPPoE padrão: 1492 bytes
    • Ping IPv4 Payload ICMP 1464;
    • Ping IPv6 Payload ICMP 1444;
  • PPPoE mikrotik: 1480 bytes
    • Ping IPv4 Payload ICMP 1452;
    • Ping IPv6 Payload ICMP 1432;
  • GRE sobre IPv4: 1476 bytes
    • Ping IPv4 Payload ICMP 1448;
    • Ping IPv6 Payload ICMP 1428;
  • GRE sobre IPv6: 1456 bytes
    • Ping IPv4 Payload ICMP 1428;
    • Ping IPv6 Payload ICMP 1408;

Teste com os valores listados acima e em seguida teste adicionando 1 byte para testar se esse é o limite aplicado à sua Internet. Sempre que você violar o MTU o ping não funcionará.

Por padrão o Payload ICMP é preenchido com bytes zero (binário 0000000 hex 0x00). Pode ser útil testar com um payload randômico para testar redes que fazem uso de compressão de dados (LZO) como Rádio, LoRa e VPNs:

Bash
# Ping com payload randomico:
fping --random -C 4 -a -M -b 1000 200.160.2.3 2001:12ff:0:2::3;
    # 200.160.2.3      : 0.808 0.847 0.866 0.808
    # 2001:12ff:0:2::3 : 1.02 0.997 1.09 1.03

3 – Argumentos e exemplos de multi-ping

Testes de argumentos e diferentes de resultados:

Bash
# Ping para multiplos destinos, usando IPs ou nomes de DNS:
fping 8.8.8.8 2001:4860:4860::8888 1.1.1.1 2606:4700:4700::1111;
    # 8.8.8.8 is alive
    # 2001:4860:4860::8888 is alive
    # 1.1.1.1 is alive
    # 2606:4700:4700::1111 is alive

# Exibir somente IPs que respondem, relatorio final apenas:
fping -a 8.8.8.8 2001:4860:4860::8888 1.1.1.1 2606:4700:4700::1111;
    # 8.8.8.8
    # 2001:4860:4860::8888
    # 1.1.1.1
    # 2606:4700:4700::1111

# Fazer 4 pings por IP, relatorio final apenas:
fping -a -C 4 8.8.8.8 2001:4860:4860::8888 1.1.1.1 2606:4700:4700::1111;
    # 8.8.8.8              : 0.363 0.379 0.571 0.368
    # 2001:4860:4860::8888 : 0.396 0.380 0.392 0.413
    # 1.1.1.1              : 0.562 0.814 0.608 0.501
    # 2606:4700:4700::1111 : 0.899 0.963 0.870 0.909

# Fazer 4 pings por IP, resultado mais detalhado:
fping -a -c 4 8.8.8.8 2001:4860:4860::8888 1.1.1.1 2606:4700:4700::1111;
   # 8.8.8.8              : xmt/rcv/%loss = 4/4/0%, min/avg/max = 0.337/0.379/0.396
   # 2001:4860:4860::8888 : xmt/rcv/%loss = 4/4/0%, min/avg/max = 0.387/0.404/0.422
   # 1.1.1.1              : xmt/rcv/%loss = 4/4/0%, min/avg/max = 0.484/0.519/0.576
   # 2606:4700:4700::1111 : xmt/rcv/%loss = 4/4/0%, min/avg/max = 0.912/0.930/0.960

Teste simples com resultados por ciclo durante os testes:

Bash
# Fazer 4 pings por IP, mostrar os pings a cada teste (mais demorado):
fping -C 4 8.8.8.8 2001:4860:4860::8888 1.1.1.1 2606:4700:4700::1111;
    # 8.8.8.8              : [0], 64 bytes, 0.339 ms (0.339 avg, 0% loss)
    # 2001:4860:4860::8888 : [0], 64 bytes, 0.520 ms (0.520 avg, 0% loss)
    # 1.1.1.1              : [0], 64 bytes, 0.502 ms (0.502 avg, 0% loss)
    # 2606:4700:4700::1111 : [0], 64 bytes, 0.857 ms (0.857 avg, 0% loss)
    # 8.8.8.8              : [1], 64 bytes, 0.369 ms (0.354 avg, 0% loss)
    # 2001:4860:4860::8888 : [1], 64 bytes, 0.394 ms (0.457 avg, 0% loss)
    # 1.1.1.1              : [1], 64 bytes, 0.510 ms (0.506 avg, 0% loss)
    # 2606:4700:4700::1111 : [1], 64 bytes, 0.962 ms (0.909 avg, 0% loss)
    # 8.8.8.8              : [2], 64 bytes, 0.362 ms (0.356 avg, 0% loss)
    # 2001:4860:4860::8888 : [2], 64 bytes, 0.466 ms (0.460 avg, 0% loss)
    # 1.1.1.1              : [2], 64 bytes, 0.517 ms (0.510 avg, 0% loss)
    # 2606:4700:4700::1111 : [2], 64 bytes, 0.886 ms (0.902 avg, 0% loss)
    # 8.8.8.8              : [3], 64 bytes, 0.348 ms (0.354 avg, 0% loss)
    # 2001:4860:4860::8888 : [3], 64 bytes, 0.522 ms (0.475 avg, 0% loss)
    # 1.1.1.1              : [3], 64 bytes, 0.498 ms (0.507 avg, 0% loss)
    # 2606:4700:4700::1111 : [3], 64 bytes, 0.849 ms (0.888 avg, 0% loss)
    # 
    # 8.8.8.8              : 0.339 0.369 0.362 0.348
    # 2001:4860:4860::8888 : 0.520 0.394 0.466 0.522
    # 1.1.1.1              : 0.502 0.510 0.517 0.498
    # 2606:4700:4700::1111 : 0.857 0.962 0.886 0.849

4 – Ping em prefixo inteiro

Detectar todos os IPs que respondem a ping (ICMP) em um prefixo:

Bash
# Visualizar todos os IPs que respondem a ping e erros (loops, unreachable, ...)
# - Listar IPs e respectivos status:
fping -g 200.160.2.0/26;

# - Listar somente IPs ativos no STDOUT e erros no STDERR:
fping -a -g 200.160.2.0/26;

# - Listar somente IPs ativos no STDOUT
fping -a -g 200.160.2.0/26 2>/dev/null;
   # 200.160.2.1
   # 200.160.2.3
   # 200.160.2.4
   # ...
   # 200.160.2.53
   # 200.160.2.54

Detectar todos os IPs que respondem a ping (ICMP) em um prefixo, extrair lista de IPs:

Bash
# Visualizar todos os IPs que respondem a ping e erros (loops, unreachable, ...)
fping -a -g 200.160.2.0/26 2>/dev/null 1>/tmp/registro-br-200-160-2-0m26.txt;

# O arquivo /tmp/registro-br-200-160-2-0m26.txt conterá os IPs que respondem a ping

Testar quais IPs respondem a ping usando um arquivo que contem a lista de IPs:

Bash
# Conferir quais IPs respondem a ping a partir da lista de IPs em um arquivo:
fping -a -f /tmp/registro-br-200-160-2-0m26.txt;

# Efetuar 2 pings por IP e exibir latencias (ou "-" para pings que falharam):
fping -C 2 -q -B1 -r1 -i1 -f /tmp/registro-br-200-160-2-0m26.txt;

Assistindo múltiplos pings em tempo real:

Bash
# Exibir pings em tempo real
# - modo extremo, 1 ping por IP, repete imediatamente
watch -n0 'fping -C 1 -q -B1 -r1 -i1 -f /tmp/registro-br-200-160-2-0m26.txt';

# - modo conservador, 2 pings por IP
watch -n0 'fping -C 2 -q -B1 -r1 -i1 -f /tmp/registro-br-200-160-2-0m26.txt';

Nota: o argumento “-g” gera a lista de IPs considerando o uso em rede local ethernet, por isso ele não gera o endereço de rede e o endereço de broadcast, o que é ruim para testes em redes baseadas em loopbacks e PPPoE, onde o ip da rede e de broadcast podem ser usados, opte por gerar a lista via script e loops e então gravar num arquivo para dar os pings:

Bash
# Gerar lista de todos os IPs de um prefixo, incluindo network e broadcast
for n in $(seq 0 1 63); do
    echo 200.160.2.$n;
done > /tmp/registro-br-all-ips-m26.txt;

fping -a -f /tmp/registro-br-all-ips-m26.txt;

Monitorando em tempo real com exibição em colunas:

Bash
# Instalar JQ para parse de JSON:
apt -y install jq;

# Instalar CURL:
apt -y install curl;

# Baixar lista de servidores DNS abertos
curl 'https://api.badblock.net.br/dns/resolvers' -o /tmp/badblock-resolvers.json;

# Extrair os enderecos IP:
cat /tmp/badblock-resolvers.json  | jq -M -r '.[].address' > /tmp/dns-resolvers;

# Pingar todos os IPs de servidores DNS abertos, dividir em colunas:
fping -C 2 -q -B1 -r1 -i1 -f /tmp/dns-resolvers 2>&1 | column;
    # 8.8.8.8              : 0.375 0.333	 2606:4700:4700::1111 : 0.849 0.914
    # 9.9.9.10             : 0.758 0.697   119.29.29.29         : 307 307
    # 8.8.4.4              : 0.377 0.360	 2606:4700:4700::1001 : 0.519 0.467
    # 2620:fe::10          : 0.293 0.268   77.88.8.8            : 282 282
    # 2001:4860:4860::8888 : 0.385 0.382	 1.1.1.2              : 0.489 0.552
    # 2620:fe::fe:10       : 0.284 0.295   77.88.8.1            : 234 234
    # 2001:4860:4860::8844 : 0.375 0.359	 1.0.0.2              : 0.803 0.902
    # 9.9.9.11             : 0.564 0.526

# Acompanhando em tempo real:
watch -n0 'fping -C 2 -q -B1 -r1 -i1 -f /tmp/dns-resolvers 2>&1 | column';

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com