Parse /etc/resolv.conf for search domains and nameservers. Returns (domains, nameservers, stub) where `stub` is True when the only nameserver is the systemd-resolved stub (127.0.0.53) -- in that case the real upstream servers must come from nmcli/resolvectl instead.
()
| 714 | if res['rc'] == 127: |
| 715 | return {'success': False, 'error': res['err'] or 'arp-scan not found', |
| 716 | 'missing_tool': 'arp-scan', 'hosts': []} |
| 717 | hosts = [] |
| 718 | for line in res['out'].splitlines(): |
| 719 | m = re.match(r'^(\d+\.\d+\.\d+\.\d+)\s+([0-9a-fA-F:]{17})\s*(.*)$', line) |
| 720 | if m: |
| 721 | hosts.append({'ip': m.group(1), 'mac': m.group(2), |
| 722 | 'vendor': m.group(3).strip() or None}) |
| 723 | return {'success': True, 'hosts': hosts, 'count': len(hosts), 'interface': interface} |
| 724 | |
| 725 | |
| 726 | # -------------------------------------------------------------------------- |
| 727 | # ARP spoofing / poisoning detection: watch the gateway's IP->MAC binding |
| 728 | # against a learned baseline (a MITM inserting itself changes it), and flag a |
| 729 | # single MAC answering for many IPs (one host impersonating the whole subnet). |
| 730 | # The kernel neighbour table is authoritative and needs no capture, so this is |
| 731 | # cheap enough to run on a schedule from the integrity monitor. |
| 732 | # -------------------------------------------------------------------------- |
| 733 | |
| 734 | _ARP_BASELINE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), |
| 735 | 'data', 'arp_baseline.json') |
| 736 | _arp_baseline_lock = threading.Lock() |
| 737 | # A MAC bound to at least this many IPs in the neighbour table is treated as a |
| 738 | # possible impersonator. Proxy-ARP routers can legitimately answer for a few, so |
| 739 | # keep the floor above normal noise. |
| 740 | _ARP_IMPERSONATOR_MIN_IPS = 4 |
| 741 | |
| 742 | |
| 743 | def _neigh_entries(iface=None): |
| 744 | """Parse `ip -4 neigh` into [(ip, mac, state)] for entries with a lladdr. |
no test coverage detected