From c930b160c4783c1f5032a0eda5a3312eb2e24e9d Mon Sep 17 00:00:00 2001 From: gpotter2 <gabriel@potter.fr> Date: Fri, 7 Apr 2017 23:13:22 +0200 Subject: [PATCH] Prettify routes --- scapy/route.py | 13 +++------ scapy/route6.py | 16 +++-------- scapy/utils.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/scapy/route.py b/scapy/route.py index 8a2495ed..0a88a232 100644 --- a/scapy/route.py +++ b/scapy/route.py @@ -9,7 +9,7 @@ Routing and handling of network interfaces. import socket from scapy.consts import LOOPBACK_NAME, getLoopbackInterface -from scapy.utils import atol, ltoa, itom +from scapy.utils import atol, ltoa, itom, pretty_routes from scapy.config import conf from scapy.error import Scapy_Exception, warning from scapy.arch import WINDOWS @@ -41,15 +41,8 @@ class Route: (iface.name if not isinstance(iface, basestring) else iface), addr)) - # Sort correctly - rtlst.sort(key=lambda x: x[0]) - # Append tag - rtlst = [("Network", "Netmask", "Gateway", "Iface", "Output IP")] + rtlst - - colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) - fmt = " ".join(map(lambda x: "%%-%ds"%x, colwidth)) - rt = "\n".join(map(lambda x: fmt % x, rtlst)) - return rt + return pretty_routes(rtlst, + [("Network", "Netmask", "Gateway", "Iface", "Output IP")]) def make_route(self, host=None, net=None, gw=None, dev=None): from scapy.arch import get_if_addr diff --git a/scapy/route6.py b/scapy/route6.py index 7c88d6d5..f171b227 100644 --- a/scapy/route6.py +++ b/scapy/route6.py @@ -50,19 +50,11 @@ class Route6: rtlst = [] for net,msk,gw,iface,cset in self.routes: - rtlst.append(('%s/%i'% (net,msk), gw, (iface if isinstance(iface, basestring) else iface.name), ", ".join(cset))) - - # Sort correctly - rtlst.sort(key=lambda x: x[0]) - # Append tag - rtlst = [('Destination', 'Next Hop', "iface", "src candidates")] + rtlst - - colwidth = [max([len(y) for y in x]) for x in zip(*rtlst)] - fmt = " ".join(["%%-%ds"%x for x in colwidth]) - rt = "\n".join([fmt % x for x in rtlst]) - - return rt + rtlst.append(('%s/%i'% (net,msk), gw, (iface if isinstance(iface, basestring) else iface.name), ", ".join(cset) if len(cset) > 0 else "")) + return pretty_routes(rtlst, + [('Destination', 'Next Hop', "Iface", "Src candidates")], + sortBy = 1) # Unlike Scapy's Route.make_route() function, we do not have 'host' and 'net' # parameters. We only have a 'dst' parameter that accepts 'prefix' and diff --git a/scapy/utils.py b/scapy/utils.py index e597c172..c221ad02 100644 --- a/scapy/utils.py +++ b/scapy/utils.py @@ -1232,6 +1232,78 @@ def hexedit(x): os.unlink(f) return x +def get_terminal_width(): + """Get terminal width if in a window""" + if WINDOWS: + from ctypes import windll, create_string_buffer + # http://code.activestate.com/recipes/440694-determine-size-of-console-window-on-windows/ + h = windll.kernel32.GetStdHandle(-12) + csbi = create_string_buffer(22) + res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) + if res: + import struct + (bufx, bufy, curx, cury, wattr, + left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) + sizex = right - left + 1 + #sizey = bottom - top + 1 + return sizex + else: + return None + else: + sizex = 0 + try: + import struct, fcntl, termios + s = struct.pack('HHHH', 0, 0, 0, 0) + x = fcntl.ioctl(1, termios.TIOCGWINSZ, s) + sizex = struct.unpack('HHHH', x)[1] + except IOError: + pass + if not sizex: + try: + sizex = int(os.environ['COLUMNS']) + except: + pass + if sizex: + return sizex + else: + return None + +def pretty_routes(rtlst, header, sortBy=0): + """Pretty route list, and add header""" + _l_header = len(header[0]) + _space = " " + # Sort correctly + rtlst.sort(key=lambda x: x[sortBy]) + # Append tag + rtlst = header + rtlst + # Detect column's width + colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) + # Make text fit in box (if exist) + # TODO: find a better and more precise way of doing this. That's currently working but very complicated + width = get_terminal_width() + if width: + if sum(colwidth) > width: + # Needs to be cropped + _med = (width // _l_header) - (1 if WINDOWS else 0) # Windows has a fat window border + # Crop biggest until size is correct + for i in range(1, len(colwidth)): # Should use while, but this is safer + if (sum(colwidth)+6) <= width: + break + _max = max(colwidth) + colwidth = [_med if x == _max else x for x in colwidth] + def _crop(x, width): + _r = x[:width] + if _r != x: + _r = x[:width-3] + return _r + "..." + return _r + rtlst = [tuple([_crop(rtlst[j][i], colwidth[i]) for i in range(0, len(rtlst[j]))]) for j in range(0, len(rtlst))] + # Recalculate column's width + colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) + fmt = _space.join(map(lambda x: "%%-%ds"%x, colwidth)) + rt = "\n".join(map(lambda x: fmt % x, rtlst)) + return rt + def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, seplinefunc=None): vx = {} vy = {} -- GitLab