GoWiki
Index
Sections
Search
Login
openbsd
DNS Server
# OpenBSD DNS Server Enable and start service: ``` rcctl enable nsd rcctl start nsd ``` ## Config Create control keys: ``` # crypto partition (optional) mkdir /mnt/nsd chmod 750 /mnt/nsd ln -s /mnt/nsd/nsd_control.key /var/nsd/etc/nsd_control.key ln -s /mnt/nsd/nsd_server.key /var/nsd/etc/nsd_server.key # create keys nsd-control-setup # crypto partition (optional) chgrp _nsd /mnt/nsd/*.key ``` ``` cat <<EOF> /var/nsd/etc/nsd.conf server: hide-version: yes verbosity: 1 database: "" username: _nsd remote-control: control-enable: yes control-interface: /var/run/nsd.sock zone: name: "example.com" zonefile: "/var/nsd/etc/example.com.zone" notify: <secondary dns server> NOKEY provide-xfr: <secondary dns server> NOKEY zone: name: "example.org" zonefile: "/var/nsd/etc/example.org.zone" notify: <secondary dns server> NOKEY provide-xfr: <secondary dns server> NOKEY EOF chmod 640 /var/nsd/etc/nsd.conf ``` ## Zone Files ``` cat <<EOF> /var/nsd/etc/example.com.zone $ORIGIN example.com. $TTL 3600 @ IN SOA ns.example.com. hostmaster.example.com. ( 1535663699 3600 1200 604800 600 ) IN NS ns.example.com. IN NS ns2.example.com. IN MX 10 mail.example.com. IN CAA 128 issue "letsencrypt.org" ; add to deny wildcard certificates ;IN CAA 128 issuewild ";" www IN A 198.51.100.1 dyn IN A 198.51.100.1 EOF ``` ## Dynamic DNS This is based on https://github.com/exitnode/nsd-dyndns ### Web Server ``` cat <<'EOF'> /etc/httpd.conf domain="ns.example.com" server $domain { listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location "/*" { block return 301 "https://$SERVER_NAME$DOCUMENT_URI" } } server $domain { listen on * tls port 443 tls { certificate "/etc/ssl/ns.example.com.fullchain.pem" key "/etc/ssl/private/ns.example.com.key" ciphers ECDHE-RSA-CHACHA20-POLY1305:CHACHA20:ECDHE+AESGCM:ECDHE+AES } hsts { max-age 31536000, subdomains } root "/htdocs/dyndns" location "/robots.txt" { root "/htdocs" } location "/update.html" { log access dyndns.log } } EOF cat <<EOF> /var/www/htdocs/robots.txt User-agent: * Disallow: / EOF mkdir /var/www/htdocs/dyndns touch /var/www/htdocs/dyndns/update.html rcctl enable httpd rcctl start httpd ``` ### Lets Encrypt See [OpenBSD Lets Encrypt](/openbsd/Lets+Encrypt) ### Config Create config directory: `mkdir -m 700 /etc/dyndns.d` Example `A Record`: ``` cat <<EOF> /etc/dyndns.d/dyn.conf key="$(openssl rand -hex 16)" init="127.0.0.1" logfile=/var/www/logs/dyndns.log timestamp=\$(date +%s) zonefile=/var/nsd/etc/example.com.zone ttl=60 subdomain="dyn" rtype=A dnssec=0 EOF chmod 600 /etc/dyndns.d/dyn.conf ``` Example `TXT Record` for ACME DNS01 challenge: ``` cat <<EOF> /etc/dyndns.d/acme.conf key="$(openssl rand -hex 16)" logfile=/var/www/logs/dyndns.log timestamp=\$(date +%s) zonefile=/var/nsd/etc/example.com.zone ttl=600 subdomain="_acme-challenge" rtype=TXT dnssec=0 EOF chmod 600 /etc/dyndns.d/acme.conf ``` Create update script: ``` cat <<'EOF'> /usr/local/sbin/dyndns-update #!/bin/sh i=0 for conf in $(find /etc/dyndns.d -name "*.conf" -type f); do . ${conf} changed=0 record="${subdomain} ${ttl} IN ${rtype}" case ${rtype} in A) data=$(grep ${key} ${logfile} | tail -1 | cut -d" " -f2) if [ -z "${data}" ]; then grep -q "${subdomain} .*${rtype}" ${zonefile} && continue echo "${record} ${init}" >>${zonefile}; changed=1 else grep -q "${record} ${data}" ${zonefile} && continue sed -i "s/^${subdomain} .*${rtype}.*/${record} ${data}/" ${zonefile}; changed=1 fi ;; TXT) data="\"$(grep -o "${key}=[^ ]*" ${logfile} | tail -1 | cut -d"=" -f2)\"" if [ "${data}" = '""' ]; then grep -q "${subdomain} .*${rtype}" ${zonefile} || continue sed -i "/^${subdomain} .*${rtype}/d" ${zonefile}; changed=1 else grep -q "${record} ${data}" ${zonefile} && continue echo "${record} ${data}" >>${zonefile}; changed=1 fi ;; esac if [[ ${changed} -eq 1 ]]; then sed -i "4s/.*/${timestamp}/" ${zonefile} [[ ${dnssec} -eq 1 ]] && /usr/local/sbin/sign-zone ${zonefile} fi logger -t dyndns-update ${conf##*/} ${rtype} set to ${data} i=$((i+1)) done [ $i -ne 0 ] && { nsd-control reload >/dev/null; nsd-control notify >/dev/null; } EOF chmod 755 /usr/local/sbin/dyndns-update ``` ### Client Extract the key from the config file: `grep key /etc/dyndns.d/dyn.conf` #### A Record Replace `<KEY>` with the key in your config file. On OpenBSD ``` echo "*/5 * * * * /usr/bin/ftp -o /dev/null https://ns.example.com/update.html?<KEY> >/dev/null" >> /var/cron/tabs/nobody chown nobody:crontab /var/cron/tabs/nobody chmod 600 /var/cron/tabs/nobody ``` On Linux ``` echo "*/5 * * * * /usr/bin/curl -s https://ns.example.com/update.html?<KEY> >/dev/null" >> /var/cron/tabs/nobody chown nobody:crontab /var/spool/cron/crontabs/nobody chmod 600 /var/spool/cron/crontabs/nobody ``` #### TXT Record Replace `<KEY>` with the key in your config file. Replace `<YOUR TXT CONTENT>` with the value you want to have in the `TXT` record. On OpenBSD ``` echo "*/5 * * * * /usr/bin/ftp -o /dev/null https://ns.example.com/update.html?<KEY>=<YOUR TXT CONTENT> >/dev/null" >> /var/cron/tabs/nobody chown nobody:crontab /var/cron/tabs/nobody chmod 600 /var/cron/tabs/nobody ``` On Linux ``` echo "*/5 * * * * /usr/bin/curl -s https://ns.example.com/update.html?<KEY>=<YOUR TXT CONTENT> >/dev/null" >> /var/spool/cron/crontabs/nobody chown nobody:crontab /var/spool/cron/crontabs/nobody chmod 600 /var/spool/cron/crontabs/nobody ``` ## DNSSEC ``` pkg_add ldns-utils mkdir -p /var/nsd/etc/keys # crypto partition (optional) mkdir -p /mnt/nsd/keys chmod 750 /mnt/nsd/keys ln -s /mnt/nsd/keys /var/nsd/etc/keys cd /var/nsd/etc/keys domain=example.com zsk=$(ldns-keygen -a RSASHA256 -b 2048 ${domain}) mv ${zsk}.key ${zsk%%.+*}.zsk.key mv ${zsk}.private ${zsk%%.+*}.zsk.private ksk=$(ldns-keygen -a RSASHA256 -b 2048 -k ${domain}) mv ${ksk}.key ${ksk%%.+*}.ksk.key mv ${ksk}.ds ${ksk%%.+*}.ksk.ds mv ${ksk}.private ${ksk%%.+*}.ksk.private ``` You need to supply the contents of `Kexample.com.ksk.ds` and `Kexample.com.ksk.key` to your domain registry. ``` cat <<'EOF'> /usr/local/sbin/sign-zone #!/bin/sh zonefile="$1" [[ -z "${zonefile}" ]] && { echo "missing zonefile argument"; exit 1; } domain=${zonefile##*/} domain=${domain%.zone} valid=6 hashes=24 dir="/var/nsd/etc" keys="${dir}/keys" zone="${dir}/${domain}.zone" signed="${zone}.signed" temp="${dir}/tmp" now=$(date +%s) sed -i "4s/.*/${now}/" ${zone} /usr/local/bin/ldns-read-zone ${zone} >${temp} cat ${keys}/K${domain}.ksk.ds ${keys}/K${domain}*.key >>${temp} exp=$(($now+$valid * 24 * 3600)) /usr/local/bin/ldns-signzone -i $now -e $exp \ -n -s $(openssl rand -hex 8) -t ${hashes} -o ${domain} \ -f ${signed} ${temp} ${keys}/K${domain}.ksk ${keys}/K${domain}.zsk rm ${temp} EOF chmod 755 /usr/local/sbin/sign-zone ``` ``` cat <<'EOF'> /usr/local/sbin/dnssec-update #!/bin/sh [[ $# -eq 0 ]] && { echo "missing domain arguments"; exit 1; } for domain in $@; do /usr/local/sbin/sign-zone ${domain} done nsd-control reload >/dev/null nsd-control notify >/dev/null EOF chmod 755 /usr/local/sbin/dnssec-update ``` ``` echo "0 2 * * * /usr/local/sbin/dnssec-update example.com example.net >/dev/null 2>&1" >> /var/cron/tabs/root ``` Test your DNSSEC domain: https://dnssec-analyzer.verisignlabs.com/ ## SSHFP ``` ssh server "ssh-keyscan -D 127.0.0.1 2>/dev/null" | grep -E "SSHFP 1 2|SSHFP 4 2" ```