]> git.ipfire.org Git - people/stevee/network.git/blob - functions
network: Remove support for blue zone.
[people/stevee/network.git] / functions
1 #!/bin/sh
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2009 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 HOME_DIR=${HOME_DIR-/lib/network}
23 CONFIG_DIR=/etc/network
24 HOOKS_DIR=${HOME_DIR}/hooks
25 LOG_DIR=/var/log/network
26
27 CONNECTIONS_FILE=/var/log/network/connections.db
28
29 CONFIG_ZONES=${CONFIG_DIR}/zones
30 CONFIG_PORTS=${CONFIG_DIR}/ports
31 CONFIG_HOOKS=${CONFIG_DIR}/hooks
32 CONFIG_PPP=${CONFIG_DIR}/ppp
33 CONFIG_UUIDS=${CONFIG_DIR}/uuids
34
35 # Create config directories
36 for dir in ${CONFIG_ZONES} ${CONFIG_PORTS} ${CONFIG_HOOKS} ${CONFIG_PPP} ${CONFIG_UUIDS}; do
37 [ -d "${dir}" ] && continue
38 mkdir -p "${dir}"
39 done
40
41 COMMON_DEVICE=port+
42
43 EXIT_OK=0
44 EXIT_ERROR=1
45 EXIT_CONF_ERROR=2
46
47 VALID_ZONES="green orange red grey"
48
49 [ -n "${DEBUG}" ] || DEBUG=
50 [ -n "${VERBOSE}" ] || VERBOSE=
51
52 function is_mac() {
53 [[ $1 =~ ^[0-9a-f][0-9a-f]\:[0-9a-f][0-9a-f]\:[0-9a-f][0-9a-f]\:[0-9a-f][0-9a-f]\:[0-9a-f][0-9a-f]\:[0-9a-f][0-9a-f]$ ]]
54 }
55
56 function is_uuid() {
57 local string=${1}
58
59 # Length must be 37 characters
60 if [ ${#string} -eq 36 ] \
61 && [ "${string:8:1}" = "-" ] \
62 && [ "${string:13:1}" = "-" ] \
63 && [ "${string:18:1}" = "-" ] \
64 && [ "${string:23:1}" = "-" ]; then
65 return ${EXIT_OK}
66 fi
67 return ${EXIT_ERROR}
68 }
69
70 function get_device_by_mac() {
71 local mac=${1}
72 local device
73
74 for device in /sys/class/net/*; do
75 [ -d "${device}" ] || continue
76 if [ "$(cat $device/address)" = "$mac" ]; then
77 device=${device##*/}
78 # Skip virtual devices
79 if [ -e "/proc/net/vlan/$device" ]; then
80 continue
81 fi
82 # Skip zones
83 if zone_exists ${device}; then
84 continue
85 fi
86 echo ${device}
87 return 0
88 fi
89 done
90 return 1
91 }
92
93 function get_device_by_mac_and_vid() {
94 local mac=$1
95 local vid=$2
96
97 local i
98 local VID
99 local DEVICE
100 if [ -e "/proc/net/vlan/config" ]; then
101 grep '|' /proc/net/vlan/config | sed "s/|//g" | \
102 while read DEVICE VID PARENT; do
103 if [ "${vid}" = "${VID}" ] && [ "$(macify ${PARENT})" = "${mac}" ]; then
104 echo "${DEVICE}"
105 return 0
106 fi
107 done
108 fi
109 return 1
110 }
111
112 function get_device() {
113 if [ ${#@} -gt 1 ]; then
114 get_device_by_mac_and_vid $@
115 else
116 get_device_by_mac $@
117 fi
118 }
119
120 function get_mac_by_device() {
121 local device
122 device=$1
123 if [ -d "/sys/class/net/$device" ]; then
124 cat /sys/class/net/$device/address
125 return 0
126 fi
127 return 1
128 }
129
130 function get_mac() {
131 get_mac_by_device $@
132 }
133
134 function devicify() {
135 local device=${1}
136 local mac
137
138 [ -n "${device}" ] || return 1
139
140 if is_mac ${device}; then
141 mac=${device}
142 device=$(get_device_by_mac ${device})
143 fi
144 if [ -n "${device}" ]; then
145 echo ${device}
146 return 0
147 else
148 echo "devicify: Could not find device of $@" >&2
149 return 1
150 fi
151 }
152
153 function macify() {
154 local input=${1}
155 local mac
156
157 if is_mac ${input}; then
158 mac=${input}
159 else
160 mac=$(get_mac_by_device ${input})
161 fi
162 echo ${mac}
163 }
164
165 function device_exists() {
166 [ -n "${1}" ] || return ${EXIT_ERROR}
167 local device=$(devicify ${1})
168 [ -n "${device}" ] || return ${EXIT_ERROR}
169 ip link show ${device} &>/dev/null
170 }
171
172 function device_is_bonding() {
173 [ -d "/sys/class/net/${1}/bonding" ]
174 }
175
176 function device_is_bonded() {
177 local dev
178 for dev in /sys/class/net/*; do
179 # Skip crappy files
180 [ -d "${dev}" ] || continue
181
182 # Continue if not a bonding device
183 device_is_bonding "${dev##*/}" || continue
184
185 if grep -q "\<${1}\>" ${dev}/bonding/slaves; then
186 return 0
187 fi
188 done
189 return 1
190 }
191
192 function device_is_bridge() {
193 [ -d "/sys/class/net/${1}/bridge" ]
194 }
195
196 function device_is_up() {
197 ip link show $(devicify ${1}) 2>/dev/null | grep -qE "<.*UP.*>"
198 }
199
200 function device_is_vlan() {
201 if [ ! -e "/proc/net/vlan/config" ]; then
202 return 1
203 fi
204 grep -q "^${1}" /proc/net/vlan/config
205 }
206
207 function device_is_ppp() {
208 # XXX need something better
209 [ "${1:0:3}" = "ppp" ]
210 }
211
212 function device_is_loopback() {
213 local device=$(devicify ${1})
214 [ "${device}" = "lo" ]
215 }
216
217 function device_is_real() {
218 local device=${1}
219
220 device_is_loopback ${device} && \
221 return ${EXIT_ERROR}
222
223 device_is_bonding ${device} && \
224 return ${EXIT_ERROR}
225
226 device_is_bridge ${device} && \
227 return ${EXIT_ERROR}
228
229 device_is_ppp ${device} && \
230 return ${EXIT_ERROR}
231
232 device_is_vlan ${device} && \
233 return ${EXIT_ERROR}
234
235 return ${EXIT_OK}
236 }
237
238 function device_type() {
239 local device=$(devicify ${1})
240
241 if device_is_vlan ${device}; then
242 echo "vlan"
243
244 elif device_is_bonding ${device}; then
245 echo "bonding"
246
247 elif device_is_bridge ${device}; then
248 echo "bridge"
249
250 elif device_is_ppp ${device}; then
251 echo "ppp"
252
253 elif device_is_loopback ${device}; then
254 echo "loopback"
255
256 elif device_is_real ${device}; then
257 echo "real"
258
259 else
260 echo "unknown"
261 fi
262 }
263
264 function device_has_vlans() {
265 if [ ! -e "/proc/net/vlan/config" ]; then
266 return 1
267 fi
268 grep -q "${1}$" /proc/net/vlan/config
269 }
270
271 function device_has_carrier() {
272 local device=$(devicify ${1})
273 [ "$(</sys/class/net/${device}/carrier)" = "1" ]
274 }
275
276 function device_get_free() {
277 local destination=${1}
278
279 # Replace + by a valid number
280 if grep -q "+$" <<<${destination}; then
281 local number=0
282 destination=$(sed -e "s/+//" <<<$destination)
283 while [ "${number}" -le "100" ]; do
284 if ! device_exists "${destination}${number}"; then
285 destination="${destination}${number}"
286 break
287 fi
288 number=$(($number + 1))
289 done
290 fi
291 echo "${destination}"
292 }
293
294 function device_rename() {
295 local source=$1
296 local destination=$(device_get_free ${2})
297
298 # Check if devices exists
299 if ! device_exists ${source} || device_exists ${destination}; then
300 return 4
301 fi
302
303 local up
304 if device_is_up ${source}; then
305 ip link set ${source} down
306 up=1
307 fi
308
309 ip link set ${source} name ${destination}
310
311 if [ "${up}" = "1" ]; then
312 ip link set ${destination} up
313 fi
314 }
315
316 function hook_exists() {
317 [ -x "${HOOKS_DIR}/${1}" ]
318 }
319
320 function port_exists() {
321 device_exists $@
322 }
323
324 function port_is_up() {
325 port_exists $@ && device_is_up $@
326 }
327
328 function zone_exists() {
329 [ -e "$CONFIG_ZONES/${1}" ]
330 }
331
332 function zone_is_up() {
333 zone_exists $@ && device_is_up $@
334 }
335
336 function zone_is_forwarding() {
337 local seconds=45
338 local zone=${1}
339
340 local device
341 while [ ${seconds} -gt 0 ]; do
342 for device in /sys/class/net/${zone}/brif/*; do
343 [ -e "${device}/state" ] || continue
344 if [ "$(<${device}/state)" = "3" ]; then
345 return ${EXIT_OK}
346 fi
347 done
348 sleep 1
349 seconds=$((${seconds} - 1))
350 done
351 return ${EXIT_ERROR}
352 }
353
354 function bridge_devices() {
355 local bridge=$1
356 [ -z "${bridge}" ] && return 2
357 brctl show | grep "^${bridge}" | awk '{ print $NF }' | grep -v "^interfaces$"
358 }
359
360 function zone_add_port() {
361 local zone=${1}
362 local port=${2}
363
364 brctl addif ${zone} ${port}
365 }
366
367 function zone_del_port() {
368 local zone=${1}
369 local port=${2}
370
371 brctl delif ${zone} ${port}
372 }
373
374 function zone_list() {
375 local zone
376 for zone in $(find ${CONFIG_ZONES}/* 2>/dev/null); do
377 [ -d "${zone}" ] && echo ${zone}
378 done
379 }
380
381 function zone_is_red() {
382 local zone=${1}
383 [ "${zone#red}" != "${zone}" ]
384 }
385
386 function _run_hooks() {
387 local action
388 local type
389
390 while [ $# -gt 0 ]; do
391 case "${1}" in
392 --type=*)
393 type=${1#--type=}
394 ;;
395 *)
396 action="${1}"
397 shift; break
398 ;;
399 esac
400 shift
401 done
402
403 local dir=${1}; shift
404 local failed
405 local hook
406 local hooks
407
408 if [ -z "${action}" ] || [ -z "${dir}" ]; then
409 echo "Not enough parameters given." >&2
410 return 1
411 fi
412
413 for hook in $(find ${dir}); do
414 # Skip dirs
415 [ -d "${hook}" ] && continue
416
417 (
418 . ${hook}
419 # Skip hooks that are not of the given type
420 if [ -n "${type}" ] && [ "$(hook_type ${HOOK})" != "${type}" ]; then
421 continue
422 fi
423 if [ -n "${HOOK}" ]; then
424 hook_run ${HOOK} --config=${hook} $@ ${action}
425 RET=$?
426 else
427 echo -e "${FAILURE}Unable to process ${hook}. Either"
428 echo -e "${FAILURE}the HOOK variable was not set,"
429 echo -e "${FAILURE}or the specified hook cannot be executed."
430 message=""
431 log_failure_msg
432 fi
433 exit ${RET}
434 ) || failed=1
435 done
436
437 return ${failed}
438 }
439
440 function hooks_run_all() {
441 _run_hooks $@
442 }
443
444 function hooks_run_ports() {
445 _run_hooks --type="port" $@
446 }
447
448 function hooks_run_zones() {
449 _run_hooks --type="zone" $@
450 }
451
452 function hook_type() {
453 local hook=${1}
454 (
455 eval $(${HOOKS_DIR}/${hook} info)
456 echo "${HOOK_TYPE}"
457 )
458 }
459
460 function hook_list() {
461 local type=${1}
462 local hook
463 for hook in ${HOOKS_DIR}/*; do
464 [ -x "${hook}" ] || continue
465
466 hook=${hook##*/}
467
468 [[ ${hook} =~ helper$ ]] && continue
469
470 if [ -n "${type}" ] && [ "$(hook_type ${hook})" != "${type}" ]; then
471 continue
472 fi
473 echo "${hook}"
474 done
475 }
476
477 function config_get_hook() {
478 local config=${1}
479 if [ ! -e "${config}" ]; then
480 log_failure_msg "Config file \"${config}\" does not exist."
481 return ${EXIT_ERROR}
482 fi
483 ( . ${config}; echo ${HOOK} )
484 }
485
486 function hook_run() {
487 local hook=${1}
488 shift
489
490 if ! hook_exists ${hook}; then
491 log_failure_msg "Hook ${hook} cannot be found or is not executeable."
492 return ${EXIT_ERROR}
493 fi
494 [ -n "${DEBUG}" ] && echo "Running hook: ${hook} $@"
495 DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOOKS_DIR}/${hook} $@
496 return $?
497 }
498
499 function hook_run_multiple() {
500 local zone
501 local config
502 local hook
503 local hook_type2
504 local type
505
506 while [ "$#" -gt "0" ]; do
507 case "${1}" in
508 --type=*)
509 type=${1#--type=}
510 ;;
511 *)
512 zone=${1}
513 break
514 ;;
515 esac
516 shift
517 done
518
519 if ! zone_exists ${zone}; then
520 return ${EXIT_ERROR}
521 fi
522
523 for config in $(find ${CONFIG_ZONES}/${zone} 2>/dev/null); do
524 hook=$(config_get_hook ${config})
525 if [ -n "${type}" ]; then
526 hook_type2=$(hook_type ${hook})
527 if [ "${type}" != "${hook_type2}" ]; then
528 continue
529 fi
530 fi
531 hook_run ${hook} $@
532 done
533 }
534
535 function zone_run() {
536 local zone=${1}
537 shift
538
539 if ! zone_exists ${zone}; then
540 log_failure_msg "Zone ${zone} does not exist."
541 exit ${EXIT_ERROR}
542 fi
543 decho "Running zone: ${zone} $@"
544 DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOME_DIR}/zone --zone=${zone} $@
545 }
546
547 function zone_valid_name() {
548 local zone=${1}
549 local match
550
551 local i
552 for i in ${VALID_ZONES}; do
553 match="${match}|${i}[0-9]{1,5}"
554 done
555 [[ ${zone} =~ ${match:1:${#match}} ]]
556 }
557
558 function isset() {
559 local key=${1}
560 [ -n "${!key}" ] && return
561 if [[ ${key} =~ port|zone ]]; then
562 echo "ERROR: The --${key} flag is not set." >&2
563 else
564 echo "ERROR: The \"${key}\" variable is not set properly." >&2
565 fi
566 return 1
567 }
568
569 # Test if device is attached to the given bridge
570 function zone_has_device_attached () {
571 local zone=${1}
572 local device=${2}
573
574 [ -d "/sys/class/net/${zone}/brif/${device}" ]
575 }
576
577 function device_has_ipv4() {
578 local device=${1}
579 local ip=${2}
580 ip addr show ${device} | grep inet | fgrep -q ${ip}
581 }
582
583 function check_config() {
584 local failed
585 local i
586
587 for i in $@; do
588 isset ${i} || failed=1
589 done
590 if [ "${failed}" = "1" ]; then
591 echo "Exiting..."
592 exit ${EXIT_ERROR}
593 fi
594 }
595
596 function mac_generate() {
597 local mac="00"
598 while [ "${#mac}" -lt 15 ]; do
599 mac="${mac}:$(cut -c 1-2 /proc/sys/kernel/random/uuid)"
600 done
601 echo "${mac}"
602 }
603
604 function connection() {
605 local action
606
607 local dns
608 local interface
609 local iplocal
610 local ipremote
611 local name
612 local status
613 local weight
614 local zone
615
616 while [ $# -gt 0 ]; do
617 case "${1}" in
618 --up)
619 action="up"
620 ;;
621 --down)
622 action="down"
623 ;;
624 --starting)
625 action="starting"
626 ;;
627 --stopping)
628 action="stopping"
629 ;;
630 --name=*)
631 name=${1#--name=}
632 ;;
633 --zone=*)
634 zone=${1#--zone=}
635 zone_is_red ${zone} || return 0
636 ;;
637 --interface=*)
638 interface=${1#--interface=}
639 ;;
640 --iplocal=*)
641 iplocal=${1#--iplocal=}
642 ;;
643 --ipremote=*)
644 ipremote=${1#--ipremote=}
645 ;;
646 --weight=*)
647 weight=${1#--weight=}
648 ;;
649 --dns=*)
650 dns=${1#--dns=}
651 ;;
652 esac
653 shift
654 done
655
656 if [ ! -e "${CONNECTIONS_FILE}" ]; then
657 sqlite3 -batch ${CONNECTIONS_FILE} <<EOF
658 CREATE TABLE connections(name, zone, interface, iplocal, ipremote, weight, dns, status);
659 EOF
660 fi
661
662 if [ -z "${zone}" ]; then
663 return 2
664 fi
665
666 status=${action}
667
668 sqlite3 -batch ${CONNECTIONS_FILE} <<EOF
669 DELETE FROM connections WHERE zone = '${zone}';
670 INSERT INTO connections(name, zone, interface, iplocal, ipremote, weight, dns, status)
671 VALUES('${name}', '${zone}', '${interface}', '${iplocal}', '${ipremote}', '${weight}', '${dns}', '${status}');
672 EOF
673
674 }
675
676 function uuid() {
677 cat /proc/sys/kernel/random/uuid
678 }