]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.ipv6
Fix creating new configs
[people/stevee/network.git] / src / functions / functions.ipv6
CommitLineData
4231f419
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2010 Michael Tremer & Christian Schmidt #
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
e617226b
MT
22IP_SUPPORTED_PROTOCOLS="${IP_SUPPORTED_PROTOCOLS} ipv6"
23
1c6a4e30 24ipv6_device_autoconf_enable() {
9f742d49
MT
25 local device="${1}"
26 assert device_exists "${device}"
4231f419 27
9f742d49
MT
28 sysctl_set "net.ipv6.conf.${device}.accept_ra" 1
29 sysctl_set "net.ipv6.conf.${device}.autoconf" 1
a4cd1796
MT
30
31 log INFO "Enabled IPv6 auto-configuration on '${device}'"
32
33 # Disable IPv6 forwarding which cannot be used when the
34 # device is using IPv6 auto-configuration.
35 ipv6_device_forwarding_disable "${device}"
4231f419
MT
36}
37
1c6a4e30 38ipv6_device_autoconf_disable() {
9f742d49
MT
39 local device="${1}"
40 assert device_exists "${device}"
58fb41ee 41
9f742d49
MT
42 sysctl_set "net.ipv6.conf.${device}.accept_ra" 0
43 sysctl_set "net.ipv6.conf.${device}.autoconf" 0
a4cd1796
MT
44
45 log INFO "Disabled IPv6 auto-configuration on '${device}'"
46
47 # Enable IPv6 forwarding again
48 ipv6_device_forwarding_enable "${device}"
49
50 # Automatically disable privacy extensions
51 ipv6_device_privacy_extensions_disable "${device}"
52}
53
1c6a4e30 54ipv6_device_forwarding_enable() {
a4cd1796 55 local device="${1}"
2024ccca
MT
56 shift
57
58 local accept_ra=0
59
60 local arg
61 while read arg; do
62 case "${arg}" in
63 --accept-ra)
64 accept_ra=2
65 ;;
66 esac
2212045f 67 done <<< "$(args "$@")"
a4cd1796
MT
68
69 sysctl_set "net.ipv6.conf.${device}.forwarding" 1
70
71 log INFO "Enabled IPv6 forwarding on '${device}'"
2024ccca
MT
72
73 # If forwarding is enabled, the kernel won't process
74 # any router advertisements any more, which is not good
75 # when we still want a default route when running in
76 # DHCP client mode on an uplink zone.
77 if [ ${accept_ra} -gt 0 ]; then
78 log INFO " and accepting router advertisements"
79
80 sysctl_set "net.ipv6.conf.${device}.accept_ra" 2
81 fi
a4cd1796
MT
82}
83
1c6a4e30 84ipv6_device_forwarding_disable() {
a4cd1796
MT
85 local device="${1}"
86
87 sysctl_set "net.ipv6.conf.${device}.forwarding" 0
88
89 log INFO "Disabled IPv6 forwarding on '${device}'"
58fb41ee
MT
90}
91
92# Enable IPv6 RFC3041 privacy extensions if desired
1c6a4e30 93ipv6_device_privacy_extensions_enable() {
9f742d49
MT
94 local device="${1}"
95 assert device_exists "${device}"
58fb41ee 96
9f742d49 97 sysctl_set "net.ipv6.conf.${device}.use_tempaddr" 2
58fb41ee
MT
98}
99
1c6a4e30 100ipv6_device_privacy_extensions_disable() {
9f742d49
MT
101 local device="${1}"
102 assert device_exists "${device}"
58fb41ee 103
9f742d49 104 sysctl_set "net.ipv6.conf.${device}.use_tempaddr" 0
4231f419
MT
105}
106
1c6a4e30 107ipv6_is_valid() {
b2cb6736
JS
108 local address=${1}
109
110 local prefix=$(ip_get_prefix ${address})
111 address=$(ip_split_prefix ${address})
112
113 # If prefix is set, we check if it is correct
114 if isset prefix; then
115 # Must be numeric
116 isinteger prefix || return ${EXIT_FALSE}
117
118 # Must be 128 if present
119 [ ${prefix} -eq 128 ] || return ${EXIT_FALSE}
120 fi
121
122 inetcalc -6 -c ${address} && return ${EXIT_TRUE} || return ${EXIT_FALSE}
13a6e69f
MT
123}
124
125ipv6_net_is_valid() {
126 local net="${1}"
127
128 local prefix="$(ip_get_prefix "${net}")"
129 local addr="$(ip_split_prefix "${net}")"
130
131 ipv6_prefix_is_valid "${prefix}" && ipv6_is_valid "${addr}"
4231f419
MT
132}
133
1c6a4e30 134ipv6_prefix_is_valid() {
cb965348 135 local prefix=${1}
0da7539d
JS
136
137 # Check if prefix is a number
138 isinteger prefix || return ${EXIT_FALSE}
cb965348
MT
139
140 [ ${prefix} -le 0 ] && return ${EXIT_FALSE}
141 [ ${prefix} -gt 128 ] && return ${EXIT_FALSE}
142
143 return ${EXIT_TRUE}
144}
145
ea878018
MT
146ipv6_prefix_size_is_valid_for_delegation() {
147 local prefix_size="${1}"
148 assert isinteger prefix_size
149
150 # For prefix delegation, the prefix must be between /48 and /64
151 # (RFC3769, section 3.1)
152 [[ ${prefix_size} -lt 48 ]] && return ${EXIT_FALSE}
153 [[ ${prefix_size} -gt 64 ]] && return ${EXIT_FALSE}
154
155 return ${EXIT_TRUE}
156}
157
1c6a4e30 158ipv6_get_prefix() {
9390b61b
SS
159 ip_get_prefix "$@"
160}
161
1c6a4e30 162ipv6_split_prefix() {
9390b61b
SS
163 ip_split_prefix "$@"
164}
165
1c6a4e30 166ipv6_address_add() {
83d72e63
MT
167 local address="${1}"
168 assert isset address
169
170 local device="${2}"
171 assert device_exists "${device}"
172 shift 2
173
174 local scope="global"
175 local preferred_lft valid_lft
176
177 # Enable to wait until DAD has finished and return
178 # an error if it has failed
179 local wait_for_dad="true"
180
181 local arg
182 while read arg; do
183 case "${arg}" in
184 --preferred-lifetime=*)
185 preferred_lft="$(cli_get_val "${arg}")"
186 ;;
187 --valid-lifetime=*)
188 valid_lft="$(cli_get_val "${arg}")"
189 ;;
190 --no-wait-for-dad)
191 wait_for_dad="false"
192 ;;
193 esac
2212045f 194 done <<< "$(args "$@")"
83d72e63
MT
195
196 local cmd="ip addr add ${address} dev ${device} scope ${scope}"
197
198 # Preferred lifetime
199 if isinteger preferred_lft; then
200 list_append cmd "preferred_lft ${preferred_lft}"
201 fi
202
203 # Valid lifetime
204 if isinteger valid_lft; then
205 list_append cmd "valid_lft ${valid_lft}"
206 fi
207
208 cmd_quiet "${cmd}" || return ${EXIT_ERROR}
209
210 if enabled wait_for_dad; then
211 log DEBUG "Waiting for DAD to complete..."
212
213 ipv6_wait_for_dad "${address}" "${device}"
214 local ret="${?}"
215
216 case "${ret}" in
217 # DAD OK
218 ${EXIT_DAD_OK})
219 log DEBUG "DAD successfully completed"
220 return ${EXIT_OK}
221 ;;
222
223 # DAD failed
224 ${EXIT_DAD_FAILED})
225 log ERROR "DAD failed"
226
227 # Remove the IP address again
228 ipv6_address_del "${address}" "${device}"
229
230 return ${EXIT_ERROR}
231 ;;
232
233 # Any unknown errors
234 *)
235 log ERROR "DAD failed with unhandled error: ${ret}"
236 return ${EXIT_ERROR}
237 ;;
238 esac
239 fi
240
241 return ${EXIT_OK}
242}
243
1c6a4e30 244ipv6_address_del() {
83d72e63
MT
245 local address="${1}"
246 local device="${2}"
247
248 ip_address_del "${device}" "${address}"
249}
250
1c6a4e30 251ipv6_address_flush() {
83d72e63
MT
252 local device="${1}"
253 assert isset device
254
255 log DEBUG "Flushing all IPv6 addresses on ${device}"
256
257 # Remove any stale addresses from aborted clients
258 cmd_quiet ip -6 addr flush dev "${device}" scope global permanent
2024ccca 259 cmd_quiet ip -6 addr flush dev "${device}" scope global dynamic
83d72e63
MT
260}
261
1c6a4e30 262ipv6_address_change_lifetime() {
83d72e63
MT
263 local address="${1}"
264 assert isset address
265
266 local device="${2}"
267 assert device_exists "${device}"
268 shift 2
269
270 local preferred_lft
271 local valid_lft
272
273 local arg
274 while read arg; do
275 case "${arg}" in
276 --preferred-lifetime=*)
277 preferred_lft="$(cli_get_val "${arg}")"
278 ;;
279 --valid-lifetime=*)
280 valid_lft="$(cli_get_val "${arg}")"
281 ;;
282 esac
2212045f 283 done <<< "$(args "$@")"
83d72e63
MT
284
285 local cmd="ip -6 addr change ${address} dev ${device} scope global"
286
287 if isinteger preferred_lft; then
288 list_append cmd "preferred_lft" "${preferred_lft}"
289 fi
290
291 if isinteger valid_lft; then
292 list_append cmd "valid_lft" "${valid_lft}"
293 fi
294
295 if ! cmd_quiet "${cmd}"; then
296 log ERROR "Could not change lifetimes of ${address} (${device})"
297 return ${EXIT_ERROR}
298 fi
299
300 log DEBUG "Changed lifetimes of ${address} (${device}) to:"
301 if isset preferred_lft; then
302 log DEBUG " preferred: ${preferred_lft}"
303 fi
304
305 if isset valid_lft; then
306 log DEBUG " valid: ${valid_lft}"
307 fi
308
309 return ${EXIT_OK}
310}
311
1c6a4e30 312ipv6_get_dad_status() {
83d72e63
MT
313 local address="${1}"
314 assert isset address
315
316 local device="${2}"
317 assert isset device
318
319 # Strip prefix from address
320 address="$(ipv6_split_prefix "${address}")"
321
322 local output="$(ip -o addr show dev "${device}" to "${address}")"
323 if ! isset output; then
324 return ${EXIT_ERROR}
325 fi
326
327 # Abort if DAD failed
328 if [[ ${output} =~ "dadfailed" ]]; then
329 return ${EXIT_DAD_FAILED}
330 fi
331
332 # Wait a little more if DAD is still in progress
333 if [[ ${output} =~ "tentative" ]]; then
334 return ${EXIT_DAD_TENTATIVE}
335 fi
336
337 # DAD has successfully completed
338 return ${EXIT_DAD_OK}
339}
340
1c6a4e30 341ipv6_wait_for_dad() {
83d72e63
MT
342 local address="${1}"
343 assert isset address
344
345 local device="${2}"
346 assert isset device
347
348 # Strip prefix from address
349 address="$(ipv6_split_prefix "${address}")"
350
351 local i
352 for i in {0..10}; do
353 # Check DAD status
354 ipv6_get_dad_status "${address}" "${interface}"
355 local ret="${?}"
356
357 case "${ret}" in
358 # DAD is still in progress. Give it a moment to settle...
359 ${EXIT_DAD_TENTATIVE})
360 sleep 0.5
361 continue
362 ;;
363
364 # Raise all other error codes
365 ${EXIT_DAD_OK}|${EXIT_DAD_FAILED}|*)
366 return ${ret}
367 ;;
368 esac
369 done
370
371 return ${EXIT_ERROR}
372}
373
1c6a4e30 374ipv6_device_get_addresses() {
83d72e63
MT
375 local device="${1}"
376 assert isset device
377 shift
378
379 local scope
380
381 local arg
382 while read arg; do
383 case "${arg}" in
384 --scope=*)
385 scope="$(cli_get_val "${arg}")"
386 ;;
387 esac
2212045f 388 done <<< "$(args "$@")"
83d72e63
MT
389
390 local cmd="ip -o addr show dev ${device}"
391 if isset scope; then
392 assert isoneof scope global dynamic link
393 list_append cmd "scope ${scope}"
394 fi
395
396 local addresses
397 local line args
398 while read line; do
399 args=( ${line} )
400
401 local i
402 for (( i=0; i < ${#args[@]} - 1; i++ )); do
403 if [ "${args[${i}]}" = "inet6" ]; then
404 list_append_one addresses "${args[$(( ${i} + 1 ))]}"
405 break
406 fi
407 done
408 done <<< "$(${cmd})"
409
410 list_sort ${addresses}
411}
412
13a6e69f 413ipv6_format() {
2212045f 414 inetcalc -6 -f "$@"
ab70371d 415}
4231f419 416
1c6a4e30 417ipv6_addr_eq() {
f480649e 418 assert [ $# -eq 2 ]
4231f419 419
13a6e69f
MT
420 local addr1="${1}"
421 local addr2="${2}"
4231f419 422
13a6e69f 423 inetcalc -6 -e "${addr1}" "${addr2}" \
ab70371d
MT
424 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
425}
4231f419 426
1c6a4e30 427ipv6_addr_gt() {
f480649e 428 assert [ $# -eq 2 ]
4231f419 429
13a6e69f
MT
430 local addr1="${1}"
431 local addr2="${2}"
4231f419 432
13a6e69f
MT
433 inetcalc -6 -g "${addr1}" "${addr2}" \
434 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
4231f419
MT
435}
436
ae02c40e 437ipv6_addr_ge() {
2212045f 438 ipv6_addr_eq "$@" || ipv6_addr_gt "$@"
ae02c40e
MT
439}
440
441ipv6_addr_lt() {
2212045f 442 ! ipv6_addr_eq "$@" && ! ipv6_addr_gt "$@"
ae02c40e
MT
443}
444
445ipv6_addr_le() {
2212045f 446 ipv6_addr_eq "$@" || ! ipv6_addr_gt "$@"
ae02c40e
MT
447}
448
1c6a4e30 449ipv6_get_network() {
2212045f 450 ip_get_network "$@"
ab70371d 451}