From c471ec95f8ccf0363cfae09c4479bf8e0907d065 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Sun, 27 Feb 2022 16:48:41 +0100 Subject: inwx-cdnskey --- overlays/inwx-cdnskey/default.nix | 28 +++++++++ overlays/inwx-cdnskey/inwx-cdnskey.py | 95 ++++++++++++++++++++++++++++++ overlays/inwx-cdnskey/python-packages.nix | 98 +++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 overlays/inwx-cdnskey/default.nix create mode 100644 overlays/inwx-cdnskey/inwx-cdnskey.py create mode 100644 overlays/inwx-cdnskey/python-packages.nix (limited to 'overlays') 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 @@ +final: prev: +let + packageOverrides = final.callPackage ./python-packages.nix {}; + inpPython = final.python39.override { inherit packageOverrides; }; +in { + inwx-cdnskey = prev.stdenv.mkDerivation rec { + name = "inwx-cdnskey"; + src = ./inwx-cdnskey.py; + + phases = [ "buildPhase" "checkPhase" "installPhase" ]; + + python = inpPython.withPackages (ps: with ps; [pyxdg inwx-domrobot configparser dnspython]); + + buildPhase = '' + substituteAll $src inwx-cdnskey + ''; + + doCheck = true; + checkPhase = '' + ${python}/bin/python -m py_compile inwx-cdnskey + ''; + + installPhase = '' + install -m 0755 -D -t $out/bin \ + inwx-cdnskey + ''; + }; +} 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 @@ +#!@python@/bin/python + +from INWX.Domrobot import ApiClient, ApiType +from xdg import BaseDirectory +import configparser +import sys +import dns.message +import dns.rdataclass +import dns.rdatatype +import dns.query +import dns.zone +import dns.rdtypes.ANY.DNSKEY +import argparse +import ipaddress +import re +import base64 + + +class ApiConnection: + username = '' + password = '' + shared_secret = None + api_client = None + + def __init__(self, **kwargs): + config = configparser.ConfigParser() + config.read(BaseDirectory.load_config_paths('inwx-cdnskey.ini')) + self.username = config.get('INWX', 'username') + self.password = config.get('INWX', 'password') + self.shared_secret = config.get('INWX', 'shared_secret', fallback=None) + self.api_client = ApiClient(api_url=ApiClient.API_LIVE_URL, api_type=ApiType.JSON_RPC, **kwargs) + + def __enter__(self): + self.api_client.login(self.username, self.password, shared_secret = self.shared_secret) + return self + + def __exit__(self, type, value, traceback): + self.logout() + + def login(self, *args, **kwargs): + return ApiConnection.check_api_result(self.api_client.login(*args, **kwargs), msg='API login error') + + def logout(self, *args, **kwargs): + return ApiConnection.check_api_result(self.api_client.logout(*args, **kwargs), msg='API logout error', success_code=1500) + + def call_api(self, *args, **kwargs): + return ApiConnection.check_api_result(self.api_client.call_api(*args, **kwargs), msg='API error') + + @staticmethod + def check_api_result(result, msg='API error', success_code=1000): + if result['code'] != success_code: + raise ApiConnection.format_exception(msg, result) + return result + + @staticmethod + def format_exception(msg, result): + return Exception(f"{msg}. Code: {result['code']} Message: {result['msg']}") + + + +def main(): + parser = argparse.ArgumentParser(prog = "inwx-cdnskey") + parser.add_argument('--resolver', metavar='ADDRESS', type=ipaddress.ip_address, default='127.0.0.1') + parser.add_argument('domains', metavar='DOMAIN', nargs='+') + args = parser.parse_args() + + with ApiConnection(debug_mode=False) as api_conn: + for domain in args.domains: + active_keys = set() + deleted_keys = set() + api_data = api_conn.call_api('dnssec.listkeys', {'domainName': domain})['resData'] + for dat in api_data: + if dat.get('publicKey') is None: + continue + + dnskey_rdat = dns.rdtypes.ANY.DNSKEY.DNSKEY(dns.rdataclass.IN, dns.rdatatype.DNSKEY, int(dat['flagId']), 3, int(dat['algorithmId']), base64.b64decode(dat['publicKey'])) + if dat['status'] == 'DELETED': + deleted_keys.add(dnskey_rdat) + else: + active_keys.add(dnskey_rdat) + + dns_keys = set() + qname = dns.name.from_text(domain) + q = dns.message.make_query(qname, dns.rdatatype.CDNSKEY) + r, _ = dns.query.udp_with_fallback(q, str(args.resolver)) + for rdat in r.find_rrset(dns.message.ANSWER, qname, dns.rdataclass.IN, dns.rdatatype.CDNSKEY): + dnskey_rdat = dns.rdtypes.ANY.DNSKEY.DNSKEY(dns.rdataclass.IN, dns.rdatatype.DNSKEY, rdat.flags, rdat.protocol, rdat.algorithm, rdat.key) + dns_keys.add(dnskey_rdat) + + print('delete: ', active_keys - dns_keys) + print('add: ', dns_keys - active_keys) + + +if __name__ == '__main__': + 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 @@ +# Generated by pip2nix 0.8.0.dev1 +# See https://github.com/nix-community/pip2nix + +{ pkgs, fetchurl, fetchgit, fetchhg }: + +self: super: { + "certifi" = super.buildPythonPackage rec { + pname = "certifi"; + version = "2021.10.8"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/37/45/946c02767aabb873146011e665728b680884cd8fe70dde973c640e45b775/certifi-2021.10.8-py2.py3-none-any.whl"; + sha256 = "0scm6gbbk4gfwb1flivxihnim9wragvvvcia0jn488scxdih2ann"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = []; + }; + "charset-normalizer" = super.buildPythonPackage rec { + pname = "charset-normalizer"; + version = "2.0.12"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/06/b3/24afc8868eba069a7f03650ac750a778862dc34941a4bebeb58706715726/charset_normalizer-2.0.12-py3-none-any.whl"; + sha256 = "1pxim0sfz7gq157k9kv88kxxzvgnid1ip0maxas3jyxipnzfv0b8"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = []; + }; + "idna" = super.buildPythonPackage rec { + pname = "idna"; + version = "3.3"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/04/a2/d918dcd22354d8958fe113e1a3630137e0fc8b44859ade3063982eacd2a4/idna-3.3-py3-none-any.whl"; + sha256 = "1zrm4xnjas13byafi11ma2q8h5rr1fmjwvi41xp5k07sgw2dvnc4"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = []; + }; + "inwx-domrobot" = super.buildPythonPackage rec { + pname = "inwx-domrobot"; + version = "3.1.0"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/ad/8f/ceda033f32e0c50285cbee1ef202c2a8c48d05126f773bb75ffa845d8905/inwx_domrobot-3.1.0-py3-none-any.whl"; + sha256 = "19z7yb2qgzkarwmilclag5wld5gw4cijmgnhrlnhc44fwgxndmrg"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = [ + self."requests" + ]; + }; + "requests" = super.buildPythonPackage rec { + pname = "requests"; + version = "2.27.1"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/2d/61/08076519c80041bc0ffa1a8af0cbd3bf3e2b62af10435d269a9d0f40564d/requests-2.27.1-py2.py3-none-any.whl"; + sha256 = "0bg7c13nfm400gx7wn5kjbjfjyz1b6bwf6p4wqbgvpf9akjs2bzj"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = [ + self."certifi" + self."charset-normalizer" + self."idna" + self."urllib3" + ]; + }; + "urllib3" = super.buildPythonPackage rec { + pname = "urllib3"; + version = "1.26.8"; + src = fetchurl { + url = "https://files.pythonhosted.org/packages/4e/b8/f5a25b22e803f0578e668daa33ba3701bb37858ec80e08a150bd7d2cf1b1/urllib3-1.26.8-py2.py3-none-any.whl"; + sha256 = "1v976ijsh5zxyjziwqhqvyzj2mrhhpp26w3c3hjw4cx2f7saf300"; + }; + format = "wheel"; + doCheck = false; + buildInputs = []; + checkInputs = []; + nativeBuildInputs = []; + propagatedBuildInputs = []; + }; +} -- cgit v1.2.3