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