|
#!/usr/bin/python -tt
|
|
# -*- coding: utf-8 -*-
|
|
|
|
""" Módulo que contiene la función selectbestchannel()
|
|
Función que escanea el espectro de canales de redes
|
|
wifi y nos devuelve el canal más idóneo para ser utilizado en
|
|
el lugar en que estamos.
|
|
|
|
La función admite dos parámetros
|
|
|
|
Utiliza la libreria pythonwifi y está basado en uno de los ejemplos
|
|
incluidos en la libreria
|
|
Debe ser ejecutado como root
|
|
|
|
El algoritmo utilizado se basa en sumar las redes que existen en cada
|
|
canal y a continuación calcular las sumas de los solapes de las redes
|
|
centradas en canales, patrón 1-6-11, escogeremos el canal cuyo valor
|
|
de las sumas sea menor.
|
|
|
|
Los canales que se solapan en el patrón 1-6-11 son los siguientes:
|
|
|
|
Canal Canales que se solapan
|
|
1 1-5
|
|
2 1-6
|
|
3 1-7
|
|
4 1-8
|
|
5 1-9
|
|
6 2-10
|
|
7 3-11
|
|
8 4-12
|
|
9 5-13
|
|
10 6-13
|
|
11 7-13
|
|
12 8-13
|
|
13 9-13
|
|
|
|
|
|
Francisco Mora Sánchez
|
|
IES Maestro Juan Calero
|
|
adminies.maestrojuancalero@edu.juntaextremadura.net
|
|
|
|
|
|
"""
|
|
|
|
import errno
|
|
import sys
|
|
import os
|
|
import socket
|
|
|
|
#from pythonwifi.iwlibs import Wireless, getWNICnames
|
|
|
|
import escanea
|
|
|
|
def actualizadatosescaneo(datosescaneo, canal, bssid, essid, calidad, intensidad):
|
|
""" Actualizamos diccionario con los datos recogidos del
|
|
escaneado, comprobamos que no hemos insertado
|
|
previamente la red, comprobando el bssid del AP
|
|
"""
|
|
if not datosescaneo.has_key(canal):
|
|
#insertamos el canal inicializando los campos
|
|
datosescaneo[canal] = [1, [[bssid,calidad,intensidad]], 0]
|
|
else:
|
|
#comprobemos que no existe ese bssid en el diccionario
|
|
#listabssid = datosescaneo[canal][1]
|
|
listabssid = [bssids[0] for bssids in datosescaneo[canal][1]]
|
|
if not bssid in listabssid:
|
|
#no está en la lista, añadimos y aumentamos el contador de redes
|
|
datosescaneo[canal][0] = datosescaneo[canal][0] + 1
|
|
datosescaneo[canal][1].append([bssid,calidad,intensidad])
|
|
|
|
def procesadatosescaneo(datosescaneo):
|
|
""" Sumamos las redes solapadas centradas en los canales, basándonos
|
|
en el patrón 1-6-11
|
|
"""
|
|
adyacentes = {1:[1,2,3,4,5],2:[1,2,3,4,5,6],3:[1,2,3,4,5,6,7],4:[1,2,3,4,5,6,7,8],5:[1,2,3,4,5,6,7,8,9], \
|
|
6:[2,3,4,5,6,7,8,9,10],7:[3,4,5,6,7,8,9,10,11],8:[4,5,6,7,8,9,10,11,12],9:[5,6,7,8,9,10,11,12,13], \
|
|
10:[6,7,8,9,10,11,12,13],11:[7,8,9,10,11,12,13],12:[8,9,10,11,12,13],13:[9,10,11,12,13]}
|
|
|
|
#Rellenamos canales faltantes
|
|
for canal in range(1, 14):
|
|
if not datosescaneo.has_key(canal):
|
|
datosescaneo[canal] = [0, [], 0]
|
|
|
|
#Sumemor las redes solapadas
|
|
for canal in range(1, 14):
|
|
for adyacente in adyacentes[canal]:
|
|
datosescaneo[canal][2] = datosescaneo[canal][2] + datosescaneo[adyacente][0]
|
|
|
|
def seleccionacanaloptimo(datosescaneo):
|
|
""" Procesamos diccionario y retornamos el canal óptimo,
|
|
aquel cuyo valor de numero de redes totales solapadas
|
|
centradas es el mínimo
|
|
"""
|
|
#El mejor canal, es el menor valor de los solapes de las redes centradas en canales
|
|
canaloptimo = 1
|
|
valor = datosescaneo[1][2]
|
|
for canal in range(1, 14):
|
|
if datosescaneo[canal][2] < valor:
|
|
canaloptimo = canal
|
|
valor = datosescaneo[canal][2]
|
|
return canaloptimo
|
|
|
|
def selectbestchannel(verbose = False):
|
|
""" Creamos diccionario para almacenar datos, la key principal es
|
|
es el canal, y para cada canal hay una lista en
|
|
la que se almacena el número de redes detectadas, sus BSSID junto
|
|
a su potencia e intensidad, además se almacenará
|
|
y el número de redes que se solapan con las redes centradas en canales
|
|
según patrón 1-6-11.
|
|
Controlaremos que no se dupliquen los canales cuando hay más de un interfaz wifi
|
|
comparando los BSSID para este menester
|
|
"""
|
|
|
|
#Esta seria la estructura que obtendriamos de nuestro escaneado
|
|
#{1:[3, [["MACAP1",70,-56], ["MACAP2",65,-61], ["MACAP3",60,-66]], 0],
|
|
# 2:[2, [["MACAP4",75,-51], ["MACAP5",65,-61]], 0]
|
|
# 3:[1, [["MACAP6",80,-45]], 0],
|
|
# 4:[1, [["MACAP7",60,-66]], 0]}
|
|
datosescaneo = {}
|
|
if verbose:
|
|
print "Escaneando redes WIFI..."
|
|
index = 1
|
|
for ifname in escanea.getWirelessInterfaces():
|
|
if verbose:
|
|
print " Escaneado de la interfaz %-8.16s" % (ifname, )
|
|
otros_datos_escaneo = escanea.ObtieneRedes(ifname)
|
|
if len(otros_datos_escaneo.keys()) == 0:
|
|
if verbose:
|
|
print "%-8.16s Escaneado sin resultados" % (ifname, )
|
|
for bssid in otros_datos_escaneo.keys():
|
|
if verbose:
|
|
print " Red: %02d - Canal: %s BSSID: %s ESSID: %s Quality: %s Signal Strength: %s" % \
|
|
(index, otros_datos_escaneo[bssid]['canal'], bssid, otros_datos_escaneo[bssid]['essid'], otros_datos_escaneo[bssid]['calidad'], otros_datos_escaneo[bssid]['intensidad'])
|
|
#vamos a actualizar nuestro diccionario
|
|
actualizadatosescaneo(datosescaneo, int(otros_datos_escaneo[bssid]['canal']), bssid, otros_datos_escaneo[bssid]['essid'], otros_datos_escaneo[bssid]['calidad'], otros_datos_escaneo[bssid]['intensidad'])
|
|
index = index +1
|
|
#para pruebas
|
|
#datosescaneo = {1:[2, [["01",99,-99],["02",98,-98]], 0], 6:[3, [["03",97,-97],["04",96,-96],["05",95,-95]], 0], 11:[1, ["06",94,-94], 0]}
|
|
procesadatosescaneo(datosescaneo)
|
|
canaloptimo = seleccionacanaloptimo(datosescaneo)
|
|
if verbose:
|
|
print "\nTabla de datos obtenida:"
|
|
print datosescaneo
|
|
print "\n"
|
|
print "El canal óptimo es el: ", canaloptimo
|
|
|
|
return canaloptimo
|
|
|
|
if __name__ == "__main__":
|
|
""" Comprobaremos que se ha pasado la ruta al archivo hostapd.conf
|
|
El archivo hostapd.conf debe contener la cadena 'canalseleccionado'
|
|
que será reemplazada por la salida de la función selectchannelwifi().
|
|
|
|
Además el SSID es el nombre de equipo menos la cadena '-pro', y
|
|
la cadena a buscar en el archivo hostapd.conf es 'ssidseleccionado'.
|
|
"""
|
|
if len(sys.argv) == 1:
|
|
print 'uso: ./parsehostapd.py /ruta/al/archivo/hostapd.conf'
|
|
sys.exit(1)
|
|
#Comprobemos la existencia del archivo
|
|
hostapdconf = sys.argv[1]
|
|
if not os.path.exists(hostapdconf):
|
|
print "El archivo",hostapdconf,"no existe"
|
|
exit(2)
|
|
print "Procesando archivo",hostapdconf
|
|
""" Aquí llamamos a la función desarrollada en este módulo
|
|
para asignar el canal de transmisión óptimo,
|
|
si ponemos True en el parámetro podremos ver las redes
|
|
que se detectan...
|
|
"""
|
|
canaloptimo = selectbestchannel(True)
|
|
|
|
ssid = socket.gethostname()
|
|
pos = ssid.find(".")
|
|
if pos > -1:
|
|
ssid = ssid[:pos]
|
|
pos = ssid.find("-pro")
|
|
if pos > -1:
|
|
ssid = ssid[:pos]
|
|
try:
|
|
#Abre el archivo para lectura de datos
|
|
archivoLectura = open(hostapdconf,"r")
|
|
lineas = archivoLectura.readlines()
|
|
archivoLectura.close()
|
|
except (RuntimeError, TypeError, NameError, IOError):
|
|
print "Error en la ubicacion o nombre del archivo"
|
|
exit()
|
|
#Modifica la cadena del channel y ssid
|
|
encontradoChannel = False
|
|
encontradoSsid = False
|
|
for numlinea in range(0, len(lineas)):
|
|
linea = lineas[numlinea]
|
|
#comprobamos si estamos en channel o en ssid
|
|
if linea[:7] == "channel":
|
|
encontradoChannel = True
|
|
lineas[numlinea] = "channel="+str(canaloptimo)+"\n"
|
|
if linea[:4] == "ssid":
|
|
encontradoSsid = True
|
|
lineas[numlinea] = "ssid="+ssid+"\n"
|
|
if not encontradoChannel:
|
|
lineas.append("channel="+str(canaloptimo)+"\n")
|
|
if not encontradoSsid:
|
|
lineas.append("ssid="+ssid+"\n")
|
|
|
|
#Abre el archivo para escritura de datos
|
|
archivoEscritura = open(hostapdconf,"w")
|
|
archivoEscritura.writelines(lineas)
|
|
archivoEscritura.close()
|
|
print "El canal establecido es",canaloptimo
|
|
print "El SSID establecido es",ssid
|
|
print "Se ha procesado el archivo",hostapdconf
|