diff --git a/.gitignore b/.gitignore index 2869ec0..be9d161 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ __pycache__/ *.pyc *.pyo - +.flake8 +.venv/ +test/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 96f4f72..3cc3c3f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "python.pythonPath": "/usr/bin/python3", - "python.linting.pylintEnabled": true, - "python.linting.enabled": true + "python.linting.enabled": true, + "python.formatting.provider": "black", + "python.linting.flake8Enabled": true } \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..33d6862 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ + + +To obtain a DNS verified certificate for the websockert server: + +certbot certonly -d w02.wrede.ca -d ws.wrede.ca --dns-rfc2136 --dns-rfc2136-credentials /usr/local/etc/letsencrypt/certbot_dns_rfc2136.ini --dns-rfc2136-propagation-seconds 10 + +and the rfc2136.ini file looks like: + +# Target DNS server +dns_rfc2136_server = 192.168.196.248 +# Target DNS port +dns_rfc2136_port = 53 +# TSIG key name +dns_rfc2136_name = tsig-key +# TSIG key secret +dns_rfc2136_secret = 1KsWP8ZkZxBDKS0RQ2n3bkz1xpVPtz3Tk1y3r/dF+4knwGBzscse8iewaEr/6jUtxaL1taGME6eqSDtV2SD8NQ== +# TSIG key algorithm +dns_rfc2136_algorithm = HMAC-SHA512 + diff --git a/hbd b/hbd index de90537..fc67997 100755 --- a/hbd +++ b/hbd @@ -2,11 +2,8 @@ # $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 = 4.2 - import time import os -import string import sys import socket import ssl @@ -20,7 +17,8 @@ import signal import pickle import smtplib import traceback -import urllib.request, urllib.parse, urllib.error +import urllib.request +import urllib.error import urllib.parse import http.client import threading @@ -38,7 +36,10 @@ from subprocess import Popen, STDOUT, PIPE # from hbdclass import * import hbdclass +VER = 4.4 + CERT_PATH = "/usr/local/etc/letsencrypt/live/w02.wrede.ca/" +CERT_PATH = "./test/" WSS_PEM = CERT_PATH + "fullchain.pem" WSS_KEY = CERT_PATH + "privkey.pem" @@ -82,18 +83,18 @@ lastfm = ["", "", ""] tcss = """ """ @@ -142,7 +143,7 @@ class LogDevice: def dicttos(ID, d, compress=False): s = [] for k in d: - if type(d[k]) == type(1.2): + if isinstance(d[k], float): s.append("%s=%0.5f" % (k, d[k])) else: s.append("%s=%s" % (k, d[k])) @@ -207,8 +208,9 @@ def email(s, msg): except smtplib.SMTPRecipientsRefused as errs: log(None, "cannot send email: %s\n" % (errs)) ret = "Fail" - except: - print(("smtp error: " + traceback.format_exc())) + except Exception as e: + print(f"smtp error: {e}") + ret = "Fail" saveandrestart() try: server.quit() @@ -294,7 +296,7 @@ def pushsignal(msg, title="hbd", recipient=RECIPIENT): "send", "-m", message, - # "-g", GROUP, + # "-g", GROUP, recipient, ] @@ -313,7 +315,7 @@ def pushsignal(msg, title="hbd", recipient=RECIPIENT): # nsupdate: set the DNS A record for a fqdn -# return: None if ok, else error text +# return: None if ok, else error text def nsupdate(hostname, newip, dyndomain): D = {} D["domain"] = dyndomain @@ -424,8 +426,7 @@ def checkoverdue(): conn.newstate(hbdclass.Connection.overdue, now, grace) pmsg.append(conn.afam) if ( - conn.state == hbdclass.Connection.overdue - and (now - conn.lastbeat) > DROPOVERDUE + conn.state == hbdclass.Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE ): conn.newstate(hbdclass.Connection.unknown, conn.lastbeat) if pmsg != []: @@ -505,7 +506,7 @@ def readsock(sock): addr = addrp[0:2] name = shortname(msg.get("name", "unknown")) - if not name in hbdclass.Host.hosts: # was: hosts.has_key(name): + if name not in hbdclass.Host.hosts: # was: hosts.has_key(name): host = hbdclass.Host(name) host.dyn = name in dyndnshosts if verbose: @@ -550,7 +551,7 @@ def readsock(sock): email("msg", message) pushmsg(message) - if conn.getstate() != hbdclass.Connection.up: # XXX and interval > 0: + if conn.getstate() != hbdclass.Connection.up: # XXX and interval > 0: lasts = conn.state d = conn.newstate(hbdclass.Connection.up, now) m = "%s back after being %s for %s" % (conn.afam, lasts, dur(d)) @@ -661,7 +662,7 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): return self.server_version def handle(self): - # return http.server.BaseHTTPRequestHandler.handle(self) + # return http.server.BaseHTTPRequestHandler.handle(self) try: return http.server.BaseHTTPRequestHandler.handle(self) except Exception as e: @@ -678,8 +679,8 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): "Last-Modified", time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)), ) - # self.send_header("Accept-Ranges","bytes") - # self.send_header("hbdclass.Connection","close") + # self.send_header("Accept-Ranges","bytes") + # self.send_header("hbdclass.Connection","close") for h in headerdict: self.send_header(h, headerdict[h]) self.end_headers() @@ -764,11 +765,11 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): uname = qa.get("h", [None])[0] if not uname: code, res = self.builderror(400, "Argument error", "need h= argument") - if not uname in hbdclass.Host.hosts: + if uname not in hbdclass.Host.hosts: code, res = self.builderror(400, "Data error", "h=%s not found" % uname) else: log(uname, "dropped") - # for addr in hbdclass.Host.hosts[uname].0i + # for addr in hbdclass.Host.hosts[uname].0i # TODO: send message to websocket about dropped host del hbdclass.Host.hosts[uname] res = self.buildhead() @@ -778,7 +779,7 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): uname = qa.get("h", [None])[0] if not uname: code, res = self.builderror(400, "Argument error", "need h= argument") - if not uname in hbdclass.Host.hosts: + if uname not in hbdclass.Host.hosts: code, res = self.builderror(400, "Data error", "h=%s not found" % uname) else: ll = hbdclass.Host.hosts[uname].registerDns() @@ -814,15 +815,15 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): elif qr.path == "/api/0/hosts": # api access to host table headerdict = {"Content-Type": "application/json; charset=utf-8"} - l = [] + lst = [] for h in hbdclass.Host.hosts: - l.append(hbdclass.Host.hosts[h].jsons()) - res = ["[" + ",".join(l) + "]"] + lst.append(hbdclass.Host.hosts[h].jsons()) + res = ["[" + ",".join(lst) + "]"] elif qr.path == "/api/0/messages": # api access to host table headerdict = {"Content-Type": "application/json; charset=utf-8"} - l = msgs[len(msgs) - 30 :] - res = [json.dumps(l)] + lst = msgs[len(msgs) - 30:] + res = [json.dumps(lst)] elif qr.path == "/r": # restart res = self.buildhead() @@ -889,7 +890,7 @@ def closeup(): except: pass - # signal.signal(signal.SIGTERM, 0) + # signal.signal(signal.SIGTERM, 0) signal.signal(signal.SIGHUP, 0) @@ -947,7 +948,7 @@ async def ws_serve(websocket, path): ) await websocket.send(jmsg) # messages in reverse order - for m in msgs[len(msgs) - 20 :]: + for m in msgs[len(msgs) - 20:]: jmsg = json.dumps({"type": "message", "data": m}) await websocket.send(jmsg) @@ -1076,17 +1077,17 @@ if f: ls = f.readline() if len(ls) == 0: break - l = ls[:-1].strip() - if len(l) == 0 or l[0] == "#": + ln = ls[:-1].strip() + if len(ln) == 0 or ln[0] == "#": continue if verbose: - print((" %s" % l)) - r = l.split("=") + print((" %s" % ln)) + r = ln.split("=") o = r[0].strip() try: a = eval(r[1].strip()) except Exception as e: - print(("error: %s" % str(r))) + print("error: %s %s" % (e, str(r))) sys.exit(1) if o == "interval": interval = a @@ -1222,7 +1223,11 @@ asyncio.set_event_loop(loop) ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) wss_pem = pathlib.Path(WSS_PEM) wss_key = pathlib.Path(WSS_KEY) -ssl_context.load_cert_chain(wss_pem, keyfile=wss_key) +try: + ssl_context.load_cert_chain(wss_pem, keyfile=wss_key) +except FileNotFoundError: + print(("warning: missing %s or %s" % (wss_pem, wss_key))) + sys.exit(1) wss_start_server = websockets.serve( ws_serve, hbd_host, WSSPORT, ssl=ssl_context, loop=loop, subprotocols=["hbd"] ) @@ -1281,8 +1286,8 @@ while running: for fh in sr[0]: if fh in [sock, sock6]: readsock(fh) - # elif fh == serv.fileno(): - # serv.handle_request() + # elif fh == serv.fileno(): + # serv.handle_request() else: sys.stderr.write("what happend just now?\n") if DEBUG > 3: diff --git a/hbdclass.py b/hbdclass.py index d99bad6..6a9501a 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -1,6 +1,6 @@ """ -host and connection class shared between hbd and -the websit's heartbeat.py +host and connection class shared between hbd and +the websit's heartbeat.py """ @@ -234,7 +234,7 @@ class Host: return self.dyn def isIPv4(self, addr): - if type(addr) == type(()): + if isinstance(addr, tuple): return addr[0].find(".") > 0 else: return addr.find(".") > 0 @@ -328,7 +328,7 @@ class Host: hostfields = Host.hostfields_long h = [] for f in hostfields: - if type(f) == type(()): + if isinstance(f, tuple): h.append(self.gene(tag, hd[f[0]], f[1])) else: h.append(self.gene(tag, hd[f])) @@ -354,7 +354,7 @@ class Host: res = [] le = max(40 - len(Host.hosts), 3) res.append("