summaryrefslogtreecommitdiff
path: root/overlays
diff options
context:
space:
mode:
Diffstat (limited to 'overlays')
-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}