Register all /api/net/* diagnostic routes on the given Flask app.
(app, logger=None)
| 1914 | verdict = 'clean' |
| 1915 | if rogue_servers: |
| 1916 | verdict = 'rogue' |
| 1917 | elif starvation >= _DHCP_STARV_MIN_CLIENTS: |
| 1918 | verdict = 'starvation' |
| 1919 | if not packets: |
| 1920 | reasons.append("no DHCP seen on the wire during the window — quiet segment, " |
| 1921 | "or the box may not actually be inline (bridge the two NICs)") |
| 1922 | |
| 1923 | return { |
| 1924 | 'success': True, 'verdict': verdict, |
| 1925 | 'trusted': trusted, 'untrusted': untrusted, |
| 1926 | 'packets': len(packets), |
| 1927 | 'servers': [{'server': sid, 'port': i['port'], 'trusted': i['trusted'], |
| 1928 | 'router': i.get('router'), |
| 1929 | 'rogue': not i['trusted']} for sid, i in servers.items()], |
| 1930 | 'bindings': list(bindings.values()), |
| 1931 | 'binding_count': len(bindings), |
| 1932 | 'rogue_count': len(rogue_servers), |
| 1933 | 'client_count': starvation, |
| 1934 | 'reasons': reasons, |
| 1935 | } |
| 1936 | |
| 1937 | |
| 1938 | # -------------------------------------------------------------------------- |
| 1939 | # Interfaces: link speed / duplex / auto-neg, static-vs-DHCP, IP/CIDR, VLAN |
| 1940 | # -------------------------------------------------------------------------- |
| 1941 | |
| 1942 | # Container/virtual interfaces that are just noise on the Interfaces tab. |
| 1943 | _VIRTUAL_IFACE_RE = re.compile(r'^(veth|docker|br-|virbr|vmnet|vboxnet|vnet|macvtap)') |
| 1944 | |
| 1945 | |
| 1946 | def _list_iface_names(include_virtual=False): |
| 1947 | res = _run(['ip', '-o', 'link', 'show'], timeout=5) |
| 1948 | names = [] |
| 1949 | for line in res['out'].splitlines(): |
| 1950 | m = re.match(r'^\d+:\s+([^:@]+)', line) |
| 1951 | if m: |
| 1952 | name = m.group(1).strip() |
| 1953 | if name == 'lo': |
| 1954 | continue |
| 1955 | if not include_virtual and _VIRTUAL_IFACE_RE.match(name): |
| 1956 | continue |
| 1957 | names.append(name) |
| 1958 | return names |
| 1959 | |
| 1960 | |
| 1961 | def _iface_link_details(iface): |
| 1962 | """MAC, operstate, and VLAN info from `ip -d link show`.""" |
| 1963 | res = _run(['ip', '-d', 'link', 'show', 'dev', iface], timeout=5) |
| 1964 | out = res['out'] |
| 1965 | d = {'mac': None, 'operstate': None, 'vlan_id': None, 'vlan_proto': None} |
| 1966 | m = re.search(r'state (\S+)', out) |
| 1967 | if m: |
| 1968 | d['operstate'] = m.group(1) |
| 1969 | m = re.search(r'link/\w+\s+([0-9a-fA-F:]{17})', out) |
| 1970 | if m: |
| 1971 | d['mac'] = m.group(1) |
| 1972 | m = re.search(r'vlan protocol (\S+) id (\d+)', out) |
| 1973 | if m: |