Authoritatively detect whether egress through `iface` leaves via a Tor exit node, by asking the Tor Project's own checker (which sees our exit IP). This is the only reliable way to catch Tor/VPN running on the *router*: in that case Ragnar's own interface is an ordinary LAN NIC, so the
(iface)
| 798 | if action == 'reset': |
| 799 | _arp_baseline_save({}) |
| 800 | return {'success': True, 'reset': True, 'gateways': {}} |
| 801 | return {'success': True, 'gateways': (_arp_baseline_load().get('gateways') or {})} |
| 802 | |
| 803 | |
| 804 | def do_arp_check(interface=None, learn=True): |
| 805 | """Detect ARP spoofing / poisoning from the kernel neighbour table. |
| 806 | |
| 807 | Signals: (1) the default gateway's MAC no longer matches the trusted |
| 808 | baseline — the classic MITM signature (an attacker ARP-replies as the |
| 809 | gateway to intercept traffic); (2) one MAC answering for many IPs — a host |
| 810 | impersonating much of the subnet. First run learns the gateway baseline. |
| 811 | |
| 812 | verdict: 'spoofed' -- gateway MAC changed from the trusted baseline |
| 813 | 'suspicious' -- a MAC is impersonating several IPs |
| 814 | 'clean' -- gateway matches baseline, no impersonators |
| 815 | 'unknown' -- no gateway, or its MAC couldn't be resolved |
| 816 | |
| 817 | With `interface` set, the check is scoped to that segment: its own default |
| 818 | gateway (a higher-metric uplink still counts) and only the neighbours on that |
| 819 | interface — the right lens on a multi-homed box.""" |
| 820 | iface = interface if _valid_iface(interface or '') else None |
| 821 | gw = _iface_gateway(iface) if iface else _default_gateway() |
no test coverage detected