Merge pull request #17303 from CarlosDerSeher/feature_bt_agent
[feed/packages.git] / net / isc-dhcp / files / dhcpd.init
1 #!/bin/sh /etc/rc.common
2
3 START=25
4 USE_PROCD=1
5 PROG=/usr/sbin/dhcpd
6
7 TTL=3600
8 PREFIX="update add"
9
10 lease_file=/tmp/dhcpd.leases
11 config_file=/tmp/run/dhcpd.conf
12
13 dyndir=/tmp/bind
14 conf_local_file=$dyndir/named.conf.local
15
16 session_key_name=local-ddns
17 session_key_file=/var/run/named/session.key
18
19 time2seconds() {
20 local timestring=$1
21 local multiplier number suffix
22
23 suffix="${timestring//[0-9 ]}"
24 number="${timestring%%$suffix}"
25 [ "$number$suffix" != "$timestring" ] && return 1
26 case "$suffix" in
27 "" | s)
28 multiplier=1
29 ;;
30 m)
31 multiplier=60
32 ;;
33 h)
34 multiplier=3600
35 ;;
36 d)
37 multiplier=86400
38 ;;
39 w)
40 multiplier=604800
41 ;;
42 *)
43 return 1
44 ;;
45 esac
46 echo $(( number * multiplier ))
47 }
48
49 trim() {
50 local arg="$1"
51
52 echo "$arg" | sed -e 's/^ *//' -e 's/ *$//'
53 }
54
55 rfc1918_prefix() {
56 local octets="$(echo "${1%%/*}" | cut -d. -f1)"
57
58 [ "$octets" = "10" ] && { echo "$octets"; return; }
59
60 octets="$(echo "${1%%/*}" | cut -d. -f1-2)"
61
62 case "$octets" in
63 172.1[6789]|172.2[0-9]|172.3[01]|192.168)
64 echo "$octets"
65 ;;
66 esac
67 }
68
69 no_ipv6() {
70 [ -n "$(named-checkconf -px \
71 | sed -r -ne '1N; N; /^\tlisten-on-v6 ?\{\n\t\t"none";\n\t\};$/{ p; q; }; D')" ]
72 }
73
74 # duplicated from dnsmasq init script
75 hex_to_hostid() {
76 local var="$1"
77 local hex="${2#0x}" # strip optional "0x" prefix
78
79 if [ -n "${hex//[0-9a-fA-F]/}" ]; then
80 # is invalid hex literal
81 return 1
82 fi
83
84 # convert into host id
85 export "$var=$(
86 printf "%0x:%0x" \
87 $(((0x$hex >> 16) % 65536)) \
88 $(( 0x$hex % 65536))
89 )"
90
91 return 0
92 }
93
94 typeof() {
95 echo "$1" | awk '
96 /^\d+\.\d+\.\d+\.\d+$/ { print "ip\n"; next; }
97 /^(true|false)$/ { print "bool\n"; next; }
98 /^\d+$/ { print "integer\n"; next; }
99 /^"[^"]*"$/ { print "string\n"; next; }
100 /^[0-9a-fA-F]{2,2}(:[0-9a-fA-F]{2,2})*$/ { print "string\n"; next; }
101 { print "other\n"; next; }
102 '
103 }
104
105 update() {
106 local lhs="$1" family="$2" type="$3"
107 shift 3
108
109 [ $dynamicdns -eq 1 ] && \
110 echo -e "$PREFIX" "$lhs $family $type $@\nsend" >> $dyn_file
111 }
112
113 explode() {
114 local arg="$1"
115
116 echo "$arg" | sed -e 's/\./, /g'
117 }
118
119 rev_str() {
120 local str="$1" delim="$2"
121 local frag result="" IFS="$delim"
122
123 for frag in $str; do
124 result="$frag${result:+$delim}$result"
125 done
126
127 echo "$result"
128 }
129
130 create_empty_zone() {
131 local zone="$1"
132
133 if [ ! -f $dyndir/db."$zone" ]; then
134 cp -p /etc/bind/db.empty $dyndir/db."$zone"
135 chmod g+w $dyndir/db."$zone"
136 chgrp bind $dyndir/db."$zone"
137 fi
138 }
139
140 append_routes() {
141 local tuple tuples="$1"
142 local string=
143
144 local IFS=','
145 for tuple in $tuples; do
146 local network prefix router save octets compacted
147
148 tuple="$(trim "$tuple")"
149
150 save="${tuple% *}"
151 router="$(trim "${tuple#${save} }")"
152
153 network="$(trim "${save%/[0-9]*}")"
154
155 prefix="$(trim "${save##${network}/}")"
156
157 octets=$((($prefix + 7) / 8))
158 compacted="$(echo "$network" | cut -d. -f1-$octets)"
159
160 string="${string:+, }$(explode "$prefix.$compacted.$router")"
161 done
162
163 echo " option classless-ipv4-route $string;"
164 }
165
166 append_dhcp_options() {
167 local tuple="$1"
168
169 # strip redundant "option:" prefix
170 tuple="${tuple#option:}"
171
172 local tag="${tuple%%,*}"
173 local values="${tuple#$tag,}"
174
175 local formatted value
176 local IFS=$', \n'
177 for value in $values; do
178 # detect type of $value and quote if necessary
179 case $(typeof "$value") in
180 ip|bool|integer|string)
181 ;;
182 other)
183 value="\"$value\""
184 ;;
185 esac
186 formatted="$formatted${formatted:+, }$value"
187 done
188 echo " option $tag $formatted;"
189 }
190
191 static_cname_add() {
192 local cfg="$1"
193 local cname target
194
195 config_get cname "$cfg" "cname"
196 [ -n "$cname" ] || return 0
197 config_get target "$cfg" "target"
198 [ -n "$target" ] || return 0
199
200 update "$cname.$domain." IN CNAME "$target.$domain."
201 }
202
203 static_cnames() {
204 config_foreach static_cname_add cname "$@"
205 }
206
207 static_domain_add() {
208 local cfg="$1"
209 local name ip ips revip
210
211 config_get name "$cfg" "name"
212 [ -n "$name" ] || return 0
213 config_get ip "$cfg" "ip"
214 [ -n "$ip" ] || return 0
215
216 ips="$ip"
217 for ip in $ips; do
218 revip="$(rev_str "$ip" ".")"
219
220 update "$name.$domain." IN A "$ip"
221 [ -n "$(rfc1918_prefix "$ip")" ] && \
222 update "$revip.in-addr.arpa." IN PTR "$name.$domain."
223 done
224 }
225
226 static_domains() {
227 config_foreach static_domain_add domain "$@"
228 }
229
230 static_mxhost_add() {
231 local cfg="$1"
232 local domain2 relay pref
233
234 config_get domain2 "$cfg" "domain"
235 [ -n "$domain2" ] || return 0
236 config_get relay "$cfg" "relay"
237 [ -n "$relay" ] || return 0
238 config_get pref "$cfg" "pref"
239 [ -n "$pref" ] || return 0
240
241 if [ "$domain2" = "@" ]; then
242 update "$domain." IN MX "$pref" "$relay.$domain."
243 else
244 update "$domain2.$domain." IN MX "$pref" "$relay.$domain."
245 fi
246 }
247
248 static_mxhosts() {
249 config_foreach static_mxhost_add mxhost "$@"
250 }
251
252 static_srvhost_add() {
253 local cfg="$1"
254 local srv target port priority weight
255
256 config_get srv "$cfg" "srv"
257 [ -n "$srv" ] || return 0
258 config_get target "$cfg" "target"
259 [ -n "$target" ] || return 0
260 config_get port "$cfg" "port"
261 [ -n "$port" ] || return 0
262 config_get priority "$cfg" "priority"
263 [ -n "$priority" ] || return 0
264 config_get weight "$cfg" "weight"
265 [ -n "$weight" ] || return 0
266
267 update "$srv.$domain." IN SRV "$priority" "$weight" "$port" "$target.$domain"
268 }
269
270 static_srvhosts() {
271 config_foreach static_srvhost_add srvhost "$@"
272 }
273
274 static_host_add() {
275 local cfg="$1"
276 local broadcast hostid macn macs mac name ip ips revip leasetime
277
278 config_get macs "$cfg" "mac"
279 [ -n "$macs" ] || return 0
280 config_get name "$cfg" "name"
281 [ -n "$name" ] || return 0
282 config_get ip "$cfg" "ip"
283 [ -n "$ip" ] || return 0
284
285 config_get_bool broadcast "$cfg" "broadcast" 0
286 config_get dns "$cfg" "dns"
287 config_get gateway "$cfg" "gateway"
288 config_get leasetime "$cfg" "leasetime"
289 if [ -n "$leasetime" ] ; then
290 leasetime="$(time2seconds "$leasetime")"
291 [ "$?" -ne 0 ] && return 1
292 fi
293
294 config_get hostid "$cfg" "hostid"
295 if [ -n "$hostid" ] ; then
296 hex_to_hostid hostid "$hostid" || return 1
297 fi
298
299 macn=0
300 for mac in $macs; do
301 macn=$(( macn + 1 ))
302 done
303
304 for mac in $macs; do
305 local secname="$name"
306 if [ $macn -gt 1 ] ; then
307 secname="${name}-${mac//:}"
308 fi
309 echo "host $secname {"
310 echo " hardware ethernet $mac;"
311 echo " fixed-address $ip;"
312 echo " option host-name \"$name\";"
313 if [ "$broadcast" -eq 1 ] ; then
314 echo " always-broadcast true;"
315 fi
316 if [ -n "$leasetime" ] ; then
317 echo " default-lease-time $leasetime;"
318 echo " max-lease-time $leasetime;"
319 fi
320 if [ -n "$hostid" ] ; then
321 echo " option dhcp-client-identifier $hostid;"
322 fi
323 if [ -n "$dns" ] ; then
324 echo " option domain-name-servers $dns;"
325 fi
326 if [ -n "$gateway" ] ; then
327 echo " option routers $gateway;"
328 fi
329 config_list_foreach "$cfg" "routes" append_routes
330 config_list_foreach "$cfg" "dhcp_option" append_dhcp_options
331 echo "}"
332 done
333
334 ips="$ip"
335 for ip in $ips; do
336 revip="$(rev_str "$ip" ".")"
337
338 update "$name.$domain." IN A "$ip"
339 update "$revip.in-addr.arpa." IN PTR "$name.$domain."
340 done
341 }
342
343 static_hosts() {
344 config_foreach static_host_add host "$@"
345 }
346
347 gen_dhcp_subnet() {
348 local cfg="$1"
349
350 echo "subnet $NETWORK netmask $NETMASK {"
351 echo " range $START $END;"
352 echo " option subnet-mask $netmask;"
353 if [ "$BROADCAST" != "0.0.0.0" ] ; then
354 echo " option broadcast-address $BROADCAST;"
355 fi
356 if [ "$dynamicdhcp" -eq 0 ] ; then
357 if [ "$authoritative" -eq 1 ] ; then
358 echo " deny unknown-clients;"
359 else
360 echo " ignore unknown-clients;"
361 fi
362 fi
363 if [ -n "$leasetime" ] ; then
364 echo " default-lease-time $leasetime;"
365 echo " max-lease-time $leasetime;"
366 fi
367 echo " option routers $gateway;"
368 echo " option domain-name-servers $DNS;"
369 config_list_foreach "$cfg" "routes" append_routes
370 config_list_foreach "$cfg" "dhcp_option" append_dhcp_options
371 echo "}"
372 }
373
374 dhcpd_add() {
375 local cfg="$1" synthesize="$2"
376 local dhcp6range="::"
377 local dynamicdhcp end gateway ifname ignore leasetime limit net netmask
378 local proto networkid start subnet
379 local IP NETMASK BROADCAST NETWORK PREFIX DNS START END
380
381 config_get_bool ignore "$cfg" "ignore" 0
382 [ "$ignore" = "0" ] || return 0
383
384 config_get net "$cfg" "interface"
385 [ -n "$net" ] || return 0
386
387 config_get start "$cfg" "start"
388 [ -n "$start" ] || return 0
389
390 config_get limit "$cfg" "limit"
391 [ -n "$limit" ] || return 0
392
393 network_get_subnet subnet "$net" || return 0
394 network_get_device ifname "$net" || return 0
395 network_get_protocol proto "$net" || return 0
396
397 [ static = "$proto" ] || return 0
398
399 local octets="$(rfc1918_prefix "$subnet")"
400
401 [ -n "$octets" ] && rfc1918_nets="$rfc1918_nets${rfc1918_nets:+ }$octets"
402
403 [ $synthesize -eq 0 ] && return
404
405 config_get_bool dynamicdhcp "$cfg" "dynamicdhcp" 1
406
407 dhcp_ifs="$dhcp_ifs $ifname"
408
409 eval "$(ipcalc.sh $subnet $start $limit)"
410
411 config_get netmask "$cfg" "netmask" "$NETMASK"
412 config_get leasetime "$cfg" "leasetime"
413 if [ -n "$leasetime" ] ; then
414 leasetime="$(time2seconds "$leasetime")"
415 [ "$?" -ne 0 ] && return 1
416 fi
417
418 if network_get_dnsserver dnsserver "$net" ; then
419 for dnsserv in $dnsserver ; do
420 DNS="$DNS${DNS:+, }$dnsserv"
421 done
422 else
423 DNS="$IP"
424 fi
425
426 if ! network_get_gateway gateway "$net" ; then
427 gateway="$IP"
428 fi
429
430 gen_dhcp_subnet "$cfg"
431 }
432
433 general_config() {
434 local always_broadcast boot_unknown_clients log_facility
435 local default_lease_time max_lease_time
436
437 config_get_bool always_broadcast "isc_dhcpd" "always_broadcast" 0
438 config_get_bool authoritative "isc_dhcpd" "authoritative" 1
439 config_get_bool boot_unknown_clients "isc_dhcpd" "boot_unknown_clients" 1
440 config_get default_lease_time "isc_dhcpd" "default_lease_time" 3600
441 config_get max_lease_time "isc_dhcpd" "max_lease_time" 86400
442 config_get log_facility "isc_dhcpd" "log_facility"
443
444 config_get domain "isc_dhcpd" "domain"
445 config_get_bool dynamicdns "isc_dhcpd" dynamicdns 0
446
447 [ $always_broadcast -eq 1 ] && echo "always-broadcast true;"
448 [ $authoritative -eq 1 ] && echo "authoritative;"
449 [ $boot_unknown_clients -eq 0 ] && echo "boot-unknown-clients false;"
450
451 default_lease_time="$(time2seconds "$default_lease_time")"
452 [ "$?" -ne 0 ] && return 1
453 max_lease_time="$(time2seconds "$max_lease_time")"
454 [ "$?" -ne 0 ] && return 1
455
456 if [ $dynamicdns -eq 1 ]; then
457 create_empty_zone "$domain"
458
459 local mynet
460
461 for mynet in $rfc1918_nets; do
462 mynet="$(rev_str "$mynet" ".")"
463 create_empty_zone "$mynet.in-addr.arpa"
464 done
465
466 cat <<EOF > $conf_local_file
467 zone "$domain" {
468 type master;
469 file "$dyndir/db.$domain";
470 allow-update { key $session_key_name; };
471 allow-transfer { key $session_key_name; };
472 };
473
474 EOF
475
476 for mynet in $rfc1918_nets; do
477 mynet="$(rev_str "$mynet" ".")"
478 cat <<EOF >> $conf_local_file
479 zone "$mynet.in-addr.arpa" {
480 type master;
481 file "$dyndir/db.$mynet.in-addr.arpa";
482 allow-update { key $session_key_name; };
483 allow-transfer { key $session_key_name; };
484 };
485
486 EOF
487 done
488
489 /etc/init.d/named reload
490 sleep 1
491
492 cat <<EOF
493 ddns-domainname "$domain.";
494 ddns-update-style standard;
495 ddns-updates on;
496 ignore client-updates;
497
498 update-static-leases on;
499 use-host-decl-names on;
500 update-conflict-detection off;
501 update-optimization off;
502
503 include "$session_key_file";
504
505 zone $domain. {
506 primary 127.0.0.1;
507 key local-ddns;
508 }
509
510 EOF
511
512 for mynet in $rfc1918_nets; do
513 mynet="$(rev_str "$mynet" ".")"
514 cat <<EOF
515 zone $mynet.in-addr.arpa. {
516 primary 127.0.0.1;
517 key local-ddns;
518 }
519
520 EOF
521 done
522 fi
523
524 if [ -n "$log_facility" ] ; then
525 echo "log-facility $log_facility;"
526 fi
527 echo "default-lease-time $default_lease_time;"
528 echo "max-lease-time $max_lease_time;"
529
530 [ -n "$domain" ] && echo "option domain-name \"$domain\";"
531
532 echo -e "\n# additional codes\noption classless-ipv4-route code 121 = array of { unsigned integer 8 };\n"
533
534 rm -f /tmp/resolv.conf
535 echo "# This file is generated by the DHCPD service" > /tmp/resolv.conf
536 [ -n "$domain" ] && echo "domain $domain" >> /tmp/resolv.conf
537 echo "nameserver 127.0.0.1" >> /tmp/resolv.conf
538 }
539
540 # base procd hooks
541
542 boot() {
543 DHCPD_BOOT=1
544 start "$@"
545 }
546
547 start_service() {
548 local domain dhcp_ifs authoritative dynamicdns
549
550 if [ -n "$DHCPD_BOOT" ] ; then
551 return 0
552 fi
553
554 if [ ! -e $lease_file ] ; then
555 touch $lease_file
556 fi
557
558 if [ -e "/etc/dhcpd.conf" ] ; then
559 config_file="/etc/dhcpd.conf"
560 else
561 . /lib/functions/network.sh
562
563 local dyn_file=$(mktemp -u /tmp/dhcpd.XXXXXX)
564
565 config_load dhcp
566
567 local rfc1918_nets=""
568
569 # alas we have to make 2 passes...
570 config_foreach dhcpd_add dhcp 0
571
572 rfc1918_nets="$(echo "$rfc1918_nets" | tr ' ' $'\n' | sort | uniq | tr $'\n' ' ')"
573
574 general_config > $config_file
575
576 if [ $dynamicdns -eq 1 ]; then
577 cat <<EOF > $dyn_file
578 ; Generated by /etc/init.d/dhcpd at $(date)
579
580 ttl $TTL
581
582 EOF
583 fi
584
585 rfc1918_nets=
586
587 config_foreach dhcpd_add dhcp 1 >> $config_file
588
589 static_hosts >> $config_file
590
591 static_cnames >> $config_file
592
593 static_domains >> $config_file
594
595 static_mxhosts >> $config_file
596
597 static_srvhosts >> $config_file
598
599 if [ $dynamicdns -eq 1 ]; then
600 local args=
601
602 no_ipv6 && args="-4"
603
604 nsupdate -l -v $args $dyn_file
605
606 fi
607
608 rm -f $dyn_file
609
610 [ -z "$dhcp_ifs" ] && return 0
611 fi
612
613 procd_open_instance
614 procd_set_param command $PROG -q -f -cf $config_file -lf $lease_file $dhcp_ifs
615 procd_close_instance
616 }
617
618 reload_service() {
619 rc_procd start_service "$@"
620 procd_send_signal dhcpd "$@"
621 }
622
623 add_interface_trigger() {
624 local cfg=$1
625 local trigger ignore
626
627 config_get trigger "$cfg" interface
628 config_get_bool ignore "$cfg" ignore 0
629
630 if [ -n "$trigger" -a $ignore -eq 0 ] ; then
631 procd_add_reload_interface_trigger "$trigger"
632 fi
633 }
634
635 service_triggers() {
636 if [ -n "$DHCPD_BOOT" ] ; then
637 # Make the first start robust to slow interfaces; wait a while
638 procd_add_raw_trigger "interface.*.up" 5000 /etc/init.d/dhcpd restart
639
640 else
641 # reload with normal parameters
642 procd_add_reload_trigger "network" "dhcp"
643 config_load dhcp
644 config_foreach add_interface_trigger dhcp
645 fi
646 }
647