123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- # -*- coding: utf-8 -*-
- '''
- Gestor de nodos para LaOtraRed La Paz - El Alto
- Copyright (C) 2017 Rodrigo Garcia
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero 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 Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- '''
- # Este archivo contiene utilidades para calcular/manejar bloques de
- # direcciones IPv4 e IPv6
- import hashlib
- import uuid
- from database.database import init_db, db_session
- from database.database import engine
- from .models import Nodo, Ubicacion
- from gestor.utils import get_randomToken
- from gestor.configs import RUTA_SCRIPT_GENERADOR_FIRMWARES, RUTA_IMAGENES_FIRMWARE_GENERADAS
- # varios red
- def numIpv4(ipv4):
- ''' Retorna el valor numerico de la direccion ipv4
- ejemplo: ejemplo: 32.126.2.129 => 545129089'''
- r = ipv4.split(".")
- return int(r[0])*(2**24)+int(r[1])*(2**16)+int(r[2])*(2**8)+int(r[3])
-
- def cadIpv4(valor_numerico_ipv4):
- ''' Retorna la representacion en cadena del valor numeico
- correspondiente a la direccion ipv4 dada
- ejemplo: 545129089 => 32.126.2.129'''
- cr = valor_numerico_ipv4
- return (str((cr&0xff000000)>>24)+"."+str((cr&0xff0000)>>16)+"." \
- +str((cr&0xff00)>>8)+"."+str(cr&0xff))
- # utilidades de comprobacion de red
- def obtener_bloqueIPv4Mayor(lista_bloques):
- ''' Dada la lista de bloques IPv4 retorna el bloque mayor
- ejemplo: [100.1.1.32, 101.24.1.32, 100.90.0.1, 100.2.1.64]
- return: 101.24.1.32
- '''
- laux = []
- for bloque in lista_bloques:
- laux.append((numIpv4(bloque), bloque))
- laux.sort(reverse=True)
- return laux[0][1]
- def obtener_bloqueIPv4Menor(lista_bloques):
- ''' Dada la lista de bloques IPv4 retorna el bloque menor
- ejemplo: [100.1.1.32, 101.24.1.32, 100.90.0.1, 100.2.1.64]
- return: 100.1.1.32
- '''
- laux = []
- for bloque in lista_bloques:
- laux.append((numIpv4(bloque), bloque))
- laux.sort()
- return laux[0][1]
- def obtener_mascaraIpv4(cidr):
- ''' Dado el CIDR obtiene la mascara de red ipv4
- ejemplo /27 => 255.255.255.224
- '''
- c = 0
- B1=""
- B2=""
- B3=""
- B4=""
- while c < cidr:
- if c < 8:
- B1+= "1"
- if c > 7 and c < 16:
- B2+= "1"
- if c > 15 and c < 24:
- B3+= "1"
- if c > 23:
- B4+= "1"
- c+=1
- #completando con 0
- while c < 32:
- if c < 8:
- B1+= "0"
- if c > 7 and c < 16:
- B2+= "0"
- if c > 15 and c < 24:
- B3+= "0"
- if c > 23:
- B4+= "0"
- c+=1
- # conversion a decimal
- return str(int(B1,base=2))+"."+str(int(B2,base=2))+ \
- "."+str(int(B3,base=2))+"."+str(int(B4,base=2))
- def obtener_direccionRedIpv4(ipv4, cidr):
- ''' Obtiene la direccion de red ipv4 , desde la ip y cidr
- ejemplo: 100.65.124.199 /26 => 100.65.124.192
- '''
- mascara = obtener_mascaraIpv4(cidr)
- ip_bytes = ipv4.split(".")
- mascara_bytes = mascara.split(".")
- B4 = str(int(ip_bytes[3]) & int(mascara_bytes[3]))
- B3 = str(int(ip_bytes[2]) & int(mascara_bytes[2]))
- B2 = str(int(ip_bytes[1]) & int(mascara_bytes[1]))
- B1 = str(int(ip_bytes[0]) & int(mascara_bytes[0]))
- return B1+"."+B2+"."+B3+"."+B4
- def siguiente_bloqueIpv4Disponible(cidr, publico=True):
- ''' Dado el CIDR comprueba en la base de datos los bloques disponibles
- en los registros de los nodos y devuelve el siguiente bloque IPv4
- disponible para ese CIDR, se sigue la politica:
- CIDR bloque
- /24 10.64.0.0 - 10.64.0.255
- /25 10.64.1.0 - 10.64.1.255
- /26 10.64.2.0 - 10.64.2.255
- /27 10.64.3.0 - 10.64.3.255
- /28 10.64.4.0 - 10.64.4.255
- /24 10.64.5.0 - 10.64.5.255
- /25 10.64.6.0 – 10.64.6.255
- ... ...
- (asi sucesivamente)
- TODO: devolver el primer bloque disponible significa tambien
- buscar entre los no usados (nodos que no han confirmado su participacion)
- Esto se puede obtener buscando los nodos proyectados con
- fecha de creacion prolongada y que no estan activos (no se han
- confirmado), luego obtener el bloque menor.
- Asi se puede llenar el 'hueco' que ha dejado el nodo no usado ni
- confirmado
- '''
- print ("---- Calculando bloque de direcciones IPv4 -----")
- # obteniendo el mayor bloque ipv4 con cidr igual
- lista = []
- if publico:
- for nodo in db_session.query(Nodo).\
- filter(Nodo.ipv4_cidr == cidr).all():
-
- lista.append(nodo.ipv4_network_addr)
- else:
- for nodo in db_session.query(Nodo).all():
- lista.append(nodo.bloque_ipv4_privado)
-
- # filtrando entre ip publicas o privadas
- nlista = []
- for ipv4addr in lista:
- if publico:
- if ipv4addr.startswith("10.64"):
- nlista.append(ipv4addr)
- else:
- if ipv4addr.startswith("172.24"):
- nlista.append(ipv4addr)
-
- # primera insercion
- if len(nlista) == 0:
- if publico:
- if cidr == 24:
- nlista.append("10.63.255.0") # truco para empezar en 10.64.0.0
- elif cidr == 25:
- nlista.append("10.64.1.0")
- elif cidr == 26:
- nlista.append("10.64.2.0")
- elif cidr == 27:
- nlista.append("10.64.3.0")
- elif cidr == 28:
- nlista.append("10.64.4.0")
- else:
- nlista.append("172.24.0.0")
- bloque_mayor = obtener_bloqueIPv4Mayor(nlista)
- ultima_dir_red = obtener_direccionRedIpv4(bloque_mayor, cidr)
- print ("Bloque mayor:"+bloque_mayor)
- print ("cidr:"+str(cidr))
- print ("Ultima red:"+ultima_dir_red)
- # calculando salto y siguiente direcicon de red
- m1 = numIpv4(ultima_dir_red) % 256
- m2 = 0
- p = 32 - cidr
- if cidr == 28:
- m2 = (numIpv4(ultima_dir_red) + 16) % 256
- elif cidr == 27:
- m2 = (numIpv4(ultima_dir_red) + 32) % 256
- elif cidr == 26:
- m2 = (numIpv4(ultima_dir_red) + 64) % 256
- elif cidr == 25:
- m2 = (numIpv4(ultima_dir_red) + 128) % 256
- elif cidr == 24:
- m2 = (numIpv4(ultima_dir_red) + 256) % 256
- if m1 > m2:
- # saltando 5 subredes /24
- n_r = numIpv4(ultima_dir_red) + (256*5)
- else:
- n_r = numIpv4(ultima_dir_red)
-
- print("Siguiente bloque:"+cadIpv4(n_r + 2**p))
- print ("------------------------------------------------")
- return cadIpv4(n_r + 2**p)
- def get_cidrIpV4(num_direcciones):
- ''' Retorna el cidr necesario para el `num_direcciones' dadas
- '''
- n = int(num_direcciones)
- if n <= 14:
- return 28
- if n > 14 and n <= 30:
- return 27
- if n > 30 and n <= 62:
- return 26
- if n > 62 and n <= 126:
- return 25
- if n > 126 and n <= 254:
- return 24
- return -1
- def siguiente_bloqueIpv6Disponible():
- ''' Dado el CIDR comprueba en la base de datos los bloques disponibles
- en los registros de los nodos y devuelve el siguiente bloque IPv6
- El bloque ipv6 se obtiene de manera aleatoria, usando el bloque:
- fc01:1934:fffe:9493::/64
- que comparten todos los nodos de la red, un router deberia tener esto:
- fc01:1934:fffe:9493:c24a:ff:fedd:5e7a/128
- La asignacion genera un valor aleatorio para los ultimos
- 4 grupos (en ipv6) es decir:
- fc01:1934:fff3:9493:<rand>:<rand>:<rand>:<rand>/128
- y comprueba que no exista este numero antes.
- '''
- print ("---- Calculando bloque de direcciones IPv6 -----")
- unico = False
- ipv6 = 'fc01:1934:fffe:9493:'
- while not unico:
- token = get_randomToken()
- g1 = token[0:4]
- g2 = token[4:8]
- g3 = token[11:15]
- g4 = token[19:23]
- aux = ipv6+g1+':'+g2+":"+g3+":"+g4+"/128"
- n1 = db_session.query(Nodo).\
- filter(Nodo.bloque_ipv6 == aux).count()
- if n1 == 0:
- unico = True
- ipv6 = aux
- print ("siguiente bloque: "+ipv6)
- print ("------------------------------------------------")
- return ipv6
-
|