要約:tcpdump
リモートの出力を UART 経由でローカルに適切にパイプするにはどうすればよいでしょうかwireshark
?
何もインストールできない組み込みデバイスを通過するパケットをキャプチャしようとしています。幸い、シリアル インターフェイスで getty が開かれており、tcpdump がインストールされています。残念ながら、SSH も dumpcap も tshark もありません。
直管
まず、tty を設定し、パイプを介してデータを wireshark に渡そうとしました。
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 は、入力が有効な libpcap 形式ではないと警告します。これは、コマンドがエコーバックされ、それを解消できなかったことが原因です。
生のPySerialを使用する
そこで、パイピングの動作を制御する Python スクリプトを作成することにしました。
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))
スクリプトが適切に終了する方法に関するいくつかの問題はさておき、これは私が想像したほどうまく動作しませんでした。Wireshark はしばらくは正常に動作しますが、すぐに入力が破損し、記録が停止します。これは、ホストの tty がまだいくつかの特殊文字 (おそらく改行または復帰) を変換しているためだと思います。
バカになる: PySerial 経由の hexdump
これがつまらないことだとはわかっていますが、他にアイデアがなかったので、次のようなものを思いつきました。
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))
残念ながら、以前のバージョンよりも少し長く動作しますが、フレームが少し大きすぎると、Wireshark はフレームが大きすぎるという問題を表示し、その長さは実にばかげています (-1562980309832 など)。そして、再び録画が停止します。
助けてください! :)
tcpdump のオプションを試してみました-s
が、少量でも機能しませんでした。
picocom からのパイピングも試しましたが、効果はありませんでした。
したがって、何かアイデアや、機能する UART トンネリング ソフトウェア、私の (不十分な) stty の使用に関するコメント、または私の Python スクリプトの改善点などがあれば、ぜひ教えてください。
Wireshark は 2.2.5、tcpdump は 4.5.0 で、libpcap は 1.5.0 です。
答え1
ついに、本当に動作するようになりました。これは完璧な設定ではありませんが、少なくとも動作するので、将来誰かの役に立つかもしれません。
私はPythonスクリプトを使ってパイシリアルUART 経由で tcpdump を開始し、hexdump を使用してバイナリ データが tty 転写ルールによって変更されることなくリンクを通過できるようにします。次に、Python スクリプトがデータを変換し直し、wireshark にパイプします。以下のスクリプトは結果です。質問のスクリプトと比較して、-v
hexdump に同じ行を圧縮しないようにオプションを追加しました。
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))