Last active
April 6, 2024 09:20
-
-
Save shift/e9dca149259c96e11b4ac007ac0f4f0d to your computer and use it in GitHub Desktop.
Enables knotd+kresd to serve as a replacement for DNSmasq and still retain the dynamic DNS updates from DHCPv4 & DHCPv6 leases.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# Configuration | |
lease_file='/tmp/hosts/odhcpd' | |
forward_zone='ber.section.me.' | |
reverse_zone_ipv4='1.168.192.in-addr.arpa.' | |
reverse_zone_ipv6='f.d.0.5.0.7.4.0.1.0.0.2.ip6.arpa.' | |
# Function for code reusability and readability | |
expand_ipv6() { | |
ip=$1 | |
# Handle leading :: | |
echo $ip | grep -qs "^:" && ip="0${ip}" | |
# Expand :: | |
if echo $ip | grep -qs "::"; then | |
colons=$(echo $ip | sed 's/[^:]//g') | |
missing=$(echo ":::::::::" | sed "s/$colons//") | |
expanded=$(echo $missing | sed 's/:/:0/g') | |
ip=$(echo $ip | sed "s/::/$expanded/") | |
fi | |
# Split into blocks | |
blocks=$(echo $ip | grep -o "[0-9a-f]\\+") | |
set $blocks | |
printf "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\\n" \ | |
$(hex2dec $1) \ | |
$(hex2dec $2) \ | |
$(hex2dec $3) \ | |
$(hex2dec $4) \ | |
$(hex2dec $5) \ | |
$(hex2dec $6) \ | |
$(hex2dec $7) \ | |
$(hex2dec $8) | |
} | |
# Function to convert hex to dec (portable version) | |
hex2dec() { | |
[ "$1" != "" ] && printf "%d" "$(( 0x$1 ))" | |
} | |
# Function to reverse a string | |
reverse_string() { | |
input=$1 | |
reversed="" | |
while [ -n "$input" ]; do | |
# Extract the last character and append it to the reversed string | |
last_char=$(echo "$input" | sed 's/.*\(.\)$/\1/') | |
reversed="${reversed}${last_char}" | |
# Remove the last character from the input string | |
input=$(echo "$input" | sed 's/.\{1\}$//') | |
done | |
echo "$reversed" | |
} | |
# Function to convert an IPv6 address to reverse DNS format | |
ipv6_to_dns() { | |
ip=$(expand_ipv6 $1) | |
# Remove colons | |
ip=$(echo $ip | tr -d ':') | |
# Reverse the nibbles | |
rev_ip=$(reverse_string $ip) | |
# Insert dots between the nibbles | |
rev_ip=$(echo $rev_ip | sed 's/./&./g') | |
# Append .ip6.arpa | |
echo "${rev_ip}ip6.arpa." | |
} | |
update_records() { | |
hostname=$1 | |
ip=$2 | |
ip_type=$3 | |
if [ "$ip_type" = "IPv4" ]; then | |
set -- $(echo "$ip" | tr '.' ' ') | |
reverse_ip="$4.$3.$2.$1" | |
last_octet="$4" | |
ptr_record="$last_octet.$reverse_zone_ipv4" | |
else # IPv6 | |
ptr_record=$(ipv6_to_dns $ip) | |
fi | |
echo "Updating $hostname <-> $ip" | |
# Update DNS records (forward and reverse zones) | |
knotc zone-begin $forward_zone | |
knotc zone-unset $forward_zone $hostname $([ "$ip_type" = "IPv4" ] && echo A || echo AAAA) | |
knotc zone-set $forward_zone $hostname 300 $([ "$ip_type" = "IPv4" ] && echo A || echo AAAA) $ip | |
knotc zone-commit $forward_zone | |
knotc zone-begin $([ "$ip_type" = "IPv4" ] && echo $reverse_zone_ipv4 || echo $reverse_zone_ipv6) | |
knotc zone-unset $([ "$ip_type" = "IPv4" ] && echo $reverse_zone_ipv4 || echo $reverse_zone_ipv6) $ptr_record PTR | |
knotc zone-set $([ "$ip_type" = "IPv4" ] && echo $reverse_zone_ipv4 || echo $reverse_zone_ipv6) $ptr_record 300 PTR $hostname.$forward_zone | |
knotc zone-commit $([ "$ip_type" = "IPv4" ] && echo $reverse_zone_ipv4 || echo $reverse_zone_ipv6) | |
} | |
# Lease parsing | |
while read -r line; do | |
if [ "${line:0:1}" != "#" ]; then | |
ip=$(echo $line | cut -d ' ' -f1) | |
hostname=$(echo $line | cut -d ' ' -f2) | |
# IP Validation with improved IPv6 check | |
if echo "$ip" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then | |
ip_type="IPv4" | |
elif echo "$ip" | grep -qE '(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,2}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,2}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,2}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,2}[0-9]){0,1}[0-9]))' ; then | |
ip_type="IPv6" | |
else | |
echo "Invalid IP address: $ip" >&2 | |
continue | |
fi | |
update_records "$hostname" "$ip" "$ip_type" | |
fi | |
done < "$lease_file" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment