TL;DR:¿Cómo canalizar correctamente a través de UART la salida de un control remoto tcpdump
a un local wireshark
?
Intento capturar paquetes que fluyen a través de un dispositivo integrado en el que no tengo la capacidad de instalar nada. Afortunadamente, hay un getty abierto en la interfaz serie y tcpdump instalado. Lamentablemente, no hay SSH, ni dumpcap, ni tshark.
Tubería directa
Primero intenté configurar el tty y pasar los datos a Wirehark a través de tuberías.
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 se queja de que la entrada no tiene un formato libpcap válido, ciertamente porque el comando se repite y no logré deshacerme de eso.
Usando PySerial sin formato
Así que decidí crear un script en Python para controlar cómo funcionaría la tubería:
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))
Dejando de lado algunos problemas sobre cómo debería terminar correctamente el guión, esto no funcionó tan bien como imaginaba. Wireshark está contento por un tiempo, pero muy pronto la entrada se corrompe y la grabación se detiene. Creo que esto se debe a que el tty del host todavía convierte algunos caracteres especiales, probablemente el avance de línea o el retorno de carro.
Volviéndose estúpido: volcado hexadecimal sobre PySerial
Sé que esto es poco convincente, pero como no tenía otras ideas, esto es lo que se me ocurrió:
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))
Por desgracia, aunque funciona un poco más que la versión anterior, cuando los marcos son demasiado grandes, Wireshark presenta un problema diciendo que el marco es demasiado grande, con una longitud que es realmente ridícula (como -1562980309832), y nuevamente la grabación se detiene.
¡Por favor ayuda! :)
Puedes notar que intenté jugar con la -s
opción de tcpdump, pero no funcionó, incluso con cantidades bajas.
También intenté conectar desde picocom, sin éxito.
Entonces, si tiene alguna idea, algún software de túnel UART que funcione, algún comentario sobre mi (incompetente) uso de stty o alguna mejora en mis scripts de Python, ¡estaría muy feliz!
Wireshark es 2.2.5, tcpdump es 4.5.0 con libpcap 1.5.0.
Respuesta1
Finalmente, lo hice realmente funcionar. Esta no es la configuración perfecta, pero al menos funciona, así que tal vez pueda ayudar a alguien en el futuro.
Utilicé un script de Python encimaPySerialpara iniciar tcpdump sobre UART y usar hexdump para que los datos binarios puedan atravesar el enlace sin ser modificados por las reglas de transcripción tty. Luego, el script de Python vuelve a convertir los datos y los canaliza a Wirehark. El siguiente script es el resultado, en comparación con el de la pregunta, agregué la -v
opción de volcado hexadecimal para que no intente comprimir líneas iguales.
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))