For a while a I have put off building out a system to detect dynamic IP address drift. In theory the system is not very complicated, however I just have not invested the energy into it. Really there are two major components which need to be checked against eachother:

  1. Current public IP address of the running system. Of course this will not work on systems like AWS however for self hosted solutions this will keep the IPs in sync.
  2. Current DNS address of public DNS records. This will result in a query against specific servers.

Checking the public IP address

The public-ip package has two interesting approaches. One via querying DNS entries from several well known systems returning the IP address. As a backup or alternative the package will ask the a set of wellknown services via HTTP(S) for the IP adress. The appears to suite my needs.

Querying the DNS server

Looks like Node has added support for working on this. Should be fairly straight forward by inovoking setServers on an instance of the resolvers.

A Rough Prototype

const {main} = require("junk-bucket");
const {Future} = require("junk-bucket/future");
const {Context} = require("junk-bucket/context");

const publicIp = require("public-ip");
const {Resolver, ADDRCONFIG} = require('dns');

main(async (l) => {
	const serviceContext = new Context("ip-dns-monitor", l);

	const hostName = process.env['MONITOR_HOSTNAME'];
	if( !hostName ) { throw new Error("env var MONITOR_HOSTNAME required"); }
	const dnsServer = process.env['MONITOR_DNS'];
	if( !dnsServer ) { throw new Error("env var MONITOR_DNS required"); }

	//check
	const myPublicIP = await publicIp.v4();
	const resolver = new Resolver();
	resolver.setServers([dnsServer]);

	const resolvedSignal = new Future();
	resolver.resolve4(hostName, (err,addresses) => {
		if( err ) { return resolvedSignal.reject(err); }
		resolvedSignal.accept(addresses);
	});
	const resolved = await resolvedSignal.promised;

	const targetMatches = resolved.includes(myPublicIP);
	if( targetMatches ) {
		serviceContext.logger.info("Hostname maps to IP address");
	} else {
		serviceContext.logger.info("Hostname does not map ", {myPublicIP, resolved});
	}
});

I’ve posted the code at github.com/meschbach/ip-dns-monitor. Might actually expand this to a fully operational battle station in the future.