2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 DHCPV6D_CONFIG_FILE
="/etc/dhcp/dhcpd6.conf"
23 DHCPV4D_CONFIG_FILE
="/etc/dhcp/dhcpd.conf"
25 DHCPV6D_CONFIG_DIR
="${NETWORK_CONFIG_DIR}/dhcpd/ipv6"
26 DHCPV4D_CONFIG_DIR
="${NETWORK_CONFIG_DIR}/dhcpd/ipv4"
28 DHCPV6D_OPTIONS_FILE
="${DHCPV6D_CONFIG_DIR}/options"
29 DHCPV4D_OPTIONS_FILE
="${DHCPV4D_CONFIG_DIR}/options"
31 DHCPV6D_SETTINGS_FILE
="${DHCPV6D_CONFIG_DIR}/settings"
32 DHCPV4D_SETTINGS_FILE
="${DHCPV4D_CONFIG_DIR}/settings"
49 DHCPD_SUBNET_PREFIX
="subnet-"
50 #DHCPD_SUBNET_POOL_PREFIX="pool-"
51 DHCPD_SUBNET_RANGE_PREFIX
="range-"
53 DHCPD_SUBNET_SETTINGS
="ADDRESS PREFIX"
54 DHCPV6D_SUBNET_SETTINGS
="${DHCPD_SUBNET_SETTINGS} PREFIX_DELEGATION \
55 DELEGATED_PREFIX_FIRST DELEGATED_PREFIX_LAST DELEGATED_PREFIX_SIZE"
56 DHCPV4D_SUBNET_SETTINGS
="${DHCPD_SUBNET_SETTINGS} ROUTERS"
58 DHCPD_SUBNET_RANGE_SETTINGS
="START END"
59 DHCPV6D_SUBNET_RANGE_SETTINGS
="${DHCPD_SUBNET_RANGE_SETTINGS}"
60 DHCPV4D_SUBNET_RANGE_SETTINGS
="${DHCPD_SUBNET_RANGE_SETTINGS}"
73 dhcp-client-identifier \
75 dhcp-max-message-size \
88 DHCPV6D_SUBNET_OPTIONS
="${DHCPV6D_OPTIONS}"
89 DHCPV4D_SUBNET_OPTIONS
="${DHCPV4D_OPTIONS}"
92 DHCP_DEFAULT_DELEGATED_PREFIX_SIZE
="64"
94 # Defaults for DHCPv6.
95 DHCPV6D_PREFERRED_LIFETIME
=""
96 DHCPV6D_VALID_LIFETIME
="43200" # 12h
98 # Defaults for DHCPv4.
99 DHCPV4D_AUTHORITATIVE
="true"
100 DHCPV4D_DEFAULT_LEASE_TIME
="43200" # 12h
101 DHCPV4D_MAX_LEASE_TIME
="86400" # 24h
102 DHCPV4D_MIN_LEASE_TIME
=""
107 print
"dhcpd6.service"
110 print
"dhcpd.service"
113 print
"dhcpd6.service dhcp.service"
121 local services
=$
(dhcpd_service
"$@")
124 for service
in ${services}; do
125 service_start
${service}
130 local services
=$
(dhcpd_service
"$@")
133 for service
in ${services}; do
134 service_stop
${service}
139 # DHCP does not support a reload, so
141 local services
=$
(dhcpd_service
"$@")
144 for service
in ${services}; do
145 service_restart
${service}
154 local services
=$
(dhcpd_service
"$@")
157 for service
in ${services}; do
158 service_enable
${service}
163 local services
=$
(dhcpd_service
"$@")
166 for service
in ${services}; do
167 service_disable
${service}
176 local settings
=$
(dhcpd_settings
${proto})
177 assert isset settings
180 dhcpd_global_settings_read
${proto}
184 _dhcpd_edit_ipv6
"$@" ||
return $?
187 _dhcpd_edit_ipv4
"$@" ||
return $?
191 dhcpd_global_settings_write
${proto}
197 while [ $# -gt 0 ]; do
200 val
=$
(cli_get_val
"${1}")
205 AUTHORITATIVE
="false"
208 --default-lease-time=*)
209 local val
=$
(cli_get_val
"${1}")
210 DEFAULT_LEASE_TIME
=$
(parse_time
${val})
212 if ! isinteger DEFAULT_LEASE_TIME
; then
213 error
"Invalid value for --default-lease-time: ${val}"
218 local val
=$
(cli_get_val
"${1}")
219 MAX_LEASE_TIME
=$
(parse_time
${val})
221 if ! isinteger MAX_LEASE_TIME
; then
222 error
"Invalid value for --max-lease-time: ${val}"
227 local val
=$
(cli_get_val
"${1}")
228 MIN_LEASE_TIME
=$
(parse_time
${val})
230 if isset MIN_LEASE_TIME
; then
231 if ! isinteger MIN_LEASE_TIME
; then
232 error
"Invalid value for --min-lease-time: ${val}"
238 error
"Unrecognized argument: ${1}"
245 if [ ${MAX_LEASE_TIME} -le ${DEFAULT_LEASE_TIME} ]; then
246 error
"The max. lease time must be higher than the default lease time."
252 while [ $# -gt 0 ]; do
254 --preferred-lifetime=*)
255 local val
=$
(cli_get_val
"${1}")
256 PREFERRED_LIFETIME
=$
(parse_time
${val})
258 if ! isinteger PREFERRED_LIFETIME
; then
259 error
"Invalid value for --preferred-lifetime: ${val}"
264 local val
=$
(cli_get_val
"${1}")
265 VALID_LIFETIME
=$
(parse_time
${val})
267 if ! isinteger VALID_LIFETIME
; then
268 error
"Invalid value for --valid-lifetime: ${val}"
273 error
"Unrecognized argument: ${1}"
281 dhcpd_settings_file
() {
287 print
"${DHCPV6D_SETTINGS_FILE}"
290 print
"${DHCPV4D_SETTINGS_FILE}"
303 print
"${DHCPV6D_SETTINGS}"
306 print
"${DHCPV4D_SETTINGS}"
313 dhcpd_options_file
() {
319 print
"${DHCPV6D_OPTIONS_FILE}"
322 print
"${DHCPV4D_OPTIONS_FILE}"
329 dhcpd_options_list
() {
335 print
"DHCPV6D_OPTIONS"
338 print
"DHCPV4D_OPTIONS"
351 print
"${DHCPV6D_OPTIONS}"
354 print
"${DHCPV4D_OPTIONS}"
361 dhcpd_global_settings_list
() {
365 dhcpd_settings
"${proto}"
368 dhcpd_global_settings_defaults
() {
372 local settings
=$
(dhcpd_settings
${proto})
373 assert isset settings
375 local prefix
="DHCPV${proto/ipv/}D_"
377 local setting setting_default
378 for setting
in ${settings}; do
379 setting_default
="${prefix}${setting}"
380 printf -v ${setting} "%s" "${!setting_default}"
384 dhcpd_global_settings_read
() {
388 local file=$
(dhcpd_settings_file
${proto})
391 local settings
=$
(dhcpd_settings
${proto})
392 assert isset settings
394 dhcpd_global_settings_defaults
${proto}
395 settings_read
${file} ${settings}
398 dhcpd_global_settings_write
() {
402 local file=$
(dhcpd_settings_file
${proto})
405 local settings
=$
(dhcpd_settings
${proto})
406 assert isset settings
408 settings_write
${file} ${settings}
411 dhcpd_global_options_read
() {
415 local options_file
=$
(dhcpd_options_file
${proto})
416 local options_list
=$
(dhcpd_options_list
${proto})
418 settings_read_array
${options_file} options
${!options_list}
420 # Check if domain-name is set.
421 if [ -z "${options["domain-name"]}" ]; then
422 options
["domain-name"]=$
(config_domainname
)
426 dhcpd_subnet_escape
() {
432 subnet
="${subnet//\//-}"
437 dhcpd_subnet_unescape
() {
442 # Unescape any slashes
443 subnet
="${subnet//-/\/}"
448 dhcpd_subnet_path
() {
449 assert
[ $# -ge 1 -a $# -le 2 ]
457 path
=${DHCPV6D_CONFIG_DIR}
460 path
=${DHCPV4D_CONFIG_DIR}
465 if ! isset subnet
; then
471 subnet
="$(dhcpd_subnet_escape ${subnet})"
474 subnet
="${DHCPD_SUBNET_PREFIX}${subnet}"
476 print
"${path}/${subnet}"
480 dhcpd_subnet_exists
() {
487 local path
=$
(dhcpd_subnet_path
${proto} ${subnet})
490 [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
493 dhcpd_subnet_match() {
500 local settings=$(dhcpd_subnet_settings ${proto})
501 assert isset settings
503 local _subnet ${settings}
504 for _subnet in $(dhcpd_subnet_list ${proto}); do
505 dhcpd_subnet_read ${proto} ${_subnet}
507 ${proto}_addr_eq "${ADDRESS}/${PREFIX}" "${subnet}" \
508 && return ${EXIT_TRUE}
514 dhcpd_subnet_exists
() {
515 dhcpd_subnet_match
"$@"
523 dhcpd_subnet_edit
${proto} "new" "$@"
526 dhcpd_subnet_edit
() {
534 if [ "${subnet}" = "new" ]; then
542 settings
=${DHCPV6D_SUBNET_SETTINGS}
545 settings
=${DHCPV4D_SUBNET_SETTINGS}
548 assert isset settings
551 # Read current settings
552 if [ "${mode}" = "edit" ]; then
553 dhcpd_subnet_read
${proto} ${subnet}
556 while [ $# -gt 0 ]; do
557 case "${proto},${mode},${1}" in
559 ipv6
,new
,*:*/*|ipv4
,new
,*.
*.
*.
*/*)
560 local subnet
="$(cli_get_val "${1}")"
562 ADDRESS
="$(ip_split_prefix ${subnet})"
563 PREFIX
="$(ip_get_prefix ${subnet})"
568 ipv6
,*,--delegated-prefix=*)
569 local subnet
="$(cli_get_val "${1}")"
570 if [[ -n "${subnet}" ]]; then
571 local delegated_prefix_first
="${subnet%-*}"
572 local delegated_prefix_last
="${subnet#*-}"
574 # Check for correct syntax
575 if ! isset delegated_prefix_first ||
! isset delegated_prefix_last
; then
576 error
"--delegated-prefix= must be formatted like 2001:db8:aaaa::-2001:db8:bbbb::"
580 # Check if the addresses are correct
582 for addr
in ${delegated_prefix_first} ${delegated_prefix_last}; do
583 if ! ipv6_is_valid
"${addr}"; then
584 error
"Invalid IP address: ${addr}"
589 # Make sure this is a range
590 if ! ipv6_addr_gt
"${delegated_prefix_last}" "${delegated_prefix_first}"; then
591 error
"--delegated-prefix: The second address must be larger than the first one"
595 PREFIX_DELEGATION
="on"
596 DELEGATED_PREFIX_FIRST
="${delegated_prefix_first}"
597 DELEGATED_PREFIX_LAST
="${delegated_prefix_last}"
599 # Prefix delegation has been disabled
601 PREFIX_DELEGATION
="off"
605 ipv6
,*,--delegated-prefix-size=*)
606 local prefix_size
="$(cli_get_val "${1}")"
608 if ipv6_prefix_size_is_valid_for_delegation
"${prefix_size}"; then
609 DELEGATED_PREFIX_SIZE
="${prefix_size}"
611 error
"Invalid prefix size for prefix delegation: ${prefix_size}"
620 ROUTERS
=$
(cli_get_val
"${1}")
624 error
"Unknown argument: ${1}"
631 if ! ${proto}_is_valid ${ADDRESS} || ! ${proto}_prefix_is_valid ${PREFIX}; then
632 error
"Invalid subnet: ${ADDRESS}/${PREFIX}"
636 # XXX Check for subnet collisions!
640 if dhcpd_subnet_exists
${proto} "${ADDRESS}/${PREFIX}"; then
641 error "DHCP subnet configuration already exists
for subnet
${ADDRESS}/${PREFIX}"
647 local file="$
(dhcpd_subnet_path
${proto} "${ADDRESS}/${PREFIX}")/settings"
648 settings_write
${file} ${settings}
651 dhcpd_subnet_remove
() {
657 local path
=$
(dhcpd_subnet_path
${proto} ${subnet})
660 # Remove everything of this subnet.
664 dhcpd_subnet_list
() {
668 local path
=$
(dhcpd_subnet_path
${proto})
670 # Return an error of the directory does not exist.
671 [ -d "${path}" ] ||
return ${EXIT_ERROR}
674 for p
in ${path}/${DHCPD_SUBNET_PREFIX}*; do
675 [ -d "${p}" ] ||
continue
678 p
="${p:${#DHCPD_SUBNET_PREFIX}}"
680 # Return unescaped subnet
681 dhcpd_subnet_unescape
"${p}"
685 dhcpd_subnet_read
() {
692 local file="$(dhcpd_subnet_path ${proto} ${subnet})/settings"
693 settings_read
${file}
696 dhcpd_subnet_range_path
() {
697 assert
[ $# -ge 2 -a $# -le 3 ]
703 if ! isset range
; then
704 dhcpd_subnet_path
${proto} ${subnet}
709 range
="${DHCPD_SUBNET_RANGE_PREFIX}${range}"
711 print
"$(dhcpd_subnet_path ${proto} ${subnet})/${range}"
715 dhcpd_subnet_range_settings
() {
720 print
"${DHCPV6D_SUBNET_RANGE_SETTINGS}"
723 print
"${DHCPV4D_SUBNET_RANGE_SETTINGS}"
730 dhcpd_subnet_range_new
() {
742 settings
=${DHCPV6D_SUBNET_RANGE_SETTINGS}
745 settings
=${DHCPV4D_SUBNET_RANGE_SETTINGS}
748 assert isset settings
749 local range
${settings}
751 while [ $# -gt 0 ]; do
760 error
"Unknown argument: ${1}"
768 for var
in START END
; do
769 if ! ${proto}_is_valid
${!var}; then
770 error
"'${!var}' is not a valid IP address"
775 # Check if the end address is larger than the start address
776 if ! ${proto}_addr_gt "${END}" "${START}"; then
777 error "The end address of the range must be greater than the start address
"
781 # Check if range already exists
782 if dhcpd_subnet_range_exists ${proto} ${subnet} ${range}; then
783 error "DHCP subnet range
${range} already exists
"
787 # Search for any overlaps
788 local overlaps=$(dhcpd_subnet_range_overlaps ${proto} ${subnet} ${range})
789 if isset overlaps; then
790 error "DHCP subnet range
${range} overlaps with
${overlaps}"
794 # Write the configuration to file.
795 local file=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range})
798 settings_write ${file} ${settings}
800 log INFO "DHCP subnet range
${range} created
"
805 dhcpd_subnet_range_remove() {
812 if ! dhcpd_subnet_range_exists ${proto} ${subnet} ${range}; then
813 error "DHCP subnet range
${range} does not exist
"
817 local path=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range})
822 log INFO "DHCP subnet range
${range} removed
"
826 dhcpd_subnet_range_list() {
832 local path=$(dhcpd_subnet_range_path ${proto} ${subnet})
835 for p in ${path}/${DHCPD_SUBNET_RANGE_PREFIX}*; do
836 [ -r "${p}" ] || continue
839 print "${p:${#DHCPD_SUBNET_RANGE_PREFIX}}"
845 dhcpd_subnet_range_read() {
852 local file=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range})
853 settings_read ${file}
856 dhcpd_subnet_range_exists() {
863 local start=${range%-*}
864 local end=${range#*-}
869 local settings=$(dhcpd_subnet_range_settings ${proto})
872 for r in $(dhcpd_subnet_range_list ${proto} ${subnet}); do
873 dhcpd_subnet_range_read ${proto} ${subnet} ${r}
875 # If start and end addresses equal we got a match
876 if ${proto}_addr_eq "${START}" "${start}" && ${proto}_addr_eq "${END}" "${end}"; then
884 dhcpd_subnet_range_overlaps
() {
891 local start
=${range%-*}
892 local end
=${range#*-}
897 local settings
=$
(dhcpd_subnet_range_settings
${proto})
900 for r
in $
(dhcpd_subnet_range_list
${proto} ${subnet}); do
901 dhcpd_subnet_range_read
${proto} ${subnet} ${r}
903 # Check if the new range is a sub-range of any existing range
905 # Check if the start address is somewhere in this range
906 if ${proto}_addr_ge ${START} ${start} && ${proto}_addr_le ${START} ${end}; then
911 # Check if the end address is somewhere in this range
912 if ${proto}_addr_ge ${END} ${start} && ${proto}_addr_le ${END} ${end}; then
917 # Check if any existing range is a sub-range of the new range
919 # Check if the start address is somewhere in this range
920 if ${proto}_addr_ge ${start} ${START} && ${proto}_addr_le ${start} ${END}; then
925 # Check if the end address is somewhere in this range
926 if ${proto}_addr_ge ${end} ${START} && ${proto}_addr_le ${end} ${END}; then
935 dhcpd_subnet_settings
() {
940 print
"${DHCPV6D_SUBNET_SETTINGS}"
943 print
"${DHCPV4D_SUBNET_SETTINGS}"
950 dhcpd_subnet_options_file
() {
951 local path
=$
(dhcpd_subnet_path
"$@")
954 print
"${path}/options"
957 dhcpd_subnet_options_list
() {
963 print
"${DHCPV6D_SUBNET_OPTIONS}"
966 print
"${DHCPV4D_SUBNET_OPTIONS}"
973 dhcpd_subnet_options_read
() {
980 local options_file
=$
(dhcpd_subnet_options_file
${proto} ${subnet})
981 local options_list
=$
(dhcpd_subnet_options_list
${proto})
983 _dhcpd_read_options
${options_file} ${options_list}
986 # Helper functions to create a DHCP configuration file.
987 _dhcpd_write_options
() {
994 local options_list
=${3}
995 assert isset options_list
999 print
"${ident}# Options" >> ${file}
1001 # Dump options array.
1003 for key
in ${!options_list}; do
1004 val
=${options[${key}]}
1006 # Skip the rest if val is empty
1007 isset val ||
continue
1009 # Enable raw formatting (i.e. quote the value?)
1012 # Update the formatting of some options
1015 val
="$(list_join val ", ")"
1020 # Prepend dhcp6 on IPv6 options.
1021 if [ "${proto}" = "ipv6" ]; then
1025 if isinteger val
; then
1027 elif enabled raw || isipaddress val
; then
1030 fmt="option %s \"%s\";"
1033 print
"${ident}${fmt}" "${key}" "${val}"
1040 _dhcpd_read_options
() {
1044 local options_list
=${2}
1045 assert isset options_list
1047 settings_read_array
${file} options
${!options_list}
1050 _dhcpd_write_subnet
() {
1057 # Check which settings we do expect.
1061 settings
=${DHCPV6D_SUBNET_SETTINGS}
1064 settings
=${DHCPV4D_SUBNET_SETTINGS}
1067 assert isset settings
1070 # Read configuration settings.
1071 dhcpd_subnet_read
${proto} ${subnet}
1073 print
"# Subnet declaration" >> ${file}
1076 print
"subnet6 ${ADDRESS}/${PREFIX} {" >> ${file}
1079 local netmask="$
(ipv4_prefix2netmask
"${PREFIX}")"
1080 print "subnet
${ADDRESS} netmask ${netmask} {" >> ${file}
1085 _dhcpd_write_subnet_options
${proto} ${subnet} ${file}
1087 # Prefix Delegation for IPv6
1088 if [[ "${proto}" = "ipv6" ]]; then
1089 _dhcpd_write_subnet_pd
"${subnet}" "${file}"
1094 for range
in $
(dhcpd_subnet_range_list
${proto} ${subnet} ${range}); do
1095 _dhcpd_write_subnet_range
${proto} ${subnet} ${range} ${file}
1098 # End this subnet block.
1099 print
"}\n" >> ${file}
1104 _dhcpd_write_subnet_options
() {
1112 local options_file
="$(dhcpd_subnet_path ${proto} ${subnet})/options"
1116 settings
=${DHCPV6D_SUBNET_SETTINGS}
1117 options_list
="DHCPV6D_OPTIONS"
1120 settings
=${DHCPV4D_SUBNET_SETTINGS}
1121 options_list
="DHCPV4D_OPTIONS"
1124 assert isset settings
1125 assert isset options_list
1128 dhcpd_subnet_read
${proto} ${subnet}
1131 _dhcpd_read_options
${options_file} ${options_list}
1133 # Fill in router, if not already set.
1134 if [ -z "${options["routers"]}" ]; then
1135 options
["routers"]=$
(_dhcpd_search_routers
${proto} "${ADDRESS}/${PREFIX}")
1138 _dhcpd_write_options ${proto} ${file} ${options_list} "\t"
1141 _dhcpd_write_subnet_pd() {
1142 # Nothing to do if prefix delegation is not enabled
1143 enabled PREFIX_DELEGATION || return ${EXIT_OK}
1150 local prefix_size="${DELEGATED_PREFIX_SIZE}"
1151 isset prefix_size || prefix_size="${DHCP_DEFAULT_DELEGATED_PREFIX_SIZE}"
1153 assert ipv6_is_valid "${DELEGATED_PREFIX_FIRST}"
1154 assert ipv6_is_valid "${DELEGATED_PREFIX_LAST}"
1155 assert ipv6_prefix_size_is_valid_for_delegation "${prefix_size}"
1158 print " # Prefix Delegation"
1159 print
" prefix6 ${DELEGATED_PREFIX_FIRST} ${DELEGATED_PREFIX_LAST} /${prefix_size};"
1164 _dhcpd_search_routers
() {
1170 # Do nothing for IPv6 (yet?).
1171 [ "${proto}" = "ipv6" ] && return ${EXIT_OK}
1173 local routers zone addr
1174 for zone
in $
(zones_get_all
); do
1175 addr
="$(db_get "${zone}/${proto}/local-ip-address
")"
1176 isset addr ||
continue
1178 if ipv4_in_subnet
${addr} ${subnet}; then
1179 list_append routers $
(ip_split_prefix
${addr})
1183 list_join routers
", "
1186 _dhcpd_write_subnet_range
() {
1194 local settings
=$
(dhcpd_subnet_range_settings
${proto})
1195 assert isset settings
1197 # Read the configuration settings.
1199 dhcpd_subnet_range_read
${proto} ${subnet} ${range}
1203 print
" range6 ${START} ${END};" >> ${file}
1206 print " range
${START} ${END};" >> ${file}
1214 dhcpd_write_config
() {
1219 local file options_list
1222 file=${DHCPV6D_CONFIG_FILE}
1223 options_list
="DHCPV6D_OPTIONS"
1226 file=${DHCPV4D_CONFIG_FILE}
1227 options_list
="DHCPV4D_OPTIONS"
1231 assert isset options_list
1234 config_header
"DHCP ${proto} daemon configuration file" > ${file}
1236 # Read global DHCP configuration
1237 dhcpd_global_settings_read
"${proto}"
1240 if enabled AUTHORITATIVE
; then
1242 print
"# This is an authoritative DHCP server for this network."
1243 print
"authoritative;\n"
1247 print
"# This is NOT an authoritative DHCP server for this network."
1248 print
"not authoritative;\n"
1255 if isinteger VALID_LIFETIME
; then
1256 print
"default-lease-time %d;" "${VALID_LIFETIME}" >> ${file}
1259 if isinteger PREFERRED_LIFETIME
; then
1260 print
"preferred-lifetime %d;" "${PREFERRED_LIFETIME}" >> ${file}
1265 if isinteger DEFAULT_LEASE_TIME
; then
1266 print
"default-lease-time %d;" "${DEFAULT_LEASE_TIME}" >> ${file}
1269 if isinteger MAX_LEASE_TIME
; then
1270 print
"max-lease-time %d;" "${MAX_LEASE_TIME}" >> ${file}
1273 if isinteger MIN_LEASE_TIME
; then
1274 print
"min-lease-time %d;" "${MIN_LEASE_TIME}" >> ${file}
1279 # Write the options to file.
1281 dhcpd_global_options_read
${proto}
1282 _dhcpd_write_options
${proto} ${file} ${options_list}
1284 # Add all subnet declarations.
1286 for subnet
in $
(dhcpd_subnet_list
${proto}); do
1287 _dhcpd_write_subnet
${proto} ${subnet} ${file}