Skip to content

Commit d065087

Browse files
authored
fix(transport): reject a bool port in TCP, UDP and SCTP make (#2287) (#2359)
Transport._make_port handed any non-AppType value to AppType.get, which looked a bool up as port 0 or 1, so UDP(srcport=True) packed port 1 and TCP(dstport=False) port 0. _make_port becomes a classmethod and raises ProtocolError "<Protocol>: invalid port: True" for a bool, which covers SCTP as well. Test: test_make_refuses_a_bool_port pins the message for True and False on either port of TCP, UDP and SCTP.
1 parent ef4d93f commit d065087

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

‎pcapkit/protocols/transport/transport.py‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from pcapkit.corekit.module import ModuleDescriptor
2020
from pcapkit.protocols.protocol import _PT, _ST, ProtocolBase
2121
from pcapkit.protocols.schema.schema import keep_short_read, replay_short_read
22-
from pcapkit.utilities.exceptions import StructError, UnsupportedCall, stacklevel
22+
from pcapkit.utilities.exceptions import ProtocolError, StructError, UnsupportedCall, stacklevel
2323
from pcapkit.utilities.logging import DEVMODE, get_logger
2424
from pcapkit.utilities.warnings import RegistryWarning, warn
2525

@@ -206,8 +206,8 @@ def __post_init__(self, file: 'Optional[IO[bytes] | bytes]' = None,
206206
# Utilities.
207207
##########################################################################
208208

209-
@staticmethod
210-
def _make_port(port: 'Enum_AppType | int',
209+
@classmethod
210+
def _make_port(cls, port: 'Enum_AppType | int',
211211
proto: 'Enum_TransportProtocol') -> 'Enum_AppType':
212212
"""Resolve a port number to its application type.
213213
@@ -219,6 +219,9 @@ def _make_port(port: 'Enum_AppType | int',
219219
Returns:
220220
The :class:`~pcapkit.const.reg.apptype.apptype.AppType` for ``port``.
221221
222+
Raises:
223+
ProtocolError: If ``port`` is a :obj:`bool` (:issue:`2287`).
224+
222225
Important:
223226
:meth:`self.make <pcapkit.protocols.protocol.Protocol.make>` accepts
224227
a bare :obj:`int` for a port, but the schema field converts it only
@@ -233,6 +236,10 @@ def _make_port(port: 'Enum_AppType | int',
233236
"""
234237
if isinstance(port, Enum_AppType):
235238
return port
239+
# NOTE: ``bool`` is an ``int`` subclass, so ``AppType.get`` would look
240+
# ``True``/``False`` up as port 1/0 rather than refuse them (#2287).
241+
if isinstance(port, bool):
242+
raise ProtocolError(f'{cls.__name__}: invalid port: {port!r}')
236243
return Enum_AppType.get(port, proto=proto)
237244

238245
def _decode_next_layer(self, dict_: '_PT', ports: 'tuple[int, int]', length: 'Optional[int]' = None, *, # type: ignore[override]

‎tests/protocols/transport/test_transport_unit.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,25 @@ def test_make_port_resolves_an_integer_and_passes_an_apptype_through(self) -> No
441441
# which would lose the protocol it was resolved for.
442442
self.assertIs(Transport._make_port(over_sctp, TransportProtocol.tcp), over_sctp)
443443

444+
def test_make_refuses_a_bool_port(self) -> None:
445+
# #2287: ``bool`` is an ``int`` subclass, so ``AppType.get`` resolving
446+
# ``True``/``False`` to port 1/0 is a defect this guards against.
447+
from pcapkit.protocols.transport.sctp import SCTP
448+
from pcapkit.protocols.transport.tcp import TCP
449+
from pcapkit.protocols.transport.udp import UDP
450+
from pcapkit.utilities.exceptions import ProtocolError
451+
452+
for cls in (TCP, UDP, SCTP):
453+
for value in (True, False):
454+
for kwargs in ({'srcport': value, 'dstport': 53}, {'srcport': 53, 'dstport': value}):
455+
with self.subTest(protocol=cls.__name__, **kwargs):
456+
with self.assertRaises(ProtocolError) as ctx:
457+
cls(**kwargs)
458+
self.assertEqual(str(ctx.exception), f'{cls.__name__}: invalid port: {value!r}')
459+
460+
# An ``int`` port resolves to its application type.
461+
self.assertEqual(UDP(srcport=1, dstport=53).info.srcport.port, 1)
462+
444463

445464
if __name__ == '__main__':
446465
unittest.main()

0 commit comments

Comments
 (0)