NEIGHBOT(8)

NAME
neighbot - network neighbor monitoring daemon

SYNOPSIS
neighbot [-B seconds] [-d] [-e days] [-f dbfile] [-i iface] [-m mailto] [-o ouifile] [-p] [-q] [-r] [-s sendmail] [-u user] [-V]

DESCRIPTION
neighbot passively monitors ARP (IPv4) and NDP (IPv6) traffic on all Ethernet interfaces. It maintains a database of IP-to-MAC address mappings and sends email alerts when new stations appear or existing mappings change. Notifications include reverse DNS hostname, hardware vendor (from the OUI database, if available), and timestamps.

The options are as follows:

-B seconds
    Bogon cooldown. Suppress duplicate bogon log lines and email notifications for the same IP and interface within seconds. Bogons are not stored in the database, so this cooldown is what bounds per-address reporting. Default: 1800 (30 minutes). Set to 0 to disable this per-address cooldown; a global rate cap on total bogon reporting still applies as a flood backstop.

-d  Daemonize. Detach from the terminal and log to syslog instead of stderr.

-e days
    Drop entries that have not been seen for more than days days. The check runs once per hour. Set to 0 (default) to keep entries indefinitely. This is independent of probe-driven cleanup, which always removes entries whose IP no longer responds at the recorded MAC.

-f dbfile
    Path to the database file. Default: /var/neighbot/neighbot.csv.

-i iface
    Monitor only the specified interface instead of all Ethernet interfaces. When monitoring all interfaces (no -i specified), trunk interfaces that have VLAN subinterfaces and no IP addresses of their own are automatically skipped. Only the VLAN subinterfaces are monitored. Trunks with IP addresses are kept since they carry native VLAN traffic. On Linux, this requires the 8021q kernel module to be loaded. Use -i to explicitly monitor a trunk interface.

-m mailto
    Email recipient for notifications. Default: ‘root’.

-o ouifile
    Path to the OUI vendor database file. Both the neighbot format (aa:bb:cc Vendor) and the arp-scan format (AABBCC<tab>Vendor) are supported. Default: /var/neighbot/oui.txt.

-p  Disable active probing. By default, when a known MAC address appears at a new IP, neighbot sends ARP requests or NDP Neighbor Solicitations to each old IP of the same address family to determine whether the device moved (old IP dead) or has multiple addresses (both active). Dual-stack hosts are not probed across IPv4/IPv6. Probes use a zero source address to avoid polluting ARP/NDP caches. Link-local addresses and IPs assigned to the local host's own interfaces are excluded from probing.

    When an IPv6 temporary address (RFC 4941) rotates, the new address is not reported as a new station; obsolete temporary addresses in the same prefix that have gone idle are dropped from the database silently. This also covers link-local address rotation on devices with randomized MACs.

    This flag makes neighbot purely passive.

-q  Quiet mode. Suppress email notifications. Events are still logged.

-r  Report mode. Load the database and print a summary of all known neighbors to stdout, grouped by interface and MAC address. No packet capture, privilege drop, or daemon setup is performed.

    When combined with -m, the report is emailed via sendmail instead of printed. When combined with -q, the report is always printed to stdout.

    The OUI vendor database is resolved in this order: the path given by -o, then /var/neighbot/oui.txt, then /usr/local/share/arp-scan/ieee-oui.txt. If none is found, vendor names show as ‘<unknown>’.

-s sendmail
    Path to the sendmail-compatible mail program used for notifications. Default: /usr/sbin/sendmail.

-u user
    Drop privileges to user after opening packet capture handles. The database directory and file are chowned to this user before dropping. Default: ‘nobody’.

-V  Print the version number and exit.

EVENTS
neighbot generates the following event types:

new A previously unknown IP address is seen for the first time. The email notification is suppressed when an IPv6 temporary address rotates (same MAC, same /64 prefix, non-EUI-64); obsolete temporary addresses in the prefix that have gone idle are dropped silently rather than reported.

changed
    An IP address is seen with a different MAC address than the one previously recorded.

flip-flop
    An IP address alternates between two previously seen MAC addresses. This typically indicates VRRP/HSRP failover, dual-homed hosts, or ARP spoofing. If the same IP flips 5 or more times within 60 seconds, an address conflict storm is declared: a single warning email is sent and further flip-flop notifications are suppressed until the storm subsides (no flips for 30 minutes) or a SIGHUP is received.

reappeared
    A known MAC/IP pair is seen again after more than 6 months of silence.

bogon
    An IP address is seen that does not belong to any subnet configured on any monitored interface. This may indicate ARP or NDP spoofing. Bogon packets are not added to the database. IPs that are foreign to the receiving interface but match another monitored interface's subnet are silently ignored (common with access points on VLAN trunks).

ra-learned
    A Router Advertisement announced a new on-link IPv6 prefix on an interface. The prefix is added to the per-interface list of known subnets so that addresses within it are no longer reported as bogons. A single email is sent the first time a given prefix is learned on an interface; refreshes and re-advertisements are silent. Prefixes expire after the RA valid-lifetime (capped at 7 days), and a prefix re-advertised with a zero valid-lifetime is withdrawn at once. Prefixes shorter than /48 are ignored and logged: real on-link prefixes are /64, and a short prefix would whitelist an implausibly wide slice of the address space.

    Router Advertisements are validated per RFC 4861: only RAs with an IPv6 hop limit of 255 and a link-local source address are accepted, so off-link or spoofed advertisements are dropped. A rogue RA sent by an on-link attacker can still suppress bogon alerts for the prefix it announces. The first-learn notification is intended to surface that event so the operator can investigate.

moved
    A MAC address is seen at a new IP address while its old IP no longer responds to probes (requires active probing). The obsolete IP entry is removed from the database after the notification is sent.

OBSOLETE ADDRESS CLEANUP
neighbot removes database entries it knows are no longer valid:

probe-confirmed
    When a probe times out, the obsolete entry is dropped (see the moved event).

IPv6 temporary address rotation
    When a host's new temporary address arrives in a /64 prefix it already uses, prior non-EUI-64 entries in the same /64 for the same MAC that have gone idle are dropped silently; an address still in active use is kept.

per-MAC cap
    At most 256 addresses per MAC are tracked; further new addresses for that MAC are ignored (logged once). This bounds a flood of addresses under a single MAC, keeping every per-MAC operation constant-time; a legitimate neighbour stays well below the limit.

stale non-EUI-64 IPv6
    Non-EUI-64, non-link-local IPv6 entries unseen for more than 7 days are dropped on the hourly sweep. Always on, regardless of -e. The test is the address shape alone, so RFC 7217 stable-privacy, DHCPv6, and manually assigned global addresses are dropped too: they cannot be distinguished from RFC 4941 privacy addresses by inspection. A host keeping such an address but silent for more than 7 days is reported as a new station when it reappears. EUI-64, link-local, and IPv4 addresses are not affected.

idle expiration
    With -e days, entries unseen for more than days days are dropped on the next hourly sweep. Disabled by default.

DATABASE FORMAT
The database is a CSV file with the following fields:

    ip,mac,interface,first_seen,last_seen,prev_mac

The prev_mac field stores the previous MAC address for flip-flop detection. Old database files without this field are loaded without errors.

Each entry is identified by the combination of interface and address, so the same address seen on two monitored interfaces is tracked as two separate entries rather than reported as a conflict.

Timestamps are in ISO 8601 format (local time). The database is saved atomically via a temporary file and rename.

The maximum number of entries is limited to 100000 to prevent memory exhaustion from spoofed traffic.

SIGNALS

SIGHUP
    Save the database to disk and clear any active storm suppression.

SIGTERM, SIGINT
    Save the database and exit.

SIGUSR1
    Dump active probe state to the log.

SIGPIPE
    Ignored.

FILES

/var/neighbot/neighbot.csv
    Default database file.

/var/neighbot/oui.txt
    OUI vendor database, installed automatically by ‘make install’. If present, email notifications include the hardware vendor name resolved from the MAC address prefix. The file is loaded once at startup. Use ‘make oui-update’ to re-download, or add a daily cron job to keep it current.

/etc/systemd/system/neighbot.service
    Systemd unit file (Linux).

/etc/rc.d/neighbot
    rc.d script (OpenBSD).

SECURITY
neighbot drops to an unprivileged user (default: nobody) after opening packet capture handles. All supplementary groups are dropped.

On OpenBSD, neighbot additionally uses pledge(2) and unveil(2) to restrict its privileges after initialization.

In quiet mode (-q), neighbot pledges stdio rpath wpath cpath and unveils only the database directory.

When email notifications are enabled, neighbot pledges stdio rpath wpath cpath proc exec dns and does not use unveil(2) so that sendmail(8) can access its configuration files.

In report mode (-r), neighbot pledges stdio after loading the database and OUI file. When combined with -m, the pledge is stdio proc exec to allow sendmail execution.

Each notification is delivered by a short-lived child process that performs a reverse DNS lookup and execs sendmail(8). To keep a flood of events, such as spoofed in-subnet ARP, from spawning children at packet rate, no more than 32 notification children run at once; further notifications are suppressed and logged until the backlog clears.

EXIT STATUS
neighbot exits 0 on clean shutdown or after printing a report, or 1 if no usable interfaces were found.

SEE ALSO
pledge(2), unveil(2), arpwatch(8), tcpdump(8)

AUTHORS
neighbot contributors