about summary refs log tree commit diff
path: root/tools/dnsmasq-leases-html
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2023-04-06 17:37:27 -0700
committerFranck Cuny <franck@fcuny.net>2023-04-06 19:21:17 -0700
commit9516b633fa651875503bb61b5194bfb7e5f409e3 (patch)
treebc63b50a4f78ca72976d27a6cee6f4ca2301e213 /tools/dnsmasq-leases-html
parentmonitoring: small fixes (diff)
downloadworld-9516b633fa651875503bb61b5194bfb7e5f409e3.tar.gz
tools/dnsmasq-leases-html: create a HTML page with leases from dnsmasq
Parse the file that contains all the leases assigned by dnsmasq, and
create a static HTML page from it. This can be served by nginx to make
it easy to see what IP is assigned to a machine, and which machines are
currently on the network.
Diffstat (limited to 'tools/dnsmasq-leases-html')
-rw-r--r--tools/dnsmasq-leases-html/README.md37
-rw-r--r--tools/dnsmasq-leases-html/default.nix36
-rwxr-xr-xtools/dnsmasq-leases-html/dnsmasq-leases-html.py37
-rw-r--r--tools/dnsmasq-leases-html/templates/index.html60
4 files changed, 170 insertions, 0 deletions
diff --git a/tools/dnsmasq-leases-html/README.md b/tools/dnsmasq-leases-html/README.md
new file mode 100644
index 0000000..2437deb
--- /dev/null
+++ b/tools/dnsmasq-leases-html/README.md
@@ -0,0 +1,37 @@
+Generates a static HTML page with a list of all the leases allocated by `dnsmasq`.
+
+A simple template written in the jinja syntax is used.
+
+The file containing the leases is expected to be at `/var/lib/dnsmasq/dnsmasq.leases`, but this can be overwritten by setting the environment variable `DNSMASQ_LEASES`.
+
+The output of the script is written to `/var/lib/dnsmasq/leases.html` by default, but the destination can be overwritten by setting the environment variable `DNSMASQ_LEASES_OUT`.
+
+The script can be executed automatically by `dnsmasq` if the configuration for `dhcp-script` is set to the path of the script. This will only be executed when a *new* lease is created or an *old* lease is deleted. To execute the script when a lease is *updated* you need to use the configuration `script-on-renewal`.
+
+A configuration looks like this:
+
+``` ini
+dhcp-script=${pkgs.tools.dnsmasq-to-html}/bin/dnsmasq-leases-html
+script-on-renewal
+```
+
+## nginx
+To serve the page with nginx, you can use the following configuration:
+
+``` nix
+services.nginx = {
+  enable = true;
+  virtualHosts."dnsmasq" = {
+    listen = [
+      {
+        addr = "192.168.6.1";
+        port = 8067;
+      }
+    ];
+    locations."/" = {
+      root = "/var/lib/dnsmasq";
+      index = "leases.html";
+    };
+  };
+};
+```
diff --git a/tools/dnsmasq-leases-html/default.nix b/tools/dnsmasq-leases-html/default.nix
new file mode 100644
index 0000000..4848ea7
--- /dev/null
+++ b/tools/dnsmasq-leases-html/default.nix
@@ -0,0 +1,36 @@
+{ self, lib, stdenvNoCC, pkgs }:
+
+stdenvNoCC.mkDerivation rec {
+  pname = "dnsmasq-leases-html";
+  src = ./dnsmasq-leases-html.py;
+  templates = ./templates;
+  version = "0.1.0";
+
+  buildInputs = [
+    (pkgs.python310.withPackages (ps: with ps; [
+      jinja2
+    ]))
+  ];
+
+  propagatedBuildInputs = [
+    (pkgs.python310.withPackages (ps: with ps; [
+      jinja2
+    ]))
+  ];
+
+  dontUnpack = true;
+  dontBuild = true;
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp $src $out/bin/${pname}
+    cp -r $templates $out/bin/templates
+  '';
+
+  meta = with pkgs.lib; {
+    description = "CLI to generate a HTML page with dnsmasq leases.";
+    license = licenses.mit;
+    platforms = platforms.unix;
+    maintainers = [ ];
+  };
+}
diff --git a/tools/dnsmasq-leases-html/dnsmasq-leases-html.py b/tools/dnsmasq-leases-html/dnsmasq-leases-html.py
new file mode 100755
index 0000000..c1f03db
--- /dev/null
+++ b/tools/dnsmasq-leases-html/dnsmasq-leases-html.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+
+import datetime
+import ipaddress
+import os
+
+from jinja2 import Environment, FileSystemLoader
+
+
+outfile = os.getenv("DNSMASQ_LEASES_OUT", "/var/lib/dnsmasq/leases.html")
+leases_file = os.getenv("DNSMASQ_LEASES", "/var/lib/dnsmasq/dnsmasq.leases")
+
+leases = []
+
+with open(leases_file, "r") as f:
+    for line in f:
+        content = line.rstrip("\n").split(" ")
+        lease = dict()
+        if int(content[0]) == 0:
+            lease["expire"] = "never"
+        else:
+            lease["expire"] = datetime.datetime.fromtimestamp(int(content[0]))
+        lease["MAC"] = content[1]
+        lease["IP"] = ipaddress.ip_address(content[2])
+        lease["hostname"] = content[3]
+        leases.append(lease)
+
+leases = sorted(leases, key=lambda d: d["IP"])
+
+dir_path = os.path.dirname(os.path.realpath(__file__))
+templates_dir = os.path.join(dir_path, "templates")
+environment = Environment(loader=FileSystemLoader(templates_dir))
+template = environment.get_template("index.html")
+
+content = template.render(leases=leases)
+with open(outfile, "w") as fh:
+    print(content, file=fh)
diff --git a/tools/dnsmasq-leases-html/templates/index.html b/tools/dnsmasq-leases-html/templates/index.html
new file mode 100644
index 0000000..913a0c9
--- /dev/null
+++ b/tools/dnsmasq-leases-html/templates/index.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>Leases assigned by dnsmasq</title>
+  <style type="text/css">
+    body {
+      margin: auto;
+      width: 70%;
+      font-family: monospace;
+      font-size: 16px;
+    }
+    .center {
+      margin-left: auto;
+      margin-right: auto;
+    }
+    td, th {
+      padding-left: 1em;
+      padding-right: 1em;
+      padding-top: .5em;
+      padding-bottom: .5em;
+    }
+    td:first-child, th:first-child {
+      padding-left: .25em;
+    }
+    td:last-child, th:last-child {
+      padding-right: .25em;
+    }
+    th {
+      padding-top: 1em;
+      text-align: left;
+    }
+    tr:nth-child(even) {
+      background: #eee;
+    }
+    form {
+      display: inline;
+    }
+  </style>
+</head>
+
+<body>
+  <table>
+    <tr>
+      <th>IP address</th>
+      <th>MAC address</th>
+      <th>Hostname</th>
+      <th>Expire</th>
+    </tr>
+    {% for lease in leases %}
+    <tr>
+      <td>{{ lease.IP }}</td>
+      <td>{{ lease.MAC }}</td>
+      <td>{{ lease.hostname }}</td>
+      <td>{{ lease.expire }}</td>
+    </tr>
+    {% endfor %}
+  </table>
+</body>
+</html>