ADDRWATCH(8)

πŸ“¦ version 1.0.2, in alpine 3.24, fedora 43, fedora 44

πŸ‘‘ ADDRWATCH β€” the addrwatch(8) glow-up πŸ’…

okay bestie, sit down, because we're about to talk about addrwatch, the ethernet/ip address monitoring tool, and honestly? it's giving network surveillance but make it cute. this is section 8 of the manual, so it's a system admin situation. buckle up πŸŽ€


✨ NAME ✨

addrwatch β€” ethernet/ip address monitoring tool πŸ¦‹


✨ SYNOPSIS ✨

addrwatch [-lmqv46dP?V] [-m[database]] [-o file] [-s sqlite3.db] [-b ip]
[-H size] [-r num] [-p pidfile] [-u user] [-h hostname] [--mysql-table=table]
[--sqlite3-table=table] [INTERFACE1 INTERFACE2 ...]

like yes, that's a lot of brackets, but we'll go through every single one, no skipping, periodt πŸ’–


✨ DESCRIPTION ✨

so addrwatch is basically arpwatch's cooler cousin. its whole main character purpose is to monitor the network and log ethernet/ip pairings β€” that's it, that's the job 🌸

want to just try it out? run it with zero arguments. when you start it with no arguments it will:

  • open the first non loopback interface
  • start logging events to the console
  • write absolutely nothing to disk

every ethernet/ip pairing it discovers gets printed to stdout. and all the debug, warning, and err messages? those get sent to syslog</> and printed to stderr. two channels, very organized, we love a multitasker 🫢


✨ OPTIONS ✨

  • -l, --syslog β€” log the discovered ethernet/ip pairings to syslog (daemon facility). log girlies rise up πŸ“œ
  • *-o *file, --output=file β€” write discovered ethernet/ip pairings to a specified file. the OUTPUT section below has the tea πŸ“
  • *-m[database*], --mysql=[database] β€” write discovered ethernet/ip pairings into a MySQL database. your default MySQL server, login info and database should live in the ~/.my.cnf config file, in an addrwatch section. here's what that file looks like:
[addrwatch]
host=localhost
user=db_user
password=db_password
database=db_name

the pairings get written into a table with this schema:

CREATE TABLE IF NOT EXISTS `addrwatch` (
    `tstamp` timestamp NOT NULL,
    `hostname` varchar(256) NOT NULL,
    `interface` varchar(16) NOT NULL,
    `vlan_tag` int(11) NOT NULL,
    `mac_address` varchar(17) NOT NULL,
    `ip_address` varchar(42) NOT NULL,
    `origin` varchar(8) NOT NULL,
    KEY `interface` (`interface`),
    KEY `vlan_tag` (`vlan_tag`),
    KEY `interface_vlan_tag` (`interface`,`vlan_tag`)
)

default table name is addrwatch unless you pass --mysql-table. slay πŸ’…

  • *--mysql-table=TBL* β€” insert the data into MySQL table TBL instead. custom naming rights, iconic ✨
  • *-s *sqlite3.db, --sqlite3=sqlite3.db β€” write discovered ethernet/ip pairings to a sqlite3 database in the sqlite3.db file. the database file and the tables get created during startup if they don't already exist. self-sufficient queen πŸ‘‘

pairings go into a table with this schema:

CREATE TABLE addrwatch(
    timestamp UNSIGNED BIG INT,
    interface varchar(16),
    vlan_tag UNSIGNED INT,
    mac_address varchar(17),
    ip_address varchar(42),
    origin TINYINT
);
  • -q, --quiet β€” suppress any output to stdout and stderr. silence. serenity. 🀫
  • -v, --verbose β€” turn on debug messages. we're nosy now πŸ”
  • -4, --ipv4-only β€” capture only IPv4 packets. four only πŸ’™
  • -6, --ipv6-only β€” capture only IPv6 packets. six only πŸ’œ
  • *-b *ip, --blacklist=ip β€” ignore pairings that involve the specified ip address. not on my watch πŸ™ˆ
  • *-r *num, --ratelimit=num β€” the dupe control. here's the breakdown:
    • if num > 0, ratelimit duplicate ethernet/ip pairings to 1 every num seconds.
    • if num = 0, ratelimiting of duplicate entries is disabled.
    • if num = -1, duplicate entries are suppressed indefinitely.
    • more details in the RATELIMITING section, go read it, i'll wait 🧚
  • *-H *size, --hashsize=size β€” the size of the ratelimiting hash table used to store recent ethernet/ip address pairings. minimum value is 1, maximum value is 65536. default value is 1 (which means no hash table, and all pairings are stored in a linked list instead).
    • bump the hash table size up in active networks with lots of nodes. a lager hash table speeds up cache lookups, but it costs you more memory usage. tradeoffs, bestie πŸ’€
  • -d, --daemon β€” become a daemon after start. this option implies the -q (--quiet) argument. it's a package deal 🎁
  • *-h *hostname, --hostname=hostname β€” override the system hostname. main character energy, rename yourself πŸŽ€
  • *-p *pidfile, --pid=pidfile β€” write the process id to pidfile. the pidfile gets deleted when the application is terminated. this option is usually used together with the -d (--daemon) argument. heads up though: when it's used with the -u (--user) argument, the pidfile will be created before changing the active user, and in most cases addrwatch will not be able to delete the pidfile on exit. so it just... lingers. ghost pidfile πŸ‘»
  • -P, --no-promisc β€” disable promisc mode on network interfaces. minding its own business, respectfully 🌸
  • *-u *user, --user=user β€” suid to user after opening the network interfaces.
  • -?, --help β€” show the command line arguments.
  • --usage β€” give a short usage message.
  • -V, --version β€” print the program version. identity check ✨

✨ OUTPUT ✨

in the output file (or stdout), each line = one ethernet/ip address pairing discovery event. every event has this format: unix timestamp, interface, vlan tag, mac address, ip address and packet type, all separated by a space. no commas, just vibes 🌈

packets that don't have a vlan tag get represented by the tag value 0.

the possible packet types are ARP_REQ, ARP_REP, ARP_ACD, ND_ND, ND_NA, ND_DAD. the ethernet address and the IP address get pulled from different parts of the packet depending on the packet type. here's the breakdown:

  • ARP_REQ β€” ARP Request packet. the sender hardware address (from the ARP header) and the sender protocol address (from the ARP header) get saved.
  • ARP_REP β€” ARP Reply packet. the sender hardware address (from the ARP header) and the sender protocol address (from the ARP header) get saved.
  • ARP_ACD β€” ARP Address collision detection packet. the sender hardware address (from the ARP header) and the target protocol address (from the ARP header) get saved.
  • ND_NS β€” Neighbor Solicitation packet. the source link-layer address (from the NS option) and the source address (from the IPv6 header) get saved.
  • ND_NA β€” Neighbor Advertisement packet. the target link-layer address (from the NA option) and the source address (from the IPv6 header) get saved.
  • ND_DAD β€” Duplicate Address Detection packet. the source MAC (from the Ethernet header) and the target address (from the NS header) get saved.

output example, look at her go πŸ’–

timestamp iface vlan mac ip type
1339405924 eth0 502 e0:ca:94:30:06:8b 2001:db8:200:4202:8946:e6b7:976a:cef3 ND_NA
1339406009 eth0 257 f0:4d:a2:2e:ad:0d 169.254.227.85 ARP_ACD
1339406018 eth0 502 58:1f:aa:d0:92:7d 2001:db8:200:4202:805d:b5ae:8374:436c ND_DAD
1339406029 eth0 502 38:59:f9:3a:de:65 172.16.2.19 ARP_REP
1339406030 eth0 12 00:c0:ee:5a:89:c7 10.1.32.221 ARP_REQ
1339406030 eth0 252 00:1c:c0:79:ab:ee 2001:db8:200:2381::657b ND_NS

✨ RATELIMITING ✨

if you run it without ratelimiting, addrwatch reports an ethernet/ip pairing every single time it gets a usable ARP or IPv6 ND packet. and in actively used networks? that generates a LOT of duplicate pairings, especially for routers and servers. it's spam. it's a group chat with no mute button 😭

the ratelimiting option -r num (--ratelimit=num) suppresses the output of duplicate pairings for at least NUM seconds. all non-duplicate pairings still get reported, don't worry. in other words: if addrwatch has discovered some pairing (mac,ip), it will not report that same (mac,ip) again unless NUM seconds have passed. πŸ‘‘

but wait β€” there's an exception, and it exists so we can still track ethernet address changes. if addrwatch has discovered these pairings:

(mac1,ip), (mac2,ip), (mac1,ip)

all within the ratelimit time window, it will report all three pairings. this way ratelimiting doesn't lose any information about ethernet address changes. smart. iconic. ate πŸ’…

so for example, if we have a stream of events like this:

time   ethernet          ip
01     11:22:33:44:55:66 192.168.0.1
15     11:22:33:44:55:66 192.168.0.1
20     aa:bb:cc:dd:ee:ff 192.168.0.1
25     aa:bb:cc:dd:ee:ff 192.168.0.1
30     11:22:33:44:55:66 192.168.0.1
35     11:22:33:44:55:66 192.168.0.1
40     aa:bb:cc:dd:ee:ff 192.168.0.1
65     aa:bb:cc:dd:ee:ff 192.168.0.1

with --ratelimit=100 we would get:

time   ethernet          ip
01     11:22:33:44:55:66 192.168.0.1
20     aa:bb:cc:dd:ee:ff 192.168.0.1
30     11:22:33:44:55:66 192.168.0.1
40     aa:bb:cc:dd:ee:ff 192.168.0.1

without that exception, the output would be:

time   ethernet          ip
01     11:22:33:44:55:66 192.168.0.1
20     aa:bb:cc:dd:ee:ff 192.168.0.1

and then we would lose the information that the address 192.168.0.1 was used by 11:22:33:44:55:66 between the 30th and 40th seconds. gone. deleted. not the vibe 😭

so to sum it all up: ratelimiting reduces the amount of duplicate information without losing any ethernet address change events. best of both worlds, we love a balanced queen ✨

the ratelimit option essentially limits the data granularity for IP address usage duration information β€” meaning when and for what time period a specific IP address was used. on the other hand, if you don't ratelimit at all, you wouldn't get very precise IP address usage duration info anyway, because some hosts might use an IP address without sending ARP or ND packets as often as other hosts do. it's not a you problem, it's a them problem πŸ™ˆ

  • if num is set to 0, ratelimiting is disabled and all pairing discovery events are reported.
  • if num is set to -1, ratelimiting is enabled with an infinitely long time window, therefore all duplicate pairings are suppressed indefinitely. in this mode addrwatch acts almost as arpwatch, with the exception that ethernet address changes are still reported. almost identical twin behavior πŸ‘―

okay so it might look tempting to always run addrwatch with --ratelimit=-1, but if you do that you lose the information about when and for what period of time a specific IP address was used. there would be no difference between a temporary IPv6 address that was used once and a statically configured permanent address. and that's a loss, bestie. don't do it πŸ’€


✨ NOTES ✨

you can send the SIGHUP signal to addrwatch to force it to reopen the output file. this may be useful if you're using it in combination with logrotate(8). signal handling, so sophisticated πŸ’…


✨ EXAMPLES ✨

start monitoring the first non loopback network interface. output goes to stdout:

addrwatch

start monitoring on multiple interfaces:

addrwatch eth0 eth1 eth2

start addrwatch as a daemon, write output to a file, enable ratelimiting to 1 event per minute:

addrwatch -d -o /var/lib/addrwatch.dat -r 60 eth0

start as a daemon, save the pid file, send output to syslog, ratelimit to 1 event per hour, suid to nobody, monitor multiple interfaces:

addrwatch -d -p /var/run/addrwatch.pid -s -r 3600 -u nobody eth0 eth1 eth3

look at all those flags living their best life πŸŽ€


✨ SEE ALSO ✨

logrotate(8) 🌸


and that's the whole page, bestie!! this was addrwatch version 0.3, dated 06 Jun 2012, and it's still out here monitoring ethernet/ip pairings like the icon it is. go forth and watch some addresses, i'm obsessed with you πŸ«ΆπŸ’–βœ¨

πŸ“¦ where this page comes from