I’m working on gathering a data stream from CAN (python-can
) and sending over TCP. I have a listener class that serializes the data using pickle
.
class Sender(MessageWriter):
def __init__(
self,
file: Optional[TextIO] = None,
l = None,
):
self.l = l
super().__init__(file, l)
def on_message_received(self, msg: Message) -> None:
self.l.sendline(pickle.dumps(msg))
main
sets up a notifier for the listener, and simply repeats the incoming data class to the listener.
from pwn import listen
def main():
with can.Bus() as bus:
l = listen(PORT)
_ = l.wait_for_connection()
echoListener = Echoer()
sendListener = Sender()
sendListener.l = l
can.Notifier(bus, [echoListener, sendListener])
input('Press enter to exit.')
echoListener.stop()
sendListener.stop()
The other end simply connects to the previous application and echos to stdout after deserializing what it receives.
from pwn import remote
from binascii import hexlify
from pickle import loads
from can import message
r = remote(HOST, PORT)
while True:
m = r.recvline()
msg = loads(m)
print(f'{msg.channel} {msg.arbitration_id} [{len(msg.data)}] {hexlify(msg.data, " ").decode()}')
pwn
was simply used because I’m more familiar with it than I am with python sockets. And maybe pickle
isn’t the best choice here. It doesn’t handle chunking data. I’m not against forgoing the use of either library for something more appropriate.
Client side echoing script
./echoclient.py
[+] Opening connection to HOST on port PORT: Done
can0 1025 [8] fe 01 04 02 01 36 1a 01
...
can0 978 [4] ff ff ff 00
Traceback (most recent call last):
File "/home/user/dev/./echoclient.py", line 11, in <module>
msg = loads(m)
^^^^^^^^
_pickle.UnpicklingError: pickle data was truncated
Sender
./piside.py
[+] Trying to bind to :: on port PORT: Done
[+] Waiting for connections on :::PORT: Got connection from ::ffff:HOST on port xPORT
can0 401 [8] fe 01 04 02 01 36 1a 01
...
can0 2fa [8] 00 01 00 08 10 c8 10 00
Exception in thread can.notifier for bus "socketcan channel 'can0'":
Traceback (most recent call last):
File "/home/user/.local/lib/python3.9/site-packages/pwnlib/tubes/sock.py", line 65, in send_raw
self.sock.sendall(data)
ConnectionResetError: [Errno 104] Connection reset by peer
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/home/user/.local/lib/python3.9/site-packages/can/notifier.py", line 126, in _rx_thread
handle_message(msg)
File "/home/user/.local/lib/python3.9/site-packages/can/notifier.py", line 146, in _on_message_received
res = callback(msg)
File "/home/user/.local/lib/python3.9/site-packages/can/listener.py", line 43, in __call__
self.on_message_received(msg)
File "/home/user/dev/pican/./piside.py", line 42, in on_message_received
self.l.sendline(pickle.dumps(msg))
File "/home/user/.local/lib/python3.9/site-packages/pwnlib/tubes/tube.py", line 817, in sendline
self.send(line + self.newline)
File "/home/user/.local/lib/python3.9/site-packages/pwnlib/tubes/tube.py", line 796, in send
self.send_raw(data)
File "/home/user/.local/lib/python3.9/site-packages/pwnlib/tubes/sock.py", line 70, in send_raw
raise EOFError
EOFError
So how do I either handle chunking the data for pickle, or what would be the better alternative method for streaming binary data classes? The messages that are being serialized and deserialized are classed objects. Each message should not be longer than a few bytes each. data
is 8 bytes, arbitration_id is 2 bytes, a few other parameters, and the overhead data.
python-can
message
reference: https://python-can.readthedocs.io/en/stable/message.html