summaryrefslogtreecommitdiff
path: root/overlays/inwx-cdnskey
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2022-02-27 16:48:41 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2022-02-27 16:48:41 +0100
commitc471ec95f8ccf0363cfae09c4479bf8e0907d065 (patch)
tree455f443e310587a6cec09447148855d204cce31c /overlays/inwx-cdnskey
parentf8cec37ed3fda24dd3e834120b0f6dbcf95e54d2 (diff)
downloadnixos-c471ec95f8ccf0363cfae09c4479bf8e0907d065.tar
nixos-c471ec95f8ccf0363cfae09c4479bf8e0907d065.tar.gz
nixos-c471ec95f8ccf0363cfae09c4479bf8e0907d065.tar.bz2
nixos-c471ec95f8ccf0363cfae09c4479bf8e0907d065.tar.xz
nixos-c471ec95f8ccf0363cfae09c4479bf8e0907d065.zip
inwx-cdnskey
Diffstat (limited to 'overlays/inwx-cdnskey')
-rw-r--r--overlays/inwx-cdnskey/default.nix28
-rw-r--r--overlays/inwx-cdnskey/inwx-cdnskey.py95
-rw-r--r--overlays/inwx-cdnskey/python-packages.nix98
3 files changed, 221 insertions, 0 deletions
diff --git a/overlays/inwx-cdnskey/default.nix b/overlays/inwx-cdnskey/default.nix
new file mode 100644
index 00000000..c19c2df5
--- /dev/null
+++ b/overlays/inwx-cdnskey/default.nix
@@ -0,0 +1,28 @@
1final: prev:
2let
3 packageOverrides = final.callPackage ./python-packages.nix {};
4 inpPython = final.python39.override { inherit packageOverrides; };
5in {
6 inwx-cdnskey = prev.stdenv.mkDerivation rec {
7 name = "inwx-cdnskey";
8 src = ./inwx-cdnskey.py;
9
10 phases = [ "buildPhase" "checkPhase" "installPhase" ];
11
12 python = inpPython.withPackages (ps: with ps; [pyxdg inwx-domrobot configparser dnspython]);
13
14 buildPhase = ''
15 substituteAll $src inwx-cdnskey
16 '';
17
18 doCheck = true;
19 checkPhase = ''
20 ${python}/bin/python -m py_compile inwx-cdnskey
21 '';
22
23 installPhase = ''
24 install -m 0755 -D -t $out/bin \
25 inwx-cdnskey
26 '';
27 };
28}
diff --git a/overlays/inwx-cdnskey/inwx-cdnskey.py b/overlays/inwx-cdnskey/inwx-cdnskey.py
new file mode 100644
index 00000000..0add24a9
--- /dev/null
+++ b/overlays/inwx-cdnskey/inwx-cdnskey.py
@@ -0,0 +1,95 @@
1#!@python@/bin/python
2
3from INWX.Domrobot import ApiClient, ApiType
4from xdg import BaseDirectory
5import configparser
6import sys
7import dns.message
8import dns.rdataclass
9import dns.rdatatype
10import dns.query
11import dns.zone
12import dns.rdtypes.ANY.DNSKEY
13import argparse
14import ipaddress
15import re
16import base64
17
18
19class ApiConnection:
20 username = ''
21 password = ''
22 shared_secret = None
23 api_client = None
24
25 def __init__(self, **kwargs):
26 config = configparser.ConfigParser()
27 config.read(BaseDirectory.load_config_paths('inwx-cdnskey.ini'))
28 self.username = config.get('INWX', 'username')
29 self.password = config.get('INWX', 'password')
30 self.shared_secret = config.get('INWX', 'shared_secret', fallback=None)
31 self.api_client = ApiClient(api_url=ApiClient.API_LIVE_URL, api_type=ApiType.JSON_RPC, **kwargs)
32
33 def __enter__(self):
34 self.api_client.login(self.username, self.password, shared_secret = self.shared_secret)
35 return self
36
37 def __exit__(self, type, value, traceback):
38 self.logout()
39
40 def login(self, *args, **kwargs):
41 return ApiConnection.check_api_result(self.api_client.login(*args, **kwargs), msg='API login error')
42
43 def logout(self, *args, **kwargs):
44 return ApiConnection.check_api_result(self.api_client.logout(*args, **kwargs), msg='API logout error', success_code=1500)
45
46 def call_api(self, *args, **kwargs):
47 return ApiConnection.check_api_result(self.api_client.call_api(*args, **kwargs), msg='API error')
48
49 @staticmethod
50 def check_api_result(result, msg='API error', success_code=1000):
51 if result['code'] != success_code:
52 raise ApiConnection.format_exception(msg, result)
53 return result
54
55 @staticmethod
56 def format_exception(msg, result):
57 return Exception(f"{msg}. Code: {result['code']} Message: {result['msg']}")
58
59
60
61def main():
62 parser = argparse.ArgumentParser(prog = "inwx-cdnskey")
63 parser.add_argument('--resolver', metavar='ADDRESS', type=ipaddress.ip_address, default='127.0.0.1')
64 parser.add_argument('domains', metavar='DOMAIN', nargs='+')
65 args = parser.parse_args()
66
67 with ApiConnection(debug_mode=False) as api_conn:
68 for domain in args.domains:
69 active_keys = set()
70 deleted_keys = set()
71 api_data = api_conn.call_api('dnssec.listkeys', {'domainName': domain})['resData']
72 for dat in api_data:
73 if dat.get('publicKey') is None:
74 continue
75
76 dnskey_rdat = dns.rdtypes.ANY.DNSKEY.DNSKEY(dns.rdataclass.IN, dns.rdatatype.DNSKEY, int(dat['flagId']), 3, int(dat['algorithmId']), base64.b64decode(dat['publicKey']))
77 if dat['status'] == 'DELETED':
78 deleted_keys.add(dnskey_rdat)
79 else:
80 active_keys.add(dnskey_rdat)
81
82 dns_keys = set()
83 qname = dns.name.from_text(domain)
84 q = dns.message.make_query(qname, dns.rdatatype.CDNSKEY)
85 r, _ = dns.query.udp_with_fallback(q, str(args.resolver))
86 for rdat in r.find_rrset(dns.message.ANSWER, qname, dns.rdataclass.IN, dns.rdatatype.CDNSKEY):
87 dnskey_rdat = dns.rdtypes.ANY.DNSKEY.DNSKEY(dns.rdataclass.IN, dns.rdatatype.DNSKEY, rdat.flags, rdat.protocol, rdat.algorithm, rdat.key)
88 dns_keys.add(dnskey_rdat)
89
90 print('delete: ', active_keys - dns_keys)
91 print('add: ', dns_keys - active_keys)
92
93
94if __name__ == '__main__':
95 sys.exit(main())
diff --git a/overlays/inwx-cdnskey/python-packages.nix b/overlays/inwx-cdnskey/python-packages.nix
new file mode 100644
index 00000000..e22f223e
--- /dev/null
+++ b/overlays/inwx-cdnskey/python-packages.nix
@@ -0,0 +1,98 @@
1# Generated by pip2nix 0.8.0.dev1
2# See https://github.com/nix-community/pip2nix
3
4{ pkgs, fetchurl, fetchgit, fetchhg }:
5
6self: super: {
7 "certifi" = super.buildPythonPackage rec {
8 pname = "certifi";
9 version = "2021.10.8";
10 src = fetchurl {
11 url = "https://files.pythonhosted.org/packages/37/45/946c02767aabb873146011e665728b680884cd8fe70dde973c640e45b775/certifi-2021.10.8-py2.py3-none-any.whl";
12 sha256 = "0scm6gbbk4gfwb1flivxihnim9wragvvvcia0jn488scxdih2ann";
13 };
14 format = "wheel";
15 doCheck = false;
16 buildInputs = [];
17 checkInputs = [];
18 nativeBuildInputs = [];
19 propagatedBuildInputs = [];
20 };
21 "charset-normalizer" = super.buildPythonPackage rec {
22 pname = "charset-normalizer";
23 version = "2.0.12";
24 src = fetchurl {
25 url = "https://files.pythonhosted.org/packages/06/b3/24afc8868eba069a7f03650ac750a778862dc34941a4bebeb58706715726/charset_normalizer-2.0.12-py3-none-any.whl";
26 sha256 = "1pxim0sfz7gq157k9kv88kxxzvgnid1ip0maxas3jyxipnzfv0b8";
27 };
28 format = "wheel";
29 doCheck = false;
30 buildInputs = [];
31 checkInputs = [];
32 nativeBuildInputs = [];
33 propagatedBuildInputs = [];
34 };
35 "idna" = super.buildPythonPackage rec {
36 pname = "idna";
37 version = "3.3";
38 src = fetchurl {
39 url = "https://files.pythonhosted.org/packages/04/a2/d918dcd22354d8958fe113e1a3630137e0fc8b44859ade3063982eacd2a4/idna-3.3-py3-none-any.whl";
40 sha256 = "1zrm4xnjas13byafi11ma2q8h5rr1fmjwvi41xp5k07sgw2dvnc4";
41 };
42 format = "wheel";
43 doCheck = false;
44 buildInputs = [];
45 checkInputs = [];
46 nativeBuildInputs = [];
47 propagatedBuildInputs = [];
48 };
49 "inwx-domrobot" = super.buildPythonPackage rec {
50 pname = "inwx-domrobot";
51 version = "3.1.0";
52 src = fetchurl {
53 url = "https://files.pythonhosted.org/packages/ad/8f/ceda033f32e0c50285cbee1ef202c2a8c48d05126f773bb75ffa845d8905/inwx_domrobot-3.1.0-py3-none-any.whl";
54 sha256 = "19z7yb2qgzkarwmilclag5wld5gw4cijmgnhrlnhc44fwgxndmrg";
55 };
56 format = "wheel";
57 doCheck = false;
58 buildInputs = [];
59 checkInputs = [];
60 nativeBuildInputs = [];
61 propagatedBuildInputs = [
62 self."requests"
63 ];
64 };
65 "requests" = super.buildPythonPackage rec {
66 pname = "requests";
67 version = "2.27.1";
68 src = fetchurl {
69 url = "https://files.pythonhosted.org/packages/2d/61/08076519c80041bc0ffa1a8af0cbd3bf3e2b62af10435d269a9d0f40564d/requests-2.27.1-py2.py3-none-any.whl";
70 sha256 = "0bg7c13nfm400gx7wn5kjbjfjyz1b6bwf6p4wqbgvpf9akjs2bzj";
71 };
72 format = "wheel";
73 doCheck = false;
74 buildInputs = [];
75 checkInputs = [];
76 nativeBuildInputs = [];
77 propagatedBuildInputs = [
78 self."certifi"
79 self."charset-normalizer"
80 self."idna"
81 self."urllib3"
82 ];
83 };
84 "urllib3" = super.buildPythonPackage rec {
85 pname = "urllib3";
86 version = "1.26.8";
87 src = fetchurl {
88 url = "https://files.pythonhosted.org/packages/4e/b8/f5a25b22e803f0578e668daa33ba3701bb37858ec80e08a150bd7d2cf1b1/urllib3-1.26.8-py2.py3-none-any.whl";
89 sha256 = "1v976ijsh5zxyjziwqhqvyzj2mrhhpp26w3c3hjw4cx2f7saf300";
90 };
91 format = "wheel";
92 doCheck = false;
93 buildInputs = [];
94 checkInputs = [];
95 nativeBuildInputs = [];
96 propagatedBuildInputs = [];
97 };
98}