#!/bin/sh . /lib/functions/ipv4.sh PROG="$(basename "$0")" # wrapper to convert an integer to an address, unless we're using # decimal output format. # hook for library function _ip2str() { local var="$1" n="$2" assert_uint32 "$n" || exit 1 if [ "$decimal" -ne 0 ]; then export -- "$var=$n" elif [ "$hexadecimal" -ne 0 ]; then export -- "$var=$(printf "%x" "$n")" else ip2str "$@" fi } usage() { echo "Usage: $PROG [ -d | -x ] address/prefix [ start limit ]" >&2 exit 1 } decimal=0 hexadecimal=0 if [ "$1" = "-d" ]; then decimal=1 shift elif [ "$1" = "-x" ]; then hexadecimal=1 shift fi if [ $# -eq 0 ]; then usage fi 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 ;; */*) # more modern prefix notation of n.n.n.n/p str2ip ipaddr "${1%/*}" || exit 1 prefix="${1#*/}" assert_uint32 "$prefix" || exit 1 if [ "$prefix" -gt 32 ]; then printf "Prefix out of range (%s)\n" "$prefix" >&2 exit 1 fi prefix2netmask netmask "$prefix" || exit 1 shift ;; *) # 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 # we either have no arguments left, or we have a range start and length if [ $# -ne 0 ] && [ $# -ne 2 ]; then usage fi # complement of the netmask, i.e. the hostmask hostmask=$((netmask ^ 0xffffffff)) network=$((ipaddr & netmask)) broadcast=$((network | hostmask)) count=$((hostmask + 1)) _ip2str IP "$ipaddr" _ip2str NETMASK "$netmask" _ip2str NETWORK "$network" echo "IP=$IP" echo "NETMASK=$NETMASK" # don't include this-network or broadcast addresses if [ "$prefix" -le 30 ]; then _ip2str BROADCAST "$broadcast" echo "BROADCAST=$BROADCAST" fi echo "NETWORK=$NETWORK" echo "PREFIX=$prefix" echo "COUNT=$count" # if there's no range, we're done [ $# -eq 0 ] && exit 0 [ -z "$1$2" ] && exit 0 if [ "$prefix" -le 30 ]; then lower=$((network + 1)) else lower="$network" fi start="$1" assert_uint32 "$start" || exit 1 start=$((network | (start & hostmask))) [ "$start" -lt "$lower" ] && start="$lower" [ "$start" -eq "$ipaddr" ] && start=$((start + 1)) if [ "$prefix" -le 30 ]; then upper=$(((network | hostmask) - 1)) elif [ "$prefix" -eq 31 ]; then upper=$((network | hostmask)) else upper="$network" fi range="$2" assert_uint32 "$range" || exit 1 end=$((start + range - 1)) [ "$end" -gt "$upper" ] && end="$upper" [ "$end" -eq "$ipaddr" ] && end=$((end - 1)) if [ "$start" -gt "$end" ]; then echo "network ($NETWORK/$prefix) too small" >&2 exit 1 fi _ip2str START "$start" _ip2str END "$end" if [ "$start" -le "$ipaddr" ] && [ "$ipaddr" -le "$end" ]; then echo "error: address $IP inside range $START..$END" >&2 exit 1 fi echo "START=$START" echo "END=$END" exit 0