]> git.ipfire.org Git - people/stevee/network.git/blob - src/functions/functions.ipv4
ip_is_valid: Refactor functions
[people/stevee/network.git] / src / functions / functions.ipv4
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 IP_SUPPORTED_PROTOCOLS="${IP_SUPPORTED_PROTOCOLS} ipv4"
23
24 ipv4_is_valid() {
25 local address=${1}
26
27 local prefix=$(ip_get_prefix ${address})
28 address=$(ip_split_prefix ${address})
29
30 # If prefix is set, we check if it is correct
31 if isset prefix; then
32 # Must be numeric
33 isinteger prefix || return ${EXIT_FALSE}
34
35 # Must be 32 if present
36 [ ${prefix} -eq 32 ] || return ${EXIT_FALSE}
37 fi
38
39 inetcalc -4 -c ${address} && return ${EXIT_TRUE} || return ${EXIT_FALSE}
40 }
41
42 ipv4_prefix_is_valid() {
43 local prefix=${1}
44
45 # Check if prefix is a number
46 isinteger prefix || return ${EXIT_FALSE}
47
48 [ ${prefix} -le 0 ] && return ${EXIT_FALSE}
49 [ ${prefix} -gt 32 ] && return ${EXIT_FALSE}
50
51 return ${EXIT_TRUE}
52 }
53
54 ipv4_netmask_is_valid() {
55 local netmask="${1}"
56
57 # XXX this check could be much better by checking
58 # if the netmask only contains leading ones
59
60 ipv4_is_valid "${netmask}"
61 }
62
63 ipv4_detect_duplicate() {
64 local device=${1}
65 local address=${2}
66
67 assert isset address
68 assert isset device
69 assert device_exists ${device}
70
71 # Don't check on PPP devices.
72 device_is_ppp ${device} && return ${EXIT_ERROR}
73
74 if ! arping -q -c 2 -w 3 -D -I ${device} ${address}; then
75 log DEBUG "Detected duplicate address '${address}' on device '${device}'."
76 return ${EXIT_OK}
77 fi
78
79 return ${EXIT_ERROR}
80 }
81
82 ipv4_update_neighbours() {
83 local device=${1}
84 local address=${2}
85
86 # Don't do anything on PPP devices.
87 device_is_ppp ${device} && return ${EXIT_OK}
88
89 arping -q -A -c 1 -I ${device} ${address}
90 ( sleep 2; arping -q -U -c 1 -I ${device} ${address} ) >/dev/null 2>&1 </dev/null &
91 }
92
93 ipv4_calculate_prefix() {
94 assert [ $# -eq 2 ]
95
96 local address="${1}"
97 local broadcast="${2}"
98
99 inetcalc -4 -p "${address}" "${broadcast}"
100 }
101
102 ipv4_flush_device() {
103 #
104 # Flushes all routes, addresses from the device
105 # and clears the ARP cache.
106 #
107
108 local device=${1}
109 assert isset device
110
111 ip -4 addr flush dev ${device} >/dev/null 2>&1
112 ip -4 route flush dev ${device} >/dev/null 2>&1
113 ip -4 neigh flush dev ${device} >/dev/null 2>&1
114
115 return 0
116 }
117
118 ipv4_prefix2netmask() {
119 local prefix="${1}"
120
121 case "${prefix}" in
122 32)
123 echo "255.255.255.255"
124 ;;
125 31)
126 echo "255.255.255.254"
127 ;;
128 30)
129 echo "255.255.255.252"
130 ;;
131 29)
132 echo "255.255.255.248"
133 ;;
134 28)
135 echo "255.255.255.240"
136 ;;
137 27)
138 echo "255.255.255.224"
139 ;;
140 26)
141 echo "255.255.255.192"
142 ;;
143 25)
144 echo "255.255.255.128"
145 ;;
146 24)
147 echo "255.255.255.0"
148 ;;
149 23)
150 echo "255.255.254.0"
151 ;;
152 22)
153 echo "255.255.252.0"
154 ;;
155 21)
156 echo "255.255.248.0"
157 ;;
158 20)
159 echo "255.255.240.0"
160 ;;
161 19)
162 echo "255.255.224.0"
163 ;;
164 18)
165 echo "255.255.192.0"
166 ;;
167 17)
168 echo "255.255.128.0"
169 ;;
170 16)
171 echo "255.255.0.0"
172 ;;
173 15)
174 echo "255.254.0.0"
175 ;;
176 14)
177 echo "255.252.0.0"
178 ;;
179 13)
180 echo "255.248.0.0"
181 ;;
182 12)
183 echo "255.240.0.0"
184 ;;
185 11)
186 echo "255.224.0.0"
187 ;;
188 10)
189 echo "255.192.0.0"
190 ;;
191 9)
192 echo "255.128.0.0"
193 ;;
194 8)
195 echo "255.0.0.0"
196 ;;
197 7)
198 echo "254.0.0.0"
199 ;;
200 6)
201 echo "252.0.0.0"
202 ;;
203 5)
204 echo "248.0.0.0"
205 ;;
206 4)
207 echo "240.0.0.0"
208 ;;
209 3)
210 echo "224.0.0.0"
211 ;;
212 2)
213 echo "192.0.0.0"
214 ;;
215 1)
216 echo "128.0.0.0"
217 ;;
218 0)
219 echo "0.0.0.0"
220 ;;
221 *)
222 return ${EXIT_ERROR}
223 ;;
224 esac
225
226 return ${EXIT_OK}
227 }
228
229 ipv4_netmask2prefix() {
230 local netmask="${1}"
231 assert isset netmask
232
233 local mask=0
234
235 local field
236 for field in ${netmask//\./ }; do
237 mask=$(( $(( ${mask} << 8 )) | ${field} ))
238 done
239
240 local cidr=0
241 local x="$(( 128 << 24 ))" # 0x80000000
242
243 while [ $(( ${x} & ${mask} )) -ne 0 ]; do
244 [ ${mask} -eq ${x} ] && mask=0 || mask=$(( ${mask} << 1 ))
245 cidr=$(( ${cidr} + 1 ))
246 done
247
248 assert [ $(( ${mask} & 2147483647 )) -eq 0 ]
249
250 print "${cidr}"
251 }
252
253 ipv4_get_network() {
254 ip_get_network $@
255 }
256
257 ipv4_get_broadcast() {
258 inetcalc -4 -b $@ && return ${EXIT_OK} || return ${EXIT_ERROR}
259 }
260
261 ipv4_encode() {
262 local addr=${1}
263 local int=0
264
265 local field
266 for field in ${addr//./ }; do
267 int=$(( $(( ${int} << 8 )) | ${field} ))
268 done
269
270 print "${int}"
271 }
272
273 ipv4_decode() {
274 local int=${1}
275
276 local addr=$(( ${int} & 255 ))
277
278 local i
279 for i in 1 2 3; do
280 int=$(( ${int} >> 8 ))
281 addr="$(( ${int} & 255 )).${addr}"
282 done
283
284 print "${addr}"
285 }
286
287 ipv4_addr_eq() {
288 local addr1=${1}
289 assert isset addr1
290
291 local addr2=${2}
292 assert isset addr2
293
294 [[ "${addr1}" = "${addr2}" ]] \
295 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
296 }
297
298 ipv4_addr_gt() {
299 assert [ $# -eq 2 ]
300
301 local addr1="${1}"
302 local addr2="${2}"
303
304 inetcalc -4 -g "${addr1}" "${addr2}" \
305 && return ${EXIT_TRUE} || return ${EXIT_FALSE}
306 }
307
308 ipv4_addr_ge() {
309 ipv4_addr_eq $@ || ipv4_addr_gt $@
310 }
311
312 ipv4_addr_lt() {
313 ! ipv4_addr_eq $@ && ! ipv4_addr_gt $@
314 }
315
316 ipv4_addr_le() {
317 ipv4_addr_eq $@ || ! ipv4_addr_gt $@
318 }
319
320 ipv4_range() {
321 local range=${1}
322
323 local first=${1%-*}
324 local last=${1#*-}
325
326 _ipv4_range "$(ipv4_encode ${first})" "$(ipv4_encode ${last})"
327 }
328
329 _ipv4_range() {
330 local first=${1}
331 local last=${2}
332
333 if [ ${first} -gt ${last} ]; then
334 local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})"
335
336 error "Invalid IPv4 address range: ${range}"
337 return ${EXIT_ERROR}
338 fi
339
340 last=$(( ${last} + 1 ))
341
342 local prefix
343 local x y z
344 while [ ${last} -gt ${first} ]; do
345 prefix=
346 x=31
347 y=2
348 z=1
349
350 while [ $(( ${first} % ${y} )) -eq 0 ] && [ ${last} -gt $(( ${first} + ${y} )) ]; do
351 prefix="/${x}"
352 x=$(( ${x} - 1 ))
353 z=${y}
354 y=$(( ${y} * 2 ))
355 done
356
357 print "$(ipv4_decode ${first})${prefix}"
358 first=$(( ${first} + ${z} ))
359 done
360 }
361
362 ipv4_range_explicit() {
363 local range=${1}
364
365 local first last
366
367 case "${range}" in
368 *.*.*.*-*.*.*.*)
369 first=${range%-*}
370 last=${range#*-}
371 ;;
372 *.*.*.*/*)
373 first=$(ipv4_get_network ${range})
374 first="$(ip_split_prefix "${range}")"
375 last=$(ipv4_get_broadcast ${range})
376 last="$(ip_split_prefix "${range}")"
377 ;;
378 esac
379
380 _ipv4_range_explicit "$(ipv4_encode ${first})" "$(ipv4_encode ${last})"
381 }
382
383 _ipv4_range_explicit() {
384 local first=${1}
385 local last=${2}
386
387 if [ ${first} -gt ${last} ]; then
388 local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})"
389
390 error "Invalid IPv4 address range: ${range}"
391 return ${EXIT_ERROR}
392 fi
393
394 while [ ${first} -le ${last} ]; do
395 ipv4_decode ${first}
396 first=$(( ${first} + 1 ))
397 done
398 }
399
400 ipv4_in_subnet() {
401 local addr=${1}
402 assert isset addr
403
404 local subnet=${2}
405 assert isset subnet
406
407 local subnet_first=$(ipv4_get_network_encoded ${subnet})
408 local subnet_last=$(ipv4_get_broadcast_encoded ${subnet})
409
410 addr=$(ipv4_encode ${addr})
411
412 if [[ "${addr}" -ge "${subnet_first}" ]] && [[ "${addr}" -le "${subnet_last}" ]]; then
413 return ${EXIT_TRUE}
414 fi
415
416 return ${EXIT_FALSE}
417 }
418
419 ipv4_ttl_valid() {
420 local ttl="${1}"
421
422 isinteger ttl || return ${EXIT_FALSE}
423
424 # Must be between 10 and 255.
425 [ "${ttl}" -lt 10 ] && return ${EXIT_FALSE}
426 [ "${ttl}" -gt 255 ] && return ${EXIT_FALSE}
427
428 return ${EXIT_TRUE}
429 }