]> git.ipfire.org Git - people/stevee/network.git/commitdiff
wireless: Enhance hook to handle encrypted connections.
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 Sep 2012 11:19:29 +0000 (11:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 Sep 2012 11:19:29 +0000 (11:19 +0000)
This is still in a very unstable state and needs a lot
testing and enhancement.

functions.wireless
functions.wpa_supplicant
helpers/wpa_supplicant [new file with mode: 0755]
helpers/wpa_supplicant-config-helper [new file with mode: 0755]
hooks/zones/wireless
hooks/zones/wireless.configs/ipv4-dhcp [new symlink]
hooks/zones/wireless.configs/ipv6-static [new symlink]

index 00e1a02f096ac2359fff3b4a5832ce5424c7f18a..7cf0b3fcdb5ae9d0af776fbc0aed1a2af3aefc84 100644 (file)
 
 function wireless_create() {
        local device=${1}
-       local phy=$(phy_get ${2})
-       local type=${3}
-       local mac=${4}
-
        assert isset device
-       assert isset phy
-       assert isset type
+       shift
 
-       isset mac || mac=$(mac_generate)
+       local address
+       local phy
+       local type="managed"
+
+       while [ $# -gt 0 ]; do
+               case "${1}" in
+                       --address=*)
+                               address=$(cli_get_val ${1})
+                               ;;
+                       --phy=*)
+                               phy=$(cli_get_val ${1})
+                               phy=$(phy_get ${phy})
+                               ;;
+                       --type=*)
+                               type=$(cli_get_val ${1})
+
+                               # ap --> __ap
+                               [ "${type}" = "ap" ] && type="__ap"
+                               ;;
+                       *)
+                               error "Unrecognized argument: ${1}"
+                               return ${EXIT_ERROR}
+                               ;;
+               esac
+               shift
+       done
 
-       assert phy_exists ${phy}
        assert isoneof type managed __ap
+       assert phy_exists ${phy}
+       isset address || address=$(mac_generate)
+
+       cmd_quiet iw phy ${phy} interface add ${device} type ${type}
+       local ret=$?
 
-       iw phy ${phy} interface add ${device} type ${type}
+       if [ ${ret} -eq ${EXIT_OK} ]; then
+               log DEBUG "created wireless device '${device}' (${type})"
 
-       if device_exists ${device}; then
-               device_set_address ${device} ${mac}
+               if isset address; then
+                       device_set_address ${device} ${address}
+               fi
+       else
+               log ERROR "could not create wireless device '${device}' (${type}): ${ret}"
        fi
 
-       device_set_up ${device}
+       return ${ret}
 }
 
 function wireless_remove() {
        local device=${1}
+       assert isset device
 
-       assert device_exists ${device}
+       if ! device_exists ${device}; then
+               return ${EXIT_OK}
+       fi
 
+       # Tear down the device (if necessary).
        device_set_down ${device}
 
-       iw dev ${device} del
+       # Remove it.
+       cmd_quiet iw dev ${device} del
+       local ret=$?
+
+       if [ ${ret} -eq ${EXIT_OK} ]; then
+               log DEBUG "removed wireless device '${device}'"
+       else
+               log ERROR "could not remove wireless device '${device}': ${ret}"
+       fi
+
+       return ${ret}
 }
 
 function wireless_set_channel() {
        local device=${1}
-       local channel=${2}
-
        assert isset device
-       assert device_exists ${device}
+
+       local channel=${2}
        assert isset channel
 
-       iw dev ${device} set channel ${channel} $@
+       device_exists ${device} || return ${EXIT_ERROR}
+
+       cmd_quiet iw dev ${device} set channel ${channel}
 }
index 3f01791b6f0eb30747124dba41b78e5819cc23fb..1c043aff857b81f4ebc9116d9847a73ec77288c0 100644 (file)
 #                                                                             #
 ###############################################################################
 
+WPA_SUPPLICANT_SOCKET_DIR="${RUN_DIR}/wpa_supplicant/ctrl"
+
 function wpa_supplicant_config_write() {
        local device=${1}
-       shift
-
        assert isset device
 
-       local ssid
-       local encryption
-       local key
+       local file=${2}
+       assert isset file
 
-       while [ $# -gt 0 ]; do
-               case "${1}" in
-                       --ssid=*)
-                               ssid=${1#--ssid=}
+       shift 2
+
+       local ap_scan=1 country_code mode key ssid
+
+       local arg
+       for arg in "$@"; do
+               case "${arg}" in
+                       --ap-scan=*)
+                               ap_scan=$(cli_get_val ${arg})
+                               ;;
+                       --country-code=*)
+                               country_code=$(cli_get_val ${arg})
+                               ;;
+                       --mode=*)
+                               mode=$(cli_get_val ${arg})
+
+                               # Empty signals no encryption.
+                               isset mode || mode="NONE"
                                ;;
-                       --encryption=*)
-                               encryption=${1#--encryption=}
+                       --ssid=*)
+                               ssid=$(cli_get_val ${arg})
                                ;;
                        --key=*)
-                               key=${1#--key=}
+                               key=$(cli_get_val ${arg})
+                               ;;
+                       *)
+                               error "Unrecognized argument: ${arg}"
+                               return ${EXIT_ERROR}
                                ;;
                esac
-               shift
        done
 
-       assert isset ssid
-       assert isset encryption
-       assert isset key
-
-       cat <<EOF
-# WPA supplicant configuration for ${device}.
-# DO NOT EDIT.
-
-network={
-       ssid="${ssid}"
-       proto=RSN
-       key_mgmt=${encryption}
-       pairwise=CCMP
-       group=TKIP
-       psk="${key}"
-}
+       assert isinteger ap_scan
+       assert isset mode
+
+       local auth_alg key_mgmt proto ssid psk wep_key0 wep_tx_keyidx
+
+       case "${mode}" in
+               # Normal WPA.
+               WPA-PSK)
+                       auth_alg="OPEN"
+                       key_mgmt="WPA-PSK"
+                       proto="WPA"
+                       pairwise="CCMP TKIP"
+                       group="CCMP TKIP WEP104 WEP40"
+                       ;;
+
+               # WPA with stronger algorithms.
+               WPA-PSK-SHA256)
+                       auth_alg="OPEN"
+                       key_mgmt="WPA-PSK-SHA256"
+                       proto="WPA"
+                       pairwise="CCMP TKIP"
+                       group="CCMP TKIP WEP104 WEP40"
+                       ;;
+
+               # Normal WPA2 (802.11i).
+               WPA2-PSK)
+                       auth_alg="OPEN"
+                       key_mgmt="WPA-PSK"
+                       proto="RSN"
+                       pairwise="CCMP TKIP"
+                       group="CCMP TKIP WEP104 WEP40"
+                       ;;
+
+               # WPA2 with stronger algorithms.
+               WPA2-PSK-SHA256)
+                       auth_alg="OPEN"
+                       key_mgmt="WPA-PSK-SHA256"
+                       proto="RSN"
+                       pairwise="CCMP TKIP"
+                       group="CCMP TKIP WEP104 WEP40"
+                       ;;
+
+               # WEP.
+               WEP)
+                       auth_alg="SHARED"
+                       wep_key0="${key}"
+                       wep_tx_keyidx="0"
+
+                       # Reset PSK.
+                       psk=""
+                       ;;
+
+               # IEEE 802.1X
+               8021X)
+                       key_mgmt="IEEE8021X"
+                       ;;
+
+               # No encryption. DANGEROUS!
+               NONE)
+                       auth_alg="OPEN"
+                       key_mgmt="NONE"
+                       ;;
+               *)
+                       log ERROR "Unknown mode: ${mode}"
+                       return ${EXIT_ERROR}
+                       ;;
+       esac
+
+       local config_dir=$(dirname ${file})
+       mkdir -p ${config_dir} 2>/dev/null
+
+       config_header "WPA supplicant configuration file" > ${file}
+
+       # AP scanning/selection
+       print "ap_scan=${ap_scan}" >> ${file}
+
+       # Set country code, if known.
+       if isset country_code; then
+               print "country=\"${country_code}\"" >> ${file}
+       fi
+
+       # Set control socket directory.
+       print "ctrl_interface=${WPA_SUPPLICANT_SOCKET_DIR}" >> ${file}
+
+       (
+               print # Network section
+               print "network={"
+
+               if isset auth_alg; then
+                       print " auth_alg=${auth_alg}"
+               fi
+
+               if isset key_mgmt; then
+                       print " key_mgmt=${key_mgmt}"
+               fi
+
+               if isset proto; then
+                       print " proto=${proto}"
+               fi
 
-EOF
+               if isset ssid; then
+                       print " ssid=${ssid}"
+               fi
+
+               if isset key; then
+                       print " psk=\"${key}\""
+               fi
+
+               if isset wep_key0; then
+                       print " wep_key0=\"${wep_key0}\""
+               fi
+
+               if isset wep_tx_keyidx; then
+                       print " wep_tx_keyidx=${wep_tx_keyidx}"
+               fi
+
+               print "}"
+       ) >> ${file}
+
+       return ${EXIT_OK}
 }
 
 function wpa_supplicant_config_dir() {
        local device=${1}
-
        assert isset device
 
-       echo "${RUN_DIR}/wireless/${device}"
+       echo "${RUN_DIR}/wpa_supplicant/${device}"
 }
 
 function wpa_supplicant_start() {
        local device=${1}
-       shift
+       assert isset device
 
-       assert device_exists ${device}
+       service_start "wpa_supplicant@${device}.service"
+}
 
-       local config_dir=$(wpa_supplicant_config_dir ${device})
-       mkdir -p ${config_dir}
+function wpa_supplicant_stop() {
+       local device=${1}
+       assert isset device
 
-       local config_file=${config_dir}/config
-       wpa_supplicant_config_write ${device} $@ > ${config_file}
+       service_stop "wpa_supplicant@${device}.service"
+}
+
+function wpa_supplicant_client() {
+       local device=${1}
+       assert isset device
+       shift
 
-       wpa_supplicant -i ${device} -D wext -B -c ${config_file} \
-               -P ${config_dir}/pid
+       local cmd="$@"
+       assert isset cmd
+
+       # Run the command and return the output.
+       cmd wpa_cli -p${WPA_SUPPLICANT_SOCKET_DIR} -i${device} ${cmd}
 }
 
-function wpa_supplicant_stop() {
+function wpa_cli_status() {
        local device=${1}
+       assert isset device
+
+       wpa_supplicant_client ${device} status verbose
+}
 
+function wpa_cli_status_get() {
+       local device=${1}
        assert isset device
 
-       local pid=$(wpa_supplicant_get_pid ${device})
+       local arg=${2}
+       assert isset arg
 
-       if isset pid; then
-               process_kill ${pid}
-       else
-               warning_log "Could not find pid file for wpa_supplicant process running for ${device}."
-       fi
+       local line key
+       while read -r line; do
+               key=$(cli_get_key ${line})
 
-       rm -rf $(wpa_supplicant_config_dir ${device})
+               if [ "${key}" = "${arg}" ]; then
+                       cli_get_val "${line}"
+                       return ${EXIT_OK}
+               fi
+       done <<< "$(wpa_cli_status ${device})"
+
+       return ${EXIT_ERROR}
 }
 
-function wpa_supplicant_get_pid() {
+function wpa_cli_bss() {
        local device=${1}
+       assert isset device
+
+       local bss=${2}
+       assert isset bss
 
+       wpa_supplicant_client ${device} bss ${bss}
+}
+
+function wpa_cli_bss_get() {
+       local device=${1}
        assert isset device
 
-       local pid_file="$(wpa_supplicant_config_dir ${device})/pid"
+       local bss=${2}
+       assert isset bss
 
-       [ -e "${pid_file}" ] || return ${EXIT_ERROR}
+       local arg=${3}
+       assert isset arg
 
-       cat ${pid_file} 2>/dev/null
-       return ${EXIT_OK}
+       local line key
+       while read -r line; do
+               key=$(cli_get_key ${line})
+
+               if [ "${key}" = "${arg}" ]; then
+                       cli_get_val "${line}"
+                       return ${EXIT_OK}
+               fi
+       done <<< "$(wpa_cli_bss ${device} ${bss})"
+
+       return ${EXIT_ERROR}
 }
 
-function wpa_supplicant_is_running() {
+function wpa_cli_bss_get_frequency() {
        local device=${1}
-
        assert isset device
 
-       local pid=$(wpa_supplicant_get_pid ${device})
+       local bssid=${2}
+       assert isset bssid
 
-       if isset pid && [ -d "/proc/${pid}" ]; then
-               return ${EXIT_OK}
-       fi
+       wpa_cli_bss_get ${device} ${bssid} freq
+}
 
-       return ${EXIT_ERROR}
+function wpa_cli_bss_get_noise() {
+       local device=${1}
+       assert isset device
+
+       local bssid=${2}
+       assert isset bssid
+
+       wpa_cli_bss_get ${device} ${bssid} noise
 }
 
-function wpa_supplicant_get_pid() {
-       local zone=${1}
-       shift
+function wpa_cli_bss_get_quality() {
+       local device=${1}
+       assert isset device
 
-       
+       local bssid=${2}
+       assert isset bssid
+
+       wpa_cli_bss_get ${device} ${bssid} qual
 }
 
-function wpa_supplicant_stop() {
-       local zone=${1}
-       shift
+function wpa_cli_bss_get_flags() {
+       local device=${1}
+       assert isset device
+
+       local bssid=${2}
+       assert isset bssid
 
-       killall wpa_supplicant
+       wpa_cli_bss_get ${device} ${bssid} flags
 }
diff --git a/helpers/wpa_supplicant b/helpers/wpa_supplicant
new file mode 100755 (executable)
index 0000000..3d1aa94
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  IPFire Network Development Team                         #
+#                                                                             #
+# 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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+. /usr/lib/network/functions
+
+zone="${1}"
+assert isset zone
+assert zone_exists ${zone}
+
+# Create socket dir.
+mkdir -p ${WPA_SUPPLICANT_SOCKET_DIR} 2>/dev/null
+
+config_file="$(wpa_supplicant_config_dir ${zone})/wpa_supplicant.conf"
+
+cmd="wpa_supplicant -i ${zone} -c ${config_file}"
+
+if device_is_wireless ${zone}; then
+       cmd="${cmd} -Dwext"
+else
+       cmd="${cmd} -Dwired"
+fi
+
+cmd_exec ${cmd}
diff --git a/helpers/wpa_supplicant-config-helper b/helpers/wpa_supplicant-config-helper
new file mode 100755 (executable)
index 0000000..bda44a9
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2012  IPFire Network Development Team                         #
+#                                                                             #
+# 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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+. /usr/lib/network/functions
+
+action="${1}"
+assert isset action
+
+zone="${2}"
+assert isset zone
+assert zone_exists ${zone}
+
+config_file="$(wpa_supplicant_config_dir ${zone})/wpa_supplicant.conf"
+
+case "${action}" in
+       create)
+               # Create the configuration file for this zone.
+               zone_config_read ${zone} || exit $?
+
+               wpa_supplicant_config_write ${zone} ${config_file} \
+                       --mode="${ENCRYPTION_MODE}" \
+                       --ssid="${SSID}" \
+                       --key="${KEY}" \
+               || exit $?
+               ;;
+
+       remove)
+               rm -f ${config_file}
+               ;;
+
+       *)
+               log ERROR "Unknown action passed: ${action}"
+               exit ${EXIT_ERROR}
+               ;;
+esac
+
+exit ${EXIT_OK}
index 9af1c4bcfab17570c434dae7fa0ba94ae2763845..327388ba2cbc8e6beeb394924303a60e5cd9263f 100755 (executable)
 HOOK_SETTINGS="HOOK PHY MAC MTU SSID KEY ENCRYPTION"
 
 # Default values
-MAC=$(mac_generate)
+ADDRESS=$(mac_generate)
 PHY=
 MTU=1500
 SSID=
 KEY=
-ENCRYPTION="WPA-PSK"
+ENCRYPTION_MODE=
 
 function _check() {
        assert isset SSID
-       assert ismac MAC
+
+       if isset ADDRESS; then
+               assert ismac ADDRESS
+       fi
+
        assert isinteger MTU
        assert ismac PHY
 
-       if [ -n "${ENCRYPTION}" ]; then
+       if [ -n "${ENCRYPTION_MODE}" ]; then
                assert isset KEY
        fi
 }
@@ -45,44 +49,51 @@ function _check() {
 function _parse_cmdline() {
        while [ $# -gt 0 ]; do
                case "${1}" in
-                       --phy=*)
-                               PHY=${1#--phy=}
+                       --phy=*|--parent-device=*)
+                               PHY=$(cli_get_val ${1})
+                               ;;
+                       --encryption-mode=*)
+                               ENCRYPTION_MODE=$(cli_get_val ${1})
+                               ;;
+                       --address=*)
+                               ADDRESS=$(cli_get_val ${1})
                                ;;
                        --ssid=*)
-                               SSID=${1#--ssid=}
+                               SSID=$(cli_get_val ${1})
                                ;;
                        --key=*)
-                               KEY=${1#--key=}
+                               KEY=$(cli_get_val ${1})
                                ;;
                        *)
-                               warning "Ignoring unknown option '${1}'"
+                               warning "Unrecognized option: ${1}"
                                ;;
                esac
                shift
        done
 
+       # Just save the MAC address of the phy.
        PHY=$(phy_get ${PHY})
        PHY=$(phy_get_address ${PHY})
 }
 
 function _up() {
        local zone=${1}
-       shift
-
        assert isset zone
 
+       # Read zone configuration.
        zone_config_read ${zone}
 
-       wireless_create ${zone} ${PHY} managed ${MAC}
-
-       [ -n "${MAC}" ] && device_set_address ${zone} ${MAC}
-       [ -n "${MTU}" ] && device_set_mtu ${zone} ${MTU} 
-
-       # Create WPA supplicant configuration.
-       wpa_supplicant_start ${zone} --ssid=${SSID} \
-               --encryption=${ENCRYPTION} --key=${KEY}
+       if ! device_exists ${zone}; then
+               #  Create the wireless interface.
+               wireless_create ${zone} \
+                       --phy=${PHY} \
+                       --type="managed" \
+                       --address="${ADDRESS}" \
+               || exit $?
+       fi
 
-       #device_set_up ${zone}
+       # Start the WPA supplicant daemon.
+       wpa_supplicant_start ${zone}
 
        zone_configs_up ${zone}
 
@@ -102,8 +113,6 @@ function _down() {
 
        wpa_supplicant_stop ${zone}
 
-       #device_set_down ${zone}
-
        wireless_remove ${zone}
 
        exit ${EXIT_OK}
@@ -113,6 +122,7 @@ function _status() {
        local zone=${1}
        assert isset zone
 
+       # Print the default header.
        cli_device_headline ${zone}
 
        # Exit if zone is down
@@ -121,32 +131,37 @@ function _status() {
                exit ${EXIT_ERROR}
        fi
 
-       # XXX Add bridge stp priority here
-       # brctl does not give any information about that
-
-       cli_headline "  Spanning Tree Protocol information:"
-       printf "${DEVICE_PRINT_LINE1}" "ID:" $(stp_bridge_get_id ${zone})
-       printf "${DEVICE_PRINT_LINE1}" "Priority:" $(stp_bridge_get_priority ${zone})
-
-       if stp_bridge_is_root ${zone}; then
-               echo -e "    ${CLR_BLACK_B}This bridge is root.${CLR_RESET}"
-       else
-               printf "${DEVICE_PRINT_LINE1}" "Designated root:" $(stp_bridge_get_designated_root ${zone})
-               printf "${DEVICE_PRINT_LINE1}" "Root path cost:" $(stp_bridge_get_root_path_cost ${zone})
-       fi
-       echo # Empty line
-
-       # Topology information
-       printf "${DEVICE_PRINT_LINE1}" "Topology changing:" $(stp_bridge_get_topology_change_detected ${zone})
-       printf "${DEVICE_PRINT_LINE1}" "Topology change time:" $(beautify_time $(stp_bridge_get_topology_change_timer ${zone}))
-       printf "${DEVICE_PRINT_LINE1}" "Topology change count:" $(stp_bridge_get_topology_change_count ${zone})
-
-       cli_headline "  Ports:"
-       zone_ports_status ${zone}
-
-       cli_headline "  Configurations:"
+       cli_headline 2 "Wireless network information"
+       cli_print_fmt1 2 "SSID" "$(wpa_cli_status_get ${zone} ssid)"
+       cli_space
+
+       cli_headline 3 "Access Point"
+       local bssid=$(wpa_cli_status_get ${zone} bssid)
+       assert isset bssid
+
+       cli_print_fmt1 3 "BSSID" "${bssid}"
+       cli_print_fmt1 3 "Frequency" \
+               "$(wpa_cli_bss_get_frequency ${zone} ${bssid}) MHz"
+       cli_print_fmt1 3 "Noise" \
+               "$(wpa_cli_bss_get_noise ${zone} ${bssid})"
+       cli_print_fmt1 3 "Quality" \
+               "$(wpa_cli_bss_get_quality ${zone} ${bssid})"
+       cli_print_fmt1 3 "Flags" \
+               "$(wpa_cli_bss_get_flags ${zone} ${bssid})"
+       cli_space
+
+       cli_headline 3 "Encryption"
+       cli_print_fmt1 3 "Mode" \
+               "$(wpa_cli_status_get ${zone} key_mgmt)"
+       cli_print_fmt1 3 "Pairwise cipher" \
+               "$(wpa_cli_status_get ${zone} pairwise_cipher)"
+       cli_print_fmt1 3 "Group cipher" \
+               "$(wpa_cli_status_get ${zone} group_cipher)"
+       cli_space
+
+       cli_headline 2 "Configurations"
        zone_configs_cmd status ${zone}
+       cli_space
 
-       echo # Empty line
        exit ${EXIT_OK}
 }
diff --git a/hooks/zones/wireless.configs/ipv4-dhcp b/hooks/zones/wireless.configs/ipv4-dhcp
new file mode 120000 (symlink)
index 0000000..5092ad1
--- /dev/null
@@ -0,0 +1 @@
+../bridge.configs/ipv4-dhcp
\ No newline at end of file
diff --git a/hooks/zones/wireless.configs/ipv6-static b/hooks/zones/wireless.configs/ipv6-static
new file mode 120000 (symlink)
index 0000000..dac121f
--- /dev/null
@@ -0,0 +1 @@
+../bridge.configs/ipv6-static
\ No newline at end of file