From cb1a23e1d501d3d1b1be7a7b6c3ac6363102580e Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:29:44 -0300 Subject: [PATCH 01/17] Changing print sintax to Python3 It makes sense, since Python2 is now deprecated. See: https://www.python.org/doc/sunset-python-2/ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 420a86a..40005b5 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,14 @@ s = # Parse the traceroute output traceroute = trparse.loads(s) # You can print the result -print traceroute +print(traceroute) # Save it as string tr_str = str(traceroute) # Or travel the tree hop = traceroute.hops[0] probe = hop.probes[0] # And print the IP address -print probe.ip +print(probe.ip) ``` # Data structures From ebd43f85cba409d0a97c12b0d0799ae04360b3e7 Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:32:51 -0300 Subject: [PATCH 02/17] Format header string using `format` Just to follow the pattern used in the project (there are lot's of other lines using `format`). --- trparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trparse.py b/trparse.py index 5eb380b..62da8f3 100644 --- a/trparse.py +++ b/trparse.py @@ -36,7 +36,7 @@ def add_hop(self, hop): self.hops.append(hop) def __str__(self): - text = "Traceroute for %s (%s)\n\n" % (self.dest_name, self.dest_ip) + text = "Traceroute for {} ({})\n\n".format(self.dest_name, self.dest_ip) for hop in self.hops: text += str(hop) return text From 07be3ffafe7f77554933bfdac3de7037b744c9a1 Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:53:20 -0300 Subject: [PATCH 03/17] Minor edit in README to improve consistency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40005b5..4c0130e 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ some tokens it expects to find in a specific format. For example: preceded by space characters). - **[AS\#]** must be surrounded by square brackets `[]` and start with `AS`. -- **Hostname** Can be a hostname or its IP address without parenthesis +- **Hostname** can be a hostname or its IP address without parenthesis. - **(IP address)** either IPv4 or IPv6 must surrounded by parenthesis `()`. - **RTT** must be in integer (without commas or dots) or float format From 85d1b97b44ba6858543578c8bed0ccf59dce6ca9 Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:54:38 -0300 Subject: [PATCH 04/17] Add syntax highlight in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c0130e..6f85674 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ Supports the following info. Parsed info in bold: # Usage -``` +```python import trparse -s = +s = "" # Parse the traceroute output traceroute = trparse.loads(s) # You can print the result From b4bb885d8ab63a539205c099a4360a9ca956cb4b Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:56:16 -0300 Subject: [PATCH 05/17] Update `idx` comment to reflect `traceroute -f` output A traceroute output can start from a hop number different from 1 (this happens when using `traceroute -f FIRST_TTL`). --- trparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trparse.py b/trparse.py index 62da8f3..5e88d7e 100644 --- a/trparse.py +++ b/trparse.py @@ -47,7 +47,7 @@ class Hop(object): Abstraction of a hop in a traceroute. """ def __init__(self, idx): - self.idx = idx # Hop count, starting at 1 + self.idx = idx # Hop count, starting at 1 (usually) self.probes = [] # Series of Probe instances def add_probe(self, probe): From b7f16e6cfb0a66fb147f1828e1352402442fe001 Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:58:56 -0300 Subject: [PATCH 06/17] Update README moving ASN to probe To be consistent with changes in v0.3.0. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f85674..eb4f383 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ Supports the following info. Parsed info in bold: - Hop - **Hop counter** - - **[AS\#]** - Probe + - **[AS\#]** - **Hostname** - **(IP address)** - **RTT** From b6d2776585c610d1c4de6f848463507572fa2908 Mon Sep 17 00:00:00 2001 From: Rarylson Freitas Date: Sun, 8 Mar 2020 11:59:51 -0300 Subject: [PATCH 07/17] Bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2950670..43b75f1 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ ] setup(name='trparse', - version='0.3.0', + version='0.3.1', description='Traceroute parser', author='Luis Benitez', url='https://github.com/lbenitez000/trparse', From f176c0dc2250e2e7cb0fc08d307913e102564120 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 21 Apr 2020 15:09:40 +0200 Subject: [PATCH 08/17] Add InvalidHeader exception --- trparse.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trparse.py b/trparse.py index 5eb380b..42cc681 100644 --- a/trparse.py +++ b/trparse.py @@ -104,6 +104,8 @@ def loads(data): # Get headers match_dest = RE_HEADER.search(lines[0]) + if not match_dest: + raise InvalidHeader dest_name = match_dest.group(1) dest_ip = match_dest.group(2) @@ -174,3 +176,6 @@ def load(data): class ParseError(Exception): pass + +class InvalidHeader(ParseError): + pass From df520fe9020ce52ce815437630ae8a33e3b03506 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 21 Apr 2020 21:45:04 +0200 Subject: [PATCH 09/17] Added Windows compatibility --- trparse.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/trparse.py b/trparse.py index 42cc681..45340eb 100644 --- a/trparse.py +++ b/trparse.py @@ -10,9 +10,14 @@ from decimal import Decimal -RE_HEADER = re.compile(r'(\S+)\s+\((?:(\d+\.\d+\.\d+\.\d+)|([0-9a-fA-F:]+))\)') +# Unix uses () for IPs whereas Windows uses [] +RE_HEADER = re.compile(r'(\S+)\s+(?:\(|\[)(?:(\d+\.\d+\.\d+\.\d+)|([0-9a-fA-F:]+))(?:\)|\])') + +# Again, we must search for () or [] here +RE_PROBE_NAME_IP = re.compile(r'(\S+)\s+(?:\(|\[)(?:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([0-9a-fA-F:]+))(?:\)|\])+') +# Fallback when no hostname present (also happens on windows) +RE_PROBE_IP_ONLY = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})+') -RE_PROBE_NAME_IP = re.compile(r'(\S+)\s+\((?:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([0-9a-fA-F:]+))\)+') RE_PROBE_ANNOTATION = re.compile(r'^(!\w*)$') RE_PROBE_TIMEOUT = re.compile(r'^(\*)$') @@ -142,8 +147,14 @@ def loads(data): probe_name = probe_name_ip_match.group(1) probe_ip = probe_name_ip_match.group(2) or probe_name_ip_match.group(3) else: - probe_name = None - probe_ip = None + # Let's try to only get IP (happens on windows) + probe_ip_match = RE_PROBE_IP_ONLY.search(hop_string) + if probe_ip_match: + probe_name = probe_ip_match.group(1) + probe_ip = probe_ip_match.group(1) + else: + probe_name = None + probe_ip = None probe_rtt_annotations = RE_PROBE_RTT_ANNOTATION.findall(hop_string) From ef46667c1796b28892381d1489b62a3be38691a2 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 21 Apr 2020 21:46:05 +0200 Subject: [PATCH 10/17] Fix error when hostname is not found --- trparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trparse.py b/trparse.py index 45340eb..4b8338a 100644 --- a/trparse.py +++ b/trparse.py @@ -93,7 +93,7 @@ def __str__(self): if self.asn is not None: text += "[AS{:d}] ".format(self.asn) if self.rtt: - text += "{:s} ({:s}) {:1.3f} ms".format(self.name, self.ip, self.rtt) + text += "{} ({}) {:1.3f} ms".format(self.name, self.ip, self.rtt) else: text = "*" if self.annotation: From 72396032dd0f5020eb3707b21ea7fc4b8061ba99 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 21 Apr 2020 22:05:58 +0200 Subject: [PATCH 11/17] Add windows self test case --- tests/data/windows_self.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/data/windows_self.txt diff --git a/tests/data/windows_self.txt b/tests/data/windows_self.txt new file mode 100644 index 0000000..6a6d56c --- /dev/null +++ b/tests/data/windows_self.txt @@ -0,0 +1,6 @@ +Détermination de l’itinéraire vers myhost [127.0.0.1] +avec un maximum de 30 sauts : + + 1 <1 ms <1 ms <1 ms myhost [127.0.0.1] + +Itinéraire déterminé. From 99845c01b3fb97be76f6714e5a8655057d9a7a46 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 21 Apr 2020 22:07:08 +0200 Subject: [PATCH 12/17] Add Windows french testcase --- tests/data/windows_fr.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/data/windows_fr.txt diff --git a/tests/data/windows_fr.txt b/tests/data/windows_fr.txt new file mode 100644 index 0000000..8a87987 --- /dev/null +++ b/tests/data/windows_fr.txt @@ -0,0 +1,16 @@ +Détermination de l’itinéraire vers google.fr [172.217.22.131] +avec un maximum de 30 sauts : + + 1 2 ms 2 ms 5 ms my.local.network.local [192.168.85.24] + 2 9 ms 6 ms 6 ms 192.168.12.254 + 3 21 ms 20 ms 22 ms i15-les02-th2-7-48-3-2.dsl.dyn.abo.bbox.fr [7.48.3.2] + 4 * 18 ms 17 ms 62.34.2.72 + 5 20 ms 19 ms 19 ms 62.34.2.76 + 6 27 ms 21 ms 19 ms lag24.rpt02-mrs.net.bbox.fr [212.194.170.56] + 7 28 ms 29 ms 29 ms 209.85.148.0 + 8 30 ms 30 ms 30 ms 74.125.244.211 + 9 32 ms 50 ms 30 ms 216.239.35.209 + 10 31 ms 31 ms 30 ms 108.170.233.115 + 11 31 ms 32 ms 30 ms 108.170.245.1 + 12 30 ms 30 ms 30 ms 66.249.95.247 + 13 30 ms 29 ms 30 ms par21s12-in-f3.1e100.net [172.217.22.131] From 02f7fa1aa767110069e3fbedd5954fb981de462a Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Wed, 22 Apr 2020 09:06:04 +0200 Subject: [PATCH 13/17] Remove empty lines from source --- trparse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trparse.py b/trparse.py index 4b8338a..1002589 100644 --- a/trparse.py +++ b/trparse.py @@ -105,7 +105,8 @@ def __str__(self): def loads(data): """Parser entry point. Parses the output of a traceroute execution""" - lines = data.splitlines() + # Remove empty lines + lines = [line for line in data.splitlines() if line != ""] # Get headers match_dest = RE_HEADER.search(lines[0]) From 4a0ea8651003bbea37769f287b283fd6b732ac7b Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Tue, 5 May 2020 20:14:09 +0200 Subject: [PATCH 14/17] Add traceroute.global_rtt property --- trparse.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trparse.py b/trparse.py index 1002589..3c7dc9f 100644 --- a/trparse.py +++ b/trparse.py @@ -36,10 +36,14 @@ def __init__(self, dest_name, dest_ip): self.dest_name = dest_name self.dest_ip = dest_ip self.hops = [] + self.global_rtt = None def add_hop(self, hop): self.hops.append(hop) + def update_global_rtt(self, rtt): + self.global_rtt = rtt + def __str__(self): text = "Traceroute for %s (%s)\n\n" % (self.dest_name, self.dest_ip) for hop in self.hops: @@ -178,6 +182,7 @@ def loads(data): annotation=probe_annotation ) hop.add_probe(probe) + traceroute.update_global_rtt(probe_rtt) return traceroute From 33b9f98dc89c48cbd54f533cd99858fd150f0773 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Mon, 30 May 2022 13:27:38 +0200 Subject: [PATCH 15/17] Update trparse header and bump version --- trparse.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/trparse.py b/trparse.py index 09c8028..2b553a9 100644 --- a/trparse.py +++ b/trparse.py @@ -1,13 +1,24 @@ -# -*- coding: utf-8 -*- +#! /usr/bin/env python +# -*- coding: utf-8 -*- """ -Copyright (C) 2015 Luis Benitez - +trparse 2015-2022 written by: + - Orsiris de Jong (@deajan) 2020-2022 +- Rarylson Freitas (@rarylson) 2018-2020 + - Luis Benitez (@lbenitez000) Copyright (C) 2015-2019 + Parses the output of a traceroute execution into an AST (Abstract Syntax Tree). """ -import re +__intname__ = "trparse" +__author__ = "Luis Benitez, Rarylson Freitas, Orsiris de Jong" +__copyright__ = "Copyright (C) 2014-2019 Luis Benitez" +__license__ = "MIT License" +__version__ = "0.4.0" +__build__ = "2022053001" + +import re from decimal import Decimal # Unix uses () for IPs whereas Windows uses [] From 2727db2d0eda6676c952772fe9a36b69e1f25021 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Mon, 30 May 2022 13:32:03 +0200 Subject: [PATCH 16/17] Update changelog --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index eb4f383..e0c425f 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,18 @@ work in a Widows system. Maybe in a future release. # Changelog +## v0.4.0 +1. Added Windows tracert compatibility +2. Fixed error when hostname not found +3. Added traceroute.global_rtt property +4. Remove empty lines from traceroutes +5. Added InvalidHeader exception when tracert/traceroute output is inconsistent +6. Improved test matrix + +## v0.3.1 +1. Add Python 3 compatibility +2. Update documentation + ## v0.3.0 1. Rebuilt the parsing function to support RTT, IP, Name and ASN in any order inside the hop/probe. 2. RTT values are now Decimal. From 31e81e524e10bc5eda86494c0d738b275f1758f9 Mon Sep 17 00:00:00 2001 From: Orsiris de Jong Date: Mon, 30 May 2022 13:38:52 +0200 Subject: [PATCH 17/17] Fixed author indent --- trparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trparse.py b/trparse.py index 2b553a9..59736ed 100644 --- a/trparse.py +++ b/trparse.py @@ -4,7 +4,7 @@ """ trparse 2015-2022 written by: - Orsiris de Jong (@deajan) 2020-2022 -- Rarylson Freitas (@rarylson) 2018-2020 + - Rarylson Freitas (@rarylson) 2018-2020 - Luis Benitez (@lbenitez000) Copyright (C) 2015-2019 Parses the output of a traceroute execution into an AST (Abstract Syntax Tree).