Source code for debinterface.hostapd

# -*- coding: utf-8 -*-
from __future__ import print_function, with_statement, absolute_import
import os
import shutil

from . import toolutils
try:
    import typing as tp
except ImportError:
    pass


[docs]class Hostapd(object): """ basic hostapd conf file handling """ _config = None # type: tp.Dict[str, tp.Any] _path = None # type: str backup_path = None # type: str def __init__(self, path, backup_path=None): # type: (str, tp.Optional[str])->None self._config = {} self._path = path if not backup_path: self.backup_path = path + ".bak" else: self.backup_path = backup_path @property def config(self): # type: ()->tp.Dict[str, tp.Any] return self._config
[docs] def set(self, key, value): # type: (str, tp.Union[str, tp.List[str]])->None if isinstance(value, str): self._config[str(key).strip()] = value.strip() else: self._config[str(key).strip()] = value
[docs] def validate(self): # type: ()->bool """Not sure which ones are really necessary for everyone, here are the ones I require. I created 4 groups of keys : basic must always be there, wireless if you want to be an AP, auth if you want to add some security, bridge for, well, bridging Not foul proof ! Returns: bool: True if everything went ok Raises: KeyError : missing key ValueError : invalid data """ basic = ['interface', 'driver'] bridge = ['bridge'] wireless = ['ssid', 'channel', 'hw_mode'] auth = ['wpa', 'wpa_passphrase', 'wpa_key_mgmt'] for k in basic: if self._config[k] is None: raise ValueError("Missing required {0} option".format(k)) if 'bridge' in self._config: for k in bridge: if self._config[k] is None: raise ValueError("Missing required {0} option " "for bridge".format(k)) if 'ssid' in self._config: for k in wireless: if self._config[k] is None: raise ValueError("Missing required {0} option for " "wireless".format(k)) # will raise value error if not int self._config['channel'] = int(self._config['channel']) if 'wpa' in self._config: self._config['wpa'] = int(self._config['wpa']) if not self._config['wpa'] in [1, 2, 3]: raise ValueError("Wpa option is not valid") for k in auth: if self._config[k] is None: raise ValueError("Missing required {0} option for " "wireless security".format(k)) if self._config['wpa'] in [1, 3]: if not self._config['wpa_pairwise']: raise ValueError("Missing required option for " "wireless security : wpa_pairwise") if self._config['wpa'] in [2, 3]: if not self._config['rsn_pairwise']: raise ValueError("Missing required option for " "wireless security rsn_pairwise") return True
[docs] def set_defaults(self): # type: ()->None """ ssid and wpa_passphrase defaults to cashpad-FTED and cashpad-GH67 """ self._config = { 'interface': 'wlan0', 'driver': 'nl80211', # logs 'logger_syslog': -1, 'logger_syslog_level': 2, 'logger_stdout': -1, 'logger_stdout_level': 2, # debug 'debug': 4, # wifi 'hw_mode': 'g', # security goodies 'macaddr_acl': 0, 'eapol_key_index_workaround': 0, 'eap_server': 0, 'eapol_version': 1, # wifi auth 'channel': 4, 'ssid': 'cashpad-FTED', 'wpa_passphrase': 'cashpad-GH67', 'auth_algs': 3, 'wpa': 3, # WPA + WPA2. set to 2 to restrict to WPA2 'wpa_key_mgmt': 'WPA-PSK', 'wpa_pairwise': 'TKIP', # some windows clients may have issues with this one: 'rsn_pairwise': 'CCMP' }
[docs] def read(self, path=None): # type: (tp.Optional[str])->None if path is None: path = self._path self._config = {} with open(path, "r") as hostapd: for line in hostapd: if line.startswith('#') is True or line == "\n" or line == "": pass else: param, value = line.replace("\n", "").split("=") if param and value: self.set(param.strip(), value.strip())
[docs] def write(self, path=None): # type: (tp.Optional[str])->None self.validate() if path is None: path = self._path self.backup() with toolutils.atomic_write(path) as hostapd: for k, v in self._config.items(): key = str(k).strip() value = str(v).strip() hostapd.write("{0}={1}\n".format(key, value))
@staticmethod
[docs] def controlService(action): # type: (str)->tp.Tuple[bool, str] """ return True/False, command output """ if action not in ["start", "stop", "restart"]: return False, "Invalid action" return toolutils.safe_subprocess(["/etc/init.d/hostapd", action])
[docs] def backup(self): # type: ()->None """ return True/False, command output """ if self.backup_path: shutil.copy(self._path, self.backup_path)
[docs] def restore(self): # type: ()->None """ return True/False, command output """ if self.backup_path: shutil.copy(self.backup_path, self._path)
[docs] def delete(self): # type: ()->None """ return True/False, command output """ if self.backup_path: os.remove(self._path)