utils_red.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Gestor de nodos para LaOtraRed La Paz - El Alto
  4. Copyright (C) 2017 Rodrigo Garcia
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Affero General Public License as
  7. published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Affero General Public License for more details.
  13. You should have received a copy of the GNU Affero General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. '''
  16. # Este archivo contiene utilidades para calcular/manejar bloques de
  17. # direcciones IPv4 e IPv6
  18. import hashlib
  19. import uuid
  20. from database.database import init_db, db_session
  21. from database.database import engine
  22. from .models import Nodo, Ubicacion
  23. from gestor.utils import get_randomToken
  24. from gestor.configs import RUTA_SCRIPT_GENERADOR_FIRMWARES, RUTA_IMAGENES_FIRMWARE_GENERADAS
  25. # varios red
  26. def numIpv4(ipv4):
  27. ''' Retorna el valor numerico de la direccion ipv4
  28. ejemplo: ejemplo: 32.126.2.129 => 545129089'''
  29. r = ipv4.split(".")
  30. return int(r[0])*(2**24)+int(r[1])*(2**16)+int(r[2])*(2**8)+int(r[3])
  31. def cadIpv4(valor_numerico_ipv4):
  32. ''' Retorna la representacion en cadena del valor numeico
  33. correspondiente a la direccion ipv4 dada
  34. ejemplo: 545129089 => 32.126.2.129'''
  35. cr = valor_numerico_ipv4
  36. return (str((cr&0xff000000)>>24)+"."+str((cr&0xff0000)>>16)+"." \
  37. +str((cr&0xff00)>>8)+"."+str(cr&0xff))
  38. # utilidades de comprobacion de red
  39. def obtener_bloqueIPv4Mayor(lista_bloques):
  40. ''' Dada la lista de bloques IPv4 retorna el bloque mayor
  41. ejemplo: [100.1.1.32, 101.24.1.32, 100.90.0.1, 100.2.1.64]
  42. return: 101.24.1.32
  43. '''
  44. laux = []
  45. for bloque in lista_bloques:
  46. laux.append((numIpv4(bloque), bloque))
  47. laux.sort(reverse=True)
  48. return laux[0][1]
  49. def obtener_bloqueIPv4Menor(lista_bloques):
  50. ''' Dada la lista de bloques IPv4 retorna el bloque menor
  51. ejemplo: [100.1.1.32, 101.24.1.32, 100.90.0.1, 100.2.1.64]
  52. return: 100.1.1.32
  53. '''
  54. laux = []
  55. for bloque in lista_bloques:
  56. laux.append((numIpv4(bloque), bloque))
  57. laux.sort()
  58. return laux[0][1]
  59. def obtener_mascaraIpv4(cidr):
  60. ''' Dado el CIDR obtiene la mascara de red ipv4
  61. ejemplo /27 => 255.255.255.224
  62. '''
  63. c = 0
  64. B1=""
  65. B2=""
  66. B3=""
  67. B4=""
  68. while c < cidr:
  69. if c < 8:
  70. B1+= "1"
  71. if c > 7 and c < 16:
  72. B2+= "1"
  73. if c > 15 and c < 24:
  74. B3+= "1"
  75. if c > 23:
  76. B4+= "1"
  77. c+=1
  78. #completando con 0
  79. while c < 32:
  80. if c < 8:
  81. B1+= "0"
  82. if c > 7 and c < 16:
  83. B2+= "0"
  84. if c > 15 and c < 24:
  85. B3+= "0"
  86. if c > 23:
  87. B4+= "0"
  88. c+=1
  89. # conversion a decimal
  90. return str(int(B1,base=2))+"."+str(int(B2,base=2))+ \
  91. "."+str(int(B3,base=2))+"."+str(int(B4,base=2))
  92. def obtener_direccionRedIpv4(ipv4, cidr):
  93. ''' Obtiene la direccion de red ipv4 , desde la ip y cidr
  94. ejemplo: 100.65.124.199 /26 => 100.65.124.192
  95. '''
  96. mascara = obtener_mascaraIpv4(cidr)
  97. ip_bytes = ipv4.split(".")
  98. mascara_bytes = mascara.split(".")
  99. B4 = str(int(ip_bytes[3]) & int(mascara_bytes[3]))
  100. B3 = str(int(ip_bytes[2]) & int(mascara_bytes[2]))
  101. B2 = str(int(ip_bytes[1]) & int(mascara_bytes[1]))
  102. B1 = str(int(ip_bytes[0]) & int(mascara_bytes[0]))
  103. return B1+"."+B2+"."+B3+"."+B4
  104. def siguiente_bloqueIpv4Disponible(cidr, publico=True):
  105. ''' Dado el CIDR comprueba en la base de datos los bloques disponibles
  106. en los registros de los nodos y devuelve el siguiente bloque IPv4
  107. disponible para ese CIDR, se sigue la politica:
  108. CIDR bloque
  109. /24 10.64.0.0 - 10.64.0.255
  110. /25 10.64.1.0 - 10.64.1.255
  111. /26 10.64.2.0 - 10.64.2.255
  112. /27 10.64.3.0 - 10.64.3.255
  113. /28 10.64.4.0 - 10.64.4.255
  114. /24 10.64.5.0 - 10.64.5.255
  115. /25 10.64.6.0 – 10.64.6.255
  116. ... ...
  117. (asi sucesivamente)
  118. TODO: devolver el primer bloque disponible significa tambien
  119. buscar entre los no usados (nodos que no han confirmado su participacion)
  120. Esto se puede obtener buscando los nodos proyectados con
  121. fecha de creacion prolongada y que no estan activos (no se han
  122. confirmado), luego obtener el bloque menor.
  123. Asi se puede llenar el 'hueco' que ha dejado el nodo no usado ni
  124. confirmado
  125. '''
  126. print ("---- Calculando bloque de direcciones IPv4 -----")
  127. # obteniendo el mayor bloque ipv4 con cidr igual
  128. lista = []
  129. if publico:
  130. for nodo in db_session.query(Nodo).\
  131. filter(Nodo.ipv4_cidr == cidr).all():
  132. lista.append(nodo.ipv4_network_addr)
  133. else:
  134. for nodo in db_session.query(Nodo).all():
  135. lista.append(nodo.bloque_ipv4_privado)
  136. # filtrando entre ip publicas o privadas
  137. nlista = []
  138. for ipv4addr in lista:
  139. if publico:
  140. if ipv4addr.startswith("10.64"):
  141. nlista.append(ipv4addr)
  142. else:
  143. if ipv4addr.startswith("172.24"):
  144. nlista.append(ipv4addr)
  145. # primera insercion
  146. if len(nlista) == 0:
  147. if publico:
  148. if cidr == 24:
  149. nlista.append("10.63.255.0") # truco para empezar en 10.64.0.0
  150. elif cidr == 25:
  151. nlista.append("10.64.1.0")
  152. elif cidr == 26:
  153. nlista.append("10.64.2.0")
  154. elif cidr == 27:
  155. nlista.append("10.64.3.0")
  156. elif cidr == 28:
  157. nlista.append("10.64.4.0")
  158. else:
  159. nlista.append("172.24.0.0")
  160. bloque_mayor = obtener_bloqueIPv4Mayor(nlista)
  161. ultima_dir_red = obtener_direccionRedIpv4(bloque_mayor, cidr)
  162. print ("Bloque mayor:"+bloque_mayor)
  163. print ("cidr:"+str(cidr))
  164. print ("Ultima red:"+ultima_dir_red)
  165. # calculando salto y siguiente direcicon de red
  166. m1 = numIpv4(ultima_dir_red) % 256
  167. m2 = 0
  168. p = 32 - cidr
  169. if cidr == 28:
  170. m2 = (numIpv4(ultima_dir_red) + 16) % 256
  171. elif cidr == 27:
  172. m2 = (numIpv4(ultima_dir_red) + 32) % 256
  173. elif cidr == 26:
  174. m2 = (numIpv4(ultima_dir_red) + 64) % 256
  175. elif cidr == 25:
  176. m2 = (numIpv4(ultima_dir_red) + 128) % 256
  177. elif cidr == 24:
  178. m2 = (numIpv4(ultima_dir_red) + 256) % 256
  179. if m1 > m2:
  180. # saltando 5 subredes /24
  181. n_r = numIpv4(ultima_dir_red) + (256*5)
  182. else:
  183. n_r = numIpv4(ultima_dir_red)
  184. print("Siguiente bloque:"+cadIpv4(n_r + 2**p))
  185. print ("------------------------------------------------")
  186. return cadIpv4(n_r + 2**p)
  187. def get_cidrIpV4(num_direcciones):
  188. ''' Retorna el cidr necesario para el `num_direcciones' dadas
  189. '''
  190. n = int(num_direcciones)
  191. if n <= 14:
  192. return 28
  193. if n > 14 and n <= 30:
  194. return 27
  195. if n > 30 and n <= 62:
  196. return 26
  197. if n > 62 and n <= 126:
  198. return 25
  199. if n > 126 and n <= 254:
  200. return 24
  201. return -1
  202. def siguiente_bloqueIpv6Disponible():
  203. ''' Dado el CIDR comprueba en la base de datos los bloques disponibles
  204. en los registros de los nodos y devuelve el siguiente bloque IPv6
  205. El bloque ipv6 se obtiene de manera aleatoria, usando el bloque:
  206. fc01:1934:fffe:9493::/64
  207. que comparten todos los nodos de la red, un router deberia tener esto:
  208. fc01:1934:fffe:9493:c24a:ff:fedd:5e7a/128
  209. La asignacion genera un valor aleatorio para los ultimos
  210. 4 grupos (en ipv6) es decir:
  211. fc01:1934:fff3:9493:<rand>:<rand>:<rand>:<rand>/128
  212. y comprueba que no exista este numero antes.
  213. '''
  214. print ("---- Calculando bloque de direcciones IPv6 -----")
  215. unico = False
  216. ipv6 = 'fc01:1934:fffe:9493:'
  217. while not unico:
  218. token = get_randomToken()
  219. g1 = token[0:4]
  220. g2 = token[4:8]
  221. g3 = token[11:15]
  222. g4 = token[19:23]
  223. aux = ipv6+g1+':'+g2+":"+g3+":"+g4+"/128"
  224. n1 = db_session.query(Nodo).\
  225. filter(Nodo.bloque_ipv6 == aux).count()
  226. if n1 == 0:
  227. unico = True
  228. ipv6 = aux
  229. print ("siguiente bloque: "+ipv6)
  230. print ("------------------------------------------------")
  231. return ipv6