[source] dnsmasq: make DHCPv6 viable for standalone dnsmasq install

LEDE Commits lede-commits at lists.infradead.org
Wed Feb 1 15:15:49 PST 2017


jow pushed a commit to source.git, branch master:
https://git.lede-project.org/9525743c076393336cd2129539c974f8a01c7894

commit 9525743c076393336cd2129539c974f8a01c7894
Author: Eric Luehrsen <ericluehrsen at hotmail.com>
AuthorDate: Thu Dec 22 13:20:25 2016 -0500

    dnsmasq: make DHCPv6 viable for standalone dnsmasq install
    
    dnsmasq has sufficient services to meet the needs of DHCP
    and RA with IP6 for single router router users. This is
    the most common use for consumer routers. Its reenforced
    as most ISP tend to only DHCP-PD /64. dnsmasq has year
    over year demonstrated great flexibility in its option
    set, and support for off-standard DHCP clients.
    
    odhcpd has enhanced capabilities focused on IP6 such
    as DHCP/RA relay and NDP proxy. However, it is not as
    flexible in its option set. odhcpd is not as forgiving
    with off-standard DHCP clients. Some points may represent
    a long term TODO list, but it is the state currently.
    
    These changes make any such combination possible. Already
    odhcpd can be set as the main dhcp server. Now odhcpd
    can be removed or disabled and dnsmasq will take over
    if DHCPv6 compiled in. The existing DHCPv6 and RA UCI
    are translated into dnsmasq.conf. The changes focus on
    '--dhcp-range', '--dhcp-host', and '--dhcp-options'.
    
    DHCP host ID is least 16 bits [::1000-::FFFF], but
    leaves low range for typical infrastructure assignments.
    dnsmasq accepts DHCPv6 options in the tranditional
    '--dhcp-option' put they must be prefixed 'option6:'.
    dnsmasq will also discover SLAAC DNS entries from DHCPv4
    clients MAC, and confirm with a ping at least renew.
    
    Long term TODO include improving use of dnsmasq relay
    options for DHCPv4 and DHCPv6 in parallel. It would also
    be possible to preconfigure DHCP-PD in host-with-options
    records for fixed infrastructure.
    
    Signed-off-by: Eric Luehrsen <ericluehrsen at hotmail.com>
    [Jo-Philipp Wich: emit proper IPv6 hostid format in dhcp-host directive]
    Signed-off-by: Jo-Philipp Wich <jo at mein.io>
---
 package/network/services/dnsmasq/Makefile          |   2 +-
 .../network/services/dnsmasq/files/dnsmasq.init    | 179 +++++++++++++++++----
 2 files changed, 152 insertions(+), 29 deletions(-)

diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index 9833385..a6689d1 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=dnsmasq
 PKG_VERSION:=2.76
-PKG_RELEASE:=7
+PKG_RELEASE:=8
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq
diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
index fe66592..40c756b 100644
--- a/package/network/services/dnsmasq/files/dnsmasq.init
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -18,6 +18,8 @@ TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf"
 TIMEVALIDFILE="/var/state/dnsmasqsec"
 BASEDHCPSTAMPFILE="/var/run/dnsmasq"
 
+DNSMASQ_DHCP_VER=4
+
 xappend() {
 	local value="$1"
 
@@ -182,6 +184,7 @@ dhcp_remoteid_add() {
 }
 
 dhcp_circuitid_add() {
+	# TODO: DHCPV6 does not have circuitid; catch "option6:"
 	local cfg="$1"
 
 	config_get networkid "$cfg" networkid
@@ -214,6 +217,7 @@ dhcp_userclass_add() {
 }
 
 dhcp_vendorclass_add() {
+	# TODO: DHCPV6 vendor class has stricter definitions; catch? fixup?
 	local cfg="$1"
 
 	config_get networkid "$cfg" networkid
@@ -247,6 +251,7 @@ dhcp_match_add() {
 
 dhcp_host_add() {
 	local cfg="$1"
+	local hosttag nametime addrs
 
 	config_get_bool force "$cfg" force 0
 
@@ -258,7 +263,9 @@ dhcp_host_add() {
 
 	config_get name "$cfg" name
 	config_get ip "$cfg" ip
-	[ -n "$ip" -o -n "$name" ] || return 0
+	config_get hostid "$cfg" hostid
+
+	[ -n "$ip" -o -n "$name" -o -n "$hostid" ] || return 0
 
 	config_get_bool dns "$cfg" dns 0
 	[ "$dns" = "1" -a -n "$ip" -a -n "$name" ] && {
@@ -266,33 +273,47 @@ dhcp_host_add() {
 	}
 
 	config_get mac "$cfg" mac
+	config_get duid "$cfg" duid
+	config_get tag "$cfg" tag
+
 	if [ -n "$mac" ]; then
 		# --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap
+		# many MAC are possible to track a laptop ON/OFF dock
 		macs=""
 		for m in $mac; do append macs "$m" ","; done
-	else
-		# --dhcp-host=lap,192.168.0.199
+	fi
+
+	if [ $DNSMASQ_DHCP_VER -eq 6 -a -n "$duid" ]; then
+		# --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap
+		# one (virtual) machine gets one DUID per RFC3315
+		duids="id:${duid// */}"
+	fi
+
+	if [ -z "$macs" -a -z "$duids" ]; then
+		# --dhcp-host=lap,192.168.0.199,[::beef]
 		[ -n "$name" ] || return 0
 		macs="$name"
 		name=""
 	fi
 
-	config_get tag "$cfg" tag
-
-	if [ "$DHCPv6CAPABLE" -eq 1 ]; then
-		config_get duid "$cfg" duid
-		config_get hostid "$cfg" hostid
-		if [ -n "$hostid" ]; then
+	if [ -n "$hostid" ]; then
 			hex_to_hostid hostid "$hostid"
-		fi
 	fi
 
 	config_get_bool broadcast "$cfg" broadcast 0
-	[ "$broadcast" = "0" ] && broadcast=
-
 	config_get leasetime "$cfg" leasetime
 
-	xappend "--dhcp-host=$macs${duid:+,id:$duid}${networkid:+,net:$networkid}${broadcast:+,set:needs-broadcast}${tag:+,set:$tag}${ip:+,$ip${hostid:+,[::$hostid]}}${name:+,$name}${leasetime:+,$leasetime}"
+	[ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast"
+
+	hosttag="${networkid:+,set:${networkid}}${tag:+,set:${tag}}$broadcast"
+	nametime="${name:+,$name}${leasetime:+,$leasetime}"
+
+	if [ $DNSMASQ_DHCP_VER -eq 6 ]; then
+		addrs="${ip:+,$ip}${hostid:+,[::$hostid]}"
+		xappend "--dhcp-host=$macs${duids:+,$duids}$hosttag$addrs$nametime"
+	else
+		xappend "--dhcp-host=$macs$hosttag${ip:+,$ip}$nametime"
+	fi
 }
 
 dhcp_this_host_add() {
@@ -345,6 +366,7 @@ dhcp_this_host_add() {
 }
 
 dhcp_tag_add() {
+	# NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
 	local cfg="$1"
 
 	tag="$cfg"
@@ -375,6 +397,7 @@ dhcp_mac_add() {
 }
 
 dhcp_boot_add() {
+	# TODO: BOOTURL is different between DHCPv4 and DHCPv6
 	local cfg="$1"
 
 	config_get networkid "$cfg" networkid
@@ -397,12 +420,12 @@ dhcp_boot_add() {
 
 dhcp_add() {
 	local cfg="$1"
+	local dhcp6range="::"
+	local nettag
+
 	config_get net "$cfg" interface
 	[ -n "$net" ] || return 0
 
-	config_get dhcpv4 "$cfg" dhcpv4
-	[ "$dhcpv4" != "disabled" ] || return 0
-
 	config_get networkid "$cfg" networkid
 	[ -n "$networkid" ] || networkid="$net"
 
@@ -430,27 +453,92 @@ dhcp_add() {
 	config_get_bool force "$cfg" force 0
 	[ $force -gt 0 ] || dhcp_check "$ifname" || return 0
 
-	config_get start "$cfg" start
-	config_get limit "$cfg" limit
-	config_get leasetime "$cfg" leasetime
+	config_get start "$cfg" start 100
+	config_get limit "$cfg" limit 150
+	config_get leasetime "$cfg" leasetime 12h
 	config_get options "$cfg" options
 	config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1
 
+	config_get dhcpv4 "$cfg" dhcpv4
+	config_get dhcpv6 "$cfg" dhcpv6
+
+	config_get ra "$cfg" ra
+	config_get ra_management "$cfg" ra_management
+	config_get ra_preference "$cfg" ra_preference
+
 	# Put the router host name on this DHCP served interface address(es)
 	dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN"
 
-	leasetime="${leasetime:-12h}"
-	start="$(dhcp_calc "${start:-100}")"
-	limit="${limit:-150}"
-	[ "$limit" -gt 0 ] && limit=$((limit-1))
+	start="$( dhcp_calc "$start" )"
+	nettag="${networkid:+set:${networkid},}"
+
+	if [ "$limit" -gt 0 ] ; then
+		limit=$((limit-1))
+	fi
+
 	eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
-	if [ "$dynamicdhcp" = "0" ]; then END="static"; fi
-	xappend "--dhcp-range=$networkid,$START,$END,$NETMASK,$leasetime${options:+ $options}"
+
+	if [ "$dynamicdhcp" = "0" ] ; then
+		END="static"
+		dhcp6range="::,static"
+	else
+		dhcp6range="::1000,::ffff"
+	fi
+
+
+	if [ "$dhcpv4" != "disabled" ] ; then
+		xappend "--dhcp-range=$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
+	fi
+
+
+	if [ $DNSMASQ_DHCP_VER -eq 6 -a "$ra" = "server" ] ; then
+		# Note: dnsmasq cannot just be a DHCPv6 server (all-in-1)
+		# and let some other machine(s) send RA pointing to it.
+
+		case $ra_preference in
+		*high*)
+			xappend "--ra-param=$ifname,high,0,7200"
+			;;
+		*low*)
+			xappend "--ra-param=$ifname,low,0,7200"
+			;;
+		*)
+			# Send UNSOLICITED RA at default interval and live for 2 hours.
+			# TODO: convert flexible lease time into route life time (only seconds).
+			xappend "--ra-param=$ifname,0,7200"
+			;;
+		esac
+
+		if [ "$dhcpv6" = "disabled" ] ; then
+			ra_management="3"
+		fi
+
+
+		case $ra_management in
+		0)
+			# SLACC with DCHP for extended options
+			xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names"
+			;;
+		2)
+			# DHCP address and RA only for management redirection
+			xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime"
+			;;
+		3)
+			# SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC
+			xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names"
+			;;
+		*)
+			# SLAAC and full DHCP
+			xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime"
+			;;
+		esac
+	fi
 
 	dhcp_option_add "$cfg" "$networkid"
 }
 
 dhcp_option_add() {
+	# NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
 	local cfg="$1"
 	local networkid="$2"
 	local force="$3"
@@ -605,6 +693,32 @@ dnsmasq_start()
 
 	$PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0
 
+
+	if [ -x /usr/sbin/odhcpd -a -x /etc/init.d/odhcpd ] ; then
+		local odhcpd_is_main odhcpd_is_enabled
+		config_get odhcpd_is_main odhcpd maindhcp
+		/etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0
+
+
+		if [ "$odhcpd_is_enabled" -eq 0 -a "$DHCPv6CAPABLE" -eq 1 ] ; then
+			# DHCP V4 and V6 in DNSMASQ
+			DNSMASQ_DHCP_VER=6
+		elif [ "$odhcpd_is_main" -gt 0 ] ; then
+			# ODHCPD is doing it all
+			DNSMASQ_DHCP_VER=0
+		else
+			# You have ODHCPD but use DNSMASQ for DHCPV4
+			DNSMASQ_DHCP_VER=4
+		fi
+
+	elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then
+		# DHCP V4 and V6 in DNSMASQ
+		DNSMASQ_DHCP_VER=6
+	else
+		DNSMASQ_DHCP_VER=4
+	fi
+
+
 	append_bool "$cfg" authoritative "--dhcp-authoritative"
 	append_bool "$cfg" nodaemon "--no-daemon"
 	append_bool "$cfg" domainneeded "--domain-needed"
@@ -772,11 +886,20 @@ dnsmasq_start()
 	config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg"
 	echo >> $CONFIGFILE_TMP
 
-	config_get odhcpd_is_active odhcpd maindhcp
-	if [ "$odhcpd_is_active" != "1" ]; then
-		config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
+
+	if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then
+		# Enable RA feature for when/if it is constructed,
+		# and RA is selected per interface pool (RA, DHCP, or both),
+		# but no one (should) want RA broadcast in syslog
+		config_foreach dhcp_add dhcp
+		xappend "--enable-ra"
+		xappend "--quiet-ra"
+
+	elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then
+		config_foreach dhcp_add dhcp
 	fi
 
+
 	echo >> $CONFIGFILE_TMP
 	config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg"
 	echo >> $CONFIGFILE_TMP



More information about the lede-commits mailing list