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