From 2248cd41347b6f7370ecd57b914c6ba778d6af33 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 19 Apr 2016 21:11:27 -0400 Subject: [PATCH] trakc both IPv4 and 6 addresses --- hbd | 139 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 49 deletions(-) diff --git a/hbd b/hbd index 67411e4..9b737d5 100755 --- a/hbd +++ b/hbd @@ -2,7 +2,7 @@ # $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $ # Wait for heartbeat messages and act on them (or their absence) # -VER = 2.00 +VER = 3.00 import time import os @@ -37,7 +37,9 @@ AEMAIL = ["andreas@wrede.ca"] NAME = "heatbeat" SMTPSERVER = "localhost" +# Table of Hosts hosts = {} +# map of addrs to names htab = {} msgs = [] @@ -74,26 +76,25 @@ def shortname(name): return r[0] +def isIPv4(addr): + return addr.find('.') > 0 + class NullDevice: def write(self, s): pass -class Addr: - def __init__(self, a4, a6): - self.a4 = a4 - self.a6 = a6 - - class Host: up = "up" down = "down" overdue = "overdue" - def __init__(self, name, addr): + + def __init__(self, name): global num - self.name = shortname(name) - self.addr = addr + self.name = name + self.addr4 = None + self.addr6 = None self.num = num self.lastbeat = time.time() self.upcount = 0 @@ -105,6 +106,37 @@ class Host: self.cmds = [] self.hdwcounts = [[0,0],[0,0],[0,0]] num += 1 + hosts[name] = self + + + def newaddr(self, addr): + if isIPv4(addr): + if self.addr4: + if self.addr4 == addr: + r = None + else: + r = "changed from %s to %s" % (self.addr4, addr) + del htab[self.addr4] + self.addr4 = addr + htab[addr] = self.name + else: + r = "new addr %s" % (addr) + self.addr4 = addr + htab[addr] = self.name + else: + if self.addr6: + if self.addr6 == addr: + r = None + else: + r = "changed from %s to %s" % (self.addr6, addr) + del htab[self.addr6] + self.addr6 = addr + htab[addr] = self.name + else: + r = "new addr %s" % (addr) + self.addr6 = addr + htab[addr] = self.name + return r # called when reloading class from pickle, add new fields here @@ -119,9 +151,21 @@ class Host: except: self.hdwcounts = [[self.doesack,self.upcount],[self.doesack,self.upcount],[self.doesack,self.upcount]] + try: + a=self.addr4 + except: + print "fix %s: addr to addr4/6 fixup" % self.name + if isIPv4(self.addr): + self.addr4 = self.addr + else: + self.addr6 = self.addr + del self.addr + + def getstate(self): return self.state + def dispstate(self): if self.state in ["down", "overdue"]: state = "%s" % self.state @@ -129,6 +173,7 @@ class Host: state = "%s" % self.state return state + def dispstats(self): if self.doesack != -1: if self.upcount > 0: @@ -148,6 +193,7 @@ class Host: return "(%s)" % (self.doesack) return 'N/A>' + # set new state, return number of secs in previous state def newstate(self, state, when=0): self.state = state @@ -255,25 +301,13 @@ def dur(sec): return "0:%02d" % s -# -def addhost(name, addr): - sname = shortname(name) - if sname in hosts: # was: hosts.has_key(sname): - del htab[hosts[sname].addr] - hosts[sname].addr = addr - htab[addr] = sname - m = "%s, changed address to %s" % (sname, addr) - log(m) - else: - hosts[sname] = Host(sname, addr) - s = hosts.keys() - s.sort() - x = 0 - for n in s: - hosts[n].num = x - x += 1 - htab[addr] = sname - +def fixsort(): + s = hosts.keys() + s.sort() + x = 0 + for n in s: + hosts[n].num = x + x += 1 # def on_exit(): @@ -286,7 +320,11 @@ def on_exit(): def initlog(logfile): - return open(logfile, "a") + try: + return open(logfile, "a+") + except: + pass + return open(logfile, "w") # @@ -337,23 +375,21 @@ def dnsupdatethread(): def fromaddr(name, addr, boot, interval, acks): global htab - newh=False if not name in hosts: # was: hosts.has_key(name): - addhost(name, addr) + host = Host(name) newh=True - host = hosts[name] + else: + host = hosts[name] + host.doesack = acks - if host.addr != addr: - if host.addr in htab: # was: htab.has_key(host.addr): - del htab[host.addr] - host.addr = addr - htab[addr] = name - m = "%s changed address to %s" % (host.name, addr) - if name in dyndnshosts and not ":" in addr: # don't try and cat ptr to IPv6 addr + res = host.newaddr(addr) + if res: + m = "%s %s" % (host.name, res) + log(m) + if name in dyndnshosts and isIPv4(addr): # don't try and cat ptr to IPv6 addr + if DEBUG > 0: print "dbg: dynhost and %s: %s" % (isIPv4(addr), addr) dnsQ.put((name, addr)) - else: - log(m) if name in watchhosts: email("address change", m) pushover(m) @@ -507,12 +543,12 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): res=self.buildhead(refresh=60) res.append("

Heartbeat status %s

%s (%s)

" % (VER, time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT'))) res.append("") - res.append("\n") + res.append("\n") hosts_sorted = hosts.keys() hosts_sorted.sort() for h in hosts_sorted: - res.append("%s\n" % \ - (h, hosts[h].dispstate(), hosts[h].dispstats(), hosts[h].addr, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime)))) + res.append("%s\n" % \ + (h, hosts[h].dispstate(), hosts[h].dispstats(), hosts[h].addr4, hosts[h].addr6, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime)))) res.append("
HostStateHrDyWkIP AddrLast change
HostStateHrDyWkIP4 AddrIP6 AddrLast change
%-24s%-7s%-16s%-17s
%-24s%-7s%-16s%-16s%-17s
") res.append("

Log of Events

") for m in msgs[len(msgs)-30:]: @@ -780,13 +816,13 @@ if f: elif r[0] == 'hbd_port': hbd_port = eval(r[1]) elif r[0] == 'hbd_host': - hbd_host = r[1] + hbd_host = eval(r[1]) elif r[0] == 'hb_port': hb_port = eval(r[1]) elif r[0] == 'logfile': - logfile = r[1] + logfile = eval(r[1]) elif r[0] == 'logfmt': - logfmt = r[1] + logfmt = eval(r[1]) elif r[0] == 'watchhosts': watchhosts = eval(r[1]) elif r[0] == 'dyndnshosts': @@ -845,7 +881,12 @@ sock6.bind(("", hb_port)) ilist.append(sock6) -serv = HttpServer((hbd_host, hbd_port), HttpHandler) +try: + serv = HttpServer((hbd_host, hbd_port), HttpHandler) +except: + print "failed to start server on %s:%s" % (hbd_host, hbd_port) + sys.exit(1) + servthread = threading.Thread(target=serv.serve_forever) servthread.daemon = True servthread.start()