From: Eugene Crosser Date: Fri, 17 Jun 2022 22:02:58 +0000 (+0200) Subject: test: message fuzzer and fix found problems X-Git-Tag: 0.99~10 X-Git-Url: http://www.average.org/gitweb/?p=loctrkd.git;a=commitdiff_plain;h=f075dbd6eea0e7326d68fd15a103d668baf67c10 test: message fuzzer and fix found problems --- diff --git a/gps303/collector.py b/gps303/collector.py index ef80cc5..36a5f8a 100644 --- a/gps303/collector.py +++ b/gps303/collector.py @@ -105,11 +105,18 @@ class Client: break packet = self.buffer[2:frameend] self.buffer = self.buffer[frameend + 2 :] + if len(packet) < 2: # frameend comes too early + log.warning("Packet too short: %s", packet) + break if proto_of_message(packet) == LOGIN.PROTO: - self.imei = parse_message(packet).imei - log.info( - "LOGIN from fd %d (IMEI %s)", self.sock.fileno(), self.imei - ) + msg = parse_message(packet) + if isinstance(msg, LOGIN): # Can be unparseable + self.imei = msg.imei + log.info( + "LOGIN from fd %d (IMEI %s)", + self.sock.fileno(), + self.imei, + ) msgs.append((when, self.addr, packet)) return msgs @@ -119,7 +126,7 @@ class Client: except OSError as e: log.error( "Sending to fd %d (IMEI %s): %s", - self.sock.fileno, + self.sock.fileno(), self.imei, e, ) diff --git a/gps303/gps303proto.py b/gps303/gps303proto.py index 2a4ae2c..2d777d9 100755 --- a/gps303/gps303proto.py +++ b/gps303/gps303proto.py @@ -313,8 +313,8 @@ class LOGIN(GPS303Pkt): # Default response for ACK, can also respond with STOP_UPLOAD def in_decode(self, length: int, payload: bytes) -> None: - self.imei = payload[:-1].hex() - self.ver = unpack("B", payload[-1:])[0] + self.imei = payload[:16].hex() + self.ver = payload[16] class SUPERVISION(GPS303Pkt): @@ -763,7 +763,7 @@ def parse_message(packet: bytes, is_incoming: bool = True) -> GPS303Pkt: length, proto = unpack("BB", packet[:2]) payload = packet[2:] if proto not in CLASSES: - cause: Union[DecodeError, ValueError] = ValueError( + cause: Union[DecodeError, ValueError, IndexError] = ValueError( f"Proto {proto} is unknown" ) else: @@ -772,7 +772,7 @@ def parse_message(packet: bytes, is_incoming: bool = True) -> GPS303Pkt: return CLASSES[proto].In(length, payload) else: return CLASSES[proto].Out(length, payload) - except DecodeError as e: + except (DecodeError, ValueError, IndexError) as e: cause = e if is_incoming: retobj = UNKNOWN.In(length, payload) diff --git a/test/test_fuzz.py b/test/test_fuzz.py index d937c95..0456fda 100644 --- a/test/test_fuzz.py +++ b/test/test_fuzz.py @@ -2,6 +2,8 @@ from random import Random from socket import getaddrinfo, socket, AF_INET6, MSG_DONTWAIT, SOCK_STREAM +from time import sleep +from typing import Optional import unittest from .common import TestWithServers @@ -23,19 +25,31 @@ class Fuzz(TestWithServers): self.sock.connect(skadr) def tearDown(self) -> None: + sleep(1) # give collector some time + self._send_and_drain(None) self.sock.close() print("finished fuzzing") super().tearDown() - def test_fuzz(self) -> None: + def _send_and_drain(self, buf: Optional[bytes]) -> None: + if buf is not None: + self.sock.send(buf) + try: + self.sock.recv(4096, MSG_DONTWAIT) + except BlockingIOError: + pass + + def test_stream(self) -> None: for _ in range(REPEAT): size = self.rnd.randint(1, 5000) buf = self.rnd.randbytes(size) - self.sock.send(buf) - try: - self.sock.recv(4096, MSG_DONTWAIT) - except BlockingIOError: - pass + self._send_and_drain(buf) + + def test_msgs(self) -> None: + for _ in range(REPEAT): + size = self.rnd.randint(0, 300) + buf = b"xx" + self.rnd.randbytes(size) + b"\r\n" + self._send_and_drain(buf) if __name__ == "__main__":