DR:Como canalizar corretamente pelo UART a saída de um controle remoto tcpdump
para um local wireshark
?
Tento capturar pacotes que fluem através de um dispositivo incorporado no qual não consigo instalar nada. Felizmente, há um getty aberto na interface serial e o tcpdump instalado. Infelizmente, sem SSH, sem dumpcap, sem tshark.
Tubo direto
Primeiro tentei configurar o tty e passar os dados para o wireshark através de pipes.
stty -F /dev/ttyUSB0 raw
stty -F /dev/ttyUSB0 -echo -echoe -echok
cat /dev/ttyUSB0 | wireshark -k -i -
# On another terminal:
echo "tcpdump -U -s0 -i eth0 -w - 2>/dev/null" > /dev/ttyUSB0
Wireshark reclama que a entrada não é um formato libpcap válido, certamente porque o comando foi repetido e não consegui me livrar dele.
Usando PySerial bruto
Então decidi criar um script python para controlar como funcionaria a tubulação:
import serial
import sys
import subprocess
import fcntl
def main(args):
with serial.Serial('/dev/ttyUSB0', 115200, timeout=0) as ser:
length = ser.write(b"tcpdump -U -s0 -i eth0 -w - 2> /dev/null\n") + 1
# Discard the echoed command line
while length > 0:
discard = ser.read(length)
length -= len(discard)
# Spawn wireshark
wireshark = subprocess.Popen(
["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
)
# Pipe data from serial to wireshark's input
while True:
data = ser.read(256)
wireshark.stdin.write(data)
try:
wireshark.stdin.flush()
except BrokenPipeError as e:
break
if len(data) > 0: print(data)
# Send "Ctrl+C" to tcpdump
ser.write(b"\x03")
wireshark.wait()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
Deixando de lado alguns problemas sobre como o script deveria terminar corretamente, isso não funcionou tão bem quanto eu imaginava. O Wireshark fica feliz por algum tempo, mas logo a entrada fica corrompida e a gravação é interrompida. Acho que isso ocorre porque o tty no host ainda converte alguns caracteres especiais, provavelmente o avanço de linha ou o retorno de carro.
Ficando estúpido: hexdump sobre PySerial
Então eu sei que isso é ridículo, mas como não tive outras ideias, foi isso que pensei:
import serial
import sys
import subprocess
import binascii
def main(args):
with serial.Serial('/dev/ttyUSB0', 115200, timeout=5) as ser:
# Spawn tcpdump on the host and convert the raw output to stupid hex format
# We need hexdump -C because that's the only format that doesn't mess up with the endianess
length = ser.write(b"tcpdump -U -s256 -i eth0 -w - 2> /dev/null | hexdump -C\n")
# Discard command line that is echoed
discard = ser.readline()
# Spawn wireshark
wireshark = subprocess.Popen(
["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
)
while True:
# Process each line separately
data = ser.readline().decode('ascii')
elements = data.split()
# Remove the address and ascii convertion of hexdump and spaces
hexa = "".join(elements[1:17])
# Convert back hex to binary
real_data = binascii.unhexlify(hexa)
# Feed to the shark
wireshark.stdin.write(real_data)
try:
wireshark.stdin.flush()
except BrokenPipeError as e:
break
# Stop tcpdump
ser.write(b"\x03")
wireshark.wait()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
Infelizmente, embora funcione um pouco mais que a versão anterior, quando os frames são um pouco grandes demais, o wireshark apresenta um problema dizendo que o frame é muito grande, com um comprimento que é realmente ridículo (como -1562980309832), e novamente a gravação para.
Por favor ajude! :)
Você pode notar que tentei brincar com a -s
opção tcpdump, mas não funcionou, mesmo com valores baixos.
Também tentei tubulação do picocom, sem sucesso.
Então, se você tiver alguma ideia, qualquer software de tunelamento UART que funcione, qualquer comentário sobre meu uso (incompetente) de stty ou qualquer melhoria em meus scripts python, eu ficaria muito feliz!
Wireshark é 2.2.5, tcpdump é 4.5.0 com libpcap 1.5.0.
Responder1
Finalmente, consegui realmente funcionar. Esta não é a configuração perfeita, mas pelo menos funciona, então talvez possa ajudar alguém no futuro.
Eu usei um script Python em cima dePySerialpara iniciar o tcpdump pelo UART e usar o hexdump para que os dados binários possam atravessar o link sem serem modificados pelas regras de transcrição tty. Em seguida, o script Python converte novamente os dados e os canaliza para o wireshark. O script abaixo é o resultado, comparado ao da pergunta, adicionei a -v
opção hexdump para que não tente compactar linhas iguais.
import serial
import sys
import subprocess
import binascii
def main(args):
with serial.Serial('/dev/ttyUSB0', 115200, timeout=5) as ser:
# Spawn tcpdump on the host and convert the raw output to stupid hex format
# We need hexdump -C because that's the only format that doesn't mess up with the endianess
length = ser.write(b"tcpdump -U -s256 -i eth0 -w - 2> /dev/null | hexdump -Cv\n")
# Discard command line that is echoed
discard = ser.readline()
# Spawn wireshark
wireshark = subprocess.Popen(
["wireshark", "-k", "-i", "-"], stdin=subprocess.PIPE
)
while True:
# Process each line separately
data = ser.readline().decode('ascii')
elements = data.split()
# Remove the address and ascii convertion of hexdump and spaces
hexa = "".join(elements[1:17])
# Convert back hex to binary
real_data = binascii.unhexlify(hexa)
# Feed to the shark
wireshark.stdin.write(real_data)
try:
wireshark.stdin.flush()
except BrokenPipeError as e:
break
# Stop tcpdump
ser.write(b"\x03")
wireshark.wait()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))