2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2009 Michael Tremer & Christian Schmidt #
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. #
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. #
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/>. #
20 ###############################################################################
22 HOME_DIR
=${HOME_DIR-/lib/network}
23 CONFIG_DIR
=/etc
/network
24 HOOKS_DIR
=${HOME_DIR}/hooks
25 LOG_DIR
=/var
/log
/network
27 CONNECTIONS_FILE
=/var
/log
/network
/connections.db
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
35 # Create config directories
36 for dir
in ${CONFIG_ZONES} ${CONFIG_PORTS} ${CONFIG_HOOKS} ${CONFIG_PPP} ${CONFIG_UUIDS}; do
37 [ -d "${dir}" ] && continue
47 VALID_ZONES
="blue green orange red grey"
49 [ -n "${DEBUG}" ] || DEBUG
=
50 [ -n "${VERBOSE}" ] || VERBOSE
=
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]$
]]
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
70 function get_device_by_mac
() {
74 for device
in /sys
/class
/net
/*; do
75 [ -d "${device}" ] ||
continue
76 if [ "$(cat $device/address)" = "$mac" ]; then
78 # Skip virtual devices
79 if [ -e "/proc/net/vlan/$device" ]; then
83 if zone_exists
${device}; then
93 function get_device_by_mac_and_vid
() {
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
112 function get_device
() {
113 if [ ${#@} -gt 1 ]; then
114 get_device_by_mac_and_vid $@
120 function get_mac_by_device
() {
123 if [ -d "/sys/class/net/$device" ]; then
124 cat /sys
/class
/net
/$device/address
134 function devicify
() {
138 [ -n "${device}" ] ||
return 1
140 if is_mac
${device}; then
142 device
=$
(get_device_by_mac
${device})
144 if [ -n "${device}" ]; then
148 echo "devicify: Could not find device of $@" >&2
157 if is_mac
${input}; then
160 mac
=$
(get_mac_by_device
${input})
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
172 function device_is_bonding
() {
173 [ -d "/sys/class/net/${1}/bonding" ]
176 function device_is_bonded
() {
178 for dev
in /sys
/class
/net
/*; do
180 [ -d "${dev}" ] ||
continue
182 # Continue if not a bonding device
183 device_is_bonding
"${dev##*/}" ||
continue
185 if grep -q "\<${1}\>" ${dev}/bonding
/slaves
; then
192 function device_is_bridge
() {
193 [ -d "/sys/class/net/${1}/bridge" ]
196 function device_is_up
() {
197 ip link show $
(devicify
${1}) 2>/dev
/null |
grep -qE "<.*UP.*>"
200 function device_is_vlan
() {
201 if [ ! -e "/proc/net/vlan/config" ]; then
204 grep -q "^${1}" /proc
/net
/vlan
/config
207 function device_is_ppp
() {
208 # XXX need something better
209 [ "${1:0:3}" = "ppp" ]
212 function device_is_loopback
() {
213 local device
=$
(devicify
${1})
214 [ "${device}" = "lo" ]
217 function device_is_real
() {
220 device_is_loopback
${device} && \
223 device_is_bonding
${device} && \
226 device_is_bridge
${device} && \
229 device_is_ppp
${device} && \
232 device_is_vlan
${device} && \
238 function device_type
() {
239 local device
=$
(devicify
${1})
241 if device_is_vlan
${device}; then
244 elif device_is_bonding
${device}; then
247 elif device_is_bridge
${device}; then
250 elif device_is_ppp
${device}; then
253 elif device_is_loopback
${device}; then
256 elif device_is_real
${device}; then
264 function device_has_vlans
() {
265 if [ ! -e "/proc/net/vlan/config" ]; then
268 grep -q "${1}$" /proc
/net
/vlan
/config
271 function device_has_carrier
() {
272 local device
=$
(devicify
${1})
273 [ "$(</sys/class/net/${device}/carrier)" = "1" ]
276 function device_get_free
() {
277 local destination
=${1}
279 # Replace + by a valid number
280 if grep -q "+$" <<<${destination}; then
282 destination
=$
(sed -e "s/+//" <<<$destination)
283 while [ "${number}" -le "100" ]; do
284 if ! device_exists
"${destination}${number}"; then
285 destination
="${destination}${number}"
288 number
=$
(($number + 1))
291 echo "${destination}"
294 function device_rename
() {
296 local destination
=$
(device_get_free
${2})
298 # Check if devices exists
299 if ! device_exists
${source} || device_exists
${destination}; then
304 if device_is_up
${source}; then
305 ip link
set ${source} down
309 ip link
set ${source} name
${destination}
311 if [ "${up}" = "1" ]; then
312 ip link
set ${destination} up
316 function hook_exists
() {
317 [ -x "${HOOKS_DIR}/${1}" ]
320 function port_exists
() {
324 function port_is_up
() {
325 port_exists $@
&& device_is_up $@
328 function zone_exists
() {
329 [ -e "$CONFIG_ZONES/${1}" ]
332 function zone_is_up
() {
333 zone_exists $@
&& device_is_up $@
336 function zone_is_forwarding
() {
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
349 seconds
=$
((${seconds} - 1))
354 function bridge_devices
() {
356 [ -z "${bridge}" ] && return 2
357 brctl show |
grep "^${bridge}" |
awk '{ print $NF }' |
grep -v "^interfaces$"
360 function zone_add_port
() {
364 brctl addif
${zone} ${port}
367 function zone_del_port
() {
371 brctl delif
${zone} ${port}
374 function zone_list
() {
376 for zone
in $
(find ${CONFIG_ZONES}/* 2>/dev
/null
); do
377 [ -d "${zone}" ] && echo ${zone}
381 function zone_is_red
() {
383 [ "${zone#red}" != "${zone}" ]
386 function _run_hooks
() {
390 while [ $# -gt 0 ]; do
403 local dir
=${1}; shift
408 if [ -z "${action}" ] ||
[ -z "${dir}" ]; then
409 echo "Not enough parameters given." >&2
413 for hook
in $
(find ${dir}); do
415 [ -d "${hook}" ] && continue
419 # Skip hooks that are not of the given type
420 if [ -n "${type}" ] && [ "$(hook_type ${HOOK})" != "${type}" ]; then
423 if [ -n "${HOOK}" ]; then
424 hook_run
${HOOK} --config=${hook} $@ ${action}
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."
440 function hooks_run_all
() {
444 function hooks_run_ports
() {
445 _run_hooks
--type="port" $@
448 function hooks_run_zones
() {
449 _run_hooks
--type="zone" $@
452 function hook_type
() {
455 eval $
(${HOOKS_DIR}/${hook} info
)
460 function hook_list
() {
463 for hook
in ${HOOKS_DIR}/*; do
466 [[ ${hook} =~ helper$
]] && continue
468 if [ -n "${type}" ] && [ "$(hook_type ${hook})" != "${type}" ]; then
475 function config_get_hook
() {
477 if [ ! -e "${config}" ]; then
478 log_failure_msg
"Config file \"${config}\" does not exist."
481 ( .
${config}; echo ${HOOK} )
484 function hook_run
() {
488 if ! hook_exists
${hook}; then
489 log_failure_msg
"Hook ${hook} cannot be found or is not executeable."
492 [ -n "${DEBUG}" ] && echo "Running hook: ${hook} $@"
493 DEBUG
=${DEBUG} VERBOSE=${VERBOSE} ${HOOKS_DIR}/${hook} $@
497 function hook_run_multiple
() {
504 while [ "$#" -gt "0" ]; do
517 if ! zone_exists
${zone}; then
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
533 function zone_run
() {
537 if ! zone_exists
${zone}; then
538 log_failure_msg
"Zone ${zone} does not exist."
541 decho
"Running zone: ${zone} $@"
542 DEBUG
=${DEBUG} VERBOSE=${VERBOSE} ${HOME_DIR}/zone --zone=${zone} $@
545 function zone_valid_name
() {
550 for i
in ${VALID_ZONES}; do
551 match
="${match}|${i}[0-9]{1,5}"
553 [[ ${zone} =~
${match:1:${#match}} ]]
558 [ -n "${!key}" ] && return
559 if [[ ${key} =~ port|zone
]]; then
560 echo "ERROR: The --${key} flag is not set." >&2
562 echo "ERROR: The \"${key}\" variable is not set properly." >&2
567 # Test if device is attached to the given bridge
568 function zone_has_device_attached
() {
572 [ -d "/sys/class/net/${zone}/brif/${device}" ]
575 function device_has_ipv4
() {
578 ip addr show
${device} |
grep inet | fgrep
-q ${ip}
581 function check_config
() {
586 isset
${i} || failed
=1
588 if [ "${failed}" = "1" ]; then
594 function mac_generate
() {
596 while [ "${#mac}" -lt 15 ]; do
597 mac
="${mac}:$(cut -c 1-2 /proc/sys/kernel/random/uuid)"
602 function connection
() {
614 while [ $# -gt 0 ]; do
633 zone_is_red
${zone} ||
return 0
636 interface
=${1#--interface=}
639 iplocal
=${1#--iplocal=}
642 ipremote
=${1#--ipremote=}
645 weight
=${1#--weight=}
654 if [ ! -e "${CONNECTIONS_FILE}" ]; then
655 sqlite3
-batch ${CONNECTIONS_FILE} <<EOF
656 CREATE TABLE connections(name, zone, interface, iplocal, ipremote, weight, dns, status);
660 if [ -z "${zone}" ]; then
666 sqlite3
-batch ${CONNECTIONS_FILE} <<EOF
667 DELETE FROM connections WHERE zone = '${zone}';
668 INSERT INTO connections(name, zone, interface, iplocal, ipremote, weight, dns, status)
669 VALUES('${name}', '${zone}', '${interface}', '${iplocal}', '${ipremote}', '${weight}', '${dns}', '${status}');
675 cat /proc
/sys
/kernel
/random
/uuid