Deleted Added
full compact
ipaddr.subr (244798) ipaddr.subr (247280)
1if [ ! "$_NETWORKING_IPADDR_SUBR" ]; then _NETWORKING_IPADDR_SUBR=1
2#
1if [ ! "$_NETWORKING_IPADDR_SUBR" ]; then _NETWORKING_IPADDR_SUBR=1
2#
3# Copyright (c) 2006-2012 Devin Teske
3# Copyright (c) 2006-2013 Devin Teske
4# All Rights Reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
4# All Rights Reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD: head/usr.sbin/bsdconfig/networking/share/ipaddr.subr 244798 2012-12-28 23:40:13Z dteske $
27# $FreeBSD: head/usr.sbin/bsdconfig/networking/share/ipaddr.subr 247280 2013-02-25 19:55:32Z dteske $
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." networking/ipaddr.subr
34f_include $BSDCFG_SHARE/dialog.subr
35f_include $BSDCFG_SHARE/strings.subr
36f_include $BSDCFG_SHARE/networking/common.subr
37
38BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="120.networking"
39f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
40
41############################################################ FUNCTIONS
42
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." networking/ipaddr.subr
34f_include $BSDCFG_SHARE/dialog.subr
35f_include $BSDCFG_SHARE/strings.subr
36f_include $BSDCFG_SHARE/networking/common.subr
37
38BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="120.networking"
39f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
40
41############################################################ FUNCTIONS
42
43# f_ifconfig_inet $interface
44#
45# Returns the IPv4 address associated with $interface.
46#
47f_ifconfig_inet()
48{
49 local interface="$1"
50 ifconfig "$interface" 2> /dev/null | awk \
51 '
52 BEGIN { found = 0 }
53 ( $1 == "inet" ) \
54 {
55 print $2
56 found = 1
57 exit
58 }
59 END { exit ! found }
60 '
61}
62
63# f_validate_ipaddr $ipaddr
64#
65# Returns zero if the given argument (an IP address) is of the proper format.
66#
67# The return status for invalid IP address is one of:
68# 1 One or more individual octets within the IP address (separated
69# by dots) contains one or more invalid characters.
70# 2 One or more individual octets within the IP address are null
71# and/or missing.
72# 3 One or more individual octets within the IP address exceeds the
73# maximum of 255 (or 2^8, being an octet comprised of 8 bits).
74# 4 The IP address has either too few or too many octets.
75#
76f_validate_ipaddr()
77{
78 local ip="$1"
79
80 ( # Operate within a sub-shell to protect the parent environment
81
82 # Track number of octets for error checking
83 noctets=0
84
85 IFS="." # Split on `dot'
86 for octet in $ip; do
87
88 # Return error if the octet is null
89 [ "$octet" ] || exit 2
90
91 # Return error if not a whole integer
92 f_isinteger "$octet" || exit 1
93
94 # Return error if not a positive integer
95 [ $octet -ge 0 ] || exit 1
96
97 # Return error if the octet exceeds 255
98 [ $octet -gt 255 ] && exit 3
99
100 noctets=$(( $noctets + 1 ))
101
102 done
103
104 [ $noctets -eq 4 ] || exit 4
105 )
106}
107
108# f_dialog_iperror $error $ipaddr
109#
110# Display a msgbox with the appropriate error message for an error returned by
43# f_dialog_iperror $error $ipaddr
44#
45# Display a msgbox with the appropriate error message for an error returned by
111# the f_validate_ipaddr function above.
46# the f_validate_ipaddr function.
112#
113f_dialog_iperror()
114{
115 local error="$1" ip="$2"
116
117 [ ${error:-0} -ne 0 ] || return $SUCCESS
118
119 case "$error" in
120 1) f_show_msg "$msg_ipv4_addr_octet_contains_invalid_chars" "$ip";;
121 2) f_show_msg "$msg_ipv4_addr_octet_is_null" "$ip";;
122 3) f_show_msg "$msg_ipv4_addr_octet_exceeds_max_value" "$ip";;
123 4) f_show_msg "$msg_ipv4_addr_octet_missing_or_extra" "$ip";;
124 esac
125}
126
127# f_dialog_validate_ipaddr $ipaddr
128#
129# Returns zero if the given argument (an IP address) is of the proper format.
130#
131# If the IP address is determined to be invalid, the appropriate error will be
132# displayed using the f_dialog_iperror function above.
133#
134f_dialog_validate_ipaddr()
135{
136 local ip="$1"
137
138 f_validate_ipaddr "$ip"
139 local retval=$?
140
141 # Produce an appropriate error message if necessary.
142 [ $retval -eq $SUCCESS ] || f_dialog_iperror $retval "$ip"
143
144 return $retval
145}
146
47#
48f_dialog_iperror()
49{
50 local error="$1" ip="$2"
51
52 [ ${error:-0} -ne 0 ] || return $SUCCESS
53
54 case "$error" in
55 1) f_show_msg "$msg_ipv4_addr_octet_contains_invalid_chars" "$ip";;
56 2) f_show_msg "$msg_ipv4_addr_octet_is_null" "$ip";;
57 3) f_show_msg "$msg_ipv4_addr_octet_exceeds_max_value" "$ip";;
58 4) f_show_msg "$msg_ipv4_addr_octet_missing_or_extra" "$ip";;
59 esac
60}
61
62# f_dialog_validate_ipaddr $ipaddr
63#
64# Returns zero if the given argument (an IP address) is of the proper format.
65#
66# If the IP address is determined to be invalid, the appropriate error will be
67# displayed using the f_dialog_iperror function above.
68#
69f_dialog_validate_ipaddr()
70{
71 local ip="$1"
72
73 f_validate_ipaddr "$ip"
74 local retval=$?
75
76 # Produce an appropriate error message if necessary.
77 [ $retval -eq $SUCCESS ] || f_dialog_iperror $retval "$ip"
78
79 return $retval
80}
81
147# f_validate_ipaddr6 $ipv6_addr
148#
149# Returns zero if the given argument (an IPv6 address) is of the proper format.
150#
151# The return status for invalid IP address is one of:
152# 1 One or more individual segments within the IP address
153# (separated by colons) contains one or more invalid characters.
154# Segments must contain only combinations of the characters 0-9,
155# A-F, or a-f.
156# 2 Too many/incorrect null segments. A single null segment is
157# allowed within the IP address (separated by colons) but not
158# allowed at the beginning or end (unless a double-null segment;
159# i.e., "::*" or "*::").
160# 3 One or more individual segments within the IP address
161# (separated by colons) exceeds the length of 4 hex-digits.
162# 4 The IP address entered has either too few (less than 3), too
163# many (more than 8), or not enough segments, separated by
164# colons.
165# 5* The IPv4 address at the end of the IPv6 address is invalid.
166# * When there is an error with the dotted-quad IPv4 address at the
167# end of the IPv6 address, the return value of 5 is OR'd with a
168# bit-shifted (<< 4) return of f_validate_ipaddr.
169#
170f_validate_ipaddr6()
171{
172 local ip="$1"
173
174 ( # Operate within a sub-shell to protect the parent environment
175
176 IFS=":" # Split on `colon'
177 set -- $ip:
178
179 # Return error if too many or too few segments
180 # Using 9 as max in case of leading or trailing null spanner
181 [ $# -gt 9 -o $# -lt 3 ] && exit 4
182
183 h="[0-9A-Fa-f]"
184 nulls=0
185 nsegments=$#
186 contains_ipv4_segment=
187
188 while [ $# -gt 0 ]; do
189
190 segment="${1%:}"
191 shift
192
193 #
194 # Return error if this segment makes one null too-many.
195 # A single null segment is allowed anywhere in the
196 # middle as well as double null segments are allowed at
197 # the beginning or end (but not both).
198 #
199 if [ ! "$segment" ]; then
200 nulls=$(( $nulls + 1 ))
201 if [ $nulls -eq 3 ]; then
202 # Only valid syntax for 3 nulls is `::'
203 [ "$ip" = "::" ] || exit 2
204 elif [ $nulls -eq 2 ]; then
205 # Only valid if begins/ends with `::'
206 case "$ip" in
207 ::*|*::) : fall thru ;;
208 *) exit 2
209 esac
210 fi
211 continue
212 fi
213
214 #
215 # Return error if not a valid hexadecimal short
216 #
217 case "$segment" in
218 $h|$h$h|$h$h$h|$h$h$h$h)
219 : valid segment of 1-4 hexadecimal digits
220 ;;
221 *[!0-9A-Fa-f]*)
222 # Segment contains at least one invalid char
223
224 # Return error immediately if not last segment
225 [ $# -eq 0 ] || exit 1
226
227 # Otherwise, check for legacy IPv4 notation
228 case "$segment" in
229 *[!0-9.]*)
230 # Segment contains at least one invalid
231 # character even for an IPv4 address
232 exit 1
233 esac
234
235 # Return error if not enough segments
236 if [ $nulls -eq 0 ]; then
237 [ $nsegments -eq 7 ] || exit 4
238 fi
239
240 contains_ipv4_segment=1
241
242 # Validate the IPv4 address
243 f_validate_ipaddr "$segment" ||
244 exit $(( 5 | $? << 4 ))
245 ;;
246 *)
247 # Segment characters are all valid but too many
248 exit 3
249 esac
250
251 done
252
253 if [ $nulls -eq 1 ]; then
254 # Single null segment cannot be at beginning/end
255 case "$ip" in
256 :*|*:) exit 2
257 esac
258 fi
259
260 #
261 # A legacy IPv4 address can span the last two 16-bit segments,
262 # reducing the amount of maximum allowable segments by-one.
263 #
264 maxsegments=8
265 if [ "$contains_ipv4_segment" ]; then
266 maxsegments=7
267 fi
268
269 case $nulls in
270 # Return error if missing segments with no null spanner
271 0) [ $nsegments -eq $maxsegments ] || exit 4 ;;
272 # Return error if null spanner with too many segments
273 1) [ $nsegments -le $maxsegments ] || exit 4 ;;
274 # Return error if leading/trailing `::' with too many segments
275 2) [ $nsegments -le $(( $maxsegments + 1 )) ] || exit 4 ;;
276 esac
277
278 exit $SUCCESS
279 )
280}
281
282# f_dialog_ip6error $error $ipv6_addr
283#
284# Display a msgbox with the appropriate error message for an error returned by
285# the f_validate_ipaddr6 function above.
286#
287f_dialog_ip6error()
288{
289 local error="$1" ip="$2"
290
291 [ ${error:-0} -ne 0 ] || return $SUCCESS
292
293 case "$error" in
294 1) f_show_msg "$msg_ipv6_addr_segment_contains_invalid_chars" "$ip";;
295 2) f_show_msg "$msg_ipv6_addr_too_many_null_segments" "$ip";;
296 3) f_show_msg "$msg_ipv6_addr_segment_contains_too_many_chars" "$ip";;
297 4) f_show_msg "$msg_ipv6_addr_too_few_or_extra_segments" "$ip";;
298 *)
299 if [ $(( $error & 0xF )) -eq 5 ]; then
300 # IPv4 at the end of IPv6 address is invalid
301 f_dialog_iperror $(( $error >> 4 )) "$ip"
302 fi
303 esac
304}
305
306# f_dialog_validate_ipaddr6 $ipv6_addr
307#
308# Returns zero if the given argument (an IPv6 address) is of the proper format.
309#
310# If the IP address is determined to be invalid, the appropriate error will be
311# displayed using the f_dialog_ip6error function above.
312#
313f_dialog_validate_ipaddr6()
314{
315 local ip="$1"
316
317 f_validate_ipaddr6 "$ip"
318 local retval=$?
319
320 # Produce an appropriate error message if necessary.
321 [ $retval -eq $SUCCESS ] || f_dialog_ip6error $retval "$ip"
322
323 return $retval
324}
325
326# f_dialog_input_ipaddr $interface $ipaddr
327#
328# Allows the user to edit a given IP address. If the user does not cancel or
329# press ESC, the $ipaddr environment variable will hold the newly-configured
330# value upon return.
331#
332# Optionally, the user can enter the format "IP_ADDRESS/NBITS" to set the
333# netmask at the same time as the IP address. If such a format is entered by
334# the user, the $netmask environment variable will hold the newly-configured
335# netmask upon return.
336#
337f_dialog_input_ipaddr()
338{
339 local interface="$1" _ipaddr="$2" _input
340
341 #
342 # Return with-error when there are NFS-mounts currently active. If the
343 # IP address is changed while NFS-exported directories are mounted, the
344 # system may hang (if any NFS mounts are using that interface).
345 #
346 if f_nfs_mounted && ! f_jailed; then
347 local setting="$( printf "$msg_current_ipaddr" \
348 "$interface" "$_ipaddr" )"
349 f_show_msg "$msg_nfs_mounts_may_cause_hang" "$setting"
350 return $FAILURE
351 fi
352
353 local msg="$( printf "$msg_please_enter_new_ip_addr" "$interface" )"
354
355 #
356 # Loop until the user provides taint-free input.
357 #
358 local retval
359 while :; do
360 #
361 # Return error status if:
362 # - User has either pressed ESC or chosen Cancel/No
363 # - User has not made any changes to the given value
364 #
365 _input=$( f_dialog_input "$msg" "$_ipaddr" \
366 "$hline_num_punc_tab_enter"
367 ) || return
368 [ "$_ipaddr" = "$_input" ] && return $FAILURE
369
370 # Return success if NULL value was entered
371 [ "$_input" ] || return $SUCCESS
372
373 # Take only the first "word" of the user's input
374 _ipaddr="$_input"
375 _ipaddr="${_ipaddr%%[$IFS]*}"
376
377 # Taint-check the user's input
378 f_dialog_validate_ipaddr "${_ipaddr%%/*}" && break
379 done
380
381 #
382 # Support the syntax: IP_ADDRESS/NBITS
383 #
384 local _netmask=""
385 case "$_ipaddr" in
386 */*)
387 local nbits="${_ipaddr#*/}" n=0
388 _ipaddr="${_ipaddr%%/*}"
389
390 #
391 # Taint-check $nbits to be (a) a positive whole-integer,
392 # and (b) to be less than or equal to 32. Otherwise, set
393 # $n so that the below loop never executes.
394 #
395 ( f_isinteger "$nbits" && [ $nbits -ge 0 -a $nbits -le 32 ] ) \
396 || n=4
397
398 while [ $n -lt 4 ]; do
399 _netmask="$_netmask${_netmask:+.}$((
400 (65280 >> ($nbits - 8 * $n) & 255)
401 * ((8*$n) < $nbits & $nbits <= (8*($n+1)))
402 + 255 * ($nbits > (8*($n+1)))
403 ))"
404 n=$(( $n + 1 ))
405 done
406 ;;
407 esac
408
409 ipaddr="$_ipaddr"
410 [ "$_netmask" ] && netmask="$_netmask"
411
412 return $SUCCESS
413}
414
415############################################################ MAIN
416
417f_dprintf "%s: Successfully loaded." networking/ipaddr.subr
418
419fi # ! $_NETWORKING_IPADDR_SUBR
82# f_dialog_ip6error $error $ipv6_addr
83#
84# Display a msgbox with the appropriate error message for an error returned by
85# the f_validate_ipaddr6 function above.
86#
87f_dialog_ip6error()
88{
89 local error="$1" ip="$2"
90
91 [ ${error:-0} -ne 0 ] || return $SUCCESS
92
93 case "$error" in
94 1) f_show_msg "$msg_ipv6_addr_segment_contains_invalid_chars" "$ip";;
95 2) f_show_msg "$msg_ipv6_addr_too_many_null_segments" "$ip";;
96 3) f_show_msg "$msg_ipv6_addr_segment_contains_too_many_chars" "$ip";;
97 4) f_show_msg "$msg_ipv6_addr_too_few_or_extra_segments" "$ip";;
98 *)
99 if [ $(( $error & 0xF )) -eq 5 ]; then
100 # IPv4 at the end of IPv6 address is invalid
101 f_dialog_iperror $(( $error >> 4 )) "$ip"
102 fi
103 esac
104}
105
106# f_dialog_validate_ipaddr6 $ipv6_addr
107#
108# Returns zero if the given argument (an IPv6 address) is of the proper format.
109#
110# If the IP address is determined to be invalid, the appropriate error will be
111# displayed using the f_dialog_ip6error function above.
112#
113f_dialog_validate_ipaddr6()
114{
115 local ip="$1"
116
117 f_validate_ipaddr6 "$ip"
118 local retval=$?
119
120 # Produce an appropriate error message if necessary.
121 [ $retval -eq $SUCCESS ] || f_dialog_ip6error $retval "$ip"
122
123 return $retval
124}
125
126# f_dialog_input_ipaddr $interface $ipaddr
127#
128# Allows the user to edit a given IP address. If the user does not cancel or
129# press ESC, the $ipaddr environment variable will hold the newly-configured
130# value upon return.
131#
132# Optionally, the user can enter the format "IP_ADDRESS/NBITS" to set the
133# netmask at the same time as the IP address. If such a format is entered by
134# the user, the $netmask environment variable will hold the newly-configured
135# netmask upon return.
136#
137f_dialog_input_ipaddr()
138{
139 local interface="$1" _ipaddr="$2" _input
140
141 #
142 # Return with-error when there are NFS-mounts currently active. If the
143 # IP address is changed while NFS-exported directories are mounted, the
144 # system may hang (if any NFS mounts are using that interface).
145 #
146 if f_nfs_mounted && ! f_jailed; then
147 local setting="$( printf "$msg_current_ipaddr" \
148 "$interface" "$_ipaddr" )"
149 f_show_msg "$msg_nfs_mounts_may_cause_hang" "$setting"
150 return $FAILURE
151 fi
152
153 local msg="$( printf "$msg_please_enter_new_ip_addr" "$interface" )"
154
155 #
156 # Loop until the user provides taint-free input.
157 #
158 local retval
159 while :; do
160 #
161 # Return error status if:
162 # - User has either pressed ESC or chosen Cancel/No
163 # - User has not made any changes to the given value
164 #
165 _input=$( f_dialog_input "$msg" "$_ipaddr" \
166 "$hline_num_punc_tab_enter"
167 ) || return
168 [ "$_ipaddr" = "$_input" ] && return $FAILURE
169
170 # Return success if NULL value was entered
171 [ "$_input" ] || return $SUCCESS
172
173 # Take only the first "word" of the user's input
174 _ipaddr="$_input"
175 _ipaddr="${_ipaddr%%[$IFS]*}"
176
177 # Taint-check the user's input
178 f_dialog_validate_ipaddr "${_ipaddr%%/*}" && break
179 done
180
181 #
182 # Support the syntax: IP_ADDRESS/NBITS
183 #
184 local _netmask=""
185 case "$_ipaddr" in
186 */*)
187 local nbits="${_ipaddr#*/}" n=0
188 _ipaddr="${_ipaddr%%/*}"
189
190 #
191 # Taint-check $nbits to be (a) a positive whole-integer,
192 # and (b) to be less than or equal to 32. Otherwise, set
193 # $n so that the below loop never executes.
194 #
195 ( f_isinteger "$nbits" && [ $nbits -ge 0 -a $nbits -le 32 ] ) \
196 || n=4
197
198 while [ $n -lt 4 ]; do
199 _netmask="$_netmask${_netmask:+.}$((
200 (65280 >> ($nbits - 8 * $n) & 255)
201 * ((8*$n) < $nbits & $nbits <= (8*($n+1)))
202 + 255 * ($nbits > (8*($n+1)))
203 ))"
204 n=$(( $n + 1 ))
205 done
206 ;;
207 esac
208
209 ipaddr="$_ipaddr"
210 [ "$_netmask" ] && netmask="$_netmask"
211
212 return $SUCCESS
213}
214
215############################################################ MAIN
216
217f_dprintf "%s: Successfully loaded." networking/ipaddr.subr
218
219fi # ! $_NETWORKING_IPADDR_SUBR