mirror of
https://github.com/jlu5/SupyPlugins.git
synced 2025-05-06 11:33:41 -05:00
BirdLGGo: support optionally printing trace hop PTR
This commit is contained in:
parent
ebcbf5a92d
commit
f6932586fa
@ -47,11 +47,15 @@ def configure(advanced):
|
|||||||
conf.registerPlugin('BirdLGGo', True)
|
conf.registerPlugin('BirdLGGo', True)
|
||||||
|
|
||||||
|
|
||||||
|
class _traceHopFormat(registry.OnlySomeStrings):
|
||||||
|
validStrings = ('ip', 'ptr', 'both')
|
||||||
|
|
||||||
BirdLGGo = conf.registerPlugin('BirdLGGo')
|
BirdLGGo = conf.registerPlugin('BirdLGGo')
|
||||||
conf.registerChannelValue(BirdLGGo, 'lgServer',
|
conf.registerChannelValue(BirdLGGo, 'lgServer',
|
||||||
registry.String("", _("""Looking glass server to query, including the scheme (http(s)://)""")))
|
registry.String("", _("""Looking glass server to query, including the scheme (http(s)://).""")))
|
||||||
conf.registerChannelValue(BirdLGGo, 'nodes',
|
conf.registerChannelValue(BirdLGGo, 'nodes',
|
||||||
registry.SpaceSeparatedListOfStrings([], _("""List of nodes to query (space separated list)""")))
|
registry.SpaceSeparatedListOfStrings([], _("""List of nodes to query (space separated list).""")))
|
||||||
|
conf.registerChannelValue(BirdLGGo, 'traceHopFormat',
|
||||||
|
_traceHopFormat(_traceHopFormat.validStrings[0], _("""Whether the plugin should show IPs, reverse DNS (PTR records), or both for each hop in a traceroute.""")))
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=120:
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=120:
|
||||||
|
@ -5,9 +5,14 @@ import subprocess
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TraceHop:
|
||||||
|
ip: str
|
||||||
|
ptr: str
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TraceResult:
|
class TraceResult:
|
||||||
ips: List[str]
|
hops: List[TraceHop]
|
||||||
latency: str = field(default=None)
|
latency: str = field(default=None)
|
||||||
notes: List[str] = field(default_factory=list)
|
notes: List[str] = field(default_factory=list)
|
||||||
|
|
||||||
@ -16,14 +21,14 @@ class TraceParseError(ValueError):
|
|||||||
|
|
||||||
# bird-lg-go enables DNS lookups and sends one query by default, but we should be a bit more flexible with what we accept
|
# bird-lg-go enables DNS lookups and sends one query by default, but we should be a bit more flexible with what we accept
|
||||||
# This will grab IPs from whichever format is used, and report the first latency / error code of the last line if there are multiple queries
|
# This will grab IPs from whichever format is used, and report the first latency / error code of the last line if there are multiple queries
|
||||||
_TRACEROUTE_RE = re.compile(r'\s*\d+\s+(?P<line>(?:[^() ]+ \((?P<IPdns>[0-9a-fA-F.:]+)\)|(?P<IPbare>[0-9a-fA-F.:]+)).*? (?P<latency>[0-9.]+ ms( \![A-Za-z0-9]+)?)|\*)')
|
_TRACEROUTE_RE = re.compile(r'\s*\d+\s+(?P<line>(?:(?P<ptr>[^() ]+) \((?P<IPdns>[0-9a-fA-F.:]+)\)|(?P<IPbare>[0-9a-fA-F.:]+)).*? (?P<latency>[0-9.]+ ms( \![A-Za-z0-9]+)?)|\*)')
|
||||||
def parse_traceroute(text):
|
def parse_traceroute(text):
|
||||||
lines = text.strip().splitlines()
|
lines = text.strip().splitlines()
|
||||||
if len(lines) < 2 or not lines[1].lstrip().startswith("1"):
|
if len(lines) < 2 or not lines[1].lstrip().startswith("1"):
|
||||||
# Assume error condition if 2nd line doesn't start with "1" (first hop)
|
# Assume error condition if 2nd line doesn't start with "1" (first hop)
|
||||||
raise TraceParseError(' '.join(lines) or "traceroute returned empty output")
|
raise TraceParseError(' '.join(lines) or "traceroute returned empty output")
|
||||||
else:
|
else:
|
||||||
ips = []
|
hops = []
|
||||||
notes = []
|
notes = []
|
||||||
latency = None
|
latency = None
|
||||||
for line in lines[1:]:
|
for line in lines[1:]:
|
||||||
@ -33,14 +38,16 @@ def parse_traceroute(text):
|
|||||||
if not m:
|
if not m:
|
||||||
notes.append(line)
|
notes.append(line)
|
||||||
continue
|
continue
|
||||||
ips.append(m.group("IPdns") or m.group("IPbare") or m.group("line"))
|
ip = m.group("IPdns") or m.group("IPbare") or m.group("line")
|
||||||
|
ptr = m.group("ptr") or ip
|
||||||
|
hops.append(TraceHop(ip, ptr))
|
||||||
latency = m.group("latency")
|
latency = m.group("latency")
|
||||||
|
|
||||||
# bird-lg-go specific truncation
|
# bird-lg-go specific truncation
|
||||||
if "hops not responding" in ''.join(notes):
|
if "hops not responding" in ''.join(notes):
|
||||||
latency = None
|
latency = None
|
||||||
|
|
||||||
return TraceResult(ips, latency, notes)
|
return TraceResult(hops, latency, notes)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
proc = subprocess.run(['traceroute', *sys.argv[1:]], encoding='utf-8', stdout=subprocess.PIPE)
|
proc = subprocess.run(['traceroute', *sys.argv[1:]], encoding='utf-8', stdout=subprocess.PIPE)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
from pprint import pprint
|
||||||
import unittest
|
import unittest
|
||||||
from parsetrace import parse_traceroute, TraceResult
|
from parsetrace import parse_traceroute, TraceResult, TraceHop
|
||||||
|
|
||||||
|
def _bareip(ip: str):
|
||||||
|
return TraceHop(ip=ip, ptr=ip)
|
||||||
|
|
||||||
class ParseTraceTestCase(unittest.TestCase):
|
class ParseTraceTestCase(unittest.TestCase):
|
||||||
maxDiff = None
|
maxDiff = None
|
||||||
@ -14,14 +18,14 @@ class ParseTraceTestCase(unittest.TestCase):
|
|||||||
6 2001:4860:0:1::5737 (2001:4860:0:1::5737) 0.870 ms
|
6 2001:4860:0:1::5737 (2001:4860:0:1::5737) 0.870 ms
|
||||||
7 ord37s33-in-x0e.1e100.net (2607:f8b0:4009:809::200e) 46.306 ms
|
7 ord37s33-in-x0e.1e100.net (2607:f8b0:4009:809::200e) 46.306 ms
|
||||||
"""
|
"""
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
"2605:4840:3::1",
|
_bareip("2605:4840:3::1"),
|
||||||
"2604:6600:2700:11::1",
|
_bareip("2604:6600:2700:11::1"),
|
||||||
"2001:418:0:5000::ec0",
|
TraceHop("2001:418:0:5000::ec0", "ce-0-7-0-2.r07.chcgil09.us.bb.gin.ntt.net"),
|
||||||
"2001:504:0:4:0:1:5169:1",
|
TraceHop("2001:504:0:4:0:1:5169:1", "eqix-ch-200g-1.google.com"),
|
||||||
"*",
|
_bareip("*"),
|
||||||
"2001:4860:0:1::5737",
|
_bareip("2001:4860:0:1::5737"),
|
||||||
"2607:f8b0:4009:809::200e"
|
TraceHop("2607:f8b0:4009:809::200e", "ord37s33-in-x0e.1e100.net")
|
||||||
], latency="46.306 ms"), parse_traceroute(s))
|
], latency="46.306 ms"), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteMultiQuery(self):
|
def testTracerouteMultiQuery(self):
|
||||||
@ -32,12 +36,12 @@ class ParseTraceTestCase(unittest.TestCase):
|
|||||||
4 cloudflare.slix.net (149.112.13.27) 9.057 ms 9.060 ms 9.504 ms
|
4 cloudflare.slix.net (149.112.13.27) 9.057 ms 9.060 ms 9.504 ms
|
||||||
5 one.one.one.one (1.1.1.1) 8.567 ms 8.688 ms 8.764 ms
|
5 one.one.one.one (1.1.1.1) 8.567 ms 8.688 ms 8.764 ms
|
||||||
"""
|
"""
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'205.185.112.1',
|
_bareip('205.185.112.1'),
|
||||||
'172.18.0.29',
|
_bareip('172.18.0.29'),
|
||||||
'184.104.194.81',
|
TraceHop('184.104.194.81', '100ge3-2.core1.slc1.he.net'),
|
||||||
'149.112.13.27',
|
TraceHop('149.112.13.27', 'cloudflare.slix.net'),
|
||||||
'1.1.1.1'
|
TraceHop('1.1.1.1', 'one.one.one.one')
|
||||||
], latency="8.567 ms"), parse_traceroute(s))
|
], latency="8.567 ms"), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteMultiQueryDifferentPaths(self):
|
def testTracerouteMultiQueryDifferentPaths(self):
|
||||||
@ -56,20 +60,21 @@ class ParseTraceTestCase(unittest.TestCase):
|
|||||||
12 142.250.210.209 (142.250.210.209) 3.812 ms 108.170.252.18 (108.170.252.18) 3.763 ms 142.250.210.209 (142.250.210.209) 3.685 ms
|
12 142.250.210.209 (142.250.210.209) 3.812 ms 108.170.252.18 (108.170.252.18) 3.763 ms 142.250.210.209 (142.250.210.209) 3.685 ms
|
||||||
13 fra16s51-in-f14.1e100.net (142.250.185.174) 3.895 ms 3.871 ms 3.945 ms
|
13 fra16s51-in-f14.1e100.net (142.250.185.174) 3.895 ms 3.871 ms 3.945 ms
|
||||||
"""
|
"""
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'172.31.1.1',
|
TraceHop(ip='172.31.1.1', ptr='172.31.1.1'),
|
||||||
'49.12.142.82',
|
TraceHop(ip='49.12.142.82', ptr='17476.your-cloud.host'),
|
||||||
'*',
|
TraceHop(ip='*', ptr='*'),
|
||||||
'78.47.3.237',
|
TraceHop(ip='78.47.3.237', ptr='static.237.3.47.78.clients.your-server.de'),
|
||||||
'85.10.239.169',
|
TraceHop(ip='85.10.239.169', ptr='static.85.10.239.169.clients.your-server.de'),
|
||||||
'85.10.228.85',
|
TraceHop(ip='85.10.228.85', ptr='static.85-10-228-85.clients.your-server.de'),
|
||||||
'213.239.245.250',
|
TraceHop(ip='213.239.245.250', ptr='core1.fra.hetzner.com'),
|
||||||
'213.239.224.217',
|
TraceHop(ip='213.239.224.217', ptr='core8.fra.hetzner.com'),
|
||||||
'142.250.169.172',
|
TraceHop(ip='142.250.169.172', ptr='142.250.169.172'),
|
||||||
'*',
|
TraceHop(ip='*', ptr='*'),
|
||||||
'142.250.226.148',
|
TraceHop(ip='142.250.226.148', ptr='142.250.226.148'),
|
||||||
'142.250.210.209',
|
TraceHop(ip='142.250.210.209', ptr='142.250.210.209'),
|
||||||
'142.250.185.174'], latency="3.895 ms"), parse_traceroute(s))
|
TraceHop(ip='142.250.185.174', ptr='fra16s51-in-f14.1e100.net')],
|
||||||
|
latency='3.895 ms'), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteTimedOut(self):
|
def testTracerouteTimedOut(self):
|
||||||
s = """
|
s = """
|
||||||
@ -105,15 +110,16 @@ traceroute to azure.microsoft.com (13.107.42.16), 30 hops max, 60 byte packets
|
|||||||
29 * * *
|
29 * * *
|
||||||
30 * * *
|
30 * * *
|
||||||
"""
|
"""
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'172.31.1.1',
|
TraceHop(ip='172.31.1.1', ptr='172.31.1.1'),
|
||||||
'49.12.142.82',
|
TraceHop(ip='49.12.142.82', ptr='17476.your-cloud.host'),
|
||||||
'*',
|
TraceHop(ip='*', ptr='*'),
|
||||||
'78.47.3.237',
|
TraceHop(ip='78.47.3.237', ptr='static.237.3.47.78.clients.your-server.de'),
|
||||||
'85.10.248.221',
|
TraceHop(ip='85.10.248.221', ptr='static.85.10.248.221.clients.your-server.de'),
|
||||||
'213.239.208.221',
|
TraceHop(ip='213.239.208.221', ptr='core11.nbg1.hetzner.com'),
|
||||||
'213.239.224.238',
|
TraceHop(ip='213.239.224.238', ptr='core5.fra.hetzner.com'),
|
||||||
'104.44.37.193'] + ["*"]*(30-9+1)), parse_traceroute(s))
|
TraceHop(ip='104.44.37.193', ptr='ae72-0.fra-96cbe-1b.ntwk.msn.net')] +
|
||||||
|
[_bareip("*")]*(30-9+1)), parse_traceroute(s))
|
||||||
|
|
||||||
|
|
||||||
def testTracerouteTimedOutTruncated(self):
|
def testTracerouteTimedOutTruncated(self):
|
||||||
@ -131,14 +137,15 @@ traceroute to azure.microsoft.com (13.107.42.16), 30 hops max, 60 byte packets
|
|||||||
23 hops not responding.
|
23 hops not responding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'172.31.1.1',
|
TraceHop(ip='172.31.1.1', ptr='172.31.1.1'),
|
||||||
'49.12.142.82',
|
TraceHop(ip='49.12.142.82', ptr='17476.your-cloud.host'),
|
||||||
'78.47.3.237',
|
TraceHop(ip='78.47.3.237', ptr='static.237.3.47.78.clients.your-server.de'),
|
||||||
'85.10.248.217',
|
TraceHop(ip='85.10.248.217', ptr='static.85.10.248.217.clients.your-server.de'),
|
||||||
'85.10.250.209',
|
TraceHop(ip='85.10.250.209', ptr='core11.nbg1.hetzner.com'),
|
||||||
'213.239.245.254',
|
TraceHop(ip='213.239.245.254', ptr='core1.fra.hetzner.com'),
|
||||||
'104.44.197.103'], notes=["23 hops not responding."]), parse_traceroute(s))
|
TraceHop(ip='104.44.197.103', ptr='hetzner.fra-96cbe-1a.ntwk.msn.net')],
|
||||||
|
notes=["23 hops not responding."]), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteNoDNS(self):
|
def testTracerouteNoDNS(self):
|
||||||
s = """
|
s = """
|
||||||
@ -152,15 +159,15 @@ traceroute to irc.hackint.dn42 (172.20.66.67), 30 hops max, 60 byte packets
|
|||||||
7 172.23.96.1 165.631 ms 182.696 ms 182.695 ms
|
7 172.23.96.1 165.631 ms 182.696 ms 182.695 ms
|
||||||
8 172.20.66.67 182.695 ms 167.117 ms 187.094 ms"""
|
8 172.20.66.67 182.695 ms 167.117 ms 187.094 ms"""
|
||||||
|
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'172.20.229.114',
|
_bareip('172.20.229.114'),
|
||||||
'172.20.229.113',
|
_bareip('172.20.229.113'),
|
||||||
'172.20.229.123',
|
_bareip('172.20.229.123'),
|
||||||
'*',
|
_bareip('*'),
|
||||||
'*',
|
_bareip('*'),
|
||||||
'172.20.129.169',
|
_bareip('172.20.129.169'),
|
||||||
'172.23.96.1',
|
_bareip('172.23.96.1'),
|
||||||
'172.20.66.67'], latency="182.695 ms"), parse_traceroute(s))
|
_bareip('172.20.66.67')], latency="182.695 ms"), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteNoDNSv6(self):
|
def testTracerouteNoDNSv6(self):
|
||||||
s = """traceroute to map.dn42 (fd42:4242:2189:e9::1), 30 hops max, 80 byte packets
|
s = """traceroute to map.dn42 (fd42:4242:2189:e9::1), 30 hops max, 80 byte packets
|
||||||
@ -170,19 +177,19 @@ traceroute to irc.hackint.dn42 (172.20.66.67), 30 hops max, 60 byte packets
|
|||||||
4 fd42:4242:2189:e9::1 208.400 ms 208.398 ms 208.543 ms
|
4 fd42:4242:2189:e9::1 208.400 ms 208.398 ms 208.543 ms
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'fd86:bad:11b7:34::1',
|
_bareip('fd86:bad:11b7:34::1'),
|
||||||
'fd86:bad:11b7:22::1',
|
_bareip('fd86:bad:11b7:22::1'),
|
||||||
'fd42:4242:2189:ef::1',
|
_bareip('fd42:4242:2189:ef::1'),
|
||||||
'fd42:4242:2189:e9::1'], latency="208.400 ms"), parse_traceroute(s))
|
_bareip('fd42:4242:2189:e9::1')], latency="208.400 ms"), parse_traceroute(s))
|
||||||
|
|
||||||
def testTracerouteError(self):
|
def testTracerouteError(self):
|
||||||
s = """traceroute to 192.168.123.123 (192.168.123.123), 30 hops max, 60 byte packets
|
s = """traceroute to 192.168.123.123 (192.168.123.123), 30 hops max, 60 byte packets
|
||||||
1 192.168.123.1 (192.168.123.1) 3079.329 ms !H 3079.304 ms !H 3079.299 ms !H
|
1 192.168.123.1 (192.168.123.1) 3079.329 ms !H 3079.304 ms !H 3079.299 ms !H
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.assertEqual(TraceResult(ips=[
|
self.assertEqual(TraceResult(hops=[
|
||||||
'192.168.123.1'], latency="3079.329 ms !H"), parse_traceroute(s))
|
_bareip('192.168.123.1')], latency="3079.329 ms !H"), parse_traceroute(s))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -65,6 +65,7 @@ class BirdLGGo(callbacks.Plugin):
|
|||||||
else:
|
else:
|
||||||
return resp["result"]
|
return resp["result"]
|
||||||
|
|
||||||
|
|
||||||
@wrap(['something'])
|
@wrap(['something'])
|
||||||
def traceroute(self, irc, msg, args, target):
|
def traceroute(self, irc, msg, args, target):
|
||||||
"""<target>
|
"""<target>
|
||||||
@ -78,18 +79,28 @@ class BirdLGGo(callbacks.Plugin):
|
|||||||
"args": target
|
"args": target
|
||||||
}
|
}
|
||||||
results = self.lg_post_request(irc, msg, query)
|
results = self.lg_post_request(irc, msg, query)
|
||||||
|
hop_display_mode = self.registryValue("traceHopFormat", network=irc.network, channel=msg.channel)
|
||||||
|
|
||||||
|
def _format_tracehop(hop):
|
||||||
|
if hop_display_mode == 'ip' or hop.ip == hop.ptr:
|
||||||
|
return hop.ip
|
||||||
|
elif hop_display_mode == 'ptr':
|
||||||
|
return hop.ptr
|
||||||
|
elif hop_display_mode == 'both':
|
||||||
|
return f'{hop.ptr}[{hop.ip}]'
|
||||||
|
irc.error("Unknown traceHopFormat setting %r" % hop_display_mode)
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
parsed_result = parsetrace.parse_traceroute(result["data"])
|
parsed_result = parsetrace.parse_traceroute(result["data"])
|
||||||
server = result["server"]
|
server = result["server"]
|
||||||
|
|
||||||
ips = " ".join(parsed_result.ips)
|
hops = " ".join(map(_format_tracehop, parsed_result.hops))
|
||||||
latency = parsed_result.latency or "(timed out)"
|
latency = parsed_result.latency or "(timed out)"
|
||||||
notes = ""
|
notes = ""
|
||||||
if parsed_result.notes:
|
if parsed_result.notes:
|
||||||
notes = "- " + ", ".join(parsed_result.notes)
|
notes = "- " + ", ".join(parsed_result.notes)
|
||||||
|
|
||||||
irc.reply(f"{server} -> {target}: {latency} | {ips} {notes}")
|
irc.reply(f"{server} -> {target}: {latency} | {hops} {notes}")
|
||||||
|
|
||||||
@wrap(['something'])
|
@wrap(['something'])
|
||||||
def showroute(self, irc, msg, args, target):
|
def showroute(self, irc, msg, args, target):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user