| #!/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 |