#!/bin/sh ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2009 Michael Tremer & Christian Schmidt # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### HOME_DIR=${HOME_DIR-/lib/network} CONFIG_DIR=/etc/network HOOKS_DIR=${HOME_DIR}/hooks LOG_DIR=/var/log/network CONNECTIONS_FILE=/var/log/network/connections.db CONFIG_ZONES=${CONFIG_DIR}/zones CONFIG_PORTS=${CONFIG_DIR}/ports CONFIG_HOOKS=${CONFIG_DIR}/hooks CONFIG_PPP=${CONFIG_DIR}/ppp CONFIG_UUIDS=${CONFIG_DIR}/uuids # Create config directories for dir in ${CONFIG_ZONES} ${CONFIG_PORTS} ${CONFIG_HOOKS} ${CONFIG_PPP} ${CONFIG_UUIDS}; do [ -d "${dir}" ] && continue mkdir -p "${dir}" done COMMON_DEVICE=port+ EXIT_OK=0 EXIT_ERROR=1 EXIT_CONF_ERROR=2 VALID_ZONES="green orange red grey" [ -n "${DEBUG}" ] || DEBUG= [ -n "${VERBOSE}" ] || VERBOSE= function is_mac() { [[ $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]$ ]] } function is_uuid() { local string=${1} # Length must be 37 characters if [ ${#string} -eq 36 ] \ && [ "${string:8:1}" = "-" ] \ && [ "${string:13:1}" = "-" ] \ && [ "${string:18:1}" = "-" ] \ && [ "${string:23:1}" = "-" ]; then return ${EXIT_OK} fi return ${EXIT_ERROR} } function get_device_by_mac() { local mac=${1} local device for device in /sys/class/net/*; do [ -d "${device}" ] || continue if [ "$(cat $device/address)" = "$mac" ]; then device=${device##*/} # Skip virtual devices if [ -e "/proc/net/vlan/$device" ]; then continue fi # Skip zones if zone_exists ${device}; then continue fi echo ${device} return 0 fi done return 1 } function get_device_by_mac_and_vid() { local mac=$1 local vid=$2 local i local VID local DEVICE if [ -e "/proc/net/vlan/config" ]; then grep '|' /proc/net/vlan/config | sed "s/|//g" | \ while read DEVICE VID PARENT; do if [ "${vid}" = "${VID}" ] && [ "$(macify ${PARENT})" = "${mac}" ]; then echo "${DEVICE}" return 0 fi done fi return 1 } function get_device() { if [ ${#@} -gt 1 ]; then get_device_by_mac_and_vid $@ else get_device_by_mac $@ fi } function get_mac_by_device() { local device device=$1 if [ -d "/sys/class/net/$device" ]; then cat /sys/class/net/$device/address return 0 fi return 1 } function get_mac() { get_mac_by_device $@ } function devicify() { local device=${1} local mac [ -n "${device}" ] || return 1 if is_mac ${device}; then mac=${device} device=$(get_device_by_mac ${device}) fi if [ -n "${device}" ]; then echo ${device} return 0 else echo "devicify: Could not find device of $@" >&2 return 1 fi } function macify() { local input=${1} local mac if is_mac ${input}; then mac=${input} else mac=$(get_mac_by_device ${input}) fi echo ${mac} } function device_exists() { [ -n "${1}" ] || return ${EXIT_ERROR} local device=$(devicify ${1}) [ -n "${device}" ] || return ${EXIT_ERROR} ip link show ${device} &>/dev/null } function device_is_bonding() { [ -d "/sys/class/net/${1}/bonding" ] } function device_is_bonded() { local dev for dev in /sys/class/net/*; do # Skip crappy files [ -d "${dev}" ] || continue # Continue if not a bonding device device_is_bonding "${dev##*/}" || continue if grep -q "\<${1}\>" ${dev}/bonding/slaves; then return 0 fi done return 1 } function device_is_bridge() { [ -d "/sys/class/net/${1}/bridge" ] } function device_is_up() { ip link show $(devicify ${1}) 2>/dev/null | grep -qE "<.*UP.*>" } function device_is_vlan() { if [ ! -e "/proc/net/vlan/config" ]; then return 1 fi grep -q "^${1}" /proc/net/vlan/config } function device_is_ppp() { # XXX need something better [ "${1:0:3}" = "ppp" ] } function device_is_loopback() { local device=$(devicify ${1}) [ "${device}" = "lo" ] } function device_is_real() { local device=${1} device_is_loopback ${device} && \ return ${EXIT_ERROR} device_is_bonding ${device} && \ return ${EXIT_ERROR} device_is_bridge ${device} && \ return ${EXIT_ERROR} device_is_ppp ${device} && \ return ${EXIT_ERROR} device_is_vlan ${device} && \ return ${EXIT_ERROR} return ${EXIT_OK} } function device_type() { local device=$(devicify ${1}) if device_is_vlan ${device}; then echo "vlan" elif device_is_bonding ${device}; then echo "bonding" elif device_is_bridge ${device}; then echo "bridge" elif device_is_ppp ${device}; then echo "ppp" elif device_is_loopback ${device}; then echo "loopback" elif device_is_real ${device}; then echo "real" else echo "unknown" fi } function device_has_vlans() { if [ ! -e "/proc/net/vlan/config" ]; then return 1 fi grep -q "${1}$" /proc/net/vlan/config } function device_has_carrier() { local device=$(devicify ${1}) [ "$(/dev/null); do [ -d "${zone}" ] && echo ${zone} done } function zone_is_red() { local zone=${1} [ "${zone#red}" != "${zone}" ] } function _run_hooks() { local action local type while [ $# -gt 0 ]; do case "${1}" in --type=*) type=${1#--type=} ;; *) action="${1}" shift; break ;; esac shift done local dir=${1}; shift local failed local hook local hooks if [ -z "${action}" ] || [ -z "${dir}" ]; then echo "Not enough parameters given." >&2 return 1 fi for hook in $(find ${dir}); do # Skip dirs [ -d "${hook}" ] && continue ( . ${hook} # Skip hooks that are not of the given type if [ -n "${type}" ] && [ "$(hook_type ${HOOK})" != "${type}" ]; then continue fi if [ -n "${HOOK}" ]; then hook_run ${HOOK} --config=${hook} $@ ${action} RET=$? else echo -e "${FAILURE}Unable to process ${hook}. Either" echo -e "${FAILURE}the HOOK variable was not set," echo -e "${FAILURE}or the specified hook cannot be executed." message="" log_failure_msg fi exit ${RET} ) || failed=1 done return ${failed} } function hooks_run_all() { _run_hooks $@ } function hooks_run_ports() { _run_hooks --type="port" $@ } function hooks_run_zones() { _run_hooks --type="zone" $@ } function hook_type() { local hook=${1} ( eval $(${HOOKS_DIR}/${hook} info) echo "${HOOK_TYPE}" ) } function hook_list() { local type=${1} local hook for hook in ${HOOKS_DIR}/*; do [ -x "${hook}" ] || continue hook=${hook##*/} [[ ${hook} =~ helper$ ]] && continue if [ -n "${type}" ] && [ "$(hook_type ${hook})" != "${type}" ]; then continue fi echo "${hook}" done } function config_get_hook() { local config=${1} if [ ! -e "${config}" ]; then log_failure_msg "Config file \"${config}\" does not exist." return ${EXIT_ERROR} fi ( . ${config}; echo ${HOOK} ) } function hook_run() { local hook=${1} shift if ! hook_exists ${hook}; then log_failure_msg "Hook ${hook} cannot be found or is not executeable." return ${EXIT_ERROR} fi [ -n "${DEBUG}" ] && echo "Running hook: ${hook} $@" DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOOKS_DIR}/${hook} $@ return $? } function hook_run_multiple() { local zone local config local hook local hook_type2 local type while [ "$#" -gt "0" ]; do case "${1}" in --type=*) type=${1#--type=} ;; *) zone=${1} break ;; esac shift done if ! zone_exists ${zone}; then return ${EXIT_ERROR} fi for config in $(find ${CONFIG_ZONES}/${zone} 2>/dev/null); do hook=$(config_get_hook ${config}) if [ -n "${type}" ]; then hook_type2=$(hook_type ${hook}) if [ "${type}" != "${hook_type2}" ]; then continue fi fi hook_run ${hook} $@ done } function zone_run() { local zone=${1} shift if ! zone_exists ${zone}; then log_failure_msg "Zone ${zone} does not exist." exit ${EXIT_ERROR} fi decho "Running zone: ${zone} $@" DEBUG=${DEBUG} VERBOSE=${VERBOSE} ${HOME_DIR}/zone --zone=${zone} $@ } function zone_valid_name() { local zone=${1} local match local i for i in ${VALID_ZONES}; do match="${match}|${i}[0-9]{1,5}" done [[ ${zone} =~ ${match:1:${#match}} ]] } function isset() { local key=${1} [ -n "${!key}" ] && return if [[ ${key} =~ port|zone ]]; then echo "ERROR: The --${key} flag is not set." >&2 else echo "ERROR: The \"${key}\" variable is not set properly." >&2 fi return 1 } # Test if device is attached to the given bridge function zone_has_device_attached () { local zone=${1} local device=${2} [ -d "/sys/class/net/${zone}/brif/${device}" ] } function device_has_ipv4() { local device=${1} local ip=${2} ip addr show ${device} | grep inet | fgrep -q ${ip} } function check_config() { local failed local i for i in $@; do isset ${i} || failed=1 done if [ "${failed}" = "1" ]; then echo "Exiting..." exit ${EXIT_ERROR} fi } function mac_generate() { local mac="00" while [ "${#mac}" -lt 15 ]; do mac="${mac}:$(cut -c 1-2 /proc/sys/kernel/random/uuid)" done echo "${mac}" } function connection() { local action local dns local interface local iplocal local ipremote local name local status local weight local zone while [ $# -gt 0 ]; do case "${1}" in --up) action="up" ;; --down) action="down" ;; --starting) action="starting" ;; --stopping) action="stopping" ;; --name=*) name=${1#--name=} ;; --zone=*) zone=${1#--zone=} zone_is_red ${zone} || return 0 ;; --interface=*) interface=${1#--interface=} ;; --iplocal=*) iplocal=${1#--iplocal=} ;; --ipremote=*) ipremote=${1#--ipremote=} ;; --weight=*) weight=${1#--weight=} ;; --dns=*) dns=${1#--dns=} ;; esac shift done if [ ! -e "${CONNECTIONS_FILE}" ]; then sqlite3 -batch ${CONNECTIONS_FILE} <