xref: /freebsd-src/tests/atf_python/sys/net/tools.py (revision b23dbabb7f3edb3f323a64f03e37be2c9a8b2a45)
18eb2bee6SAlexander V. Chernikov#!/usr/local/bin/python3
28eb2bee6SAlexander V. Chernikovimport json
38eb2bee6SAlexander V. Chernikovimport os
4*b23dbabbSKristof Provostimport subprocess
58eb2bee6SAlexander V. Chernikov
68eb2bee6SAlexander V. Chernikov
78eb2bee6SAlexander V. Chernikovclass ToolsHelper(object):
88eb2bee6SAlexander V. Chernikov    NETSTAT_PATH = "/usr/bin/netstat"
9cfc9cf9bSAlexander V. Chernikov    IFCONFIG_PATH = "/sbin/ifconfig"
108eb2bee6SAlexander V. Chernikov
118eb2bee6SAlexander V. Chernikov    @classmethod
128eb2bee6SAlexander V. Chernikov    def get_output(cls, cmd: str, verbose=False) -> str:
138eb2bee6SAlexander V. Chernikov        if verbose:
148eb2bee6SAlexander V. Chernikov            print("run: '{}'".format(cmd))
158eb2bee6SAlexander V. Chernikov        return os.popen(cmd).read()
168eb2bee6SAlexander V. Chernikov
178eb2bee6SAlexander V. Chernikov    @classmethod
18*b23dbabbSKristof Provost    def pf_rules(cls, rules, verbose=True):
19*b23dbabbSKristof Provost        pf_conf = ""
20*b23dbabbSKristof Provost        for r in rules:
21*b23dbabbSKristof Provost            pf_conf = pf_conf + r + "\n"
22*b23dbabbSKristof Provost
23*b23dbabbSKristof Provost        if verbose:
24*b23dbabbSKristof Provost            print("Set rules:")
25*b23dbabbSKristof Provost            print(pf_conf)
26*b23dbabbSKristof Provost
27*b23dbabbSKristof Provost        ps = subprocess.Popen("/sbin/pfctl -g -f -", shell=True,
28*b23dbabbSKristof Provost            stdin=subprocess.PIPE)
29*b23dbabbSKristof Provost        ps.communicate(bytes(pf_conf, 'utf-8'))
30*b23dbabbSKristof Provost        ret = ps.wait()
31*b23dbabbSKristof Provost        if ret != 0:
32*b23dbabbSKristof Provost            raise Exception("Failed to set pf rules %d" % ret)
33*b23dbabbSKristof Provost
34*b23dbabbSKristof Provost        if verbose:
35*b23dbabbSKristof Provost            cls.print_output("/sbin/pfctl -sr")
36*b23dbabbSKristof Provost
37*b23dbabbSKristof Provost    @classmethod
38cfc9cf9bSAlexander V. Chernikov    def print_output(cls, cmd: str, verbose=True):
39cfc9cf9bSAlexander V. Chernikov        if verbose:
40cfc9cf9bSAlexander V. Chernikov            print("======= {} =====".format(cmd))
41cfc9cf9bSAlexander V. Chernikov        print(cls.get_output(cmd))
42cfc9cf9bSAlexander V. Chernikov        if verbose:
43cfc9cf9bSAlexander V. Chernikov            print()
44cfc9cf9bSAlexander V. Chernikov
45cfc9cf9bSAlexander V. Chernikov    @classmethod
46cfc9cf9bSAlexander V. Chernikov    def print_net_debug(cls):
47cfc9cf9bSAlexander V. Chernikov        cls.print_output("ifconfig")
48cfc9cf9bSAlexander V. Chernikov        cls.print_output("netstat -rnW")
49cfc9cf9bSAlexander V. Chernikov
50cfc9cf9bSAlexander V. Chernikov    @classmethod
51cfc9cf9bSAlexander V. Chernikov    def set_sysctl(cls, oid, val):
52cfc9cf9bSAlexander V. Chernikov        cls.get_output("sysctl {}={}".format(oid, val))
53cfc9cf9bSAlexander V. Chernikov
54cfc9cf9bSAlexander V. Chernikov    @classmethod
558eb2bee6SAlexander V. Chernikov    def get_routes(cls, family: str, fibnum: int = 0):
568eb2bee6SAlexander V. Chernikov        family_key = {"inet": "-4", "inet6": "-6"}.get(family)
578eb2bee6SAlexander V. Chernikov        out = cls.get_output(
587064c94aSAlexander V. Chernikov            "{} {} -rnW -F {} --libxo json".format(cls.NETSTAT_PATH, family_key, fibnum)
598eb2bee6SAlexander V. Chernikov        )
608eb2bee6SAlexander V. Chernikov        js = json.loads(out)
618eb2bee6SAlexander V. Chernikov        js = js["statistics"]["route-information"]["route-table"]["rt-family"]
628eb2bee6SAlexander V. Chernikov        if js:
638eb2bee6SAlexander V. Chernikov            return js[0]["rt-entry"]
648eb2bee6SAlexander V. Chernikov        else:
658eb2bee6SAlexander V. Chernikov            return []
66cfc9cf9bSAlexander V. Chernikov
67cfc9cf9bSAlexander V. Chernikov    @classmethod
687064c94aSAlexander V. Chernikov    def get_nhops(cls, family: str, fibnum: int = 0):
697064c94aSAlexander V. Chernikov        family_key = {"inet": "-4", "inet6": "-6"}.get(family)
707064c94aSAlexander V. Chernikov        out = cls.get_output(
717064c94aSAlexander V. Chernikov            "{} {} -onW -F {} --libxo json".format(cls.NETSTAT_PATH, family_key, fibnum)
727064c94aSAlexander V. Chernikov        )
737064c94aSAlexander V. Chernikov        js = json.loads(out)
747064c94aSAlexander V. Chernikov        js = js["statistics"]["route-nhop-information"]["nhop-table"]["rt-family"]
757064c94aSAlexander V. Chernikov        if js:
767064c94aSAlexander V. Chernikov            return js[0]["nh-entry"]
777064c94aSAlexander V. Chernikov        else:
787064c94aSAlexander V. Chernikov            return []
797064c94aSAlexander V. Chernikov
807064c94aSAlexander V. Chernikov    @classmethod
81cfc9cf9bSAlexander V. Chernikov    def get_linklocals(cls):
82cfc9cf9bSAlexander V. Chernikov        ret = {}
83cfc9cf9bSAlexander V. Chernikov        ifname = None
84cfc9cf9bSAlexander V. Chernikov        ips = []
85cfc9cf9bSAlexander V. Chernikov        for line in cls.get_output(cls.IFCONFIG_PATH).splitlines():
86cfc9cf9bSAlexander V. Chernikov            if line[0].isalnum():
87cfc9cf9bSAlexander V. Chernikov                if ifname:
88cfc9cf9bSAlexander V. Chernikov                    ret[ifname] = ips
89cfc9cf9bSAlexander V. Chernikov                    ips = []
90cfc9cf9bSAlexander V. Chernikov                ifname = line.split(":")[0]
91cfc9cf9bSAlexander V. Chernikov            else:
92cfc9cf9bSAlexander V. Chernikov                words = line.split()
93cfc9cf9bSAlexander V. Chernikov                if words[0] == "inet6" and words[1].startswith("fe80"):
94cfc9cf9bSAlexander V. Chernikov                    # inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
95cfc9cf9bSAlexander V. Chernikov                    ip = words[1].split("%")[0]
96cfc9cf9bSAlexander V. Chernikov                    scopeid = int(words[words.index("scopeid") + 1], 16)
97cfc9cf9bSAlexander V. Chernikov                    ips.append((ip, scopeid))
98cfc9cf9bSAlexander V. Chernikov        if ifname:
99cfc9cf9bSAlexander V. Chernikov            ret[ifname] = ips
100cfc9cf9bSAlexander V. Chernikov        return ret
101