From: Michael Tremer Date: Wed, 26 Sep 2012 11:19:29 +0000 (+0000) Subject: wireless: Enhance hook to handle encrypted connections. X-Git-Tag: 005~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22a61046a7b13a72b7c6b9b17a07163423d2bd49;p=network.git wireless: Enhance hook to handle encrypted connections. This is still in a very unstable state and needs a lot testing and enhancement. --- diff --git a/functions.wireless b/functions.wireless index 00e1a02f..7cf0b3fc 100644 --- a/functions.wireless +++ b/functions.wireless @@ -21,45 +21,88 @@ 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} } diff --git a/functions.wpa_supplicant b/functions.wpa_supplicant index 3f01791b..1c043aff 100644 --- a/functions.wpa_supplicant +++ b/functions.wpa_supplicant @@ -19,128 +19,298 @@ # # ############################################################################### +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 </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 index 00000000..3d1aa947 --- /dev/null +++ b/helpers/wpa_supplicant @@ -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 . # +# # +############################################################################### + +. /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 index 00000000..bda44a90 --- /dev/null +++ b/helpers/wpa_supplicant-config-helper @@ -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 . # +# # +############################################################################### + +. /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} diff --git a/hooks/zones/wireless b/hooks/zones/wireless index 9af1c4bc..327388ba 100755 --- a/hooks/zones/wireless +++ b/hooks/zones/wireless @@ -24,20 +24,24 @@ 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 index 00000000..5092ad19 --- /dev/null +++ b/hooks/zones/wireless.configs/ipv4-dhcp @@ -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 index 00000000..dac121f1 --- /dev/null +++ b/hooks/zones/wireless.configs/ipv6-static @@ -0,0 +1 @@ +../bridge.configs/ipv6-static \ No newline at end of file