#!/usr/bin/env python3 from flask import Flask, Response, request, jsonify from flask_httpauth import HTTPBasicAuth from base64 import b64encode from requests import get, put, delete from os import getenv # Define global variables for MIAB host and auth header, to be set during authentication MIAB_HOST = getenv('MIAB_HOST', 'localhost') MIAB_AUTH_HEADER = '' app = Flask('dns-updater') auth = HTTPBasicAuth() # Verify username and password by attempting to access a dummy DNS record @auth.verify_password def verify(username, password): global MIAB_AUTH_HEADER, MIAB_HOST MIAB_AUTH_HEADER = "Basic " + b64encode(f"{username}:{password}".encode()).decode() result = get(f'https://{MIAB_HOST}/admin/dns/custom/test/A', headers={'Authorization': MIAB_AUTH_HEADER}) if result.status_code != 200: return False return True @app.route('/api/setrecord//', methods=['GET'], defaults={'rtype': 'A'}) @app.route('/api/setrecord///', methods=['GET']) @app.route('/api/setrecord/', methods=['PUT'], defaults={'rtype': 'A'}) @app.route('/api/setrecord//', methods=['PUT']) @auth.login_required def set_record(qname, rtype, value = None): global MIAB_HOST, MIAB_AUTH_HEADER # Use request data as value for PUT method if request.method == 'PUT': value = request.data.decode() url = f'https://{MIAB_HOST}/admin/dns/custom/{qname}/{rtype}' resp = put(url, headers={'Authorization': MIAB_AUTH_HEADER, 'Content-Type': 'text/plain'}, data=value) # Propagate 400-499 as is, 500+ as 502 if resp.status_code != 200: if 400 <= resp.status_code < 500: status = resp.status_code elif resp.status_code >= 500: status = 502 else: status = 500 return Response(f'Error: {resp.status_code} {resp.text}\n', status=status) # Success return f'OK, created record name = {qname}, type = {rtype.upper()}, value = {value}\n' @app.route('/api/deleterecord//', methods=['GET', 'DELETE']) @auth.login_required def delete_record(qname, rtype): global MIAB_HOST, MIAB_AUTH_HEADER url = f'https://{MIAB_HOST}/admin/dns/custom/{qname}/{rtype}' resp = delete(url, headers={'Authorization': MIAB_AUTH_HEADER, 'Content-Type': 'text/plain'}, data='') # Propagate 400-499 as is, 500+ as 502 if resp.status_code != 200: if 400 <= resp.status_code < 500: status = resp.status_code elif resp.status_code >= 500: status = 502 else: status = 500 return Response(f'Error: {resp.status_code} {resp.text}\n', status=status) # Success return f'OK, deleted record name = {qname}, type = {rtype.upper()}\n' @app.route('/api/listrecords', methods=['GET'], defaults={'qname': None, 'rtype': None}) @app.route('/api/listrecords/', methods=['GET'], defaults={'rtype': None}) @app.route('/api/listrecords//', methods=['GET']) @auth.login_required def list_records(qname, rtype): global MIAB_HOST, MIAB_AUTH_HEADER url = f'https://{MIAB_HOST}/admin/dns/custom' if qname: url += f'/{qname}' if rtype: url += f'/{rtype}' resp = get(url, headers={'Authorization': MIAB_AUTH_HEADER}) return jsonify(resp.json()) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=8080)