]> www.average.org Git - loctrkd.git/commitdiff
test: message fuzzer and fix found problems
authorEugene Crosser <crosser@average.org>
Fri, 17 Jun 2022 22:02:58 +0000 (00:02 +0200)
committerEugene Crosser <crosser@average.org>
Fri, 17 Jun 2022 22:02:58 +0000 (00:02 +0200)
gps303/collector.py
gps303/gps303proto.py
test/test_fuzz.py

index ef80cc534c0a9683f5219fc676fddb0bd0708d69..36a5f8a8efd9455b047da437ed60fbfe1c9853a3 100644 (file)
@@ -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,
             )
index 2a4ae2ce93b8fe25bf11111c5f73b42505948ce7..2d777d94fa5bfbec0b4c4b15192a0a56f9427954 100755 (executable)
@@ -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)
index d937c95a3dd216a064e2718ce38dbdf68b391b23..0456fda0352ddede2b315fb351bf431b500929ba 100644 (file)
@@ -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__":