diff options
Diffstat (limited to 'src/lib/network')
-rwxr-xr-x[-rw-r--r--] | src/lib/network | 419 |
1 files changed, 73 insertions, 346 deletions
diff --git a/src/lib/network b/src/lib/network index 1aa384c..1117737 100644..100755 --- a/src/lib/network +++ b/src/lib/network @@ -1,368 +1,95 @@ -### Globals -. /usr/lib/network/globals -# will load hooks - -## Loads a profile. -# $1: profile name -load_profile() -{ - unset ROUTES - [[ -z "$1" ]] && return 1 - if [[ ! -f "$PROFILE_DIR/$1" ]]; then - report_err "Profile \"$1\" does not exist" - return 1 - fi - report_debug "Loading profile $1" - INTERFACE=$(. "$PROFILE_DIR/$1"; echo "$INTERFACE") - report_debug "Configuring interface $INTERFACE" - if [[ -z "$INTERFACE" ]]; then - report_err "Profile missing an interface to configure" - return 1 - fi - if [[ -f "$IFACE_DIR/$INTERFACE" ]]; then - report_debug "Interface level configuration enabled: $IFACE_DIR/$INTERFACE" - . "$IFACE_DIR/$INTERFACE" - fi - . "$PROFILE_DIR/$1" # we want profile settings to override, so need to source profile again - if [[ ! -f "$CONN_DIR/$CONNECTION" ]]; then - report_err "$CONNECTION is not a valid connection, check spelling or look at examples" - return 1 - fi -} - -################## -# Profile up/down -################## - -## Take all registered profiles down. -all_down() -{ - find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - profile_down "$prof" - done -} +#! /bin/bash -## Create the state dir and sub directories if they don't already exist. -check_make_state_dir() -{ - [[ ! -d "$STATE_DIR" ]] && mkdir -p "$STATE_DIR"/{interfaces,profiles} - for d in interfaces profiles suspend; do - [[ ! -d "$STATE_DIR/$d" ]] && mkdir "$STATE_DIR/$d" - done -} +. /usr/lib/network/globals -## Save the list of running profiles and take them down if needed -# $1: interface name or "all" -# $2: take associated profiles down (optional, default="yes") -interface_suspend() -{ - report_debug interface_suspend "$@" - check_make_state_dir - find "$STATE_DIR/profiles/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/profiles/$prof"; echo "$INTERFACE") - if [[ "$1" == all || "$1" == "$INTERFACE" ]]; then - report_notice "suspending interface $INTERFACE with profile $prof" - cp "$STATE_DIR/profiles/$prof" "$STATE_DIR/suspend/" - if checkyesno "${2:-yes}"; then - profile_down "$prof" - fi - fi - done -} - -## Save the list of all running profiles and take them down -all_suspend() { - interface_suspend all +## Check if a string represents a network interface +# $1: potential interface name +is_interface() { + # Strip any old school alias specifier + [[ -d "/sys/class/net/${1%%:?*}" ]] } -## Restore saved profiles (for resume purposes). -# $@: a list of interfaces not to resume (e.g., because they're disabled) -all_resume() -{ - report_debug all_resume "$@" - find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE") - if [[ $# -eq 0 || ! " $* " =~ " $INTERFACE " ]]; then - report_notice "resuming interface $INTERFACE with profile $prof" - profile_up "$prof" - rm -f "$STATE_DIR/suspend/$prof" # if profile_up succeeds, it will have already removed this - fi - done +## Check if an interface is up +# $1: interface name +interface_is_up() { + local flags + read flags < "/sys/class/net/${1%%:?*}/flags" + # IFF_UP is defined as 0x1 in linux/if.h + (( flags & 0x1 )) } -## Puts up a profile. -# $1: the profile name -profile_up() -{ - ( - # Keep inside subshell so that options from one profile don't cross to others - # exit 1 used in a subshell is effectively exiting a new process - check_make_state_dir - - local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks - - load_profile "$PROFILE" || exit 1 - - if check_profile "$PROFILE"; then - report_err "$PROFILE already connected" +## Activate an interface +# $1: interface name +bring_interface_up() { + local interface=$1 + ip link set dev "$interface" up &>/dev/null + timeout_wait "${TimeoutUp:-5}" 'interface_is_up "$interface"' +} + +## Deactivate an interface +# $1: interface name +bring_interface_down() { + local interface=$1 + ip addr flush dev "$interface" &>/dev/null + ip link set dev "$interface" down &>/dev/null + # We reuse the up timeout (down normally is faster) + timeout_wait "${TimeoutUp:-5}" '! interface_is_up "$interface"' +} + + +if [[ $# -ne 2 || $1 != @(start|stop) ]]; then + exit_error "Usage: $0 {start|stop} <profile>" +fi +ensure_root netctl +# Ensure we are not in a transient directory +cd / + +# Expose the profile name +Profile=$2 +load_profile "$Profile" +source "$CONN_DIR/$Connection" +case $1 in + start) + report_notice "Starting network profile '$Profile'..." + if is_interface "$Interface" && interface_is_up "$Interface" && \ + ! is_yes "${ForceConnect:-no}"; then + report_error "The interface of network profile '$Profile' is already up" exit 1 fi - - # EXCLUSIVE, network.d/profile: Individual profile is mutually exclusive - if checkyesno "$EXCLUSIVE"; then - all_down - fi - - report_try "$PROFILE up" - - status=$(check_iface "$INTERFACE") - report_debug "status reported to profile_up as: $status" - case "$status" in - external) - report_fail "Interface $INTERFACE externally controlled" - exit 1 - ;; - disabled) - report_fail "Interface $INTERFACE is disabled" - exit 1 - ;; - "") - ;; - *) - if checkyesno "$CHECK"; then - report_fail "Interface $INTERFACE already in use" - exit 1 - - # not necessary to sandbox this call or reload PROFILE afterwards - elif ! interface_down "$INTERFACE"; then - report_fail - exit 1 - fi - ;; - esac - - if ! ( eval $PRE_UP ); then # JP: sandbox the eval so variables don't bleed into current function - report_debug profile_up "PRE_UP failed" - report_fail + if ! "${Connection}_up"; then + report_error "Failed to bring the network up for profile '$Profile'" exit 1 fi - - if ! "$CONN_DIR/$CONNECTION" up "$PROFILE"; then - report_debug profile_up "connect failed" - report_fail - # "$CONN_DIR/$CONNECTION" down "$PROFILE" # JP: should we do this to make sure? + # JP: sandbox the eval + if ! ( eval $ExecUpPost ); then + report_error "ExecUpPost failed for network profile '$Profile'" + # Failing ExecUpPost will take the connection down + "${Connection}_down" exit 1 fi - - if ! ( eval $POST_UP ); then # JP: sandbox the eval - report_debug profile_up "POST_UP failed" - report_fail - # failing POST_UP will take interface down - "$CONN_DIR/$CONNECTION" down "$PROFILE" + report_notice "Started network profile '$Profile'" + ;; + stop) + report_notice "Stopping network profile '$Profile'..." + # JP: sandbox the eval + if ! ( eval $ExecDownPre ); then + report_error "ExecDownPre failed for network profile '$Profile'" + # Failing ExecDownPre will leave the profile active exit 1 fi - - set_profile up "$PROFILE" - unset EXCLUSIVE - - # Successfully running a new profile; erase any suspended profiles on this interface - local iface="$INTERFACE" - find "$STATE_DIR/suspend/" -maxdepth 1 -type f -printf '%f\n' \ - | while read prof; do - # the pipe to "while read" will create a subshell - INTERFACE=$(. "$STATE_DIR/suspend/$prof"; echo "$INTERFACE") - if [[ "$iface" == "$INTERFACE" ]]; then - rm "$STATE_DIR/suspend/$prof" - fi - done - - report_success - ); return $? -} - -## Puts a profile down. -# $1: the profile name -profile_down() -{ - ( - check_make_state_dir - - local status PROFILE="$1" # save PROFILE in a variable so that it's available to PRE_UP/POST_DOWN etc hooks - - load_profile "$PROFILE" || exit 1 - - status=$(check_iface "$INTERFACE") - report_debug "status reported to profile_down as: $status" - - if [[ "$status" != "$PROFILE" ]]; then - # if interface not available to be controlled by netcfg, then - # any profiles should have been removed by check_iface - # else we get here if another profile is running - report_err "Profile not connected" + if ! "${Connection}_down"; then + report_error "Failed to bring the network down for profile '$Profile'" exit 1 fi - - report_try "$PROFILE down" - if [[ "$(check_iface "$INTERFACE")" == "external" ]]; then - report_fail "$interface was connected by another application" + if is_interface "$Interface" && interface_is_up "$Interface" && \ + ! is_yes "${ForceConnect:-no}"; then + report_error "The interface of network profile '$Profile' did not go down" exit 1 fi + report_notice "Stopped network profile '$Profile'" + ;; +esac - if ! ( eval $PRE_DOWN ); then # JP: sandbox the eval - report_debug profile_down "PRE_DOWN failed" - # true # JP: did we want failing PRE_DOWN to leave the profile active? - report_fail - exit 1 - fi - - if ! "$CONN_DIR/$CONNECTION" down "$PROFILE"; then - report_debug profile_up "disconnect failed" - report_fail - exit 1 - fi - - if ! ( eval $POST_DOWN ); then # JP: sandbox the eval - report_debug profile_down "POST_DOWN failed" - report_fail - exit 1 - fi - - set_profile down "$PROFILE" - report_success - ); return $? -} - -# interface_down interface -# take interface down -# -interface_down() -{ - local profile=$(check_iface "$1") - case "$profile" in - ""|disabled) return 0 ;; - external) return 1 ;; - *) profile_down "$profile" ;; - esac -} - -# interface_reconnect interface -# reconnects the profile active on interface -interface_reconnect() -{ - local profile=$(check_iface "$1") - case "$profile" in - ""|disabled|external) - return 1 - ;; - *) - profile_down "$profile" - profile_up "$profile" - ;; - esac -} - -## -# check_iface interface -# Return 0 if interface unavailable (in use by a profile or externally, or disabled) -# Return 1 if interface down and available to be used -# -check_iface() { - if [[ -f "$STATE_DIR/interfaces/$1" ]]; then - cat "$STATE_DIR/interfaces/$1" - return 0 - else - return 1 - fi -} - -# list_profiles -# Outputs a list of all profiles -list_profiles() { - # JP: follow aliases with -L, also skip profiles that start with '.' or end with '~' or '.conf' (so profile.conf can be the wpa.conf file for profile) - find -L "$PROFILE_DIR/" -maxdepth 1 -type f -not -name '*~' -not -name '*.conf' -not -name '.*' -printf "%f\n" -} - -# check_profile profile -# Return 0 if profile registered as being up -# Return 1 if profile not registered -# -check_profile() { - [[ -f "$STATE_DIR/profiles/$1" && ! -f "$STATE_DIR/suspend/$1" ]] && return 0 - return 1 -} - -### Status setting functions -## -# set_profile up/down profile -# Set profile state, either up or down -# -set_profile() { - local INTERFACE - if [[ "$1" == "up" ]]; then - INTERFACE=$(. "$PROFILE_DIR/$2"; echo "$INTERFACE") - cp "$PROFILE_DIR/$2" "$STATE_DIR/profiles/" - set_iface up "$INTERFACE" "$2" - elif [[ "$1" == "down" && -f "$STATE_DIR/profiles/$2" ]]; then # JP: skip if profile not already up - INTERFACE=$(. "$STATE_DIR/profiles/$2"; echo "$INTERFACE") - rm "$STATE_DIR/profiles/$2" - set_iface down "$INTERFACE" "$2" - fi -} - -# set_iface up/down interface [profile] -# Set interface status to up/down -# optionally link it to a profile. -# -set_iface() { - local PROFILE="${3:-external}" - if [[ "$1" == "up" ]]; then - echo "$PROFILE" > "$STATE_DIR/interfaces/$2" - elif [[ "$1" == "down" ]]; then - rm -f "$STATE_DIR/interfaces/$2" # JP: add -f so we don't complain if the interface isn't up - fi -} - -is_interface() { - local INTERFACE="$1" - if [[ ! -e "/sys/class/net/$INTERFACE" ]]; then - if ! echo "$INTERFACE" | grep -F -q ":"; then - return 1 - fi - fi - return 0 -} - -interface_is_up() { - local flags - read flags < "/sys/class/net/$1/flags" - # IFF_UP is defined as 0x1 in linux/if.h - (( flags & 0x1 )) -} - -## Changes a network interface state. -# $1: up, flush, or down. -# $2: the interface name -bring_interface() -{ - local INTERFACE="$2" - case "$1" in - up) - ip link set dev "$INTERFACE" up &>/dev/null - timeout_wait "${UP_TIMEOUT:-5}" 'interface_is_up "$INTERFACE"' || return 1 - ;; - flush|down) - ip addr flush dev "$INTERFACE" &>/dev/null - ;;& - down) - ip link set dev "$INTERFACE" down &>/dev/null - ;; - esac -} # vim: ft=sh ts=4 et sw=4: |