b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | |
| 3 | . /lib/functions/ipv4.sh |
| 4 | |
| 5 | PROG="$(basename "$0")" |
| 6 | |
| 7 | # wrapper to convert an integer to an address, unless we're using |
| 8 | # decimal output format. |
| 9 | # hook for library function |
| 10 | _ip2str() { |
| 11 | local var="$1" n="$2" |
| 12 | assert_uint32 "$n" || exit 1 |
| 13 | |
| 14 | if [ "$decimal" -ne 0 ]; then |
| 15 | export -- "$var=$n" |
| 16 | elif [ "$hexadecimal" -ne 0 ]; then |
| 17 | export -- "$var=$(printf "%x" "$n")" |
| 18 | else |
| 19 | ip2str "$@" |
| 20 | fi |
| 21 | } |
| 22 | |
| 23 | usage() { |
| 24 | echo "Usage: $PROG [ -d | -x ] address/prefix [ start limit ]" >&2 |
| 25 | exit 1 |
| 26 | } |
| 27 | |
| 28 | decimal=0 |
| 29 | hexadecimal=0 |
| 30 | if [ "$1" = "-d" ]; then |
| 31 | decimal=1 |
| 32 | shift |
| 33 | elif [ "$1" = "-x" ]; then |
| 34 | hexadecimal=1 |
| 35 | shift |
| 36 | fi |
| 37 | |
| 38 | if [ $# -eq 0 ]; then |
| 39 | usage |
| 40 | fi |
| 41 | |
| 42 | case "$1" in |
| 43 | */*.*) |
| 44 | # data is n.n.n.n/m.m.m.m format, like on a Cisco router |
| 45 | str2ip ipaddr "${1%/*}" || exit 1 |
| 46 | str2ip netmask "${1#*/}" || exit 1 |
| 47 | netmask2prefix prefix "$netmask" || exit 1 |
| 48 | shift |
| 49 | ;; |
| 50 | */*) |
| 51 | # more modern prefix notation of n.n.n.n/p |
| 52 | str2ip ipaddr "${1%/*}" || exit 1 |
| 53 | prefix="${1#*/}" |
| 54 | assert_uint32 "$prefix" || exit 1 |
| 55 | if [ "$prefix" -gt 32 ]; then |
| 56 | printf "Prefix out of range (%s)\n" "$prefix" >&2 |
| 57 | exit 1 |
| 58 | fi |
| 59 | prefix2netmask netmask "$prefix" || exit 1 |
| 60 | shift |
| 61 | ;; |
| 62 | *) |
| 63 | # address and netmask as two separate arguments |
| 64 | str2ip ipaddr "$1" || exit 1 |
| 65 | str2ip netmask "$2" || exit 1 |
| 66 | netmask2prefix prefix "$netmask" || exit 1 |
| 67 | shift 2 |
| 68 | ;; |
| 69 | esac |
| 70 | |
| 71 | # we either have no arguments left, or we have a range start and length |
| 72 | if [ $# -ne 0 ] && [ $# -ne 2 ]; then |
| 73 | usage |
| 74 | fi |
| 75 | |
| 76 | # complement of the netmask, i.e. the hostmask |
| 77 | hostmask=$((netmask ^ 0xffffffff)) |
| 78 | network=$((ipaddr & netmask)) |
| 79 | broadcast=$((network | hostmask)) |
| 80 | count=$((hostmask + 1)) |
| 81 | |
| 82 | _ip2str IP "$ipaddr" |
| 83 | _ip2str NETMASK "$netmask" |
| 84 | _ip2str NETWORK "$network" |
| 85 | |
| 86 | echo "IP=$IP" |
| 87 | echo "NETMASK=$NETMASK" |
| 88 | # don't include this-network or broadcast addresses |
| 89 | if [ "$prefix" -le 30 ]; then |
| 90 | _ip2str BROADCAST "$broadcast" |
| 91 | echo "BROADCAST=$BROADCAST" |
| 92 | fi |
| 93 | echo "NETWORK=$NETWORK" |
| 94 | echo "PREFIX=$prefix" |
| 95 | echo "COUNT=$count" |
| 96 | |
| 97 | # if there's no range, we're done |
| 98 | [ $# -eq 0 ] && exit 0 |
| 99 | [ -z "$1$2" ] && exit 0 |
| 100 | |
| 101 | if [ "$prefix" -le 30 ]; then |
| 102 | lower=$((network + 1)) |
| 103 | else |
| 104 | lower="$network" |
| 105 | fi |
| 106 | |
| 107 | start="$1" |
| 108 | assert_uint32 "$start" || exit 1 |
| 109 | start=$((network | (start & hostmask))) |
| 110 | [ "$start" -lt "$lower" ] && start="$lower" |
| 111 | [ "$start" -eq "$ipaddr" ] && start=$((start + 1)) |
| 112 | |
| 113 | if [ "$prefix" -le 30 ]; then |
| 114 | upper=$(((network | hostmask) - 1)) |
| 115 | elif [ "$prefix" -eq 31 ]; then |
| 116 | upper=$((network | hostmask)) |
| 117 | else |
| 118 | upper="$network" |
| 119 | fi |
| 120 | |
| 121 | range="$2" |
| 122 | assert_uint32 "$range" || exit 1 |
| 123 | end=$((start + range - 1)) |
| 124 | [ "$end" -gt "$upper" ] && end="$upper" |
| 125 | [ "$end" -eq "$ipaddr" ] && end=$((end - 1)) |
| 126 | |
| 127 | if [ "$start" -gt "$end" ]; then |
| 128 | echo "network ($NETWORK/$prefix) too small" >&2 |
| 129 | exit 1 |
| 130 | fi |
| 131 | |
| 132 | _ip2str START "$start" |
| 133 | _ip2str END "$end" |
| 134 | |
| 135 | if [ "$start" -le "$ipaddr" ] && [ "$ipaddr" -le "$end" ]; then |
| 136 | echo "error: address $IP inside range $START..$END" >&2 |
| 137 | exit 1 |
| 138 | fi |
| 139 | |
| 140 | echo "START=$START" |
| 141 | echo "END=$END" |
| 142 | |
| 143 | exit 0 |