From dd256099c3fbf48e108381dea8588c38e89cf14a Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Sat, 11 Nov 2023 12:37:20 -0700 Subject: [PATCH] base-files: ipcalc.sh: Add netmask2prefix function Also add is_contiguous to check if it's a valid netmask. Signed-off-by: Philip Prindeville --- package/base-files/files/bin/ipcalc.sh | 7 +--- .../base-files/files/lib/functions/ipv4.sh | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/package/base-files/files/bin/ipcalc.sh b/package/base-files/files/bin/ipcalc.sh index 4f48e0a79271..9e2702c60d22 100755 --- a/package/base-files/files/bin/ipcalc.sh +++ b/package/base-files/files/bin/ipcalc.sh @@ -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)) diff --git a/package/base-files/files/lib/functions/ipv4.sh b/package/base-files/files/lib/functions/ipv4.sh index 9405a635525d..c6fcd2af2e58 100644 --- a/package/base-files/files/lib/functions/ipv4.sh +++ b/package/base-files/files/lib/functions/ipv4.sh @@ -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" +} + -- 2.30.2