blob: 871a49ed6e73170f70ff088f0bea36d51ce36c76 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/bin/sh
2
3. /lib/functions/ipv4.sh
4
5PROG="$(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
23usage() {
24 echo "Usage: $PROG [ -d | -x ] address/prefix [ start limit ]" >&2
25 exit 1
26}
27
28decimal=0
29hexadecimal=0
30if [ "$1" = "-d" ]; then
31 decimal=1
32 shift
33elif [ "$1" = "-x" ]; then
34 hexadecimal=1
35 shift
36fi
37
38if [ $# -eq 0 ]; then
39 usage
40fi
41
42case "$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 ;;
69esac
70
71# we either have no arguments left, or we have a range start and length
72if [ $# -ne 0 ] && [ $# -ne 2 ]; then
73 usage
74fi
75
76# complement of the netmask, i.e. the hostmask
77hostmask=$((netmask ^ 0xffffffff))
78network=$((ipaddr & netmask))
79broadcast=$((network | hostmask))
80count=$((hostmask + 1))
81
82_ip2str IP "$ipaddr"
83_ip2str NETMASK "$netmask"
84_ip2str NETWORK "$network"
85
86echo "IP=$IP"
87echo "NETMASK=$NETMASK"
88# don't include this-network or broadcast addresses
89if [ "$prefix" -le 30 ]; then
90 _ip2str BROADCAST "$broadcast"
91 echo "BROADCAST=$BROADCAST"
92fi
93echo "NETWORK=$NETWORK"
94echo "PREFIX=$prefix"
95echo "COUNT=$count"
96
97# if there's no range, we're done
98[ $# -eq 0 ] && exit 0
99[ -z "$1$2" ] && exit 0
100
101if [ "$prefix" -le 30 ]; then
102 lower=$((network + 1))
103else
104 lower="$network"
105fi
106
107start="$1"
108assert_uint32 "$start" || exit 1
109start=$((network | (start & hostmask)))
110[ "$start" -lt "$lower" ] && start="$lower"
111[ "$start" -eq "$ipaddr" ] && start=$((start + 1))
112
113if [ "$prefix" -le 30 ]; then
114 upper=$(((network | hostmask) - 1))
115elif [ "$prefix" -eq 31 ]; then
116 upper=$((network | hostmask))
117else
118 upper="$network"
119fi
120
121range="$2"
122assert_uint32 "$range" || exit 1
123end=$((start + range - 1))
124[ "$end" -gt "$upper" ] && end="$upper"
125[ "$end" -eq "$ipaddr" ] && end=$((end - 1))
126
127if [ "$start" -gt "$end" ]; then
128 echo "network ($NETWORK/$prefix) too small" >&2
129 exit 1
130fi
131
132_ip2str START "$start"
133_ip2str END "$end"
134
135if [ "$start" -le "$ipaddr" ] && [ "$ipaddr" -le "$end" ]; then
136 echo "error: address $IP inside range $START..$END" >&2
137 exit 1
138fi
139
140echo "START=$START"
141echo "END=$END"
142
143exit 0