]> git.ipfire.org Git - people/amarx/ipfire-3.x.git/blame - pkgs/core/network/src/functions
network: New package.
[people/amarx/ipfire-3.x.git] / pkgs / core / network / src / functions
CommitLineData
63ef8328
MT
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
e68e56b5 22HOME_DIR=${HOME_DIR-/lib/network}
84b5fed9 23CONFIG_DIR=/etc/network
6ad03435 24HOOKS_DIR=${HOME_DIR}/hooks
642c6f37
MT
25LOG_DIR=/var/log/network
26
27CONNECTIONS_FILE=/var/log/network/connections.db
ae69ea7e
MT
28
29CONFIG_ZONES=${CONFIG_DIR}/zones
30CONFIG_PORTS=${CONFIG_DIR}/ports
42b87165 31CONFIG_HOOKS=${CONFIG_DIR}/hooks
642c6f37 32CONFIG_PPP=${CONFIG_DIR}/ppp
42b87165
MT
33CONFIG_UUIDS=${CONFIG_DIR}/uuids
34
35# Create config directories
36for dir in ${CONFIG_ZONES} ${CONFIG_PORTS} ${CONFIG_HOOKS} ${CONFIG_PPP} ${CONFIG_UUIDS}; do
37 [ -d "${dir}" ] && continue
38 mkdir -p "${dir}"
39done
b5238f57 40
2b6a66e1 41COMMON_DEVICE=port+
cd1bc684 42
6ad03435
MT
43EXIT_OK=0
44EXIT_ERROR=1
45EXIT_CONF_ERROR=2
46
e70f9d78
MT
47VALID_ZONES="blue green orange red grey"
48
6ad03435
MT
49[ -n "${DEBUG}" ] || DEBUG=
50[ -n "${VERBOSE}" ] || VERBOSE=
51
b5238f57 52function is_mac() {
e70f9d78 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]$ ]]
b5238f57 54}
63ef8328 55
d28dce25
MT
56function 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
63ef8328 70function get_device_by_mac() {
e70f9d78 71 local mac=${1}
4bded844 72 local device
ae69ea7e 73
4bded844 74 for device in /sys/class/net/*; do
42b87165 75 [ -d "${device}" ] || continue
4bded844
MT
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
63ef8328
MT
88 fi
89 done
4bded844 90 return 1
63ef8328
MT
91}
92
ae69ea7e 93function get_device_by_mac_and_vid() {
6ad03435
MT
94 local mac=$1
95 local vid=$2
ae69ea7e
MT
96
97 local i
98 local VID
99 local DEVICE
4bded844
MT
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
ae69ea7e
MT
109 return 1
110}
111
90af6f24
MT
112function 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
63ef8328 120function get_mac_by_device() {
ae69ea7e
MT
121 local device
122 device=$1
63ef8328
MT
123 if [ -d "/sys/class/net/$device" ]; then
124 cat /sys/class/net/$device/address
125 return 0
126 fi
127 return 1
128}
b5238f57 129
90af6f24
MT
130function get_mac() {
131 get_mac_by_device $@
132}
133
ae69ea7e 134function devicify() {
6ad03435 135 local device=${1}
ae69ea7e
MT
136 local mac
137
76210e7e
MT
138 [ -n "${device}" ] || return 1
139
ae69ea7e
MT
140 if is_mac ${device}; then
141 mac=${device}
142 device=$(get_device_by_mac ${device})
143 fi
4bded844
MT
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
ae69ea7e
MT
151}
152
153function macify() {
6ad03435 154 local input=${1}
ae69ea7e
MT
155 local mac
156
ae69ea7e
MT
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
b5238f57 165function device_exists() {
42b87165
MT
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
172function device_is_bonding() {
173 [ -d "/sys/class/net/${1}/bonding" ]
174}
175
176function 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
ae69ea7e
MT
190}
191
8ff69702
MT
192function device_is_bridge() {
193 [ -d "/sys/class/net/${1}/bridge" ]
194}
195
cd1bc684
MT
196function device_is_up() {
197 ip link show $(devicify ${1}) 2>/dev/null | grep -qE "<.*UP.*>"
198}
199
42b87165
MT
200function 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
8ff69702
MT
207function device_is_ppp() {
208 # XXX need something better
209 [ "${1:0:3}" = "ppp" ]
210}
211
d28dce25
MT
212function device_is_loopback() {
213 local device=$(devicify ${1})
214 [ "${device}" = "lo" ]
215}
216
8ff69702
MT
217function device_is_real() {
218 local device=${1}
219
d28dce25 220 device_is_loopback ${device} && \
8ff69702
MT
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
d28dce25
MT
238function 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
42b87165
MT
264function 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
26bfb541
MT
271function device_has_carrier() {
272 local device=$(devicify ${1})
273 [ "$(</sys/class/net/${device}/carrier)" = "1" ]
274}
275
42b87165
MT
276function device_get_free() {
277 local destination=${1}
ae69ea7e 278
4bded844 279 # Replace + by a valid number
02dbf7e7 280 if grep -q "+$" <<<${destination}; then
76210e7e 281 local number=0
4bded844 282 destination=$(sed -e "s/+//" <<<$destination)
6ad03435 283 while [ "${number}" -le "100" ]; do
4bded844
MT
284 if ! device_exists "${destination}${number}"; then
285 destination="${destination}${number}"
286 break
287 fi
288 number=$(($number + 1))
289 done
290 fi
42b87165
MT
291 echo "${destination}"
292}
293
294function device_rename() {
295 local source=$1
296 local destination=$(device_get_free ${2})
4bded844 297
76210e7e 298 # Check if devices exists
ae69ea7e
MT
299 if ! device_exists ${source} || device_exists ${destination}; then
300 return 4
301 fi
302
26bfb541
MT
303 local up
304 if device_is_up ${source}; then
305 ip link set ${source} down
306 up=1
307 fi
308
ae69ea7e 309 ip link set ${source} name ${destination}
26bfb541
MT
310
311 if [ "${up}" = "1" ]; then
312 ip link set ${destination} up
313 fi
b5238f57
MT
314}
315
6ad03435
MT
316function hook_exists() {
317 [ -x "${HOOKS_DIR}/${1}" ]
318}
319
320function port_exists() {
321 device_exists $@
b5238f57
MT
322}
323
cd1bc684 324function port_is_up() {
6ad03435
MT
325 port_exists $@ && device_is_up $@
326}
327
328function zone_exists() {
329 [ -e "$CONFIG_ZONES/${1}" ]
cd1bc684
MT
330}
331
332function zone_is_up() {
333 zone_exists $@ && device_is_up $@
334}
335
8ff69702
MT
336function 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
b5238f57 354function bridge_devices() {
6ad03435 355 local bridge=$1
ae69ea7e
MT
356 [ -z "${bridge}" ] && return 2
357 brctl show | grep "^${bridge}" | awk '{ print $NF }' | grep -v "^interfaces$"
358}
359
360function zone_add_port() {
6ad03435
MT
361 local zone=${1}
362 local port=${2}
90af6f24
MT
363
364 brctl addif ${zone} ${port}
365}
366
367function zone_del_port() {
6ad03435
MT
368 local zone=${1}
369 local port=${2}
90af6f24
MT
370
371 brctl delif ${zone} ${port}
ae69ea7e
MT
372}
373
6ad03435 374function zone_list() {
ae69ea7e 375 local zone
6ad03435 376 for zone in $(find ${CONFIG_ZONES}/* 2>/dev/null); do
ae69ea7e
MT
377 [ -d "${zone}" ] && echo ${zone}
378 done
b5238f57 379}
1135a884 380
642c6f37
MT
381function zone_is_red() {
382 local zone=${1}
383 [ "${zone#red}" != "${zone}" ]
384}
385
42b87165
MT
386function _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
1135a884
MT
404 local failed
405 local hook
406 local hooks
1135a884
MT
407
408 if [ -z "${action}" ] || [ -z "${dir}" ]; then
409 echo "Not enough parameters given." >&2
410 return 1
411 fi
412
42b87165
MT
413 for hook in $(find ${dir}); do
414 # Skip dirs
415 [ -d "${hook}" ] && continue
416
1135a884
MT
417 (
418 . ${hook}
42b87165
MT
419 # Skip hooks that are not of the given type
420 if [ -n "${type}" ] && [ "$(hook_type ${HOOK})" != "${type}" ]; then
421 continue
422 fi
e70f9d78
MT
423 if [ -n "${HOOK}" ]; then
424 hook_run ${HOOK} --config=${hook} $@ ${action}
1135a884
MT
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}
6ad03435 439
42b87165
MT
440function hooks_run_all() {
441 _run_hooks $@
442}
443
444function hooks_run_ports() {
445 _run_hooks --type="port" $@
446}
447
448function hooks_run_zones() {
449 _run_hooks --type="zone" $@
450}
451
6ad03435
MT
452function hook_type() {
453 local hook=${1}
454 (
42b87165 455 eval $(${HOOKS_DIR}/${hook} info)
6ad03435
MT
456 echo "${HOOK_TYPE}"
457 )
458}
459
8ff69702
MT
460function hook_list() {
461 local type=${1}
462 local hook
463 for hook in ${HOOKS_DIR}/*; do
464 hook=${hook##*/}
465
466 [[ ${hook} =~ helper$ ]] && continue
467
468 if [ -n "${type}" ] && [ "$(hook_type ${hook})" != "${type}" ]; then
469 continue
470 fi
471 echo "${hook}"
472 done
473}
474
6ad03435
MT
475function config_get_hook() {
476 local config=${1}
477 if [ ! -e "${config}" ]; then
478 log_failure_msg "Config file \"${config}\" does not exist."
479 return ${EXIT_ERROR}
480 fi
481 ( . ${config}; echo ${HOOK} )
482}
483
484function hook_run() {
485 local hook=${1}
486 shift
487
488 if ! hook_exists ${hook}; then
489 log_failure_msg "Hook ${hook} cannot be found or is not executeable."
490 return ${EXIT_ERROR}
491 fi
e70f9d78 492 [ -n "${DEBUG}" ] && echo "Running hook: ${hook} $@"
6ad03435
MT
493 DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOOKS_DIR}/${hook} $@
494 return $?
495}
496
497function hook_run_multiple() {
498 local zone
499 local config
500 local hook
501 local hook_type2
502 local type
503
504 while [ "$#" -gt "0" ]; do
505 case "${1}" in
506 --type=*)
507 type=${1#--type=}
508 ;;
509 *)
510 zone=${1}
511 break
512 ;;
513 esac
514 shift
515 done
516
517 if ! zone_exists ${zone}; then
518 return ${EXIT_ERROR}
519 fi
520
521 for config in $(find ${CONFIG_ZONES}/${zone} 2>/dev/null); do
522 hook=$(config_get_hook ${config})
523 if [ -n "${type}" ]; then
524 hook_type2=$(hook_type ${hook})
525 if [ "${type}" != "${hook_type2}" ]; then
526 continue
527 fi
528 fi
529 hook_run ${hook} $@
530 done
531}
532
533function zone_run() {
534 local zone=${1}
535 shift
536
537 if ! zone_exists ${zone}; then
538 log_failure_msg "Zone ${zone} does not exist."
539 exit ${EXIT_ERROR}
540 fi
541 decho "Running zone: ${zone} $@"
542 DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOME_DIR}/zone --zone=${zone} $@
6ad03435 543}
e70f9d78
MT
544
545function zone_valid_name() {
546 local zone=${1}
547 local match
548
549 local i
550 for i in ${VALID_ZONES}; do
551 match="${match}|${i}[0-9]{1,5}"
552 done
553 [[ ${zone} =~ ${match:1:${#match}} ]]
e70f9d78
MT
554}
555
556function isset() {
557 local key=${1}
558 [ -n "${!key}" ] && return
559 if [[ ${key} =~ port|zone ]]; then
560 echo "ERROR: The --${key} flag is not set." >&2
561 else
562 echo "ERROR: The \"${key}\" variable is not set properly." >&2
563 fi
564 return 1
565}
566
567# Test if device is attached to the given bridge
568function zone_has_device_attached () {
569 local zone=${1}
570 local device=${2}
571
e70f9d78 572 [ -d "/sys/class/net/${zone}/brif/${device}" ]
e70f9d78
MT
573}
574
575function device_has_ipv4() {
576 local device=${1}
577 local ip=${2}
578 ip addr show ${device} | grep inet | fgrep -q ${ip}
579}
580
581function check_config() {
582 local failed
583 local i
584
585 for i in $@; do
586 isset ${i} || failed=1
587 done
588 if [ "${failed}" = "1" ]; then
589 echo "Exiting..."
590 exit ${EXIT_ERROR}
591 fi
592}
642c6f37 593
42b87165
MT
594function mac_generate() {
595 local mac="00"
596 while [ "${#mac}" -lt 15 ]; do
597 mac="${mac}:$(cut -c 1-2 /proc/sys/kernel/random/uuid)"
598 done
599 echo "${mac}"
600}
601
642c6f37
MT
602function connection() {
603 local action
604
605 local dns
606 local interface
607 local iplocal
608 local ipremote
609 local name
610 local status
611 local weight
612 local zone
613
614 while [ $# -gt 0 ]; do
615 case "${1}" in
616 --up)
617 action="up"
618 ;;
619 --down)
620 action="down"
621 ;;
622 --starting)
623 action="starting"
624 ;;
625 --stopping)
626 action="stopping"
627 ;;
628 --name=*)
629 name=${1#--name=}
630 ;;
631 --zone=*)
632 zone=${1#--zone=}
633 zone_is_red ${zone} || return 0
634 ;;
635 --interface=*)
636 interface=${1#--interface=}
637 ;;
638 --iplocal=*)
639 iplocal=${1#--iplocal=}
640 ;;
641 --ipremote=*)
642 ipremote=${1#--ipremote=}
643 ;;
644 --weight=*)
645 weight=${1#--weight=}
646 ;;
647 --dns=*)
648 dns=${1#--dns=}
649 ;;
650 esac
651 shift
652 done
653
654 if [ ! -e "${CONNECTIONS_FILE}" ]; then
655 sqlite3 -batch ${CONNECTIONS_FILE} <<EOF
656CREATE TABLE connections(name, zone, interface, iplocal, ipremote, weight, dns, status);
657EOF
658 fi
659
660 if [ -z "${zone}" ]; then
661 return 2
662 fi
663
664 status=${action}
665
666 sqlite3 -batch ${CONNECTIONS_FILE} <<EOF
667DELETE FROM connections WHERE zone = '${zone}';
668INSERT INTO connections(name, zone, interface, iplocal, ipremote, weight, dns, status)
669 VALUES('${name}', '${zone}', '${interface}', '${iplocal}', '${ipremote}', '${weight}', '${dns}', '${status}');
670EOF
671
672}
42b87165
MT
673
674function uuid() {
675 cat /proc/sys/kernel/random/uuid
676}