martes, 21 de enero de 2025

Condicionales en Python para Ingenieros de Redes: Guia de Estudio (5)

Sentencias Condicionales en Python: Tu Guía Definitiva

En esta entrada se revisarán las sentencias condicionales. Estas estructuras nos permiten tomar decisiones en nuestro código, ejecutando diferentes bloques de instrucciones dependiendo de si se cumplen ciertas condiciones. Es como darle cerebro a nuestros scripts.

Los Tres Pilares de las Sentencias Condicionales

En Python, tenemos tres tipos principales de sentencias condicionales que podemos utilizar:

  • if: La base de todo. Es la única sentencia obligatoria cuando trabajamos con condicionales. Usamos if para evaluar una condición inicial y ejecutar un bloque de código si esa condición es verdadera.
  • elif: ¿Qué pasa si la primera condición no se cumple? Ahí es donde entra elif ("else if"). Esta sentencia es opcional y nos permite añadir condiciones adicionales a evaluar. Se ejecutará solo si la condición del if y cualquier elif anterior es falsa.
  • else: El comodín. Esta sentencia también es opcional y se utiliza como un "catch-all". Si ninguna de las condiciones if o elif se cumple, entonces se ejecutará el bloque de código dentro de else.

La Estructura: Clave para el Éxito

La sintaxis de estas sentencias es crucial:

  1. Comenzamos con if, elif o else, seguido de una condición (en el caso de if y elif).

  2. Después de la condición (o de la palabra clave else), ponemos dos puntos (:).

  3. ¡La indentación es fundamental! El código que se ejecutará si la condición es verdadera debe estar indentado. La convención en Python es usar cuatro espacios para cada nivel de indentación.

    • VS Code y otros editores inteligentes suelen indentar automáticamente a 4 espacios cuando creas sentencias condicionales.
    • Recuerda, ¡la indentación es la base de la estructura en Python! Si la olvidas o la haces mal, tu programa fallará.

viernes, 17 de enero de 2025

Strings en Python para Ingenieros de Redes: Guia de Estudio (4)


En esta serie de artículos, exploraremos a fondo el manejo de cadenas de texto (strings) en Python, un concepto fundamental para cualquier persona interesada en la programación, y especialmente crucial para la automatización de redes

  • Definición de Cadenas (Strings) en Python:
    • Las cadenas son secuencias ordenadas de caracteres.
    • Se crean utilizando comillas simples o dobles. Por ejemplo, "Rambo" o 'wifispainreles'.
    • El orden de los caracteres en una cadena es importante. "Rambo" no es lo mismo que "obmar".
    • Podemos acceder a cada uno de los caracteres  mediante su posició:

lunes, 13 de enero de 2025

Datos Mutable e Inmutables en Python para Ingenieros de Redes: Guia de Estudio (3)

 

Tipos de datos mutables:

  • Los tipos de datos mutables son aquellos que se pueden actualizar sin alterar la ubicación de los datos en la memoria.
  • Los ejemplos de tipos de datos mutables en Python son listas, diccionarios y conjuntos.

Listas:

  • Las listas se crean usando corchetes [].
  • Los elementos de una lista se separan con comas.


  • El primer elemento de una lista se encuentra en la posición 0.
  • Las listas se pueden actualizar usando el método append() para agregar nuevos elementos. Por ejemplo: my_routes.append("8.8.8.8/32").


  • Se puede acceder a elementos específicos de una lista usando su posición entre corchetes. Por ejemplo, my_routes[0] accede al primer elemento.

miércoles, 8 de enero de 2025

Tipos de Datos en Python para Ingenieros de Redes: Guia de Estudio (2)



Guía de Estudio: Tipos de Datos en Python para Ingenieros de Redes

Introducción En Python, los tipos de datos son fundamentales porque determinan qué tipo de valores pueden almacenar las variables y qué operaciones se pueden realizar con ellas. Aunque Python es un lenguaje de escritura dinámica, donde no es necesario declarar explícitamente el tipo de dato de una variable, es crucial entender los diferentes tipos para escribir un código eficiente y sin errores. Este post servirá como una guía para comprender los tipos de datos más comunes en Python, especialmente en el contexto de la automatización de redes.

Tipos de Datos Primitivos Estos son los tipos de datos básicos que se utilizan para representar valores individuales:

  • Texto (str): Este tipo de dato se utiliza para representar texto y cadenas de caracteres. Es una secuencia ordenada de caracteres.

    • Ejemplos: "VLAN", "show version", "show ip interface brief".
    • Este tipo de dato es muy común en la automatización de redes.
  • Numéricos (int, float):

    • int: Representa números enteros.
      • Ejemplos: 1, 500, 5324.
    • float: Representa números con decimales.
      • Ejemplos: 15.8, 15.0.
      • Es importante notar que 15.0 es un float debido al punto decimal, no un int.
    • complex: Aunque Python soporta números complejos, estos son menos relevantes en la automatización de redes y se utilizan más en campos como el aprendizaje automático y la ciencia de datos.
  • Booleanos (bool): Representan valores lógicos que pueden ser True o False.

    • Son esenciales para la lógica condicional en programas.

Tipos de Datos de Secuencia Estos tipos de datos se utilizan para almacenar colecciones de elementos:

  • Listas (list): Son secuencias ordenadas y mutables de objetos.
    • Ordenadas: La posición de cada elemento importa.
      • Por ejemplo, una lista de instrucciones debe seguir un orden lógico.
    • Mutables: Los elementos de una lista pueden ser modificados después de su creación.
  • Tuplas (tuple): Similar a las listas, son secuencias ordenadas de objetos.
    • Inmutables: Una vez creadas, no se pueden modificar.

Tipos de Datos de Mapeo

  • Diccionarios (dict): Son colecciones de pares clave-valor no ordenados.
    • Son muy útiles en automatización de redes.
    • Permiten acceder a información específica mediante una clave.
    • A diferencia de las listas y tuplas, los diccionarios no tienen un orden inherente.

Tipos de Datos de Conjuntos

  • Conjuntos (set): Son colecciones mutables de objetos únicos y no ordenados.
    • No permiten duplicados.
  • Conjuntos Congelados (frozenset): Similar a los conjuntos, pero inmutables.

Importancia de los Tipos de Datos Comprender los tipos de datos en Python es vital porque cada tipo tiene sus propias características y comportamientos. Esto permite:

  • Manejar datos de manera efectiva: Saber si un dato es un entero, un texto, una lista o un diccionario permite utilizar las operaciones correctas.
  • Escribir código eficiente: Los distintos tipos de datos están optimizados para diferentes usos.
  • Evitar errores: Intentar realizar una operación no válida en un tipo de dato (como sumar texto y números) puede generar errores.

Conclusión Este post te proporciona una base sólida para entender los tipos de datos más comunes en Python, lo cual es esencial para programar y especialmente en el contexto de la automatización de redes. Familiarízate con la diferencia entre strings, ints, floats, lists, tuples, dictionaries, sets y booleans. Entender cómo se almacenan y manipulan los datos es fundamental para cualquier proyecto de automatización que quieras emprender. Sigue aprendiendo y experimentando con estos tipos de datos, y verás cómo la programación en Python te será más intuitiva y eficiente.

martes, 7 de enero de 2025

Variables en Python para Ingenieros de Redes: Una Guía de Estudio


 



Variables en Python para Ingenieros de Redes: Una Guía de Estudio

¡Hola a todos! En esta guía, exploraremos un concepto fundamental en Python: las variables. Como ingenieros de redes, usarán variables constantemente para la automatización, por lo que es crucial entenderlas bien. Aunque hay algunos conceptos en Python que tal vez no se utilicen en este campo, las variables son esenciales.

¿Qué son las variables?

Las variables son contenedores que se utilizan para almacenar datos temporalmente en la memoria de la computadora. Los datos pueden ser de diferentes tipos, como números o texto.

Una característica importante de Python es que es un lenguaje dinámicamente tipado. Esto significa que no es necesario especificar el tipo de dato que se almacenará en una variable antes de guardarlo. Python manejará el tipo de dato de forma automática. Esto le da flexibilidad y facilidad de uso.

Ejemplos prácticos en Ipython

Para entender mejor cómo funcionan las variables, podemos usar la terminal interactiva Ipython:

  1. Asignación de un valor a una variable:
  • Para crear una variable, se le da un nombre y se usa el signo igual (=) para asignarle un valor.
  • Por ejemplo, podemos crear una variable llamada name y asignarle el valor "Juan": name = "Juan".
  • Para verificar el valor de la variable, simplemente se escribe su nombre en Ipython y se presiona enter
     2. Otros ejemplos de variables:

  • Podemos crear otra variable llamada a_random_number y asignarle el valor 5: a_random_number = 5.
Al igual que antes, si escribimos a_random_number en Ipython y presionamos enter, veremos que su valor es 5.


     3. ID único de un objeto:

  • Python asigna un ID único a cada objeto en memoria.
  • Podemos inspeccionar el ID de una variable utilizando la función id().


  • Si comparamos los ID de diferentes variables, veremos que son distintos.

     4. Actualización de variables:

  • El valor de una variable puede ser cambiado.
  • Por ejemplo, si cambiamos el valor de la variable name de "Juan" a "Laura", el valor anterior se sobreescribirá. name = "Laura"
  • Si escribimos name nuevamente en Ipython, el valor mostrado ahora será "Laura".
  • El ID del objeto también cambia, lo que indica que se ha creado un nuevo objeto en memoria.
  • Lo mismo aplica para las variables numéricas. Si actualizamos a_random_number de 5 a 16, el valor anterior se sobreescribe y el ID también cambiará.

     5. Ejemplos de uso con VLANs:

  • En la práctica, se usan variables para almacenar información como nombres de VLANs.
  • Por ejemplo: my_vlan = "marketing VLAN" y my_new_vlan = "human resources department".
  • Luego, se pueden usar estas variables en funciones como print() para mostrar los valores en la pantalla.

Importancia de las variables

Aunque al principio el uso de variables puede no ser tan obvio, a medida que se comience a escribir scripts, se apreciará su utilidad. Las variables permiten almacenar información que puede ser usada y modificada a lo largo de un programa.

Puntos clave a recordar:

  • Las variables almacenan datos temporalmente en la memoria del computador.
  • Python es un lenguaje dinámicamente tipado, lo que facilita el trabajo con variables.
  • El valor de una variable puede cambiar.
  • Cada variable tiene un ID único.
  • Las variables son fundamentales en la programación y la automatización de redes.
Reglas y Convenciones Clave
  • Uso de Mayúsculas y Minúsculas: En general, las variables deben escribirse en minúsculas o mayúsculas. Aunque Python permite mezclar mayúsculas y minúsculas, se recomienda mantener una sola convención para mejorar la claridad. 
Por ejemplo, usa router o ROUTER, pero evita RoUtEr.
  • Caracteres Permitidos: Los nombres de las variables pueden contener letras (mayúsculas o minúsculas), guiones bajos (_), y dígitos.Ejemplos válidos: router_1, numberOfRoutes, DeviceR2.
  • Restricción de Dígitos al Inicio: Los nombres de las variables no deben comenzar con un dígito.
Ejemplo incorrecto: 1router. Ejemplo correcto: router1.
  • Guiones Bajos para Separar Palabras: Los guiones bajos se utilizan para separar palabras en nombres de variables, lo cual facilita la lectura.
Ejemplo: number_of_routes.
  • Prohibición de Caracteres Especiales: No se deben utilizar caracteres especiales como @, $, %, etc., en los nombres de las variables.○
Ejemplos incorrectos: my-email, number$, percentage%.
Estos caracteres especiales causarán errores de sintaxis.
  • Convenciones de Estilo: Aunque Python no impone ciertas restricciones, seguir las convenciones de estilo es vital para un código limpio y profesional.

Ejemplo: Prefiere router en lugar de ROUTER para variables genéricas.
Ejemplos Prácticos Para ilustrar mejor las reglas, veamos algunos ejemplos de cómo nombrar variables correctamente:

router_name = "R1" (Correcto: minúsculas y guiones bajos).

NUMBER_OF_PORTS = 24 (Correcto: mayúsculas para constantes).
deviceR2 = "Cisco" (Correcto: mezcla de mayúsculas y minúsculas con un número pero no comienza con un número).
number_of_routes = 20 (Correcto: guiones bajos para separar palabras).
SO1_router = "R1" (Incorrecto: comienza con un dígito).
my_email = "user@example.com" (Incorrecto: contiene un caracter especial).
network_down_2_percent = 2 (Correcto: dígitos en el medio del nombre).

Conclusión:
 Aunque Python tiene cierta flexibilidad en el nombramiento de variables, es importante adherirse a las reglas básicas y las convenciones de estilo para mejorar la legibilidad y el mantenimiento del código. Recuerda: no empieces con un dígito, no uses caracteres especiales, y usa guiones bajos para separar palabras. Al seguir estas pautas, asegurarás que tu código Python sea profesional y fácil de entender. El poder y la utilidad de las variables se harán más claros a medida que sigas aprendiendo


sábado, 10 de agosto de 2024

Cómo configurar GeoIP en Wireshark para mejorar la seguridad de la red

 



Wireshark es una herramienta poderosa para analizar el tráfico de red, y con la configuración GeoIP, puedes añadir una capa adicional de información a tu análisis al ver la ubicación geográfica de las direcciones IP. Esto puede ser especialmente útil para detectar ataques, ya que puedes identificar rápidamente el origen de tráfico sospechoso.

Configuración de GeoIP en Wireshark:

  1. Descarga las bases de datos GeoIP: Primero, necesitas descargar las bases de datos GeoLite2 desde MaxMind. Necesitarás registrarte para obtener una cuenta gratuita en su sitio web. Puedes descargar las bases de datos en formato Gzip para GeoLite2 ASN, GeoLite2 City y GeoLite2 Country. Ten en cuenta que estas bases de datos gratuitas son menos precisas que las de pago, que se actualizan con más frecuencia.
    Las bases de datos se pueden descargar desde la siguiente url:
  2. Importa las bases de datos a Wireshark:
    • Abre las Preferencias de Wireshark (en Mac: Wireshark > Preferencias; en Windows/Linux: Editar > Preferencias).
    • Ve a Resolución de nombres > Directorios de bases de datos MaxMind.




    • Haz clic en "Editar" y luego en "Añadir" para seleccionar la carpeta donde has extraído las bases de datos GeoLite2.
    • Puedes eliminar cualquier ruta de base de datos antigua si es necesario.
    • Haz clic en "Aceptar" para guardar los cambios.
  3. Reinicia Wireshark: Es posible que debas reiniciar Wireshark para que los cambios surtan efecto.


Uso de GeoIP para detectar ataques:

Una vez que hayas configurado GeoIP, puedes utilizarlo para identificar el origen geográfico del tráfico de red en Wireshark. Esto puede ser útil para detectar varios tipos de ataques, como:

  • Escaneos de red: Si ves un gran número de conexiones entrantes desde diferentes direcciones IP, puedes utilizar GeoIP para ver si provienen de la misma ubicación geográfica. Esto podría indicar un ataque de escaneo de red distribuido.
  • Ataques de denegación de servicio (DoS): Si experimentas un ataque DoS, puedes utilizar GeoIP para identificar la ubicación de los atacantes. Esta información puede ser útil para bloquear el tráfico malicioso.
  • Explotación de vulnerabilidades: Si detectas tráfico sospechoso que intenta explotar una vulnerabilidad en tu red, puedes utilizar GeoIP para determinar su origen y tomar medidas para mitigar el ataque.

Ejemplo de uso de GeoIP:

En un archivo de captura de Wireshark, puedes encontrar información GeoIP en la sección IP de un paquete. Para ver la ubicación geográfica de todas las direcciones IP en un archivo de captura, puedes ir a Estadísticas > Puntos finales y seleccionar la pestaña "IP".



También puedes filtrar el tráfico por país utilizando el código ISO de dos letras. Por ejemplo, para filtrar el tráfico procedente de Rusia, puedes utilizar el filtro "ip.geoip.country_iso == RU".

Recuerda: La información GeoIP no siempre es precisa, ya que las direcciones IP pueden ser falsificadas. Sin embargo, puede ser una herramienta útil para detectar y analizar ataques de red.

sábado, 9 de marzo de 2024

Modulación , codificación y cálculo del bitrate.



La idea que principal de las redes inalámbricas es pode trasmitir los datos generados o almacenados en una aplicación de un dispositivo a otro dispositivo remoto. La trasmisión de estos datos ha de ser lo más rápido posible y al ser un medio compartido que donde pueden haber interferencias, se ha de integrar algunos mecanismo que permitan recuperar los datos en caso de que parte en algún de la emisión éstos se hayas visto corrompido. 

Hemos de tener en cuenta que los datos normalmente son representados por bits (unos y ceros), pero las redes inalámbricas trabaja por señales analógicas representadas por ondas. Es por eso que para poder cumplir todo lo mencionado anteriormente, se hace meter en el juego lo que se denomina modulación y codificación.

Si nos centramos en la modulación podríamos decir que consiste en representar mediante ondas cada bits de datos que se ha de propagar de un dispositivo a otro por el aire. Las cualidades que se utilizan para modificar las ondas son las siguientes:

  • Amplitud: es la fuerza con la que se emite la señal en función de si la potencia sigue constante podemos decir que el valor del bit es 0 y cuando hay cambio en la amplitud quiere decir que se envía un 1. En OFDM por ejemplo se utilizan varios intervalos de amplitud para poder representar múltiples bits.


  • Fase: se utiliza en comparación con otra onda. Si la fase es la misma, esta en fase y la potencia se duplica. En cambio si están desfasado 180º la señal se suprime. Si en un momento de la señalización la fase cambia, el valor cambia, en caso contrario el valor se mantiene.



Los tipos de modulación se pueden usar de forma simultánea para poder trasmitir más bits.

Al total de bits que se permite enviar mediante los diferentes tipos de modulación se le denomina Symbols = #waveform

Mientras mas datos que queramos enviar en un determinado espacio de tiempo, más cambios en las ondas se han de poder realizar. De manera que si por ejemplo una onda permite 4 formas distintas (ya sea en cambio de fase o de amplitud) podríamos llegar a representar 16 bits. La función para saber el numero de bit en una waveform se puede obtener mediante la operación 2x.



Ej. Si elevamos 2 a la 8 (8 formas diferentes de onda) podemos llegar a representar 256 bits.

A la cantidad de bits que se pueden representar con una waveform se le denomina "symbol"



Mientras más datos se quiere enviar más compleja debe ser la modulación y mejor la calidad de la señal. A continuación hay una captura de la constelación usada por OFDM de 64 QAM (modula modificando la fase y la amplitud simultáneamente) donde se detalla la cantidad de símbolos que se pueden combinar. Como podemos ver cada símbolo esta representado por 6 bits



A partir de este punto interviene el "Data Encoding"

Data Encoding: es el proceso que usado para convertir los datos que provienen de la aplicación en ondas de radio (waveform) para poder ser enviadas por el aire y ser descodificadas en el destino. El mecanismo que se utiliza es la modulación.


Como hemos comentado también recomendable disponer de un mecanismo para poder recuperar estos bit que se envían en caso que la señal se pueda ver afectada por alguna interferencia. Aquí entra en acción un elemento denominado Convultional Coding. Este mecanismo permite corregir errores antes de que la trama pase por el proceso de CRC y sea descartado si hay algún error. Para ello se introduce bits adicionales para poder hacer esa corrección de errores. Estos bits de añaden desde el inicio de la trasmisión y el proceso de corrección se denomina Forward Error Correction (FEC). El "coding rate" especifica del total de bits enviados representan datos útiles y el número de bits que se utilizan para recuperación de datos en caso de interferencias. En ratio se representa en forma de fracción como por ejemplo 2/3. En este ejemplo la interpretación sería que de cada 3 bits enviado sólo hay dos bits que representan datos útiles y 1 más para recuperación de datos en caso de corrupción de la señal. Mientras mas bits utilizados para la corrección de datos, menor es el data rate que se consigue.
Como hemos comentado, cuando trasmitimos mediante Wifi usamos Coding Rate para recuperar datos en caso de interferencia. Por lo que si queremos trasmitir 12000 bit el tamaño final del paquete aumenta para aplicar la codificación. En 2/3 aumentaría a 18000.

En OFDM tenemos 48 subportadoras de datos. Si modulamos en 64-QAM permitimos enviar 6 bit por símbolo. 6 bit x 48 subcarrier = 288 bit/sim . 
Para poder trasmitir los 18 000 bits necesitaríamos 63 símbolos (18000/288).


En OFDM la trasmisión de un símbolo dura 3.2 µ . Una vez realizada la trasmisión el receptor ha de esperar un tiempo antes de volver a trasmitir el siguiente símbolo para permitir que la trama anterior llegue al destino y las trasmisiones no se solapen. A este intervalo de tiempo se le denomina "Guard Interval". Existen dos intervalos, el "Short Guard Interval" SGI que tiene una duración de 0.4 microsegundos o el "Long Guard Interval" LGI que tiene una duración de 0.8 microsegundos
Si usamos LGI necesitaríamos  para trasmitir cada símbolo. En total para trasmitir los 18000 bits necesitaríamos 252 µs (63 símbolos * 4µs para trasmitir cada símbolo)
Los anchos de banda conseguidos en función del ratio de codificación se puede consulta en la tabla de MCS index. Ahí aparecen todos los valores en función de la tecnología PHY usada y amplitudes de canal.



Un elemento que influye a la hora de decidir que modulación utilizada es el SNR. Mientras mas bajo es el SNR menor es el coding rate y menos bits de datos útiles se envían, pero más tolerante a corrección de errores.
Visto todo lo anterior solo quedaría un punto. ¿Cómo se calcula el data rate que aparece asociado a cada modulación?
Recordemos que OFDM cuando se modula para 802.11n y 80211ac dispone de 52 subportadoras para el envío de datos. Recordemos que cada símbolo se trasmite en 3.2µs + 0.8µs de LGI. Para obtener las transmisiones que se realizan en un µs se ha de dividir las 52 subportadoras entre 4 µs, lo que nos da un total de 13 transmisiones cada µs. Si lo pasamos a segundos, 1µs = 1.0E-6 s

13 trans/1.0E-6 s= 13*10E6 = 13000000 trans/seg (13M trans/seg)


Vamos a ver como calcularíamos el data rate para 256-QAM. Esta modulación permite enviar 8 bit por símbolo. Si tomamos como referencia un coding rate de 2/3 con LGI, tendríamos que multiplicar los 13.000 retrasmisiones que se hacen por segundo por los 8 bit que se envían por trasmisión lo que nos.

13M Tras/seg * 8bit/1 Trans = 104 Mbps

Si usamos usamos un coding rate de 3/4 nos queda los siguiente:

104 Mbps * 3/4= 78 Mbps

Si usamos SGI  tenemos que el numero de trasmisión por segundo es 14.4 (52/(3.2µs+04µs)

14.4M Tras/seg * 8 bit/1tra = 115 Mbps

Si usamos usamos un coding rate de 3/4 nos queda los siguiente:

115 Mbps * 3/4 = 86.2

DNS al Descubierto: Una Guía Esencial de Seguridad para Analistas 2

En la entrada anterior se vió información general del funcionamiento de DNS. A continuación, se describen las técnicas de análisis y los at...