]>
Commit | Line | Data |
---|---|---|
6c07160e MT |
1 | #!/bin/bash |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2012 IPFire Network Development Team # | |
6 | # # | |
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. # | |
11 | # # | |
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. # | |
16 | # # | |
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/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | DHCPV6D_CONFIG_FILE="/etc/dhcp/dhcpd6.conf" | |
23 | DHCPV4D_CONFIG_FILE="/etc/dhcp/dhcpd.conf" | |
24 | ||
25 | DHCPV6D_CONFIG_DIR="${NETWORK_CONFIG_DIR}/dhcpd/ipv6" | |
26 | DHCPV4D_CONFIG_DIR="${NETWORK_CONFIG_DIR}/dhcpd/ipv4" | |
27 | ||
28 | DHCPV6D_OPTIONS_FILE="${DHCPV6D_CONFIG_DIR}/options" | |
29 | DHCPV4D_OPTIONS_FILE="${DHCPV4D_CONFIG_DIR}/options" | |
30 | ||
31 | DHCPV6D_SETTINGS_FILE="${DHCPV6D_CONFIG_DIR}/settings" | |
32 | DHCPV4D_SETTINGS_FILE="${DHCPV4D_CONFIG_DIR}/settings" | |
33 | ||
34 | DHCPD_SETTINGS="\ | |
35 | AUTHORITATIVE | |
36 | " | |
37 | DHCPV6D_SETTINGS="\ | |
38 | ${DHCPD_SETTINGS} \ | |
ea878018 | 39 | PREFERRED_LIFETIME \ |
6c07160e MT |
40 | VALID_LIFETIME |
41 | " | |
42 | DHCPV4D_SETTINGS="\ | |
43 | ${DHCPD_SETTINGS} \ | |
44 | DEFAULT_LEASE_TIME \ | |
45 | MAX_LEASE_TIME \ | |
46 | MIN_LEASE_TIME \ | |
47 | " | |
48 | ||
49 | DHCPD_SUBNET_PREFIX="subnet-" | |
50 | #DHCPD_SUBNET_POOL_PREFIX="pool-" | |
51 | DHCPD_SUBNET_RANGE_PREFIX="range-" | |
52 | ||
ea878018 MT |
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" | |
6c07160e MT |
57 | |
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}" | |
61 | ||
62 | DHCPV6D_OPTIONS="\ | |
63 | domain-search \ | |
64 | name-servers \ | |
65 | " | |
66 | DHCPV4D_OPTIONS="\ | |
67 | all-subnets-local \ | |
68 | arp-cache-timeout \ | |
69 | bootfile-name \ | |
70 | broadcast-address \ | |
71 | default-ip-ttl \ | |
72 | default-tcp-ttl \ | |
73 | dhcp-client-identifier \ | |
74 | dhcp-lease-time \ | |
75 | dhcp-max-message-size \ | |
76 | dhcp-rebinding-time \ | |
77 | dhcp-renewal-time \ | |
78 | domain-name \ | |
79 | domain-name-servers \ | |
80 | domain-search \ | |
81 | interface-mtu \ | |
82 | ntp-servers \ | |
83 | root-path \ | |
84 | routers \ | |
85 | tftp-server-name \ | |
86 | " | |
87 | ||
cf0d2484 MT |
88 | DHCPV6D_SUBNET_OPTIONS="${DHCPV6D_OPTIONS}" |
89 | DHCPV4D_SUBNET_OPTIONS="${DHCPV4D_OPTIONS}" | |
6c07160e | 90 | |
ea878018 MT |
91 | # Global defaults |
92 | DHCP_DEFAULT_DELEGATED_PREFIX_SIZE="64" | |
93 | ||
6c07160e MT |
94 | # Defaults for DHCPv6. |
95 | DHCPV6D_PREFERRED_LIFETIME="" | |
96 | DHCPV6D_VALID_LIFETIME="43200" # 12h | |
97 | ||
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="" | |
103 | ||
1c6a4e30 | 104 | dhcpd_service() { |
6c07160e MT |
105 | case "${1}" in |
106 | ipv6) | |
107 | print "dhcpd6.service" | |
108 | ;; | |
109 | ipv4) | |
110 | print "dhcpd.service" | |
111 | ;; | |
112 | "") | |
113 | print "dhcpd6.service dhcp.service" | |
114 | ;; | |
115 | esac | |
116 | ||
117 | return ${EXIT_OK} | |
118 | } | |
119 | ||
1c6a4e30 | 120 | dhcpd_start() { |
6c07160e MT |
121 | local services=$(dhcpd_service $@) |
122 | ||
123 | local service | |
124 | for service in ${services}; do | |
125 | service_start ${service} | |
126 | done | |
127 | } | |
128 | ||
1c6a4e30 | 129 | dhcpd_stop() { |
6c07160e MT |
130 | local services=$(dhcpd_service $@) |
131 | ||
132 | local service | |
133 | for service in ${services}; do | |
134 | service_stop ${service} | |
135 | done | |
136 | } | |
137 | ||
1c6a4e30 | 138 | dhcpd_restart() { |
6c07160e MT |
139 | # DHCP does not support a reload, so |
140 | # we retsart it. | |
141 | local services=$(dhcpd_service $@) | |
142 | ||
143 | local service | |
144 | for service in ${services}; do | |
145 | service_restart ${service} | |
146 | done | |
147 | } | |
148 | ||
1c6a4e30 | 149 | dhcpd_reload() { |
6c07160e MT |
150 | dhcpd_restart $@ |
151 | } | |
152 | ||
9ff233f0 MT |
153 | dhcpd_enable() { |
154 | local services=$(dhcpd_service $@) | |
155 | ||
156 | local service | |
157 | for service in ${services}; do | |
158 | service_enable ${service} | |
159 | done | |
160 | } | |
161 | ||
162 | dhcpd_disable() { | |
163 | local services=$(dhcpd_service $@) | |
164 | ||
165 | local service | |
166 | for service in ${services}; do | |
167 | service_disable ${service} | |
168 | done | |
169 | } | |
170 | ||
1c6a4e30 | 171 | dhcpd_edit() { |
6c07160e MT |
172 | local proto=${1} |
173 | assert isset proto | |
174 | shift | |
175 | ||
176 | local settings=$(dhcpd_settings ${proto}) | |
177 | assert isset settings | |
178 | ||
179 | local ${settings} | |
180 | dhcpd_global_settings_read ${proto} | |
181 | ||
182 | case "${proto}" in | |
183 | ipv6) | |
184 | _dhcpd_edit_ipv6 $@ || return $? | |
185 | ;; | |
186 | ipv4) | |
187 | _dhcpd_edit_ipv4 $@ || return $? | |
188 | ;; | |
189 | esac | |
190 | ||
191 | dhcpd_global_settings_write ${proto} | |
192 | } | |
193 | ||
1c6a4e30 | 194 | _dhcpd_edit_ipv4() { |
6c07160e MT |
195 | local val |
196 | ||
197 | while [ $# -gt 0 ]; do | |
198 | case "${1}" in | |
199 | --authoritative=*) | |
200 | val=$(cli_get_val ${1}) | |
201 | ||
202 | if enabled val; then | |
203 | AUTHORITATIVE="true" | |
204 | else | |
205 | AUTHORITATIVE="false" | |
206 | fi | |
207 | ;; | |
208 | --default-lease-time=*) | |
b383499d MT |
209 | local val=$(cli_get_val ${1}) |
210 | DEFAULT_LEASE_TIME=$(parse_time ${val}) | |
6c07160e MT |
211 | |
212 | if ! isinteger DEFAULT_LEASE_TIME; then | |
b383499d | 213 | error "Invalid value for --default-lease-time: ${val}" |
6c07160e MT |
214 | return ${EXIT_ERROR} |
215 | fi | |
216 | ;; | |
217 | --max-lease-time=*) | |
b383499d MT |
218 | local val=$(cli_get_val ${1}) |
219 | MAX_LEASE_TIME=$(parse_time ${val}) | |
6c07160e MT |
220 | |
221 | if ! isinteger MAX_LEASE_TIME; then | |
b383499d | 222 | error "Invalid value for --max-lease-time: ${val}" |
6c07160e MT |
223 | return ${EXIT_ERROR} |
224 | fi | |
225 | ;; | |
226 | --min-lease-time=*) | |
b383499d MT |
227 | local val=$(cli_get_val ${1}) |
228 | MIN_LEASE_TIME=$(parse_time ${val}) | |
6c07160e MT |
229 | |
230 | if isset MIN_LEASE_TIME; then | |
231 | if ! isinteger MIN_LEASE_TIME; then | |
b383499d | 232 | error "Invalid value for --min-lease-time: ${val}" |
6c07160e MT |
233 | return ${EXIT_ERROR} |
234 | fi | |
235 | fi | |
236 | ;; | |
237 | *) | |
238 | error "Unrecognized argument: ${1}" | |
239 | return ${EXIT_ERROR} | |
240 | ;; | |
241 | esac | |
242 | shift | |
243 | done | |
244 | ||
245 | if [ ${MAX_LEASE_TIME} -le ${DEFAULT_LEASE_TIME} ]; then | |
246 | error "The max. lease time must be higher than the default lease time." | |
247 | return ${EXIT_ERROR} | |
248 | fi | |
249 | } | |
250 | ||
1c6a4e30 | 251 | _dhcpd_edit_ipv6() { |
6c07160e MT |
252 | while [ $# -gt 0 ]; do |
253 | case "${1}" in | |
254 | --preferred-lifetime=*) | |
b383499d MT |
255 | local val=$(cli_get_val ${1}) |
256 | PREFERRED_LIFETIME=$(parse_time ${val}) | |
6c07160e MT |
257 | |
258 | if ! isinteger PREFERRED_LIFETIME; then | |
b383499d | 259 | error "Invalid value for --preferred-lifetime: ${val}" |
6c07160e MT |
260 | return ${EXIT_ERROR} |
261 | fi | |
262 | ;; | |
263 | --valid-lifetime=*) | |
b383499d MT |
264 | local val=$(cli_get_val ${1}) |
265 | VALID_LIFETIME=$(parse_time ${val}) | |
6c07160e MT |
266 | |
267 | if ! isinteger VALID_LIFETIME; then | |
b383499d | 268 | error "Invalid value for --valid-lifetime: ${val}" |
6c07160e MT |
269 | return ${EXIT_ERROR} |
270 | fi | |
271 | ;; | |
272 | *) | |
273 | error "Unrecognized argument: ${1}" | |
274 | return ${EXIT_ERROR} | |
275 | ;; | |
276 | esac | |
277 | shift | |
278 | done | |
279 | } | |
280 | ||
1c6a4e30 | 281 | dhcpd_settings_file() { |
6c07160e MT |
282 | local proto=${1} |
283 | assert isset proto | |
284 | ||
285 | case "${proto}" in | |
286 | ipv6) | |
287 | print "${DHCPV6D_SETTINGS_FILE}" | |
288 | ;; | |
289 | ipv4) | |
290 | print "${DHCPV4D_SETTINGS_FILE}" | |
291 | ;; | |
292 | esac | |
293 | ||
294 | return ${EXIT_OK} | |
295 | } | |
296 | ||
1c6a4e30 | 297 | dhcpd_settings() { |
6c07160e MT |
298 | local proto=${1} |
299 | assert isset proto | |
300 | ||
301 | case "${proto}" in | |
302 | ipv6) | |
303 | print "${DHCPV6D_SETTINGS}" | |
304 | ;; | |
305 | ipv4) | |
306 | print "${DHCPV4D_SETTINGS}" | |
307 | ;; | |
308 | esac | |
309 | ||
310 | return ${EXIT_OK} | |
311 | } | |
312 | ||
1c6a4e30 | 313 | dhcpd_options_file() { |
6c07160e MT |
314 | local proto=${1} |
315 | assert isset proto | |
316 | ||
317 | case "${proto}" in | |
318 | ipv6) | |
319 | print "${DHCPV6D_OPTIONS_FILE}" | |
320 | ;; | |
321 | ipv4) | |
322 | print "${DHCPV4D_OPTIONS_FILE}" | |
323 | ;; | |
324 | esac | |
325 | ||
326 | return ${EXIT_OK} | |
327 | } | |
328 | ||
1c6a4e30 | 329 | dhcpd_options_list() { |
6c07160e MT |
330 | local proto=${1} |
331 | assert isset proto | |
332 | ||
333 | case "${proto}" in | |
334 | ipv6) | |
335 | print "DHCPV6D_OPTIONS" | |
336 | ;; | |
337 | ipv4) | |
338 | print "DHCPV4D_OPTIONS" | |
339 | ;; | |
340 | esac | |
341 | ||
342 | return ${EXIT_OK} | |
343 | } | |
344 | ||
1c6a4e30 | 345 | dhcpd_options() { |
6c07160e MT |
346 | local proto=${1} |
347 | assert isset proto | |
348 | ||
349 | case "${proto}" in | |
350 | ipv6) | |
351 | print "${DHCPV6D_OPTIONS}" | |
352 | ;; | |
353 | ipv4) | |
354 | print "${DHCPV4D_OPTIONS}" | |
355 | ;; | |
356 | esac | |
357 | ||
358 | return ${EXIT_OK} | |
359 | } | |
360 | ||
1c6a4e30 | 361 | dhcpd_global_settings_list() { |
cc02f6be MT |
362 | local proto="${1}" |
363 | assert isset proto | |
364 | ||
365 | dhcpd_settings "${proto}" | |
366 | } | |
367 | ||
1c6a4e30 | 368 | dhcpd_global_settings_defaults() { |
6c07160e MT |
369 | local proto=${1} |
370 | assert isset proto | |
371 | ||
372 | local settings=$(dhcpd_settings ${proto}) | |
373 | assert isset settings | |
374 | ||
375 | local prefix="DHCPV${proto/ipv/}D_" | |
376 | ||
377 | local setting setting_default | |
378 | for setting in ${settings}; do | |
379 | setting_default="${prefix}${setting}" | |
380 | printf -v ${setting} "%s" "${!setting_default}" | |
381 | done | |
382 | } | |
383 | ||
1c6a4e30 | 384 | dhcpd_global_settings_read() { |
6c07160e MT |
385 | local proto=${1} |
386 | assert isset proto | |
387 | ||
388 | local file=$(dhcpd_settings_file ${proto}) | |
389 | assert isset file | |
390 | ||
391 | local settings=$(dhcpd_settings ${proto}) | |
392 | assert isset settings | |
393 | ||
394 | dhcpd_global_settings_defaults ${proto} | |
e9df08ad | 395 | settings_read ${file} ${settings} |
6c07160e MT |
396 | } |
397 | ||
1c6a4e30 | 398 | dhcpd_global_settings_write() { |
6c07160e MT |
399 | local proto=${1} |
400 | assert isset proto | |
401 | ||
402 | local file=$(dhcpd_settings_file ${proto}) | |
403 | assert isset file | |
404 | ||
405 | local settings=$(dhcpd_settings ${proto}) | |
406 | assert isset settings | |
407 | ||
e9df08ad | 408 | settings_write ${file} ${settings} |
6c07160e MT |
409 | } |
410 | ||
1c6a4e30 | 411 | dhcpd_global_options_read() { |
6c07160e MT |
412 | local proto=${1} |
413 | assert isset proto | |
414 | ||
415 | local options_file=$(dhcpd_options_file ${proto}) | |
416 | local options_list=$(dhcpd_options_list ${proto}) | |
417 | ||
e9df08ad | 418 | settings_read_array ${options_file} options ${!options_list} |
6c07160e MT |
419 | |
420 | # Check if domain-name is set. | |
421 | if [ -z "${options["domain-name"]}" ]; then | |
422 | options["domain-name"]=$(config_domainname) | |
423 | fi | |
424 | } | |
425 | ||
94784eb9 MT |
426 | dhcpd_subnet_escape() { |
427 | assert [ $# -eq 1 ] | |
428 | ||
429 | local subnet="${1}" | |
430 | ||
431 | # Escape any slashes | |
432 | subnet="${subnet//\//-}" | |
433 | ||
434 | print "${subnet}" | |
435 | } | |
436 | ||
437 | dhcpd_subnet_unescape() { | |
438 | assert [ $# -eq 1 ] | |
439 | ||
440 | local subnet="${1}" | |
441 | ||
442 | # Unescape any slashes | |
443 | subnet="${subnet//-/\/}" | |
444 | ||
445 | print "${subnet}" | |
446 | } | |
447 | ||
1c6a4e30 | 448 | dhcpd_subnet_path() { |
94784eb9 | 449 | assert [ $# -ge 1 -a $# -le 2 ] |
6c07160e | 450 | |
94784eb9 MT |
451 | local proto=${1} |
452 | local subnet=${2} | |
6c07160e MT |
453 | |
454 | local path | |
455 | case "${proto}" in | |
456 | ipv6) | |
457 | path=${DHCPV6D_CONFIG_DIR} | |
458 | ;; | |
459 | ipv4) | |
460 | path=${DHCPV4D_CONFIG_DIR} | |
461 | ;; | |
462 | esac | |
463 | assert isset path | |
464 | ||
94784eb9 MT |
465 | if ! isset subnet; then |
466 | print "${path}" | |
467 | return ${EXIT_OK} | |
468 | fi | |
469 | ||
470 | # Escape subnet | |
471 | subnet="$(dhcpd_subnet_escape ${subnet})" | |
472 | ||
473 | # Add path prefix | |
474 | subnet="${DHCPD_SUBNET_PREFIX}${subnet}" | |
475 | ||
476 | print "${path}/${subnet}" | |
6c07160e MT |
477 | return ${EXIT_OK} |
478 | } | |
479 | ||
1c6a4e30 | 480 | dhcpd_subnet_exists() { |
6c07160e MT |
481 | local proto=${1} |
482 | assert isset proto | |
483 | ||
94784eb9 MT |
484 | local subnet=${2} |
485 | assert isset subnet | |
6c07160e | 486 | |
94784eb9 | 487 | local path=$(dhcpd_subnet_path ${proto} ${subnet}) |
6c07160e MT |
488 | assert isset path |
489 | ||
490 | [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE} | |
491 | } | |
492 | ||
1c6a4e30 | 493 | dhcpd_subnet_match() { |
6c07160e MT |
494 | local proto=${1} |
495 | assert isset proto | |
496 | ||
497 | local subnet=${2} | |
498 | assert isset subnet | |
499 | ||
500 | local settings=$(dhcpd_subnet_settings ${proto}) | |
501 | assert isset settings | |
502 | ||
94784eb9 MT |
503 | local _subnet ${settings} |
504 | for _subnet in $(dhcpd_subnet_list ${proto}); do | |
505 | dhcpd_subnet_read ${proto} ${_subnet} | |
6c07160e MT |
506 | |
507 | ${proto}_addr_eq "${ADDRESS}/${PREFIX}" "${subnet}" \ | |
508 | && return ${EXIT_TRUE} | |
509 | done | |
510 | ||
511 | return ${EXIT_FALSE} | |
512 | } | |
513 | ||
94784eb9 MT |
514 | dhcpd_subnet_exists() { |
515 | dhcpd_subnet_match $@ | |
6c07160e MT |
516 | } |
517 | ||
1c6a4e30 | 518 | dhcpd_subnet_new() { |
6c07160e MT |
519 | local proto=${1} |
520 | assert isset proto | |
521 | shift | |
522 | ||
94784eb9 | 523 | dhcpd_subnet_edit ${proto} "new" $@ |
6c07160e MT |
524 | } |
525 | ||
1c6a4e30 | 526 | dhcpd_subnet_edit() { |
94784eb9 MT |
527 | assert [ $# -ge 2 ] |
528 | ||
6c07160e | 529 | local proto=${1} |
94784eb9 MT |
530 | local subnet=${2} |
531 | shift 2 | |
6c07160e | 532 | |
94784eb9 MT |
533 | local mode="edit" |
534 | if [ "${subnet}" = "new" ]; then | |
535 | mode="new" | |
536 | subnet="" | |
537 | fi | |
6c07160e MT |
538 | |
539 | local settings | |
540 | case "${proto}" in | |
541 | ipv6) | |
542 | settings=${DHCPV6D_SUBNET_SETTINGS} | |
543 | ;; | |
544 | ipv4) | |
545 | settings=${DHCPV4D_SUBNET_SETTINGS} | |
546 | ;; | |
547 | esac | |
548 | assert isset settings | |
549 | local ${settings} | |
550 | ||
94784eb9 MT |
551 | # Read current settings |
552 | if [ "${mode}" = "edit" ]; then | |
553 | dhcpd_subnet_read ${proto} ${subnet} | |
554 | fi | |
6c07160e MT |
555 | |
556 | while [ $# -gt 0 ]; do | |
94784eb9 | 557 | case "${proto},${mode},${1}" in |
ea878018 | 558 | # Common options |
94784eb9 MT |
559 | ipv6,new,*:*/*|ipv4,new,*.*.*.*/*) |
560 | local subnet="$(cli_get_val ${1})" | |
6c07160e | 561 | |
94784eb9 MT |
562 | ADDRESS="$(ip_split_prefix ${subnet})" |
563 | PREFIX="$(ip_get_prefix ${subnet})" | |
6c07160e | 564 | ;; |
ea878018 MT |
565 | |
566 | # IPv6 options | |
567 | ||
94784eb9 | 568 | ipv6,*,--delegated-prefix=*) |
ea878018 MT |
569 | local subnet="$(cli_get_val "${1}")" |
570 | if [[ -n "${subnet}" ]]; then | |
571 | local delegated_prefix_first="${subnet%-*}" | |
572 | local delegated_prefix_last="${subnet#*-}" | |
573 | ||
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::" | |
577 | return ${EXIT_ERROR} | |
578 | fi | |
579 | ||
580 | # Check if the addresses are correct | |
581 | local addr | |
582 | for addr in ${delegated_prefix_first} ${delegated_prefix_last}; do | |
583 | if ! ipv6_is_valid "${addr}"; then | |
584 | error "Invalid IP address: ${addr}" | |
585 | return ${EXIT_ERROR} | |
586 | fi | |
587 | done | |
588 | ||
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" | |
592 | return ${EXIT_ERROR} | |
593 | fi | |
594 | ||
595 | PREFIX_DELEGATION="on" | |
596 | DELEGATED_PREFIX_FIRST="${delegated_prefix_first}" | |
597 | DELEGATED_PREFIX_LAST="${delegated_prefix_last}" | |
598 | ||
599 | # Prefix delegation has been disabled | |
600 | else | |
601 | PREFIX_DELEGATION="off" | |
602 | fi | |
603 | ;; | |
604 | ||
94784eb9 | 605 | ipv6,*,--delegated-prefix-size=*) |
ea878018 MT |
606 | local prefix_size="$(cli_get_val "${1}")" |
607 | ||
608 | if ipv6_prefix_size_is_valid_for_delegation "${prefix_size}"; then | |
609 | DELEGATED_PREFIX_SIZE="${prefix_size}" | |
610 | else | |
611 | error "Invalid prefix size for prefix delegation: ${prefix_size}" | |
612 | return ${EXIT_ERROR} | |
613 | fi | |
614 | ;; | |
615 | ||
94784eb9 | 616 | |
ea878018 MT |
617 | # IPv4 options |
618 | ||
94784eb9 | 619 | ipv4,*,--routers=*) |
6c07160e MT |
620 | ROUTERS=$(cli_get_val ${1}) |
621 | ;; | |
94784eb9 | 622 | |
6c07160e MT |
623 | *) |
624 | error "Unknown argument: ${1}" | |
625 | return ${EXIT_ERROR} | |
626 | ;; | |
627 | esac | |
628 | shift | |
629 | done | |
630 | ||
94784eb9 MT |
631 | if ! ${proto}_is_valid ${ADDRESS} || ! ${proto}_prefix_is_valid ${PREFIX}; then |
632 | error "Invalid subnet: ${ADDRESS}/${PREFIX}" | |
633 | return ${EXIT_ERROR} | |
634 | fi | |
6c07160e | 635 | |
94784eb9 | 636 | # XXX Check for subnet collisions! |
6c07160e | 637 | |
94784eb9 MT |
638 | case "${mode}" in |
639 | new) | |
640 | if dhcpd_subnet_exists ${proto} "${ADDRESS}/${PREFIX}"; then | |
641 | error "DHCP subnet configuration already exists for subnet ${ADDRESS}/${PREFIX}" | |
6c07160e MT |
642 | return ${EXIT_ERROR} |
643 | fi | |
644 | ;; | |
645 | esac | |
646 | ||
94784eb9 | 647 | local file="$(dhcpd_subnet_path ${proto} "${ADDRESS}/${PREFIX}")/settings" |
e9df08ad | 648 | settings_write ${file} ${settings} |
6c07160e MT |
649 | } |
650 | ||
1c6a4e30 | 651 | dhcpd_subnet_remove() { |
94784eb9 | 652 | assert [ $# -eq 2 ] |
6c07160e | 653 | |
94784eb9 MT |
654 | local proto=${1} |
655 | local subnet=${2} | |
6c07160e | 656 | |
94784eb9 | 657 | local path=$(dhcpd_subnet_path ${proto} ${subnet}) |
6c07160e MT |
658 | assert isset path |
659 | ||
660 | # Remove everything of this subnet. | |
661 | rm -rf ${path} | |
662 | } | |
663 | ||
1c6a4e30 | 664 | dhcpd_subnet_list() { |
6c07160e MT |
665 | local proto=${1} |
666 | assert isset proto | |
667 | ||
94784eb9 | 668 | local path=$(dhcpd_subnet_path ${proto}) |
6c07160e MT |
669 | |
670 | # Return an error of the directory does not exist. | |
671 | [ -d "${path}" ] || return ${EXIT_ERROR} | |
672 | ||
673 | local p | |
674 | for p in ${path}/${DHCPD_SUBNET_PREFIX}*; do | |
675 | [ -d "${p}" ] || continue | |
676 | ||
677 | p=$(basename ${p}) | |
94784eb9 MT |
678 | p="${p:${#DHCPD_SUBNET_PREFIX}}" |
679 | ||
680 | # Return unescaped subnet | |
681 | dhcpd_subnet_unescape "${p}" | |
6c07160e MT |
682 | done |
683 | } | |
684 | ||
1c6a4e30 | 685 | dhcpd_subnet_read() { |
6c07160e MT |
686 | local proto=${1} |
687 | assert isset proto | |
688 | ||
94784eb9 MT |
689 | local subnet=${2} |
690 | assert isset subnet | |
6c07160e | 691 | |
94784eb9 | 692 | local file="$(dhcpd_subnet_path ${proto} ${subnet})/settings" |
e9df08ad | 693 | settings_read ${file} |
6c07160e MT |
694 | } |
695 | ||
1c6a4e30 | 696 | dhcpd_subnet_range_path() { |
f3ac1159 | 697 | assert [ $# -ge 2 -a $# -le 3 ] |
6c07160e | 698 | |
94784eb9 MT |
699 | local proto=${1} |
700 | local subnet=${2} | |
6c07160e | 701 | |
f3ac1159 MT |
702 | local range=${3} |
703 | if ! isset range; then | |
704 | dhcpd_subnet_path ${proto} ${subnet} | |
705 | return $? | |
706 | fi | |
707 | ||
708 | # Add prefix | |
709 | range="${DHCPD_SUBNET_RANGE_PREFIX}${range}" | |
710 | ||
711 | print "$(dhcpd_subnet_path ${proto} ${subnet})/${range}" | |
6c07160e MT |
712 | return ${EXIT_OK} |
713 | } | |
714 | ||
1c6a4e30 | 715 | dhcpd_subnet_range_settings() { |
6c07160e MT |
716 | local proto=${1} |
717 | ||
718 | case "${proto}" in | |
719 | ipv6) | |
720 | print "${DHCPV6D_SUBNET_RANGE_SETTINGS}" | |
721 | ;; | |
722 | ipv4) | |
723 | print "${DHCPV4D_SUBNET_RANGE_SETTINGS}" | |
724 | ;; | |
725 | esac | |
726 | ||
727 | return ${EXIT_OK} | |
728 | } | |
729 | ||
1c6a4e30 | 730 | dhcpd_subnet_range_new() { |
6c07160e MT |
731 | local proto=${1} |
732 | assert isset proto | |
733 | shift | |
734 | ||
94784eb9 MT |
735 | local subnet=${1} |
736 | assert isset subnet | |
6c07160e MT |
737 | shift |
738 | ||
6c07160e MT |
739 | local settings |
740 | case "${proto}" in | |
741 | ipv6) | |
6c07160e MT |
742 | settings=${DHCPV6D_SUBNET_RANGE_SETTINGS} |
743 | ;; | |
744 | ipv4) | |
6c07160e MT |
745 | settings=${DHCPV4D_SUBNET_RANGE_SETTINGS} |
746 | ;; | |
747 | esac | |
748 | assert isset settings | |
52f69c52 | 749 | local range ${settings} |
6c07160e MT |
750 | |
751 | while [ $# -gt 0 ]; do | |
752 | case "${1}" in | |
f3ac1159 | 753 | *-*) |
52f69c52 | 754 | range=${1} |
f3ac1159 MT |
755 | |
756 | START="${range%-*}" | |
757 | END="${range#*-}" | |
6c07160e MT |
758 | ;; |
759 | *) | |
760 | error "Unknown argument: ${1}" | |
761 | return ${EXIT_ERROR} | |
762 | ;; | |
763 | esac | |
764 | shift | |
765 | done | |
766 | ||
6c07160e MT |
767 | local var |
768 | for var in START END; do | |
f3ac1159 MT |
769 | if ! ${proto}_is_valid ${!var}; then |
770 | error "'${!var}' is not a valid IP address" | |
6c07160e MT |
771 | return ${EXIT_ERROR} |
772 | fi | |
773 | done | |
774 | ||
7da6a387 MT |
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" | |
778 | return ${EXIT_ERROR} | |
6c07160e MT |
779 | fi |
780 | ||
089e7410 MT |
781 | # Check if range already exists |
782 | if dhcpd_subnet_range_exists ${proto} ${subnet} ${range}; then | |
783 | error "DHCP subnet range ${range} already exists" | |
784 | return ${EXIT_ERROR} | |
785 | fi | |
786 | ||
ae02c40e MT |
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}" | |
791 | return ${EXIT_ERROR} | |
792 | fi | |
793 | ||
6c07160e | 794 | # Write the configuration to file. |
52f69c52 | 795 | local file=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range}) |
6c07160e MT |
796 | assert isset file |
797 | ||
e9df08ad | 798 | settings_write ${file} ${settings} |
f3ac1159 | 799 | |
52f69c52 | 800 | log INFO "DHCP subnet range ${range} created" |
f2c9ad8c | 801 | |
f3ac1159 | 802 | return ${EXIT_OK} |
6c07160e MT |
803 | } |
804 | ||
1c6a4e30 | 805 | dhcpd_subnet_range_remove() { |
1b9e7008 MT |
806 | assert [ $# -eq 3 ] |
807 | ||
808 | local proto=${1} | |
809 | local subnet=${2} | |
810 | local range=${3} | |
811 | ||
812 | if ! dhcpd_subnet_range_exists ${proto} ${subnet} ${range}; then | |
813 | error "DHCP subnet range ${range} does not exist" | |
814 | return ${EXIT_ERROR} | |
815 | fi | |
816 | ||
817 | local path=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range}) | |
6c07160e MT |
818 | assert isset path |
819 | ||
820 | rm -f ${path} | |
1b9e7008 MT |
821 | |
822 | log INFO "DHCP subnet range ${range} removed" | |
823 | return ${EXIT_OK} | |
6c07160e MT |
824 | } |
825 | ||
1c6a4e30 | 826 | dhcpd_subnet_range_list() { |
1b9e7008 | 827 | assert [ $# -eq 2 ] |
6c07160e | 828 | |
1b9e7008 | 829 | local proto=${1} |
94784eb9 | 830 | local subnet=${2} |
6c07160e | 831 | |
f3ac1159 | 832 | local path=$(dhcpd_subnet_range_path ${proto} ${subnet}) |
6c07160e MT |
833 | |
834 | local p | |
835 | for p in ${path}/${DHCPD_SUBNET_RANGE_PREFIX}*; do | |
836 | [ -r "${p}" ] || continue | |
837 | ||
838 | p=$(basename ${p}) | |
839 | print "${p:${#DHCPD_SUBNET_RANGE_PREFIX}}" | |
840 | done | |
841 | ||
842 | return ${EXIT_OK} | |
843 | } | |
844 | ||
1c6a4e30 | 845 | dhcpd_subnet_range_read() { |
f3ac1159 | 846 | assert [ $# -eq 3 ] |
6c07160e | 847 | |
f3ac1159 | 848 | local proto=${1} |
94784eb9 | 849 | local subnet=${2} |
f3ac1159 | 850 | local range=${3} |
6c07160e | 851 | |
f3ac1159 | 852 | local file=$(dhcpd_subnet_range_path ${proto} ${subnet} ${range}) |
e9df08ad | 853 | settings_read ${file} |
6c07160e MT |
854 | } |
855 | ||
1b9e7008 MT |
856 | dhcpd_subnet_range_exists() { |
857 | assert [ $# -eq 3 ] | |
858 | ||
859 | local proto=${1} | |
860 | local subnet=${2} | |
861 | local range=${3} | |
862 | ||
863 | local start=${range%-*} | |
864 | local end=${range#*-} | |
865 | ||
866 | assert isset start | |
867 | assert isset end | |
868 | ||
869 | local settings=$(dhcpd_subnet_range_settings ${proto}) | |
870 | ||
871 | local r ${settings} | |
872 | for r in $(dhcpd_subnet_range_list ${proto} ${subnet}); do | |
873 | dhcpd_subnet_range_read ${proto} ${subnet} ${r} | |
874 | ||
875 | # If start and end addresses equal we got a match | |
876 | if ${proto}_addr_eq "${START}" "${start}" && ${proto}_addr_eq "${END}" "${end}"; then | |
877 | return ${EXIT_TRUE} | |
878 | fi | |
879 | done | |
880 | ||
881 | return ${EXIT_FALSE} | |
882 | } | |
883 | ||
ae02c40e MT |
884 | dhcpd_subnet_range_overlaps() { |
885 | assert [ $# -eq 3 ] | |
886 | ||
887 | local proto=${1} | |
888 | local subnet=${2} | |
889 | local range=${3} | |
890 | ||
891 | local start=${range%-*} | |
892 | local end=${range#*-} | |
893 | ||
894 | assert isset start | |
895 | assert isset end | |
896 | ||
897 | local settings=$(dhcpd_subnet_range_settings ${proto}) | |
898 | ||
899 | local r ${settings} | |
900 | for r in $(dhcpd_subnet_range_list ${proto} ${subnet}); do | |
901 | dhcpd_subnet_range_read ${proto} ${subnet} ${r} | |
902 | ||
903 | # Check if the new range is a sub-range of any existing range | |
904 | ||
905 | # Check if the start address is somewhere in this range | |
906 | if ${proto}_addr_ge ${START} ${start} && ${proto}_addr_le ${START} ${end}; then | |
907 | print "${r}" | |
908 | return ${EXIT_TRUE} | |
909 | fi | |
910 | ||
911 | # Check if the end address is somewhere in this range | |
912 | if ${proto}_addr_ge ${END} ${start} && ${proto}_addr_le ${END} ${end}; then | |
913 | print "${r}" | |
914 | return ${EXIT_TRUE} | |
915 | fi | |
916 | ||
917 | # Check if any existing range is a sub-range of the new range | |
918 | ||
919 | # Check if the start address is somewhere in this range | |
920 | if ${proto}_addr_ge ${start} ${START} && ${proto}_addr_le ${start} ${END}; then | |
921 | print "${r}" | |
922 | return ${EXIT_TRUE} | |
923 | fi | |
924 | ||
925 | # Check if the end address is somewhere in this range | |
926 | if ${proto}_addr_ge ${end} ${START} && ${proto}_addr_le ${end} ${END}; then | |
927 | print "${r}" | |
928 | return ${EXIT_TRUE} | |
929 | fi | |
930 | done | |
931 | ||
932 | return ${EXIT_FALSE} | |
933 | } | |
934 | ||
1c6a4e30 | 935 | dhcpd_subnet_settings() { |
6c07160e MT |
936 | local proto=${1} |
937 | ||
938 | case "${proto}" in | |
939 | ipv6) | |
940 | print "${DHCPV6D_SUBNET_SETTINGS}" | |
941 | ;; | |
942 | ipv4) | |
943 | print "${DHCPV4D_SUBNET_SETTINGS}" | |
944 | ;; | |
945 | esac | |
946 | ||
947 | return ${EXIT_OK} | |
948 | } | |
949 | ||
1c6a4e30 | 950 | dhcpd_subnet_options_file() { |
6c07160e MT |
951 | local path=$(dhcpd_subnet_path $@) |
952 | assert isset path | |
953 | ||
954 | print "${path}/options" | |
955 | } | |
956 | ||
1c6a4e30 | 957 | dhcpd_subnet_options_list() { |
6c07160e | 958 | local proto=${1} |
cc02f6be | 959 | assert isset proto |
6c07160e MT |
960 | |
961 | case "${proto}" in | |
962 | ipv6) | |
963 | print "${DHCPV6D_SUBNET_OPTIONS}" | |
964 | ;; | |
965 | ipv4) | |
966 | print "${DHCPV4D_SUBNET_OPTIONS}" | |
967 | ;; | |
968 | esac | |
969 | ||
970 | return ${EXIT_OK} | |
971 | } | |
972 | ||
1c6a4e30 | 973 | dhcpd_subnet_options_read() { |
6c07160e MT |
974 | local proto=${1} |
975 | assert isset proto | |
976 | ||
94784eb9 MT |
977 | local subnet=${2} |
978 | assert isset subnet | |
6c07160e | 979 | |
94784eb9 | 980 | local options_file=$(dhcpd_subnet_options_file ${proto} ${subnet}) |
6c07160e MT |
981 | local options_list=$(dhcpd_subnet_options_list ${proto}) |
982 | ||
983 | _dhcpd_read_options ${options_file} ${options_list} | |
984 | } | |
985 | ||
986 | # Helper functions to create a DHCP configuration file. | |
1c6a4e30 | 987 | _dhcpd_write_options() { |
6c07160e MT |
988 | local proto=${1} |
989 | assert isset proto | |
990 | ||
991 | local file=${2} | |
992 | assert isset file | |
993 | ||
994 | local options_list=${3} | |
995 | assert isset options_list | |
996 | ||
997 | local ident=${4} | |
998 | ||
ea878018 MT |
999 | print "${ident}# Options" >> ${file} |
1000 | ||
6c07160e MT |
1001 | # Dump options array. |
1002 | local key val fmt | |
1003 | for key in ${!options_list}; do | |
1004 | val=${options[${key}]} | |
1005 | ||
ea878018 MT |
1006 | # Skip the rest if val is empty |
1007 | isset val || continue | |
1008 | ||
1009 | # Enable raw formatting (i.e. quote the value?) | |
1010 | local raw="false" | |
1011 | ||
1012 | # Update the formatting of some options | |
1013 | case "${key}" in | |
1014 | name-servers) | |
1015 | val="$(list_join val ", ")" | |
1016 | raw="true" | |
1017 | ;; | |
1018 | esac | |
1019 | ||
6c07160e MT |
1020 | # Prepend dhcp6 on IPv6 options. |
1021 | if [ "${proto}" = "ipv6" ]; then | |
1022 | key="dhcp6.${key}" | |
1023 | fi | |
1024 | ||
ea878018 MT |
1025 | if isinteger val; then |
1026 | fmt="option %s %d;" | |
1027 | elif enabled raw || isipaddress val; then | |
1028 | fmt="option %s %s;" | |
1029 | else | |
1030 | fmt="option %s \"%s\";" | |
6c07160e | 1031 | fi |
ea878018 MT |
1032 | |
1033 | print "${ident}${fmt}" "${key}" "${val}" | |
6c07160e MT |
1034 | done >> ${file} |
1035 | ||
ea878018 MT |
1036 | # Empty line |
1037 | print >> ${file} | |
6c07160e MT |
1038 | } |
1039 | ||
1c6a4e30 | 1040 | _dhcpd_read_options() { |
6c07160e MT |
1041 | local file=${1} |
1042 | assert isset file | |
1043 | ||
1044 | local options_list=${2} | |
1045 | assert isset options_list | |
1046 | ||
4f366759 | 1047 | settings_read_array ${file} options ${!options_list} |
6c07160e MT |
1048 | } |
1049 | ||
1c6a4e30 | 1050 | _dhcpd_write_subnet() { |
94784eb9 | 1051 | assert [ $# -eq 3 ] |
6c07160e | 1052 | |
94784eb9 MT |
1053 | local proto=${1} |
1054 | local subnet=${2} | |
6c07160e | 1055 | local file=${3} |
6c07160e MT |
1056 | |
1057 | # Check which settings we do expect. | |
1058 | local settings | |
1059 | case "${proto}" in | |
1060 | ipv6) | |
1061 | settings=${DHCPV6D_SUBNET_SETTINGS} | |
1062 | ;; | |
1063 | ipv4) | |
1064 | settings=${DHCPV4D_SUBNET_SETTINGS} | |
1065 | ;; | |
1066 | esac | |
1067 | assert isset settings | |
1068 | local ${settings} | |
1069 | ||
1070 | # Read configuration settings. | |
94784eb9 | 1071 | dhcpd_subnet_read ${proto} ${subnet} |
6c07160e | 1072 | |
94784eb9 | 1073 | print "# Subnet declaration" >> ${file} |
6c07160e MT |
1074 | case "${proto}" in |
1075 | ipv6) | |
1076 | print "subnet6 ${ADDRESS}/${PREFIX} {" >> ${file} | |
1077 | ;; | |
1078 | ipv4) | |
13a6e69f | 1079 | local netmask="$(ipv4_prefix2netmask "${PREFIX}")" |
6c07160e MT |
1080 | print "subnet ${ADDRESS} netmask ${netmask} {" >> ${file} |
1081 | ;; | |
1082 | esac | |
1083 | ||
1084 | # Add options. | |
94784eb9 | 1085 | _dhcpd_write_subnet_options ${proto} ${subnet} ${file} |
6c07160e | 1086 | |
ea878018 MT |
1087 | # Prefix Delegation for IPv6 |
1088 | if [[ "${proto}" = "ipv6" ]]; then | |
94784eb9 | 1089 | _dhcpd_write_subnet_pd "${subnet}" "${file}" |
ea878018 MT |
1090 | fi |
1091 | ||
6c07160e | 1092 | # Add the ranges. |
f3ac1159 MT |
1093 | local range |
1094 | for range in $(dhcpd_subnet_range_list ${proto} ${subnet} ${range}); do | |
1095 | _dhcpd_write_subnet_range ${proto} ${subnet} ${range} ${file} | |
6c07160e MT |
1096 | done |
1097 | ||
1098 | # End this subnet block. | |
1099 | print "}\n" >> ${file} | |
1100 | ||
1101 | return ${EXIT_OK} | |
1102 | } | |
1103 | ||
1c6a4e30 | 1104 | _dhcpd_write_subnet_options() { |
94784eb9 | 1105 | assert [ $# -eq 3 ] |
6c07160e | 1106 | |
94784eb9 MT |
1107 | local proto=${1} |
1108 | local subnet=${2} | |
6c07160e | 1109 | local file=${3} |
6c07160e MT |
1110 | |
1111 | local settings | |
94784eb9 | 1112 | local options_file="$(dhcpd_subnet_path ${proto} ${subnet})/options" |
6c07160e MT |
1113 | local options_list |
1114 | case "${proto}" in | |
1115 | ipv6) | |
1116 | settings=${DHCPV6D_SUBNET_SETTINGS} | |
1117 | options_list="DHCPV6D_OPTIONS" | |
1118 | ;; | |
1119 | ipv4) | |
1120 | settings=${DHCPV4D_SUBNET_SETTINGS} | |
1121 | options_list="DHCPV4D_OPTIONS" | |
1122 | ;; | |
1123 | esac | |
1124 | assert isset settings | |
1125 | assert isset options_list | |
1126 | ||
1127 | local ${settings} | |
94784eb9 | 1128 | dhcpd_subnet_read ${proto} ${subnet} |
6c07160e MT |
1129 | |
1130 | local -A options | |
1131 | _dhcpd_read_options ${options_file} ${options_list} | |
1132 | ||
1133 | # Fill in router, if not already set. | |
1134 | if [ -z "${options["routers"]}" ]; then | |
1135 | options["routers"]=$(_dhcpd_search_routers ${proto} "${ADDRESS}/${PREFIX}") | |
1136 | fi | |
1137 | ||
1138 | _dhcpd_write_options ${proto} ${file} ${options_list} "\t" | |
1139 | } | |
1140 | ||
ea878018 MT |
1141 | _dhcpd_write_subnet_pd() { |
1142 | # Nothing to do if prefix delegation is not enabled | |
1143 | enabled PREFIX_DELEGATION || return ${EXIT_OK} | |
1144 | ||
94784eb9 | 1145 | assert [ $# -eq 2 ] |
ea878018 | 1146 | |
94784eb9 | 1147 | local subnet="${1}" |
ea878018 | 1148 | local file="${2}" |
ea878018 MT |
1149 | |
1150 | local prefix_size="${DELEGATED_PREFIX_SIZE}" | |
1151 | isset prefix_size || prefix_size="${DHCP_DEFAULT_DELEGATED_PREFIX_SIZE}" | |
1152 | ||
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}" | |
1156 | ||
1157 | ( | |
1158 | print " # Prefix Delegation" | |
1159 | print " prefix6 ${DELEGATED_PREFIX_FIRST} ${DELEGATED_PREFIX_LAST} /${prefix_size};" | |
1160 | print "" | |
1161 | ) >> "${file}" | |
1162 | } | |
1163 | ||
1c6a4e30 | 1164 | _dhcpd_search_routers() { |
94784eb9 MT |
1165 | assert [ $# -eq 2 ] |
1166 | ||
6c07160e | 1167 | local proto=${1} |
94784eb9 | 1168 | local subnet=${2} |
6c07160e MT |
1169 | |
1170 | # Do nothing for IPv6 (yet?). | |
1171 | [ "${proto}" = "ipv6" ] && return ${EXIT_OK} | |
1172 | ||
94784eb9 | 1173 | local routers zone addr |
6c07160e | 1174 | for zone in $(zones_get_all); do |
c041b631 | 1175 | addr="$(db_get "${zone}/${proto}/local-ip-address")" |
6c07160e MT |
1176 | isset addr || continue |
1177 | ||
1178 | if ipv4_in_subnet ${addr} ${subnet}; then | |
1179 | list_append routers $(ip_split_prefix ${addr}) | |
1180 | fi | |
1181 | done | |
1182 | ||
1183 | list_join routers ", " | |
1184 | } | |
1185 | ||
1c6a4e30 | 1186 | _dhcpd_write_subnet_range() { |
94784eb9 | 1187 | assert [ $# -eq 4 ] |
6c07160e | 1188 | |
94784eb9 MT |
1189 | local proto=${1} |
1190 | local subnet=${2} | |
f3ac1159 | 1191 | local range=${3} |
6c07160e | 1192 | local file=${4} |
6c07160e MT |
1193 | |
1194 | local settings=$(dhcpd_subnet_range_settings ${proto}) | |
1195 | assert isset settings | |
1196 | ||
1197 | # Read the configuration settings. | |
1198 | local ${settings} | |
f3ac1159 | 1199 | dhcpd_subnet_range_read ${proto} ${subnet} ${range} |
6c07160e MT |
1200 | |
1201 | case "${proto}" in | |
1202 | ipv6) | |
1203 | print " range6 ${START} ${END};" >> ${file} | |
1204 | ;; | |
1205 | ipv4) | |
1206 | print " range ${START} ${END};" >> ${file} | |
1207 | ;; | |
1208 | esac | |
1209 | print >> ${file} | |
1210 | ||
1211 | return ${EXIT_OK} | |
1212 | } | |
1213 | ||
1c6a4e30 | 1214 | dhcpd_write_config() { |
94784eb9 MT |
1215 | assert [ $# -eq 1 ] |
1216 | ||
6c07160e | 1217 | local proto=${1} |
6c07160e MT |
1218 | |
1219 | local file options_list | |
1220 | case "${proto}" in | |
1221 | ipv6) | |
1222 | file=${DHCPV6D_CONFIG_FILE} | |
1223 | options_list="DHCPV6D_OPTIONS" | |
1224 | ;; | |
1225 | ipv4) | |
1226 | file=${DHCPV4D_CONFIG_FILE} | |
1227 | options_list="DHCPV4D_OPTIONS" | |
1228 | ;; | |
1229 | esac | |
1230 | assert isset file | |
1231 | assert isset options_list | |
1232 | ||
1233 | # Writing header. | |
1234 | config_header "DHCP ${proto} daemon configuration file" > ${file} | |
1235 | ||
ea878018 MT |
1236 | # Read global DHCP configuration |
1237 | dhcpd_global_settings_read "${proto}" | |
1238 | ||
6c07160e MT |
1239 | # Authoritative. |
1240 | if enabled AUTHORITATIVE; then | |
1241 | ( | |
1242 | print "# This is an authoritative DHCP server for this network." | |
1243 | print "authoritative;\n" | |
1244 | ) >> ${file} | |
1245 | else | |
1246 | ( | |
1247 | print "# This is NOT an authoritative DHCP server for this network." | |
1248 | print "not authoritative;\n" | |
1249 | ) >> ${file} | |
1250 | fi | |
1251 | ||
1252 | case "${proto}" in | |
1253 | ipv6) | |
1254 | # Lease times. | |
ea878018 | 1255 | if isinteger VALID_LIFETIME; then |
6c07160e MT |
1256 | print "default-lease-time %d;" "${VALID_LIFETIME}" >> ${file} |
1257 | fi | |
1258 | ||
1259 | if isinteger PREFERRED_LIFETIME; then | |
1260 | print "preferred-lifetime %d;" "${PREFERRED_LIFETIME}" >> ${file} | |
1261 | fi | |
1262 | ;; | |
1263 | ipv4) | |
1264 | # Lease times. | |
1265 | if isinteger DEFAULT_LEASE_TIME; then | |
1266 | print "default-lease-time %d;" "${DEFAULT_LEASE_TIME}" >> ${file} | |
1267 | fi | |
1268 | ||
1269 | if isinteger MAX_LEASE_TIME; then | |
1270 | print "max-lease-time %d;" "${MAX_LEASE_TIME}" >> ${file} | |
1271 | fi | |
1272 | ||
1273 | if isinteger MIN_LEASE_TIME; then | |
1274 | print "min-lease-time %d;" "${MIN_LEASE_TIME}" >> ${file} | |
1275 | fi | |
1276 | ;; | |
1277 | esac | |
1278 | ||
1279 | # Write the options to file. | |
1280 | local -A options | |
1281 | dhcpd_global_options_read ${proto} | |
1282 | _dhcpd_write_options ${proto} ${file} ${options_list} | |
1283 | ||
1284 | # Add all subnet declarations. | |
94784eb9 MT |
1285 | local subnet |
1286 | for subnet in $(dhcpd_subnet_list ${proto}); do | |
1287 | _dhcpd_write_subnet ${proto} ${subnet} ${file} | |
6c07160e MT |
1288 | done |
1289 | ||
1290 | return ${EXIT_OK} | |
1291 | } |