From 4df351052644986d02f4f2b8d7a76bf2e65fbc6d Mon Sep 17 00:00:00 2001 From: dteske Date: Sat, 24 Nov 2012 06:27:46 +0000 Subject: Add IPv6 address-validation routine. Approved by: adrian (co-mentor) (implicit) --- .../bsdconfig/networking/include/messages.subr | 6 +- usr.sbin/bsdconfig/networking/share/ipaddr.subr | 153 ++++++++++++++++++++- 2 files changed, 157 insertions(+), 2 deletions(-) diff --git a/usr.sbin/bsdconfig/networking/include/messages.subr b/usr.sbin/bsdconfig/networking/include/messages.subr index dac8e20..d430505 100644 --- a/usr.sbin/bsdconfig/networking/include/messages.subr +++ b/usr.sbin/bsdconfig/networking/include/messages.subr @@ -58,7 +58,11 @@ msg_ipaddr4="ipaddr" msg_ipv4_addr_octet_contains_invalid_chars="ERROR! One or more individual octets within the IP address\n(separated by dots) contains one or more invalid characters.\nOctets must contain only the characters 0-9.\n\nInvalid IP Address: %s" msg_ipv4_addr_octet_exceeds_max_value="ERROR! One or more individual octets within the IP address\n(separated by dots) exceeds the maximum of 255.\n\nInvalid IP Address: %s" msg_ipv4_addr_octet_is_null="ERROR! One or more individual octets within the IP address\n(separated by dots) are null and/or missing.\n\nInvalid IP Address: %s" -msg_ipv4_addr_octet_missing_or_extra="ERROR! The IP address entered has either too few or too many\noctets.\n\nInvalid IP Address: %s" +msg_ipv4_addr_octet_missing_or_extra="ERROR! The IP address entered has either too few (less than\nfour) or too many (more than four) octets, separated by dots.\n\nInvalid IP Address: %s" +msg_ipv6_addr_segment_contains_invalid_chars="ERROR! One or more individual segments within the IP address\n(separated by colons) contains one or more invalid characters.\nSegments must contain only combinations of the characters 0-9,\nA-F, or a-f.\n\nInvalid IPv6 Address: %s" +msg_ipv6_addr_segment_contains_too_many_chars="ERROR! One or more individual segments within the IP address\n(separated by colons) exceeds the length of 4 hex-digits.\n\nInvalid IPv6 Address: %s" +msg_ipv6_addr_too_few_or_extra_segments="ERROR! The IP address entered has either too few (less than 3), too\nmany (more than 8), or not enough segments, separated by colons.\n\nInvalid IPv6 Address: %s" +msg_ipv6_addr_too_many_null_segments="ERROR! Too many/incorrect null segments. A single null\nsegment is allowed within the IP address (separated by\ncolons) but not allowed at the beginning or end (unless\na double-null segment; i.e., \"::*\" or \"*::\").\n\nInvalid IPv6 Address: %s" msg_ipv4_mask_field_contains_invalid_chars="ERROR! One or more individual fields within the subnet mask\n(separated by dots) contains one or more invalid characters.\n\nInvalid Subnet Mask: %s" msg_ipv4_mask_field_exceeds_max_value="ERROR! One or more individual fields within the subnet mask\n(separated by dots) exceeds the maximum of 255.\n\nInvalid Subnet Mask: %s" msg_ipv4_mask_field_invalid_value="ERROR! One or more individual fields within the subnet mask\n(separated by dots) contains one or more invalid integers.\nFields must be one of 0/128/192/224/240/248/252/254/255.\n\nInvalid Subnet Mask: %s" diff --git a/usr.sbin/bsdconfig/networking/share/ipaddr.subr b/usr.sbin/bsdconfig/networking/share/ipaddr.subr index 7e858dc..c64cfb9 100644 --- a/usr.sbin/bsdconfig/networking/share/ipaddr.subr +++ b/usr.sbin/bsdconfig/networking/share/ipaddr.subr @@ -74,7 +74,7 @@ f_ifconfig_inet() # 4 The IP address has either too few or too many octets. # # If the IP address is determined to be invalid, the appropriate error will be -# displayed using the above dialog_msgbox function. +# displayed using the f_dialog_msgbox function. # f_dialog_validate_ipaddr() { @@ -125,6 +125,157 @@ f_dialog_validate_ipaddr() return $retval } +# f_dialog_validate_ipaddr6 $ipv6_addr +# +# Returns zero if the given argument (an IPv6 address) is of the proper format. +# +# The return status for invalid IP address is one of: +# 1 One or more individual segments within the IP address +# (separated by colons) contains one or more invalid characters. +# 2 More than two segments within the IP address are null or the +# the second null segment is not at the end of the address. +# 3 One or more individual segments within the IP address exceeds +# the word length of 32-bits (segments are always hexadecimal). +# 4 The IP address has either too few or too many segments. +# 5 The IPv4 address at the end of the IPv6 address is invalid. +# +# If the IP address is determined to be invalid, the appropriate error will be +# displayed using the f_dialog_msgbox function. +# +f_dialog_validate_ipaddr6() +{ + local ip="$1" + + ( # Operate within a sub-shell to protect the parent environment + + oldIFS="$IFS" + IFS=":" # Split on `colon' + set -- $ip: + + # Return error if too many or too few segments + # Using 9 as max in case of leading or trailing null spanner + [ $# -gt 9 -o $# -lt 3 ] && exit 4 + + h="[0-9A-Fa-f]" + nulls=0 + nsegments=$# + contains_ipv4_segment= + + while [ $# -gt 0 ]; do + + segment="${1%:}" + shift + + # + # Return error if this segment makes one null too-many. + # A single null segment is allowed anywhere in the + # middle as well as double null segments are allowed at + # the beginning or end (but not both). + # + if [ ! "$segment" ]; then + nulls=$(( $nulls + 1 )) + if [ $nulls -eq 3 ]; then + # Only valid syntax for 3 nulls is `::' + [ "$ip" = "::" ] || exit 2 + elif [ $nulls -eq 2 ]; then + # Only valid if begins/ends with `::' + case "$ip" in + ::*|*::) : fall thru ;; + *) exit 2 + esac + fi + continue + fi + + # + # Return error if not a valid hexadecimal short + # + case "$segment" in + $h|$h$h|$h$h$h|$h$h$h$h) + : valid segment of 1-4 hexadecimal digits + ;; + *[!0-9A-Fa-f]*) + # Segment contains at least one invalid char + + # Return error immediately if not last segment + [ $# -eq 0 ] || exit 1 + + # Otherwise, check for legacy IPv4 notation + case "$segment" in + *[!0-9.]*) + # Segment contains at least one invalid + # character even for an IPv4 address + exit 1 + esac + + # Return error if not enough segments + if [ $nulls -eq 0 ]; then + [ $nsegments -eq 7 ] || exit 4 + fi + + contains_ipv4_segment=1 + + # Validate the IPv4 address + IFS="$oldIFS" + f_dialog_validate_ipaddr "$segment" || exit 5 + IFS=":" + ;; + *) + # Segment characters are all valid but too many + exit 3 + esac + + done + + if [ $nulls -eq 1 ]; then + # Single null segment cannot be at beginning/end + case "$ip" in + :*|*:) exit 2 + esac + fi + + # + # A legacy IPv4 address can span the last two 16-bit segments, + # reducing the amount of maximum allowable segments by-one. + # + maxsegments=8 + if [ "$contains_ipv4_segment" ]; then + maxsegments=7 + fi + + case $nulls in + # Return error if missing segments with no null spanner + 0) [ $nsegments -eq $maxsegments ] || exit 4 ;; + # Return error if null spanner with too many segments + 1) [ $nsegments -le $maxsegments ] || exit 4 ;; + # Return error if leading/trailing `::' with too many segments + 2) [ $nsegments -le $(( $maxsegments + 1 )) ] || exit 4 ;; + esac + + exit $SUCCESS + ) + + # + # Produce an appropriate error message if necessary. + # + local retval=$? + case $retval in + 1) f_dialog_msgbox "$( printf \ + "$msg_ipv6_addr_segment_contains_invalid_chars" "$ip" )";; + 2) f_dialog_msgbox "$( printf \ + "$msg_ipv6_addr_too_many_null_segments" "$ip" )";; + 3) f_dialog_msgbox "$( printf \ + "$msg_ipv6_addr_segment_contains_too_many_chars" "$ip" )";; + 4) f_dialog_msgbox "$( printf \ + "$msg_ipv6_addr_too_few_or_extra_segments" "$ip" )";; + 5) : IPv4 at the end of IPv6 address is invalid ;; + # Don't display an error because f_dialog_validate_ipaddr + # already displayed one for the particular issue encountered. + esac + + return $retval +} + # f_dialog_input_ipaddr $interface $ipaddr # # Allows the user to edit a given IP address. If the user does not cancel or -- cgit v1.1