isc-dhcp: integrate IPv4 DHCP service with procd and netifd 4237/head
authorDaniel Golle <daniel@makrotopia.org>
Wed, 5 Apr 2017 11:21:54 +0000 (13:21 +0200)
committerDaniel Golle <daniel@makrotopia.org>
Sat, 20 May 2017 01:23:48 +0000 (03:23 +0200)
Convert init-script to procd and allow to configure
isc-dhcp-server via UCI. Allow most by-network and by-host options
supported by dnsmasq.
User-defined dhcp-options are not supported yet, neither are tags.

Existing configurations with use-edited /etc/dhcpd.conf are still
respected, hence to enjoy the new features you have to migrate
your configuration to UCI and delete /etc/dhcpd.conf.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
net/isc-dhcp/Makefile
net/isc-dhcp/files/dhcpd.conf [deleted file]
net/isc-dhcp/files/dhcpd.defaults [new file with mode: 0644]
net/isc-dhcp/files/dhcpd.init

index e3eeb93b49db4aadd07298dd0b6e0c1e793cea2a..48e63da16c133bae955b84bffc97a07c0b97768b 100644 (file)
@@ -200,11 +200,10 @@ define Package/isc-dhcp-relay-$(BUILD_VARIANT)/install
 endef
 
 define Package/isc-dhcp-server-$(BUILD_VARIANT)/install
-       $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc
-       $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d
+       $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/uci-defaults
        $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/dhcpd $(1)/usr/sbin
        $(INSTALL_BIN) ./files/dhcpd.init $(1)/etc/init.d/dhcpd
-       $(INSTALL_BIN) ./files/dhcpd.conf $(1)/etc
+       $(INSTALL_BIN) ./files/dhcpd.defaults $(1)/etc/uci-defaults
 ifeq ($(BUILD_VARIANT),ipv6)
        $(INSTALL_BIN) ./files/dhcpd6.init $(1)/etc/init.d/dhcpd6
        $(INSTALL_BIN) ./files/dhcpd6.conf $(1)/etc
diff --git a/net/isc-dhcp/files/dhcpd.conf b/net/isc-dhcp/files/dhcpd.conf
deleted file mode 100644 (file)
index 11985ce..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# dhcpd.conf
-
-authoritative;
-
-default-lease-time 3600;
-max-lease-time 86400;
-
-option domain-name-servers 192.168.1.1;
-
-subnet 192.168.1.0 netmask 255.255.255.0 {
-  range 192.168.1.10 192.168.1.50;
-  option routers 192.168.1.1;
-}
diff --git a/net/isc-dhcp/files/dhcpd.defaults b/net/isc-dhcp/files/dhcpd.defaults
new file mode 100644 (file)
index 0000000..bd6f3d2
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+uci -q get dhcp.isc_dhcpcd && exit 0
+touch /etc/config/dhcp
+
+uci batch <<EOF
+set dhcp.isc_dhcpd=isc_dhcpd
+set dhcp.isc_dhcpd.authoritative='1'
+set dhcp.isc_dhcpd.default_lease_time='3600'
+set dhcp.isc_dhcpd.max_lease_time='86400'
+commit dhcp
+EOF
index 3ca6c641ee43eb5994f05ed5b5335426d5194b2c..e853ffe0a1af76592feb37d1d3bd25d693abb78f 100644 (file)
 #!/bin/sh /etc/rc.common
 
-START=65
+START=19
+USE_PROCD=1
+PROG=/usr/sbin/dhcpd
 
 lease_file=/tmp/dhcpd.leases
-config_file=/etc/dhcpd.conf
-pid_file=/var/run/dhcpd.pid
+config_file=/tmp/run/dhcpd.conf
 
-start() {
-       if [ ! -e $lease_file ]; then
-               touch $lease_file
-       fi
+time2seconds() {
+       local timestring=$1
+       local multiplier number suffix
+
+       suffix="${timestring//[0-9 ]}"
+       number="${timestring%%$suffix}"
+       [ "$number$suffix" != "$timestring" ] && return 1
+       case "$suffix" in
+               "" | s)
+                       multiplier=1
+                       ;;
+               m)
+                       multiplier=60
+                       ;;
+               h)
+                       multiplier=3600
+                       ;;
+               d)
+                       multiplier=86400
+                       ;;
+               w)
+                       multiplier=604800
+                       ;;
+               *)
+                       return 1
+                       ;;
+       esac
+       echo $(( number * multiplier ))
+}
 
-       /usr/sbin/dhcpd -q -cf $config_file -lf $lease_file -pf $pid_file $dhcp_ifs
+# duplicated from dnsmasq init script
+hex_to_hostid() {
+       local var="$1"
+       local hex="${2#0x}" # strip optional "0x" prefix
 
-       if [ $? -ne 0 ]; then
+       if [ -n "${hex//[0-9a-fA-F]/}" ]; then
+               # is invalid hex literal
                return 1
        fi
+
+       # convert into host id
+       export "$var=$(
+               printf "%0x:%0x" \
+               $(((0x$hex >> 16) % 65536)) \
+               $(( 0x$hex        % 65536))
+               )"
+
+       return 0
 }
 
-stop() {
-       if [ ! -e $pid_file ]; then
-               return 1
+static_host_add() {
+       local cfg="$1"
+       local broadcast hostid macn macs mac name ip leasetime
+
+       config_get macs "$cfg" "mac"
+       [ -n "$macs" ] || return 0
+       config_get name "$cfg" "name"
+       [ -n "$name" ] || return 0
+       config_get ip "$cfg" "ip"
+       [ -n "$ip" ] || return 0
+
+       config_get_bool broadcast "$cfg" "broadcast" 0
+       config_get dns "$cfg" "dns"
+       config_get gateway "$cfg" "gateway"
+       config_get leasetime "$cfg" "leasetime"
+       if [ -n "$leasetime" ] ; then
+               leasetime="$(time2seconds "$leasetime")"
+               [ "$?" -ne 0 ] && return 1
+       fi
+
+       config_get hostid "$cfg" "hostid"
+       if [ -n "$hostid" ] ; then
+               hex_to_hostid hostid "$hostid" || return 1
        fi
 
-       kill -9 `cat $pid_file`
+       macn=0
+       for mac in $macs; do
+               macn=$(( macn + 1 ))
+       done
 
-       if [ $? -ne 0 ]; then
-               return 1
+       for mac in $macs; do
+               local secname="$name"
+               if [ $macn -gt 1 ] ; then
+                       secname="${name}-${mac//:}"
+               fi
+               echo "host $secname {"
+               echo " hardware ethernet $mac;"
+               echo " fixed-address $ip;"
+               echo " option host-name \"$name\";"
+               if [ "$broadcast" -eq 1 ] ; then
+                       echo " always-broadcast true;"
+               fi
+               if [ -n "$leasetime" ] ; then
+                       echo " default-lease-time $leasetime;"
+                       echo " max-lease-time $leasetime;"
+               fi
+               if [ -n "$hostid" ] ; then
+                       echo " option dhcp-client-identifier $hostid;"
+               fi
+               if [ -n "$dns" ] ; then
+                       echo " option domain-name-servers $dns;"
+               fi
+               if [ -n "$gateway" ] ; then
+                       echo " option routers $gateway;"
+               fi
+               echo "}"
+       done
+}
+
+static_hosts() {
+       config_foreach static_host_add host "$@"
+}
+
+gen_dhcp_subnet() {
+       echo "subnet $NETWORK netmask $NETMASK {"
+       echo " range $START $END;"
+       echo " option subnet-mask $netmask;"
+       if [ "$BROADCAST" != "0.0.0.0" ] ; then
+               echo " option broadcast-address $BROADCAST;"
+       fi
+       if [ "$dynamicdhcp" -eq 0 ] ; then
+               if [ "$authoritative" -eq 1 ] ; then
+                       echo " deny unknown-clients;"
+               else
+                       echo " ignore unknown-clients;"
+               fi
        fi
+       if [ -n "$leasetime" ] ; then
+               echo " default-lease-time $leasetime;"
+               echo " max-lease-time $leasetime;"
+       fi
+       echo " option routers $gateway;"
+       echo " option domain-name-servers $DNS;"
+       echo "}"
+}
+
+dhcpd_add() {
+       local cfg="$1"
+       local dhcp6range="::"
+       local dynamicdhcp end gateway ifname ignore leasetime limit net netmask
+       local proto networkid start subnet
+       local IP NETMASK BROADCAST NETWORK PREFIX DNS START END
+
+       config_get_bool ignore "$cfg" "ignore" 0
+       [ "$ignore" = "0" ] || return 0
+
+       config_get net "$cfg" "interface"
+       [ -n "$net" ] || return 0
+
+       config_get start "$cfg" "start"
+       [ -n "$start" ] || return 0
+
+       config_get limit "$cfg" "limit"
+       [ -n "$limit" ] || return 0
+
+       network_get_subnet subnet "$net" || return 0
+       network_get_device ifname "$net" || return 0
+       network_get_protocol proto "$net" || return 0
+
+       [ static = "$proto" ] || return 0
+
+       config_get_bool dynamicdhcp "$cfg" "dynamicdhcp" 1
+
+       dhcp_ifs="$dhcp_ifs $ifname"
+
+       eval "$(ipcalc.sh $subnet $start $limit)"
+
+       config_get netmask "$cfg" "netmask" "$NETMASK"
+       config_get leasetime "$cfg" "leasetime"
+       if [ -n "$leasetime" ] ; then
+               leasetime="$(time2seconds "$leasetime")"
+               [ "$?" -ne 0 ] && return 1
+       fi
+
+       if network_get_dnsserver dnsserver "$net" ; then
+               for dnsserv in $dnsserver ; do
+                       DNS="$DNS${DNS:+, }$dnsserv"
+               done
+       else
+               DNS="$IP"
+       fi
+
+       if ! network_get_gateway gateway "$net" ; then
+               gateway="$IP"
+       fi
+
+       gen_dhcp_subnet >> $config_file
+}
+
+general_config() {
+       local always_broadcast boot_unknown_clients log_facility
+       local default_lease_time max_lease_time
+       config_get_bool always_broadcast "isc_dhcpd" "always_broadcast" 0
+       config_get_bool authoritative "isc_dhcpd" "authoritative" 1
+       config_get_bool boot_unknown_clients "isc_dhcpd" "boot_unknown_clients" 1
+       config_get default_lease_time "isc_dhcpd" "default_lease_time" 3600
+       config_get max_lease_time "isc_dhcpd" "max_lease_time" 86400
+       config_get log_facility "isc_dhcpd" "log_facility"
+
+       [ $always_broadcast -eq 1 ] && echo "always-broadcast true;"
+       [ $authoritative -eq 1 ] && echo "authoritative;"
+       [ $boot_unknown_clients -eq 0 ] && echo "boot-unknown-clients false;"
+
+       default_lease_time="$(time2seconds "$default_lease_time")"
+       [ "$?" -ne 0 ] && return 1
+       max_lease_time="$(time2seconds "$max_lease_time")"
+       [ "$?" -ne 0 ] && return 1
+
+       if [ -n "$log_facility" ] ; then
+               echo "log-facility $log_facility;"
+       fi
+       echo "default-lease-time $default_lease_time;"
+       echo "max-lease-time $max_lease_time;"
+}
+
+start_service() {
+       if [ -n "$DHCPD_BOOT" ] ; then
+               return 0
+       fi
+
+       if [ ! -e $lease_file ] ; then
+               touch $lease_file
+       fi
+
+       dhcp_ifs=""
+
+       if [ -e "/etc/dhcpd.conf" ] ; then
+               config_file="/etc/dhcpd.conf"
+       else
+               . /lib/functions/network.sh
+
+               config_load dhcp
+               local authoritative
+               general_config > $config_file
+
+               config_foreach dhcpd_add dhcp
+
+               static_hosts >> $config_file
+
+               [ -z "$dhcp_ifs" ] && return 0
+       fi
+
+       procd_open_instance
+       procd_set_param command $PROG -q -f -cf $config_file -lf $lease_file $dhcp_ifs
+       procd_close_instance
+}
+
+boot() {
+       DHCPD_BOOT=1
+       start "$@"
+}
 
-       rm $pid_file
+service_triggers()
+{
+       procd_add_reload_trigger "dhcp"
+       procd_add_raw_trigger "interface.*" 3000 /etc/init.d/dhcpd reload
 }