Example #1
0
 def execute_cli(self):
     r = []
     # Fallback to CLI
     lldp = self.cli("show lldp neighbors")
     for link in parse_table(
             lldp,
             allow_wrap=True,
             line_wrapper=None,
             row_wrapper=lambda x: x.strip(),
             footer="\r\n\r\n",
     ):
         if link[0] == "":
             continue
         local_interface = link[0]
         remote_chassis_id = link[1]
         remote_port = link[2]
         remote_system_name = link[3]
         # Build neighbor data
         # Get capability
         cap = lldp_caps_to_bits(
             link[4].strip().split(","),
             {
                 "O": LLDP_CAP_OTHER,
                 "r": LLDP_CAP_REPEATER,
                 "B": LLDP_CAP_BRIDGE,
                 "W": LLDP_CAP_WLAN_ACCESS_POINT,
                 "R": LLDP_CAP_ROUTER,
                 "T": LLDP_CAP_TELEPHONE,
                 "D": LLDP_CAP_DOCSIS_CABLE_DEVICE,
                 "S": LLDP_CAP_STATION_ONLY,  # S-VLAN
                 "C": 256,  # C-VLAN
                 "H": 512,  # Host
                 "TP": 1024,  # Two Ports MAC Relay
             },
         )
         if is_ipv4(remote_chassis_id) or is_ipv6(remote_chassis_id):
             remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(remote_chassis_id):
             remote_chassis_id = MACAddressParameter().clean(
                 remote_chassis_id)
             remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_MAC
         else:
             remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_LOCAL
         # Get remote port subtype
         remote_port_subtype = LLDP_PORT_SUBTYPE_ALIAS
         if is_ipv4(remote_port):
             # Actually networkAddress(4)
             remote_port_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(remote_port):
             # Actually macAddress(3)
             # Convert MAC to common form
             remote_port = MACAddressParameter().clean(remote_port)
             remote_port_subtype = LLDP_PORT_SUBTYPE_MAC
         elif is_int(remote_port):
             # Actually local(7)
             remote_port_subtype = LLDP_PORT_SUBTYPE_LOCAL
         i = {"local_interface": local_interface, "neighbors": []}
         n = {
             "remote_chassis_id": remote_chassis_id,
             "remote_chassis_id_subtype": remote_chassis_id_subtype,
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_capabilities": cap,
         }
         if remote_system_name:
             n["remote_system_name"] = remote_system_name
         #
         # XXX: Dirty hack for older firmware. Switch rebooted.
         #
         if remote_chassis_id_subtype != LLDP_CHASSIS_SUBTYPE_LOCAL:
             i["neighbors"] = [n]
             r += [i]
             continue
         try:
             c = self.cli("show lldp neighbors %s" % local_interface)
             match = self.rx_detail.search(c)
             if match:
                 remote_chassis_id = match.group("dev_id")
                 if is_ipv4(remote_chassis_id) or is_ipv6(
                         remote_chassis_id):
                     remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
                 elif is_mac(remote_chassis_id):
                     remote_chassis_id = MACAddressParameter().clean(
                         remote_chassis_id)
                     remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_MAC
                 else:
                     remote_chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_LOCAL
                 n["remote_chassis_id"] = remote_chassis_id
                 n["remote_chassis_id_subtype"] = remote_chassis_id_subtype
                 if match.group("sys_name").strip():
                     sys_name = match.group("sys_name").strip()
                     n["remote_system_name"] = sys_name
                 if match.group("sys_descr").strip():
                     sys_descr = match.group("sys_descr").strip()
                     n["remote_system_description"] = sys_descr
                 if match.group("port_descr").strip():
                     port_descr = match.group("port_descr").strip()
                     n["remote_port_description"] = port_descr
         except Exception:
             pass
         i["neighbors"] += [n]
         r += [i]
     return r
Example #2
0
 def execute(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     if v.startswith("%"):
         # % LLDP is not enabled
         return []
     v = self.rx_summary_split.split(v)[1]
     lldp_interfaces = []
     # Get LLDP interfaces with neighbors
     for ll in v.splitlines():
         ll = ll.strip()
         if not ll:
             break
         match = self.rx_s_line.match(ll)
         if not match:
             continue
         lldp_interfaces += [match.group("local_if")]
     # Get LLDP neighbors
     for local_if in lldp_interfaces:
         i = {"local_interface": local_if, "neighbors": []}
         # Get neighbors details
         try:
             v = self.cli("show lldp neighbors interface %s detail" %
                          local_if)
         except self.CLISyntaxError:
             # Found strange CLI syntax on Catalyst 4900
             # Allow ONLY interface name or "detail"
             # Need testing...
             raise self.NotSupportedError()
         # Get remote port
         match = self.rx_remote_port.search(v)
         remote_port = match.group("remote_if")
         remote_port_subtype = 128
         if self.rx_mac.match(remote_port):
             # Actually macAddress(3)
             # Convert MAC to common form
             remote_port = MACAddressParameter().clean(remote_port)
             remote_port_subtype = 3
         elif is_ipv4(remote_port):
             # Actually networkAddress(4)
             remote_port_subtype = 4
         elif is_int(remote_port):
             # Actually local(7)
             remote_port_subtype = 7
         n = {
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_chassis_id_subtype": 4,
         }
         # Get chassis id
         match = self.rx_chassis_id.search(v)
         if not match:
             continue
         n["remote_chassis_id"] = match.group("id")
         # Get capabilities
         cap = 0
         match = self.rx_enabled_caps.search(v)
         if match:
             for c in match.group("caps").split(","):
                 c = c.strip()
                 if c:
                     cap |= {
                         "O": 1,
                         "P": 2,
                         "B": 4,
                         "W": 8,
                         "R": 16,
                         "T": 32,
                         "C": 64,
                         "S": 128,
                         "N/A": 256,
                     }[c]
         n["remote_capabilities"] = cap
         # Get remote chassis id
         match = self.rx_system.search(v)
         if match:
             n["remote_system_name"] = match.group("name")
         i["neighbors"] += [n]
         r += [i]
     return r
Example #3
0
 def execute_cli(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     t = parse_table(v, allow_wrap=True)
     for i in t:
         chassis_id = i[1]
         if is_ipv4(chassis_id) or is_ipv6(chassis_id):
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(chassis_id):
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_MAC
         else:
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_LOCAL
         port_id = i[2]
         if is_ipv4(port_id) or is_ipv6(port_id):
             port_id_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(port_id):
             port_id_subtype = LLDP_PORT_SUBTYPE_MAC
         else:
             port_id_subtype = LLDP_PORT_SUBTYPE_LOCAL
         caps = lldp_caps_to_bits(
             i[4].split(","),
             {
                 "o": LLDP_CAP_OTHER,
                 "p": LLDP_CAP_REPEATER,
                 "b": LLDP_CAP_BRIDGE,
                 "w": LLDP_CAP_WLAN_ACCESS_POINT,
                 "r": LLDP_CAP_ROUTER,
                 "t": LLDP_CAP_TELEPHONE,
                 "c": LLDP_CAP_DOCSIS_CABLE_DEVICE,
                 "s": LLDP_CAP_STATION_ONLY,
             },
         )
         neighbor = {
             "remote_chassis_id": chassis_id,
             "remote_chassis_id_subtype": chassis_id_subtype,
             "remote_port": port_id,
             "remote_port_subtype": port_id_subtype,
             "remote_capabilities": caps,
         }
         if i[3]:
             neighbor["remote_system_name"] = i[3]
         r += [{"local_interface": i[0], "neighbors": [neighbor]}]
     if not t:
         for iface in self.scripts.get_interface_status():
             c = self.cli("show lldp neighbors interface %s" %
                          iface["interface"],
                          ignore_errors=True)
             c = c.replace("\n\n", "\n")
             neighbors = []
             for match in self.rx_neighbor.finditer(c):
                 chassis_id = match.group("chassis_id")
                 if is_ipv4(chassis_id) or is_ipv6(chassis_id):
                     chassis_id_subtype = 5
                 elif is_mac(chassis_id):
                     chassis_id_subtype = 4
                 else:
                     chassis_id_subtype = 7
                 port_id = match.group("port_id")
                 if is_ipv4(port_id) or is_ipv6(port_id):
                     port_id_subtype = 4
                 elif is_mac(port_id):
                     port_id_subtype = 3
                 else:
                     port_id_subtype = 7
                 caps = 0
                 if match.group("caps").strip():
                     for c in match.group("caps").split():
                         c = c.strip()
                         if c in {"not", "advertised"}:
                             # not caps
                             break
                         if c and (c != "--"):
                             caps |= {
                                 "O": 1,
                                 "P": 2,
                                 "B": 4,
                                 "W": 8,
                                 "R": 16,
                                 "r": 16,
                                 "T": 32,
                                 "C": 64,
                                 "S": 128,
                             }[c]
                 neighbor = {
                     "remote_chassis_id": chassis_id,
                     "remote_chassis_id_subtype": chassis_id_subtype,
                     "remote_port": port_id,
                     "remote_port_subtype": port_id_subtype,
                     "remote_capabilities": caps,
                 }
                 port_descr = match.group("port_descr").strip()
                 system_name = match.group("system_name").strip()
                 system_descr = match.group("system_descr").strip()
                 if bool(port_descr):
                     neighbor["remote_port_description"] = port_descr
                 if bool(system_name):
                     neighbor["remote_system_name"] = system_name
                 if bool(system_descr):
                     neighbor["remote_system_description"] = system_descr
                 neighbors += [neighbor]
             if neighbors:
                 r += [{
                     "local_interface": iface["interface"],
                     "neighbors": neighbors
                 }]
     return r
Example #4
0
 def normalize_ntp_server(self, tokens):
     if is_ipv4(".".join(tokens[4:])):
         yield self.make_ntp_server_address(name="0",
                                            address=".".join(tokens[4:]))
Example #5
0
    def execute(self):
        r = []
        # Try SNMP first

        # Fallback to CLI
        # LLDP First
        try:
            lldp = self.cli("show lldp neighbors")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        for match in self.rx_lldp_nei.finditer(lldp):
            local_interface = match.group("interface")
            remote_chassis_id = match.group("chassis_id")
            remote_port = match.group("port_id")

            # Build neighbor data
            # Get capability
            cap = 4
            # Get remote port subtype
            remote_port_subtype = LLDP_PORT_SUBTYPE_NAME
            if is_ipv4(remote_port):
                # Actually networkAddress(4)
                remote_port_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
            elif is_mac(remote_port):
                # Actually macAddress(3)
                # Convert MAC to common form
                remote_port = MACAddressParameter().clean(remote_port)
                remote_port_subtype = LLDP_PORT_SUBTYPE_MAC
            elif is_int(remote_port):
                # Actually local(7)
                remote_port_subtype = LLDP_PORT_SUBTYPE_LOCAL

            i = {"local_interface": local_interface, "neighbors": []}
            n = {
                "remote_chassis_id": remote_chassis_id,
                "remote_port": remote_port,
                "remote_capabilities": cap,
                "remote_port_subtype": remote_port_subtype,
            }
            if is_ipv4(n["remote_chassis_id"]) or is_ipv6(
                    n["remote_chassis_id"]):
                n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
            else:
                n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_MAC
            try:
                c = self.cli("show lldp ports %s neighbors detailed" %
                             local_interface)
                match = self.rx_lldp_detail.search(c)
                if match:
                    port_descr = match.group("port_descr")
                    if port_descr:
                        n["remote_port_description"] = port_descr.replace(
                            '"', "").strip()
                        n["remote_port_description"] = re.sub(
                            r"\\\n\s*", "", n["remote_port_description"])
                    n["remote_system_name"] = match.group(
                        "system_name").replace('"', "").strip()
                    n["remote_system_name"] = re.sub(r"\\\n\s*", "",
                                                     n["remote_system_name"])
                    sys_descr = match.group("system_descr")
                    if sys_descr:
                        n["remote_system_description"] = sys_descr.replace(
                            '"', "").strip()
                        n["remote_system_description"] = re.sub(
                            r"\\\n\s*", "", n["remote_system_description"])
                    n["remote_port_subtype"] = self.port_types[match.group(
                        "port_id_subtype").strip()]
                    n["remote_chassis_id_subtype"] = self.chassis_types[
                        match.group("chassis_id_subtype").strip()]
            except self.CLISyntaxError:
                pass

            i["neighbors"].append(n)
            r.append(i)
        # Try EDP Second
        try:
            lldp = self.cli("show edp ports all")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        for match in self.rx_edp_nei.finditer(lldp):
            local_interface = match.group("interface")
            remote_chassis_id = match.group("chassis_id")
            remote_port = match.group("port_id")
            remote_system_name = match.group("name")

            # Build neighbor data
            # Get capability
            cap = 4
            # Get remote port subtype
            remote_port_subtype = LLDP_PORT_SUBTYPE_NAME
            if is_ipv4(remote_port):
                # Actually networkAddress(4)
                remote_port_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
            elif is_mac(remote_port):
                # Actually macAddress(3)
                # Convert MAC to common form
                remote_port = MACAddressParameter().clean(remote_port)
                remote_port_subtype = LLDP_PORT_SUBTYPE_MAC
            elif is_int(remote_port):
                # Actually local(7)
                remote_port_subtype = LLDP_PORT_SUBTYPE_LOCAL

            i = {"local_interface": local_interface, "neighbors": []}
            n = {
                "remote_chassis_id": remote_chassis_id,
                "remote_port": remote_port,
                "remote_capabilities": cap,
                "remote_port_subtype": remote_port_subtype,
            }
            if remote_system_name:
                n["remote_system_name"] = remote_system_name
            if is_ipv4(n["remote_chassis_id"]) or is_ipv6(
                    n["remote_chassis_id"]):
                n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
            else:
                n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_MAC

            i["neighbors"].append(n)
            r.append(i)

        return r
Example #6
0
    def execute_cli(self):
        r = []
        data = []
        try:
            v = self.cli("show lldp neighbors")
        except self.CLISyntaxError:
            raise self.NotSupportedError()
        v = v.replace("\n\n", "\n")
        for l in parse_table(v):
            if not l[0]:
                data[-1] = [s[0] + s[1] for s in zip(data[-1], l)]
                continue
            data += [l]

        for d in data:
            try:
                ifname = self.profile.convert_interface_name(d[0])
            except ValueError:
                continue
            v = self.cli("show lldp neighbors %s" % ifname)
            match = self.rx_neighbor.search(v)
            chassis_id = match.group("chassis_id").strip()
            if is_ipv4(chassis_id) or is_ipv6(chassis_id):
                chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
            elif is_mac(chassis_id):
                chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_MAC
            else:
                chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_LOCAL
            port_id = match.group("port_id").strip()
            if is_ipv4(port_id) or is_ipv6(port_id):
                port_id_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
            elif is_mac(port_id):
                port_id_subtype = LLDP_PORT_SUBTYPE_MAC
            else:
                port_id_subtype = LLDP_PORT_SUBTYPE_LOCAL
            caps = lldp_caps_to_bits(
                match.group("caps").strip().split(","),
                {
                    "other": LLDP_CAP_OTHER,
                    "repeater": LLDP_CAP_REPEATER,
                    "bridge": LLDP_CAP_BRIDGE,
                    "wlan-access-point": LLDP_CAP_WLAN_ACCESS_POINT,
                    "router": LLDP_CAP_ROUTER,
                    "telephone": LLDP_CAP_TELEPHONE,
                    "d": LLDP_CAP_DOCSIS_CABLE_DEVICE,
                    "h": LLDP_CAP_STATION_ONLY,
                },
            )
            neighbor = {
                "remote_chassis_id": chassis_id,
                "remote_chassis_id_subtype": chassis_id_subtype,
                "remote_port": port_id,
                "remote_port_subtype": port_id_subtype,
                "remote_capabilities": caps,
            }
            system_name = match.group("system_name").strip()
            if system_name:
                neighbor["remote_system_name"] = system_name
            system_descr = match.group("system_descr").strip()
            if system_descr:
                neighbor["remote_system_description"] = system_descr
            port_descr = match.group("port_descr").strip()
            if port_descr:
                neighbor["remote_port_description"] = port_descr
            r += [{"local_interface": ifname, "neighbors": [neighbor]}]

        return r
Example #7
0
def test_is_ipv4(raw, expected):
    assert is_ipv4(raw) is expected
Example #8
0
 def execute_cli(self):
     r = []
     r_rem = []
     v = self.cli("show lldp remote")
     for match in self.rx_lldp_rem.finditer(v):
         chassis_id = match.group("ch_id")
         if is_ipv4(chassis_id) or is_ipv6(chassis_id):
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(chassis_id):
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_MAC
         else:
             chassis_id_subtype = LLDP_CHASSIS_SUBTYPE_LOCAL
         r_rem += [{
             "local_interface": match.group("port"),
             "remote_chassis_id": chassis_id,
             "remote_chassis_id_subtype": chassis_id_subtype,
         }]
     v = self.cli("show lldp remote detail")
     # If detail command not contain ch id
     ext_ch_id = False
     lldp_iter = list(self.rx_lldp.finditer(v))
     if not lldp_iter:
         ext_ch_id = True
         lldp_iter = list(self.rx_lldp_womac.finditer(v))
         self.logger.debug("Not Find MAC in re")
     for match in lldp_iter:
         i = {"local_interface": match.group("port"), "neighbors": []}
         cap = lldp_caps_to_bits(
             match.group("sys_caps_enabled").strip().split(","),
             {
                 "n/a": 0,
                 "other": LLDP_CAP_OTHER,
                 "repeater/hub": LLDP_CAP_REPEATER,
                 "bridge/switch": LLDP_CAP_BRIDGE,
                 "router": LLDP_CAP_ROUTER,
                 "telephone": LLDP_CAP_TELEPHONE,
                 "station": LLDP_CAP_STATION_ONLY,
             },
         )
         n = {
             "remote_chassis_id_subtype": {
                 "macAddress": LLDP_CHASSIS_SUBTYPE_MAC,
                 "networkAddress": LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS,
             }[match.group("ch_type")],
             "remote_chassis_id":
             match.group("ch_id") if not ext_ch_id else None,
             "remote_port_subtype": {
                 "ifAlias": LLDP_PORT_SUBTYPE_ALIAS,
                 "macAddress": LLDP_PORT_SUBTYPE_MAC,
                 "ifName": LLDP_PORT_SUBTYPE_NAME,
                 "portComponent": LLDP_PORT_SUBTYPE_NAME,
                 "local": LLDP_PORT_SUBTYPE_LOCAL,
             }[match.group("port_id_subtype")],
             "remote_port": match.group("port_id"),
             "remote_capabilities": cap,
         }
         if match.group("sys_name").strip() != "N/A":
             n["remote_system_name"] = match.group("sys_name").strip()
         if match.group("sys_descr").strip() != "N/A":
             sd = match.group("sys_descr").strip()
             if "SysDesc:" in sd:
                 sd = sd.split()[-1]
             n["remote_system_description"] = re.sub(r"\n\s{29,30}", "", sd)
         if match.group("port_descr").strip() != "N/A":
             n["remote_port_description"] = re.sub(
                 r"\n\s{29,30}", "",
                 match.group("port_descr").strip())
             match.group("port_descr")
         if n["remote_chassis_id"] is None:
             for j in r_rem:
                 if i["local_interface"] == j["local_interface"]:
                     n["remote_chassis_id"] = j["remote_chassis_id"]
                     n["remote_chassis_id_subtype"] = j[
                         "remote_chassis_id_subtype"]
                     break
         i["neighbors"] += [n]
         r += [i]
     return r
Example #9
0
    def execute_cli(self, **kwargs):
        r = []

        # Fallback to CLI
        try:
            lldp = self.cli("show lldp interface")
        except self.CLISyntaxError:
            raise NotImplementedError
        for match in self.rx_line.finditer(lldp):
            local_interface = match.group("interface")
            remote_chassis_id = match.group("chassis_id")
            remote_port = match.group("port_id")
            remote_system_name = match.group("name")
            system_description = match.group("system_description")
            port_description = match.group("port_description")

            # Build neighbor data
            # Get capability
            cap = 0
            """
            for c in match.group("capabilities").split(","):
            if cap:
                c = c.strip()
                if c:
                    cap |= {
                        "O": 1, "r": 2, "B": 4,
                        "W": 8, "R": 16, "T": 32,
                        "C": 64, "S": 128, "D": 256,
                        "H": 512, "TP": 1024,
                    }[c]
            """
            # Get remote port subtype
            remote_port_subtype = 5
            if is_ipv4(remote_port):
                # Actually networkAddress(4)
                remote_port_subtype = 4
            elif is_mac(remote_port):
                # Actually macAddress(3)
                remote_port_subtype = 3
            elif is_int(remote_port):
                # Actually local(7)
                remote_port_subtype = 7

            i = {"local_interface": local_interface, "neighbors": []}
            n = {
                "remote_chassis_id": remote_chassis_id,
                "remote_port": remote_port,
                "remote_capabilities": cap,
                "remote_port_subtype": remote_port_subtype,
            }
            if remote_system_name and remote_system_name != "NULL":
                n["remote_system_name"] = remote_system_name
            if system_description and system_description != "NULL":
                n["remote_system_description"] = system_description
            if port_description and port_description != "NULL":
                n["remote_port_description"] = port_description

            # TODO:
            #            n["remote_chassis_id_subtype"] = 4

            i["neighbors"].append(n)
            r.append(i)
        return r
Example #10
0
 def execute_cli(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     if v.startswith("%"):
         # % LLDP is not enabled
         return []
     v = self.rx_summary_split.split(v)[1]
     lldp_interfaces = []
     # Get LLDP interfaces with neighbors
     for line in v.splitlines():
         line = line.strip()
         if not line:
             break
         match = self.rx_s_line.match(line)
         if not match:
             continue
         lldp_interfaces += [match.group("local_if")]
     # Get LLDP neighbors
     for local_if in lldp_interfaces:
         i = {"local_interface": local_if, "neighbors": []}
         # Get neighbors details
         try:
             v = self.cli("show lldp neighbors %s detail" % local_if)
         except self.CLISyntaxError:
             # Found strange CLI syntax on Catalyst 4900
             # Allow ONLY interface name or "detail"
             # Need testing...
             raise self.NotSupportedError()
         # Get remote port
         match = self.re_search(self.rx_remote_port, v)
         remote_port = match.group("remote_if")
         remote_port_subtype = LLDP_PORT_SUBTYPE_ALIAS
         if is_ipv4(remote_port):
             remote_port = IPv4Parameter().clean(remote_port)
             remote_port_subtype = LLDP_PORT_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(remote_port):
             # Convert MAC to common form
             remote_port = MACAddressParameter().clean(remote_port)
             remote_port_subtype = LLDP_PORT_SUBTYPE_MAC
         elif is_int(remote_port):
             remote_port_subtype = LLDP_PORT_SUBTYPE_LOCAL
         n = {
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_chassis_id_subtype": LLDP_CHASSIS_SUBTYPE_MAC,
         }
         match = self.rx_descr.search(v)
         if match:
             n["remote_port_description"] = match.group("descr")
         # Get chassis id
         match = self.rx_chassis_id.search(v)
         if not match:
             continue
         n["remote_chassis_id"] = match.group("id")
         # Get capabilities
         cap = 0
         match = self.rx_enabled_caps.search(v)
         if match:
             cap = lldp_caps_to_bits(
                 match.group("caps").strip().split(","),
                 {
                     "o": LLDP_CAP_OTHER,
                     "p": LLDP_CAP_REPEATER,
                     "b": LLDP_CAP_BRIDGE,
                     "w": LLDP_CAP_WLAN_ACCESS_POINT,
                     "r": LLDP_CAP_ROUTER,
                     "t": LLDP_CAP_TELEPHONE,
                     "c": LLDP_CAP_DOCSIS_CABLE_DEVICE,
                     "s": LLDP_CAP_STATION_ONLY,
                 },
             )
         n["remote_capabilities"] = cap
         # Get remote chassis id
         match = self.rx_system.search(v)
         if match:
             n["remote_system_name"] = match.group("name")
         if is_ipv4(n["remote_chassis_id"]) or is_ipv6(
                 n["remote_chassis_id"]):
             n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS
         elif is_mac(n["remote_chassis_id"]):
             pass
         else:
             n["remote_chassis_id_subtype"] = LLDP_CHASSIS_SUBTYPE_LOCAL
         i["neighbors"] += [n]
         r += [i]
     return r
Example #11
0
async def fetch(
    url: str,
    method: str = "GET",
    headers=None,
    body: Optional[bytes] = None,
    connect_timeout=DEFAULT_CONNECT_TIMEOUT,
    request_timeout=DEFAULT_REQUEST_TIMEOUT,
    resolver=resolve,
    max_buffer_size=DEFAULT_BUFFER_SIZE,
    follow_redirects: bool = False,
    max_redirects=DEFAULT_MAX_REDIRECTS,
    validate_cert=config.http_client.validate_certs,
    allow_proxy: bool = False,
    proxies=None,
    user: Optional[str] = None,
    password: Optional[str] = None,
    content_encoding: Optional[str] = None,
    eof_mark: Optional[bytes] = None,
) -> Tuple[int, Dict[str, Any], bytes]:
    """

    :param url: Fetch URL
    :param method: request method "GET", "POST", "PUT" etc
    :param headers: Dict of additional headers
    :param body: Request body for POST and PUT request
    :param connect_timeout:
    :param request_timeout:
    :param resolver:
    :param follow_redirects:
    :param max_redirects:
    :param validate_cert:
    :param allow_proxy:
    :param proxies:
    :param user:
    :param password:
    :param max_buffer_size:
    :param content_encoding:
    :param eof_mark: Do not consider connection reset as error if
      eof_mark received (string or list)
    :return: code, headers, body
    """
    def get_connect_options():
        opts = {}
        if use_tls and not proxy:
            ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
            if validate_cert:
                ctx.check_hostname = True
                ctx.verify_mode = ssl.CERT_REQUIRED
            else:
                ctx.check_hostname = False
                ctx.verify_mode = ssl.CERT_NONE
            opts["ssl"] = ctx
        return opts

    metrics["httpclient_requests", ("method", method.lower())] += 1
    #
    if eof_mark:
        eof_mark = smart_bytes(eof_mark)
    # Detect proxy when necessary
    u = urlparse(str(url))
    use_tls = u.scheme == "https"
    proto = "HTTPS" if use_tls else "HTTP"
    logger.debug("%s %s %s", proto, method, url)
    if ":" in u.netloc:
        host, port = u.netloc.rsplit(":")
        port = int(port)
    else:
        host = u.netloc
        port = DEFAULT_PORTS.get(u.scheme)
        if not port:
            return ERR_TIMEOUT, {}, b"Cannot resolve port for scheme: %s" % smart_bytes(
                u.scheme)
    if is_ipv4(host):
        addr = host
    else:
        addr = await resolver(host)
    if not addr:
        return ERR_TIMEOUT, {}, "Cannot resolve host: %s" % host
    # Detect proxy server
    if allow_proxy:
        proxy = (proxies or SYSTEM_PROXIES).get(u.scheme)
    else:
        proxy = None
    # Connect
    reader, writer = None, None
    if proxy:
        connect_address = proxy
    elif isinstance(addr, tuple):
        connect_address = addr
    else:
        connect_address = (addr, port)
    try:
        try:
            if proxy:
                logger.debug("Connecting to proxy %s:%s", connect_address[0],
                             connect_address[1])
            reader, writer = await asyncio.wait_for(
                asyncio.open_connection(connect_address[0], connect_address[1],
                                        **get_connect_options()),
                connect_timeout,
            )
        except ConnectionRefusedError:
            metrics["httpclient_timeouts"] += 1
            return ERR_TIMEOUT, {}, b"Connection refused"
        except OSError as e:
            metrics["httpclient_timeouts"] += 1
            return ERR_TIMEOUT, {}, b"Connection error: %s" % smart_bytes(e)
        except asyncio.TimeoutError:
            metrics["httpclient_timeouts"] += 1
            return ERR_TIMEOUT, {}, b"Connection timed out"
        # Proxy CONNECT
        if proxy:
            logger.debug("Sending CONNECT %s:%s", addr, port)
            # Send CONNECT request
            req = b"CONNECT %s:%s HTTP/1.1\r\nUser-Agent: %s\r\n\r\n" % (
                smart_bytes(addr),
                smart_bytes(port),
                smart_bytes(DEFAULT_USER_AGENT),
            )
            writer.write(smart_bytes(req))
            try:
                await asyncio.wait_for(writer.drain(), request_timeout)
            except asyncio.TimeoutError:
                metrics["httpclient_proxy_timeouts"] += 1
                return ERR_TIMEOUT, {}, b"Timed out while sending request to proxy"
            # Wait for proxy response
            parser = HttpParser()
            while not parser.is_headers_complete():
                try:
                    data = await asyncio.wait_for(reader.read(max_buffer_size),
                                                  request_timeout)
                except asyncio.TimeoutError:
                    metrics["httpclient_proxy_timeouts"] += 1
                    return ERR_TIMEOUT, {}, b"Timed out while sending request to proxy"
                received = len(data)
                parsed = parser.execute(data, received)
                if parsed != received:
                    return ERR_PARSE_ERROR, {}, b"Parse error"
            code = parser.get_status_code()
            logger.debug("Proxy response: %s", code)
            if not 200 <= code <= 299:
                return code, parser.get_headers(), "Proxy error: %s" % code
        # Process request
        body = body or ""
        content_type = "application/binary"
        if not isinstance(body, (str, bytes)):
            body = smart_text(orjson.dumps(body))
            content_type = "text/json"
        body = smart_bytes(body)  # Here and below body is binary
        h = {
            "Host": str(u.netloc),
            "Connection": "close",
            "User-Agent": DEFAULT_USER_AGENT
        }
        if body and content_encoding:
            if content_encoding == CE_DEFLATE:
                # Deflate compression
                h["Content-Encoding"] = CE_DEFLATE
                compress = zlib.compressobj(
                    zlib.Z_DEFAULT_COMPRESSION,
                    zlib.DEFLATED,
                    -zlib.MAX_WBITS,
                    zlib.DEF_MEM_LEVEL,
                    zlib.Z_DEFAULT_STRATEGY,
                )
                body = compress.compress(body) + compress.flush()
            elif content_encoding == CE_GZIP:
                # gzip compression
                h["Content-Encoding"] = CE_GZIP
                compress = zlib.compressobj(6, zlib.DEFLATED, -zlib.MAX_WBITS,
                                            zlib.DEF_MEM_LEVEL, 0)
                crc = zlib.crc32(body, 0) & 0xFFFFFFFF
                body = b"\x1f\x8b\x08\x00%s\x02\xff%s%s%s%s" % (
                    to32u(int(time.time())),
                    compress.compress(body),
                    compress.flush(),
                    to32u(crc),
                    to32u(len(body)),
                )
        if method in REQUIRE_LENGTH_METHODS:
            h["Content-Length"] = str(len(body))
            h["Content-Type"] = content_type
        if user and password:
            # Include basic auth header
            uh = smart_text("%s:%s" % (user, password))
            h["Authorization"] = b"Basic %s" % codecs.encode(
                uh.encode("utf-8"), "base64").strip()
        if headers:
            h.update(headers)
        path = u.path
        if u.query:
            path += "?%s" % u.query
        req = b"%s %s HTTP/1.1\r\n%s\r\n\r\n%s" % (
            smart_bytes(method),
            smart_bytes(path),
            b"\r\n".join(b"%s: %s" % (smart_bytes(k), smart_bytes(h[k]))
                         for k in h),
            body,
        )
        try:
            writer.write(req)
            await asyncio.wait_for(writer.drain(), request_timeout)
        except ConnectionResetError:
            metrics["httpclient_timeouts"] += 1
            return ERR_TIMEOUT, {}, b"Connection reset while sending request"
        except asyncio.TimeoutError:
            metrics["httpclient_timeouts"] += 1
            return ERR_TIMEOUT, {}, b"Timed out while sending request"
        parser = HttpParser()
        response_body: List[bytes] = []
        while not parser.is_message_complete():
            try:
                data = await asyncio.wait_for(reader.read(max_buffer_size),
                                              request_timeout)
                is_eof = not data
            except (asyncio.IncompleteReadError, ConnectionResetError):
                is_eof = True
            except asyncio.TimeoutError:
                metrics["httpclient_timeouts"] += 1
                return ERR_READ_TIMEOUT, {}, b"Request timed out"
            if is_eof:
                if eof_mark and response_body:
                    # Check if EOF mark is in received data
                    response_body = [b"".join(response_body)]
                    if isinstance(eof_mark, str):
                        if eof_mark in response_body[0]:
                            break
                    else:
                        found = False
                        for m in eof_mark:
                            if m in response_body[0]:
                                found = True
                                break
                        if found:
                            break
                metrics["httpclient_timeouts"] += 1
                return ERR_READ_TIMEOUT, {}, b"Connection reset"
            received = len(data)
            parsed = parser.execute(data, received)
            if parsed != received:
                return ERR_PARSE_ERROR, {}, b"Parse error"
            if parser.is_partial_body():
                response_body += [parser.recv_body()]
        code = parser.get_status_code()
        parsed_headers = parser.get_headers()
        logger.debug("HTTP Response %s", code)
        if 300 <= code <= 399 and follow_redirects:
            # Process redirects
            if max_redirects > 0:
                new_url = parsed_headers.get("Location")
                if not new_url:
                    return ERR_PARSE_ERROR, {}, b"No Location header"
                logger.debug("HTTP redirect %s %s", code, new_url)
                return await fetch(
                    new_url,
                    method="GET",
                    headers=headers,
                    connect_timeout=connect_timeout,
                    request_timeout=request_timeout,
                    resolver=resolver,
                    max_buffer_size=max_buffer_size,
                    follow_redirects=follow_redirects,
                    max_redirects=max_redirects - 1,
                    validate_cert=validate_cert,
                    allow_proxy=allow_proxy,
                    proxies=proxies,
                )
            else:
                return 404, {}, b"Redirect limit exceeded"
        # @todo: Process gzip and deflate Content-Encoding
        return code, parsed_headers, b"".join(response_body)
    finally:
        if writer:
            writer.close()
            try:
                await writer.wait_closed()
            except ConnectionResetError:
                pass
Example #12
0
 def execute_cli(self):
     r = []
     try:
         v = self.cli("show lldp neighbors")
     except self.CLISyntaxError:
         raise self.NotSupportedError()
     t = parse_table(v, allow_wrap=True)
     for i in t:
         local_if = i[0]
         v = self.cli("show lldp neighbors %s" % local_if)
         match = self.rx_neighbor.search(v)
         remote_chassis_id = match.group("remote_chassis_id")
         if is_ipv4(remote_chassis_id) or is_ipv6(remote_chassis_id):
             # Actually networkAddress(4)
             remote_chassis_id_subtype = 5
         elif is_mac(remote_chassis_id):
             # Actually macAddress(3)
             # Convert MAC to common form
             remote_chassis_id_subtype = 4
         else:
             remote_chassis_id_subtype = 7
         remote_port = match.group("remote_port")
         if is_ipv4(remote_port) or is_ipv6(remote_port):
             # Actually networkAddress(4)
             remote_port_subtype = 4
         elif is_mac(remote_port):
             # Actually macAddress(3)
             remote_port_subtype = 3
         elif is_int(remote_port):
             # Actually local(7)
             remote_port_subtype = 7
         else:
             remote_port_subtype = 5
         # Get capability
         cap = 0
         s = match.group("caps")
         for c in s.strip().split(", "):
             cap |= {
                 "Other": 1,
                 "Repeater": 2,
                 "Bridge": 4,
                 "WLAN": 8,
                 "Router": 16,
                 "Telephone": 32,
                 "Cable": 64,
                 "Station": 128,
             }[c]
         n = {
             "remote_chassis_id": remote_chassis_id,
             "remote_chassis_id_subtype": remote_chassis_id_subtype,
             "remote_port": remote_port,
             "remote_port_subtype": remote_port_subtype,
             "remote_capabilities": cap,
         }
         match = self.rx_system_name.search(v)
         if match and match.group("system_name"):
             n["remote_system_name"] = match.group("system_name")
         match = self.rx_port_descr.search(v)
         if match and match.group("port_descr"):
             n["remote_port_description"] = match.group("port_descr")
         i = {"local_interface": local_if, "neighbors": [n]}
         r += [i]
     return r