slaac-prefix-watch

Logs which global IPv6 prefixes the host it runs on holds, to find out how often the ISP renumbers the line.

Most consumer routers get a dynamic prefix by DHCPv6-PD and announce a /64 of it to the LAN, but can't be asked about it themselves. Every host on that LAN can be: its SLAAC addresses carry the prefix and the lifetimes the router announced.

./slaac-prefix-watch.py            # append one sample (what cron runs; silent unless the prefixes changed)
./slaac-prefix-watch.py --report   # samples taken, changes seen, how long the current prefix has held

Samples go to ~/.local/state/slaac-prefix-watch/slaac-prefix-watch.jsonl (or under $XDG_STATE_HOME), one JSON line each. A sample lists every global-unicast prefix (2000::/3) on any interface, with its remaining preferred/valid lifetimes in seconds and whether it is deprecated. ULAs and privacy (temporary) addresses are left out.

A change means the set of non-deprecated prefixes differs from the previous sample. That includes a prefix appearing on a host that had none, so the tool also works as a sentinel on a LAN without IPv6. When a router renumbers, it keeps announcing the old prefix as deprecated (preferred lifetime 0) until it expires, so the old and new prefixes overlap in the log for a while.

Running it from cron

It needs only the standard library and runs on Python 3.10+, so on hosts without uv you can call the system interpreter:

*/15 * * * * /usr/bin/python3 $HOME/dev/tools/slaac-prefix-watch/slaac-prefix-watch.py

A failure to run ip is logged as an {"error": ...} line and printed, so --report's failure count is real.

Contents

๐Ÿ“„README.md1.6 KB
๐Ÿ“„slaac-prefix-watch.py3.8 KB