62e184b77b856eab96ce48ccab6000cf8774343d
[packages.git] / ipv6 / radvd / files / radvd.init
1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2008-2011 OpenWrt.org
3 # Copyright (C) 2008  Alina Friedrichsen <x-alina@gmx.net>
4
5 START=50
6
7 SERVICE_USE_PID=1
8
9 RADVD_INTERFACE_STRING_OPTIONS='MaxRtrAdvInterval MinRtrAdvInterval MinDelayBetweenRAs AdvLinkMTU AdvReachableTime AdvRetransTimer AdvCurHopLimit AdvDefaultLifetime AdvDefaultPreference HomeAgentLifetime HomeAgentPreference'
10 RADVD_INTERFACE_BOOLEAN_OPTIONS='IgnoreIfMissing AdvSendAdvert UnicastOnly AdvManagedFlag AdvOtherConfigFlag AdvSourceLLAddress AdvHomeAgentFlag AdvHomeAgentInfo AdvMobRtrSupportFlag AdvIntervalOpt'
11
12 RADVD_PREFIX_STRING_OPTIONS='AdvValidLifetime AdvPreferredLifetime'
13 RADVD_PREFIX_BOOLEAN_OPTIONS='AdvOnLink AdvAutonomous AdvRouterAddr DeprecatePrefix DecrementLifetimes'
14
15 RADVD_ROUTE_STRING_OPTIONS='AdvRouteLifetime AdvRoutePreference'
16 RADVD_ROUTE_BOOLEAN_OPTIONS='RemoveRoute'
17
18 RADVD_RDNSS_STRING_OPTIONS='AdvRDNSSLifetime FlushRDNSS'
19
20 RADVD_DNSSL_STRING_OPTIONS='AdvDNSSLLifetime FlushDNSSL'
21
22 validate_varname() {
23         local varname=$1
24         [ -z "$varname" -o "$varname" != "${varname%%[!A-Za-z0-9_]*}" ] && return 1
25         return 0
26 }
27
28 validate_ifname() {
29         local ifname=$1
30         [ -z "$ifname" -o "$ifname" != "${ifname%%[!A-Za-z0-9.:_-]*}" ] && return 1
31         return 0
32 }
33
34 validate_ip6addr() {
35         local ip6addr=$1
36         [ -z "$ip6addr" -o "$ip6addr" != "${ip6addr%%[!A-Fa-f0-9.:]*}" ] && return 1
37         return 0
38 }
39
40 validate_ip6prefix() {
41         local ip6prefix=$1
42         [ -z "$ip6prefix" -o "$ip6prefix" != "${ip6prefix%%[!A-Fa-f0-9./:]*}" ] && return 1
43         return 0
44 }
45
46 validate_radvd_string() {
47         local radvd_string=$1
48         [ -z "$radvd_string" -o "$radvd_string" != "${radvd_string%%[!a-z0-9.:_-]*}" ] && return 1
49         return 0
50 }
51
52 get_ifname() {
53         local interface=$1
54         validate_varname "$interface" || return 1
55         local cfgt
56         local ifname
57
58         scan_interfaces
59         config_get cfgt "$interface" TYPE
60         [ "$cfgt" != "interface" ] && return 1
61         config_get ifname "$interface" ifname
62         validate_ifname "$ifname" || return 1
63         printf '%s\n' "$ifname"
64
65         return 0
66 }
67
68 get_ip6addr() {
69         local ifname=$1
70         local scope=$2
71         local iproute2_scope
72         local ifconfig_scope
73         local ip6addr
74
75         case "$scope" in
76                 host) iproute2_scope=host ifconfig_scope=Host;;
77                 link) iproute2_scope=link ifconfig_scope=Link;;
78                 site) iproute2_scope=site ifconfig_scope=Site;;
79                 global) iproute2_scope=global ifconfig_scope=Global;;
80                 "") get_ip6addr "$ifname" global || get_ip6addr "$ifname" site; return;;
81                 *) return 1;;
82         esac
83
84         ip6addr=$(LANG=C ip -f inet6 -- addr show dev "$ifname" 2> /dev/null | sed -n -e 's/^  *inet6 \([A-Fa-f0-9.:]*[/][0-9]*\) scope '"$iproute2_scope"' $/\1/p' | head -n 1)
85         if [ -z "$ip6addr" ]; then
86                 ip6addr=$(LANG=C ifconfig "$ifname" 2> /dev/null | sed -n -e 's/^  *inet6 addr: \([A-Fa-f0-9.:]*[/][0-9]*\) Scope:'"$ifconfig_scope"'$/\1/p' | tail -n 1)
87                 [ -z "$ip6addr" ] && return 1
88         fi
89
90         printf '%s\n' "$ip6addr"
91
92         return 0
93 }
94
95 radvd_find_config_file() {
96         local cfg=$1
97         validate_varname "$cfg" || return 0
98
99         config_get_bool ignore "$cfg" ignore 0
100         [ "$ignore" -ne 0 ] && return 0
101         config_get RADVD_CONFIG_FILE "$cfg" config_file
102
103         return 0
104 }
105
106 radvd_add_interface() {
107         local cfg=$1
108         validate_varname "$cfg" || return 0
109         local ignore
110         local interfaces
111         local interface
112         local list_interface
113         local exist
114
115         config_get_bool ignore "$cfg" ignore 0
116         [ "$ignore" -ne 0 ] && return 0
117
118         config_get interfaces "$cfg" interface
119         for interface in $interfaces; do
120                 validate_varname "$interface" || continue
121                 exist=0
122                 for list_interface in $RADVD_INTERFACES; do
123                         [ "$interface" = "$list_interface" ] && exist=1
124                 done
125                 [ "$exist" -eq 0 ] && RADVD_INTERFACES="$RADVD_INTERFACES $interface"
126         done
127
128         return 0
129 }
130
131 radvd_write_interface() {
132         local cfg=$1
133         validate_varname "$cfg" || return 0
134         local ignore
135         local interfaces
136         local interface
137         local name
138         local value
139
140         config_get_bool ignore "$cfg" ignore 0
141         [ "$ignore" -ne 0 ] && return 0
142
143         config_get interfaces "$cfg" interface
144         exist=0
145         for interface in $interfaces; do
146                 [ "$INTERFACE" = "$interface" ] && exist=1
147         done
148         [ "$exist" -eq 0 ] && return 0
149
150         for name in $RADVD_INTERFACE_STRING_OPTIONS; do
151                 config_get value "$cfg" "$name"
152                 validate_radvd_string "$value" || continue
153                 printf '\t%s %s;\n' "$name" "$value"
154         done
155
156         for name in $RADVD_INTERFACE_BOOLEAN_OPTIONS; do
157                 config_get value "$cfg" "$name"
158                 [ -z "$value" ] && continue
159                 config_get_bool value "$cfg" "$name" 0
160                 if [ "$value" -ne 0 ]; then 
161                         printf '\t%s on;\n' "$name"
162                 else
163                         printf '\t%s off;\n' "$name"
164                 fi
165         done
166
167         config_get clients "$cfg" client
168         if [ -n "$clients" ]; then
169                 printf '\n\tclients\n\t{\n'
170
171                 for client in $clients; do
172                         validate_ip6addr "$client" || continue
173                         printf '\t\t%s;\n' "$client"
174                 done
175
176                 printf '\t};\n'
177         fi
178
179         return 0
180 }
181
182 radvd_write_prefix() {
183         local cfg=$1
184         validate_varname "$cfg" || return 0
185         local ignore
186         local interfaces
187         local interface
188         local prefixes
189         local prefix
190         local name
191         local value
192         local cfgt
193
194         config_get_bool ignore "$cfg" ignore 0
195         [ "$ignore" -ne 0 ] && return 0
196
197         config_get interfaces "$cfg" interface
198         exist=0
199         for interface in $interfaces; do
200                 [ "$INTERFACE" = "$interface" ] && exist=1
201         done
202         [ "$exist" -eq 0 ] && return 0
203
204         config_get prefixes "$cfg" prefix
205         if [ -z "$prefixes" ]; then
206                 prefixes=$(get_ip6addr "$IFNAME") || return 0
207         fi
208
209         for prefix in $prefixes; do
210                 validate_ip6prefix "$prefix" || continue
211                 printf '\n\tprefix %s\n\t{\n' "$prefix"
212
213                 for name in $RADVD_PREFIX_STRING_OPTIONS; do
214                         config_get value "$cfg" "$name"
215                         validate_radvd_string "$value" || continue
216                         printf '\t\t%s %s;\n' "$name" "$value"
217                 done
218
219                 for name in $RADVD_PREFIX_BOOLEAN_OPTIONS; do
220                         config_get value "$cfg" "$name"
221                         [ -z "$value" ] && continue
222                         config_get_bool value "$cfg" "$name" 0
223                         if [ "$value" -ne 0 ]; then 
224                                 printf '\t\t%s on;\n' "$name"
225                         else
226                                 printf '\t\t%s off;\n' "$name"
227                         fi
228                 done
229
230                 config_get value "$cfg" Base6Interface
231                 if [ -n "$value" ]; then
232                         if ifname=$(get_ifname "$value"); then
233                                 printf '\t\t%s %s;\n' "Base6Interface" "$ifname"
234                         fi
235                 fi
236
237                 config_get value "$cfg" Base6to4Interface
238                 if [ -n "$value" ]; then
239                         if ifname=$(get_ifname "$value"); then
240                                 printf '\t\t%s %s;\n' "Base6to4Interface" "$ifname"
241                         fi
242                 fi
243
244                 printf '\t};\n'
245         done
246
247         return 0
248 }
249
250 radvd_write_route() {
251         local cfg=$1
252         validate_varname "$cfg" || return 0
253         local ignore
254         local interfaces
255         local interface
256         local prefixes
257         local prefix
258         local name
259         local value
260
261         config_get_bool ignore "$cfg" ignore 0
262         [ "$ignore" -ne 0 ] && return 0
263
264         config_get interfaces "$cfg" interface
265         exist=0
266         for interface in $interfaces; do
267                 [ "$INTERFACE" = "$interface" ] && exist=1
268         done
269         [ "$exist" -eq 0 ] && return 0
270
271         config_get prefixes "$cfg" prefix
272         for prefix in $prefixes; do
273                 validate_ip6prefix "$prefix" || continue
274                 printf '\n\troute %s\n\t{\n' "$prefix"
275
276                 for name in $RADVD_ROUTE_STRING_OPTIONS; do
277                         config_get value "$cfg" "$name"
278                         validate_radvd_string "$value" || continue
279                         printf '\t\t%s %s;\n' "$name" "$value"
280                 done
281
282                 for name in $RADVD_ROUTE_BOOLEAN_OPTIONS; do
283                         config_get value "$cfg" "$name"
284                         [ -z "$value" ] && continue
285                         config_get_bool value "$cfg" "$name" 0
286                         if [ "$value" -ne 0 ]; then 
287                                 printf '\t\t%s on;\n' "$name"
288                         else
289                                 printf '\t\t%s off;\n' "$name"
290                         fi
291                 done
292
293                 printf '\t};\n'
294         done
295
296         return 0
297 }
298
299 radvd_write_rdnss() {
300         local cfg=$1
301         validate_varname "$cfg" || return 0
302         local ignore
303         local interfaces
304         local interface
305         local addrs
306         local addr
307         local addr_list
308         local name
309         local value
310         local i
311
312         config_get_bool ignore "$cfg" ignore 0
313         [ "$ignore" -ne 0 ] && return 0
314
315         config_get interfaces "$cfg" interface
316         exist=0
317         for interface in $interfaces; do
318                 [ "$INTERFACE" = "$interface" ] && exist=1
319         done
320         [ "$exist" -eq 0 ] && return 0
321
322         config_get addrs "$cfg" addr
323         i=0
324         for addr in $addrs; do
325                 [ "$i" -ge 3 ] && break
326                 validate_ip6addr "$addr" || continue
327                 addr_list="$addr_list $addr"
328                 i=$(($i+1))
329         done
330
331         if [ -z "$addr_list" ]; then
332                 addr=$(get_ip6addr "$IFNAME" link) || return 0
333                 addr_list=" ${addr%%[/]*}"
334         fi
335
336         printf '\n\tRDNSS%s\n\t{\n' "$addr_list"
337
338         for name in $RADVD_RDNSS_STRING_OPTIONS; do
339                 config_get value "$cfg" "$name"
340                 validate_radvd_string "$value" || continue
341                 printf '\t\t%s %s;\n' "$name" "$value"
342         done
343
344         printf '\t};\n'
345
346         return 0
347 }
348
349 radvd_write_dnssl() {
350         local cfg=$1
351         validate_varname "$cfg" || return 0
352         local ignore
353         local interfaces
354         local interface
355         local suffixes
356         local suffix
357         local suffix_list
358         local name
359         local value
360
361         config_get_bool ignore "$cfg" ignore 0
362         [ "$ignore" -ne 0 ] && return 0
363
364         config_get interfaces "$cfg" interface
365         exist=0
366         for interface in $interfaces; do
367                 [ "$INTERFACE" = "$interface" ] && exist=1
368         done
369         [ "$exist" -eq 0 ] && return 0
370
371         config_get suffixes "$cfg" suffix
372         for suffix in $suffixes; do
373                 validate_radvd_string "$suffix" || continue
374                 suffix_list="$suffix_list $suffix"
375         done
376
377         printf '\n\tDNSSL%s\n\t{\n' "$suffix_list"
378
379         for name in $RADVD_DNSSL_STRING_OPTIONS; do
380                 config_get value "$cfg" "$name"
381                 validate_radvd_string "$value" || continue
382                 printf '\t\t%s %s;\n' "$name" "$value"
383         done
384
385         printf '\t};\n'
386
387         return 0
388 }
389
390 radvd_write_config() {
391         include /lib/network
392
393         RADVD_INTERFACES=
394         config_foreach radvd_add_interface interface
395         config_foreach radvd_add_interface prefix
396         config_foreach radvd_add_interface route
397         config_foreach radvd_add_interface RDNSS
398         config_foreach radvd_add_interface DNSSL
399
400         for INTERFACE in $RADVD_INTERFACES; do
401                 IFNAME=$(get_ifname "$INTERFACE") || continue
402                 printf 'interface %s\n{\n' "$IFNAME"
403                 config_foreach radvd_write_interface interface
404                 config_foreach radvd_write_prefix prefix
405                 config_foreach radvd_write_route route
406                 config_foreach radvd_write_rdnss rdnss
407                 config_foreach radvd_write_dnssl dnssl
408                 printf '};\n\n'
409         done
410
411         return 0
412 }
413
414 start() {
415         config_load radvd
416
417         RADVD_CONFIG_FILE=
418         config_foreach radvd_find_config_file radvd
419
420         if [ -z "$RADVD_CONFIG_FILE" ]; then
421                 mkdir -p -- /var/etc/
422                 radvd_write_config > /var/etc/radvd.conf
423                 if [ -s "/var/etc/radvd.conf" ]; then
424                         RADVD_CONFIG_FILE=/var/etc/radvd.conf
425                 fi
426         fi
427
428         [ -z "$RADVD_CONFIG_FILE" ] && return 1
429
430         sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null 2> /dev/null
431
432         service_start /usr/sbin/radvd -C "$RADVD_CONFIG_FILE" -m stderr_syslog -p /var/run/radvd.pid
433 }
434
435 stop() {
436         service_stop /usr/sbin/radvd
437 }