From 071748d4ffc265be978501c8ee75466db98dfbf7 Mon Sep 17 00:00:00 2001 From: Alessandro Maggio Date: Sun, 9 Aug 2020 12:16:51 +0200 Subject: [PATCH 1/6] refactor: Update version patch number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 53633bd..54461ce 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ long_description = file.read() setup(name='pythonping', - version='1.0.10', + version='1.0.11', description='A simple way to ping in Python', url='https://github.com/alessandromaggio/pythonping', author='Alessandro Maggio', From 61ce6ed0fb1cbb2c629e1187a341dd27de6a6f29 Mon Sep 17 00:00:00 2001 From: Micah Albers Date: Mon, 10 Aug 2020 15:00:52 -0500 Subject: [PATCH 2/6] update documentation to reflect Union of string and bytes as payload input internally, correct bug in match code made from wrong assumptions based on previously misleading documentation --- pythonping/executor.py | 15 +++++++++------ pythonping/payload_provider.py | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pythonping/executor.py b/pythonping/executor.py index 545672d..2531404 100644 --- a/pythonping/executor.py +++ b/pythonping/executor.py @@ -252,14 +252,17 @@ def send_ping(self, packet_id, sequence_number, payload): :param packet_id: The ID to use for the packet :type packet_id: int - :param sequence_number: The seuqnce number to use for the packet + :param sequence_number: The sequence number to use for the packet :type sequence_number: int :param payload: The payload of the ICMP message - :type payload: bytes""" - self.socket.send(icmp.ICMP( + :type payload: Union[str, bytes] + :rtype: bytes""" + i = icmp.ICMP( icmp.Types.EchoRequest, payload=payload, - identifier=packet_id, sequence_number=sequence_number).packet) + identifier=packet_id, sequence_number=sequence_number) + self.socket.send(i.packet) + return i.payload def listen_for(self, packet_id, timeout, payload_pattern=None): """Listens for a packet of a given id for a given timeout @@ -313,10 +316,10 @@ def run(self, match_payloads=False): identifier = self.seed_id seq = 1 for payload in self.provider: - self.send_ping(identifier, seq, payload) + payload_bytes_sent = self.send_ping(identifier, seq, payload) if not match_payloads: self.responses.append(self.listen_for(identifier, self.timeout)) else: - self.responses.append(self.listen_for(identifier, self.timeout, payload)) + self.responses.append(self.listen_for(identifier, self.timeout, payload_bytes_sent)) seq = self.increase_seq(seq) diff --git a/pythonping/payload_provider.py b/pythonping/payload_provider.py index c456295..25fea77 100644 --- a/pythonping/payload_provider.py +++ b/pythonping/payload_provider.py @@ -38,7 +38,7 @@ def __init__(self, pattern, count): """Creates a provider of many identical payloads :param pattern: The existing payload - :type pattern: bytes + :type pattern: Union[str, bytes] :param count: How many payloads to generate :type count: int""" self.pattern = pattern @@ -61,7 +61,7 @@ def __init__(self, pattern, start_size, end_size): """Creates a provider of payloads of increasing size :param pattern: The existing payload, may be cut or replicated to fit the size - :type pattern: bytes + :type pattern: Union[str, bytes] :param start_size: The first payload size to start with, included :type start_size: int :param end_size: The payload size to end with, included From d3efdeec0f69ccf74703a8c5d9705735e5a7d6b1 Mon Sep 17 00:00:00 2001 From: Micah Albers Date: Wed, 12 Aug 2020 12:35:55 -0500 Subject: [PATCH 3/6] fix broken linux legacy match off case in threaded scenario --- pythonping/executor.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pythonping/executor.py b/pythonping/executor.py index 2531404..d95808e 100644 --- a/pythonping/executor.py +++ b/pythonping/executor.py @@ -283,15 +283,18 @@ def listen_for(self, packet_id, timeout, payload_pattern=None): # If we actually received something if raw_packet != b'': response.unpack(raw_packet) - # To allow Windows-like behaviour (no payload inspection, but only match packet identifiers), - # simply allow for it to be an always true in the legacy usage case - if payload_pattern is None: - payload_pattern = response.payload # Ensure we have not unpacked the packet we sent (RHEL will also listen to outgoing packets) - if (response.id == packet_id and response.message_type != icmp.Types.EchoRequest.type_id - and response.payload == payload_pattern): - return Response(Message('', response, source_socket[0]), timeout - time_left) + if response.id == packet_id and response.message_type != icmp.Types.EchoRequest.type_id: + if payload_pattern is None: + # To allow Windows-like behaviour (no payload inspection, but only match packet identifiers), + # simply allow for it to be an always true in the legacy usage case + payload_matched = True + else: + payload_matched = (payload_pattern == response.payload) + + if payload_matched: + return Response(Message('', response, source_socket[0]), timeout - time_left) return Response(None, timeout) @staticmethod From 6f6bc1fdbcc0da55acea3c4be3be3b57db5a3c1f Mon Sep 17 00:00:00 2001 From: Alessandro Maggio Date: Wed, 12 Aug 2020 20:43:15 +0200 Subject: [PATCH 4/6] refactor: Update version number --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 54461ce..7ed0b9a 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ long_description = file.read() setup(name='pythonping', - version='1.0.11', + version='1.0.12', description='A simple way to ping in Python', url='https://github.com/alessandromaggio/pythonping', author='Alessandro Maggio', From 956969785e8439f9c79707411488b26351bc41b2 Mon Sep 17 00:00:00 2001 From: Micah Albers Date: Mon, 24 Aug 2020 16:17:52 -0500 Subject: [PATCH 5/6] remove typing annotation for thread safe implementation of SEED_IDs to keep backwards compatibility with python 3.5 --- pythonping/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pythonping/__init__.py b/pythonping/__init__.py index 3fc40a0..5abd97d 100644 --- a/pythonping/__init__.py +++ b/pythonping/__init__.py @@ -2,11 +2,10 @@ from . import network, executor, payload_provider from .utils import random_text from random import randint -from typing import List -# this needs to be available across all thread usages -SEED_IDs: List[int] = [] +# this needs to be available across all thread usages and will hold ints +SEED_IDs = [] def ping(target, From 1088882ec656c1e3c501e06bf83951fb42fc8d0e Mon Sep 17 00:00:00 2001 From: Micah Albers Date: Mon, 24 Aug 2020 16:18:37 -0500 Subject: [PATCH 6/6] add ping match parameter documenation and expand advanced users section to explain thread safe necessity --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b2d5026..a6b7d2b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ Note that if you defined `size`, these two fields will be ignored * `verbose` enables the verbose mode, printing output to a stream (see `out`) * `out` is the target stream of verbose mode. If you enable the verbose mode and do not provide `out`, verbose output will be send to the `sys.stdout` stream. You may want to use a file here. +* `match` is a flag that, if set to True, will enable payload matching between a ping request +and reply (default behaviour follows that of Windows which counts a successful reply by a +matched packet identifier only; Linux behaviour counts a non equivalent payload with a matched +packet identifier in reply as fail, such as when pinging 8.8.8.8 with 1000 bytes and the reply +is truncated to only the first 74 of request payload with a matching packet identifier) ## FAQ ### Do I need privileged mode or root? @@ -59,8 +64,10 @@ to create custom IP packets. Unfortunately, there is simply no other way to crea If you wish to extend PythonPing, or integrate it in your application, we recommend to use the classes that are part of Python Ping instead of the `ping` function. `executor.Communicator` handles the communication with the target device, it takes care of sending ICMP requests and -processing responses. It ultimately produces the `executor.ResponseList` object. The `Communicator` -needs to know a target and which payloads to send to the remote device. For that, we have several -classes in the `payload_provider` module. You may want to create your own provider by extending +processing responses (note that for it to be thread safe you must then handle making a unique +seed ID for each thread instance, see ping.__init\__ for an example of this). It ultimately +produces the `executor.ResponseList` object. The `Communicator` needs to know a target and +which payloads to send to the remote device. For that, we have several classes in the +`payload_provider` module. You may want to create your own provider by extending `payload_provider.PayloadProvider`. If you are interested in that, you should check the documentation of both `executor` and `payload_provider` module.