base-files: ipcalc.sh: Add netmask2prefix function
authorPhilip Prindeville <philipp@redfish-solutions.com>
Sat, 11 Nov 2023 19:37:20 +0000 (12:37 -0700)
committerPhilip Prindeville <philipp@redfish-solutions.com>
Tue, 12 Dec 2023 19:30:35 +0000 (12:30 -0700)
Also add is_contiguous to check if it's a valid netmask.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
package/base-files/files/bin/ipcalc.sh
package/base-files/files/lib/functions/ipv4.sh

index 4f48e0a79271fb12c98b91ffc3c37462e93684d1..9e2702c60d2216cf365d05c7e500266fe3298201 100755 (executable)
@@ -44,6 +44,7 @@ case "$1" in
     # data is n.n.n.n/m.m.m.m format, like on a Cisco router
     str2ip ipaddr "${1%/*}" || exit 1
     str2ip netmask "${1#*/}" || exit 1
+    netmask2prefix prefix "$netmask" || exit 1
     shift
     ;;
 */*)
@@ -62,6 +63,7 @@ case "$1" in
     # address and netmask as two separate arguments
     str2ip ipaddr "$1" || exit 1
     str2ip netmask "$2" || exit 1
+    netmask2prefix prefix "$netmask" || exit 1
     shift 2
     ;;
 esac
@@ -71,11 +73,6 @@ if [ $# -ne 0 ] && [ $# -ne 2 ]; then
     usage
 fi
 
-if ! bitcount prefix "$netmask"; then
-    printf "Invalid netmask (%s)\n" "$netmask" >&2
-    exit 1
-fi
-
 # complement of the netmask, i.e. the hostmask
 hostmask=$((netmask ^ 0xffffffff))
 network=$((ipaddr & netmask))
index 9405a635525df5410a71f22d667157d69ee46c23..c6fcd2af2e587c858226b7bb22c0e3cc48375c0b 100644 (file)
@@ -157,3 +157,42 @@ prefix2netmask() {
     export -- "$__var=$(((~(uint_max >> __n)) & uint_max))"
 }
 
+_is_contiguous() {
+    local __x="$1"     # no checking done
+    local __y=$((~__x & uint_max))
+    local __z=$(((__y + 1) & uint_max))
+
+    [ $((__z & __y)) -eq 0 ]
+}
+
+# check argument as being contiguous upper bits (and yes,
+# 0 doesn't have any discontiguous bits).
+is_contiguous() {
+    local __var="$1" __x="$2" __val=0
+    assert_uint32 "$__x" || return 1
+
+    local __y=$((~__x & uint_max))
+    local __z=$(((__y + 1) & uint_max))
+
+    [ $((__z & __y)) -eq 0 ] && __val=1
+
+    export -- "$__var=$__val"
+}
+
+# convert mask to prefix, validating that it's a conventional
+# (contiguous) netmask.
+netmask2prefix() {
+    local __var="$1" __n="$2" __cont __bits
+    assert_uint32 "$__n" || return 1
+
+    is_contiguous __cont "$__n" || return 1
+    if [ $__cont -eq 0 ]; then
+       printf "Not a contiguous netmask (%08x)\n" "$__n" >&2
+       return 1
+    fi
+
+    bitcount __bits "$__n"             # already checked
+
+    export -- "$__var=$__bits"
+}
+