dnsmasq: store leases in sqlite database
To avoid dnsmasq writing out the whole leasefile on each request before replying. This gets slow on high‐latency storage. Also tweak DNS updates a bit.
This commit is contained in:
parent
b6b4a16fd4
commit
8e3772e475
|
@ -2,9 +2,10 @@
|
||||||
package:
|
package:
|
||||||
name:
|
name:
|
||||||
- dnsmasq
|
- dnsmasq
|
||||||
- bind-tools
|
- bind-tools # for DNS updates
|
||||||
- krb5
|
- krb5 # for DNS updates
|
||||||
- py3-pexpect
|
- py3-pexpect # for creating kerberos keytab
|
||||||
|
- sqlite # for lease DB
|
||||||
|
|
||||||
- name: Configure kerberos
|
- name: Configure kerberos
|
||||||
template:
|
template:
|
||||||
|
@ -23,11 +24,11 @@
|
||||||
args:
|
args:
|
||||||
creates: /etc/krb5.keytab
|
creates: /etc/krb5.keytab
|
||||||
|
|
||||||
- name: Copy DNS updater script
|
- name: Copy DHCP lease script
|
||||||
template:
|
template:
|
||||||
dest: "/usr/local/bin/dns-update"
|
dest: "/usr/local/bin/dnsmasq-script"
|
||||||
src: "dns-update.j2"
|
src: "dnsmasq-script.j2"
|
||||||
mode: 0700
|
mode: 0755
|
||||||
|
|
||||||
- name: Configure dnsmasq
|
- name: Configure dnsmasq
|
||||||
template:
|
template:
|
||||||
|
|
|
@ -18,4 +18,8 @@ interface = {{ interfaces | map(attribute='name') | join(',') }}
|
||||||
dhcp-option = option:dns-server,{{ dns | join(',') }}
|
dhcp-option = option:dns-server,{{ dns | join(',') }}
|
||||||
dhcp-option = option:ntp-server,{{ ntp | join(',') }}
|
dhcp-option = option:ntp-server,{{ ntp | join(',') }}
|
||||||
|
|
||||||
dhcp-script = /usr/local/bin/dns-update
|
dhcp-script = /usr/local/bin/dnsmasq-script
|
||||||
|
dhcp-scriptuser = dnsmasq
|
||||||
|
|
||||||
|
# track leases with dnsmasq-script instead
|
||||||
|
leasefile-ro
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# don’t spam the DNS server when starting dnsmasq
|
|
||||||
if [ -n "${DNSMASQ_INTERFACE}" ] ; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
domain={{ domain }}
|
|
||||||
ldap_user={{ password.ldap_user }}
|
|
||||||
ttl=3600
|
|
||||||
|
|
||||||
address="${3}"
|
|
||||||
|
|
||||||
case "${1}" in
|
|
||||||
add)
|
|
||||||
host="${4}"
|
|
||||||
kinit -k "${ldap_user}"
|
|
||||||
nsupdate -g <<EOF
|
|
||||||
update add ${host}.${domain} ${ttl} A ${address}
|
|
||||||
send
|
|
||||||
EOF
|
|
||||||
;;
|
|
||||||
old)
|
|
||||||
if [ -n "${DNSMASQ_OLD_HOSTNAME}" -a -n "${DNSMASQ_SUPPLIED_HOSTNAME}" ] ; then
|
|
||||||
kinit -k "${ldap_user}"
|
|
||||||
nsupdate -g <<EOF
|
|
||||||
update del ${DNSMASQ_OLD_HOSTNAME}.${domain}
|
|
||||||
update add ${DNSMASQ_SUPPLIED_HOSTNAME}.${domain} ${ttl} A ${address}
|
|
||||||
send
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
# TODO del, probably
|
|
||||||
esac
|
|
76
roles/dnsmasq/templates/dnsmasq-script.j2
Normal file
76
roles/dnsmasq/templates/dnsmasq-script.j2
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This script replaces the dnsmasq leasefile with an sqlite database
|
||||||
|
# for performance on slow storage, and updates DNS records for
|
||||||
|
# assigned addresses.
|
||||||
|
|
||||||
|
cmd="${1}"
|
||||||
|
|
||||||
|
# dnsmasq calls this script on startup for each known lease, ignore it
|
||||||
|
[ "${cmd}" != "init" ] && [ -z "${DNSMASQ_INTERFACE}" ] && exit 0
|
||||||
|
|
||||||
|
# parameters
|
||||||
|
db=/var/lib/misc/dnsmasq.leases.db
|
||||||
|
domain={{ domain }}
|
||||||
|
ldap_user={{ password.ldap_user }}
|
||||||
|
ttl=3600
|
||||||
|
|
||||||
|
# sanitize input
|
||||||
|
mac="${2//[![:xdigit:]:]/}"
|
||||||
|
ipv4="${3//[![:digit:].]/}"
|
||||||
|
hostname="${4//[![:alnum:]_-]/}"
|
||||||
|
client_id="${DNSMASQ_CLIENT_ID//[![:xdigit:]:]/}"
|
||||||
|
|
||||||
|
# construct SQL to query or update leases, and nsupdate script to update DNS records
|
||||||
|
dns=""
|
||||||
|
sql=""
|
||||||
|
case "${cmd}" in
|
||||||
|
"init")
|
||||||
|
# init runs as root, so ensure the dnsmasq user can write to database later
|
||||||
|
touch "${db}"
|
||||||
|
chown dnsmasq:dnsmasq "${db}"
|
||||||
|
setfacl -m u:dnsmasq:rwx "$(dirname ${db})"
|
||||||
|
setfacl -m u:dnsmasq:r "/etc/krb5.keytab" # needed for DNS updates
|
||||||
|
|
||||||
|
# ensure the leases table exists, and get all leases from it
|
||||||
|
sql="CREATE TABLE IF NOT EXISTS leases (
|
||||||
|
ipv4 TEXT PRIMARY KEY NOT NULL,
|
||||||
|
mac TEXT NOT NULL,
|
||||||
|
hostname TEXT NOT NULL,
|
||||||
|
client_id TEXT NOT NULL,
|
||||||
|
renewed INTEGER NOT NULL);
|
||||||
|
SELECT renewed, mac, ipv4, hostname, client_id FROM leases;"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"add" | "old")
|
||||||
|
# add or update the lease
|
||||||
|
sql="INSERT INTO leases
|
||||||
|
VALUES ('${ipv4}', '${mac}', '${hostname:-*}', '${client_id:-*}', unixepoch())
|
||||||
|
ON CONFLICT(ipv4) DO UPDATE SET renewed = unixepoch();"
|
||||||
|
|
||||||
|
# add or update the DNS record
|
||||||
|
if [ -n "${hostname}" ] ; then
|
||||||
|
dns="update add ${hostname}.${domain} ${ttl} A ${ipv4}\n"
|
||||||
|
fi
|
||||||
|
if [ -n "${DNSMASQ_OLD_HOSTNAME}" ] ; then
|
||||||
|
dns="${dns}update del ${DNSMASQ_OLD_HOSTNAME}.${domain}\n"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"del")
|
||||||
|
# delete the lease
|
||||||
|
sql="DELETE FROM leases WHERE ipv4 = '${ipv4}';"
|
||||||
|
# TODO probably delete the DNS record
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# update lease database
|
||||||
|
if [ -n "${sql}" ]; then
|
||||||
|
sqlite3 -separator " " "${db}" "${sql}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# update DNS records
|
||||||
|
if [ -n "${dns}" ]; then
|
||||||
|
kinit -k "${ldap_user}"
|
||||||
|
echo -e "${dns}send" | nsupdate -g
|
||||||
|
fi
|
Loading…
Reference in a new issue