blob: d0b93dbcb9b5e6fcdb90d5e1c1852697942f7704 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001uint_max=4294967295
2
3d_10_0_0_0=167772160
4d_10_255_255_255=184549375
5
6d_172_16_0_0=2886729728
7d_172_31_255_255=2887778303
8
9d_192_168_0_0=3232235520
10d_192_168_255_255=3232301055
11
12d_169_254_0_0=2851995648
13d_169_254_255_255=2852061183
14
15d_127_0_0_0=2130706432
16d_127_255_255_255=2147483647
17
18d_224_0_0_0=3758096384
19d_239_255_255_255=4026531839
20
21# check that $1 is only base 10 digits, and that it doesn't
22# exceed 2^32-1
23assert_uint32() {
24 local __n="$1"
25
26 if [ -z "$__n" -o -n "${__n//[0-9]/}" ]; then
27 printf "Not a decimal integer (%s)\n" "$__n ">&2
28 return 1
29 fi
30
31 if [ "$__n" -gt $uint_max ]; then
32 printf "Out of range (%s)\n" "$__n" >&2
33 return 1
34 fi
35
36 if [ "$((__n + 0))" != "$__n" ]; then
37 printf "Not normalized notation (%s)\n" "$__n" >&2
38 return 1
39 fi
40
41 return 0
42}
43
44# return a count of the number of bits set in $1
45bitcount() {
46 local __var="$1" __c="$2"
47 assert_uint32 "$__c" || return 1
48
49 __c=$((((__c >> 1) & 0x55555555) + (__c & 0x55555555)))
50 __c=$((((__c >> 2) & 0x33333333) + (__c & 0x33333333)))
51 __c=$((((__c >> 4) & 0x0f0f0f0f) + (__c & 0x0f0f0f0f)))
52 __c=$((((__c >> 8) & 0x00ff00ff) + (__c & 0x00ff00ff)))
53 __c=$((((__c >> 16) & 0x0000ffff) + (__c & 0x0000ffff)))
54
55 export -- "$__var=$__c"
56}
57
58# tedious but portable with busybox's limited shell
59# we check each octet to be in the range of 0..255,
60# and also make sure there's no extaneous characters.
61str2ip() {
62 local __var="$1" __ip="$2" __n __val=0
63
64 case "$__ip" in
65 [0-9].*)
66 __n="${__ip:0:1}"
67 __ip="${__ip:2}"
68 ;;
69 [1-9][0-9].*)
70 __n="${__ip:0:2}"
71 __ip="${__ip:3}"
72 ;;
73 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
74 __n="${__ip:0:3}"
75 __ip="${__ip:4}"
76 ;;
77 *)
78 printf "Not a dotted quad (%s)\n" "$2" >&2
79 return 1
80 ;;
81 esac
82
83 __val=$((__n << 24))
84
85 case "$__ip" in
86 [0-9].*)
87 __n="${__ip:0:1}"
88 __ip="${__ip:2}"
89 ;;
90 [1-9][0-9].*)
91 __n="${__ip:0:2}"
92 __ip="${__ip:3}"
93 ;;
94 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
95 __n="${__ip:0:3}"
96 __ip="${__ip:4}"
97 ;;
98 *)
99 printf "Not a dotted quad (%s)\n" "$2" >&2
100 return 1
101 ;;
102 esac
103
104 __val=$((__val + (__n << 16)))
105
106 case "$__ip" in
107 [0-9].*)
108 __n="${__ip:0:1}"
109 __ip="${__ip:2}"
110 ;;
111 [1-9][0-9].*)
112 __n="${__ip:0:2}"
113 __ip="${__ip:3}"
114 ;;
115 1[0-9][0-9].*|2[0-4][0-9].*|25[0-5].*)
116 __n="${__ip:0:3}"
117 __ip="${__ip:4}"
118 ;;
119 *)
120 printf "Not a dotted quad (%s)\n" "$2" >&2
121 return 1
122 ;;
123 esac
124
125 __val=$((__val + (__n << 8)))
126
127 case "$__ip" in
128 [0-9])
129 __n="${__ip:0:1}"
130 __ip="${__ip:1}"
131 ;;
132 [1-9][0-9])
133 __n="${__ip:0:2}"
134 __ip="${__ip:2}"
135 ;;
136 1[0-9][0-9]|2[0-4][0-9]|25[0-5])
137 __n="${__ip:0:3}"
138 __ip="${__ip:3}"
139 ;;
140 *)
141 printf "Not a dotted quad (%s)\n" "$2" >&2
142 return 1
143 ;;
144 esac
145
146 __val=$((__val + __n))
147
148 if [ -n "$__ip" ]; then
149 printf "Not a dotted quad (%s)\n" "$2" >&2
150 return 1
151 fi
152
153 export -- "$__var=$__val"
154 return 0
155}
156
157# convert back from an integer to dotted-quad.
158ip2str() {
159 local __var="$1" __n="$2"
160 assert_uint32 "$__n" || return 1
161
162 export -- "$__var=$((__n >> 24)).$(((__n >> 16) & 255)).$(((__n >> 8) & 255)).$((__n & 255))"
163}
164
165# convert prefix into an integer bitmask
166prefix2netmask() {
167 local __var="$1" __n="$2"
168 assert_uint32 "$__n" || return 1
169
170 if [ "$__n" -gt 32 ]; then
171 printf "Prefix out-of-range (%s)" "$__n" >&2
172 return 1
173 fi
174
175 export -- "$__var=$(((~(uint_max >> __n)) & uint_max))"
176}
177
178_is_contiguous() {
179 local __x="$1" # no checking done
180 local __y=$((~__x & uint_max))
181 local __z=$(((__y + 1) & uint_max))
182
183 [ $((__z & __y)) -eq 0 ]
184}
185
186# check argument as being contiguous upper bits (and yes,
187# 0 doesn't have any discontiguous bits).
188is_contiguous() {
189 local __var="$1" __x="$2" __val=0
190 assert_uint32 "$__x" || return 1
191
192 local __y=$((~__x & uint_max))
193 local __z=$(((__y + 1) & uint_max))
194
195 [ $((__z & __y)) -eq 0 ] && __val=1
196
197 export -- "$__var=$__val"
198}
199
200# convert mask to prefix, validating that it's a conventional
201# (contiguous) netmask.
202netmask2prefix() {
203 local __var="$1" __n="$2" __cont __bits
204 assert_uint32 "$__n" || return 1
205
206 is_contiguous __cont "$__n" || return 1
207 if [ $__cont -eq 0 ]; then
208 printf "Not a contiguous netmask (%08x)\n" "$__n" >&2
209 return 1
210 fi
211
212 bitcount __bits "$__n" # already checked
213
214 export -- "$__var=$__bits"
215}
216
217# check the argument as being an rfc-1918 address
218is_rfc1918() {
219 local __var="$1" __x="$2" __val=0
220 assert_uint32 "$__x" || return 1
221
222 if [ $d_10_0_0_0 -le $__x ] && [ $__x -le $d_10_255_255_255 ]; then
223 __val=1
224 elif [ $d_172_16_0_0 -le $__x ] && [ $__x -le $d_172_31_255_255 ]; then
225 __val=1
226 elif [ $d_192_168_0_0 -le $__x ] && [ $__x -le $d_192_168_255_255 ]; then
227 __val=1
228 fi
229
230 export -- "$__var=$__val"
231}
232
233# check the argument as being an rfc-3927 address
234is_rfc3927() {
235 local __var="$1" __x="$2" __val=0
236 assert_uint32 "$__x" || return 1
237
238 if [ $d_169_254_0_0 -le $__x ] && [ $__x -le $d_169_254_255_255 ]; then
239 __val=1
240 fi
241
242 export -- "$__var=$__val"
243}
244
245# check the argument as being an rfc-1122 loopback address
246is_loopback() {
247 local __var="$1" __x="$2" __val=0
248 assert_uint32 "$__x" || return 1
249
250 if [ $d_127_0_0_0 -le $__x ] && [ $__x -le $d_127_255_255_255 ]; then
251 __val=1
252 fi
253
254 export -- "$__var=$__val"
255}
256
257# check the argument as being a multicast address
258is_multicast() {
259 local __var="$1" __x="$2" __val=0
260 assert_uint32 "$__x" || return 1
261
262 if [ $d_224_0_0_0 -le $__x ] && [ $__x -le $d_239_255_255_255 ]; then
263 __val=1
264 fi
265
266 export -- "$__var=$__val"
267}
268