Servidor DHCP+Mysql en Python

Servidor DHCP+Mysql en Python

El propósito de este proyecto fue:

  • Aprenda sobre DHCP en una red IPv4
  • Aprendiendo Python (un poco más que desde cero 😉)
  • reemplazo del servidor DB2DHCP (mi tenedor), original aquí, que cada vez es más difícil de montar para el nuevo sistema operativo. Y no me gusta que sea un binario que no hay manera de “cambiar ahora mismo”
  • obtener un servidor DHCP que funcione con la capacidad de seleccionar la dirección IP de un suscriptor usando la combinación mac del suscriptor o switch mac+puerto (Opción 82)
  • escribiendo otra bicicleta (¡Oh! esta es mi actividad favorita)
  • recibir comentarios sobre tu habilidad con el garrote en Habrahabr (o mejor aún, una invitación) 😉

Resultado: funciona 😉 Probado en FreeBSD y Ubuntu OS. En teoría, se puede pedir que el código funcione en cualquier sistema operativo, porque Parece que no hay enlaces específicos en el código.
¡Con cuidado! Hay mucho más por venir.

Enlace al repositorio para aficionados. "tocar vivo".

El proceso de instalación, configuración y uso es el resultado de "estudiar el hardware" mucho más abajo, y luego un poco de teoría sobre el protocolo DHCP. Para mí. Y para la historia 😉

una pequeña teoría

¿Qué es DHCP?

Este es un protocolo de red que permite a un dispositivo averiguar su dirección IP (y otros parámetros como puerta de enlace, DNS, etc.) desde un servidor DHCP. Los paquetes se intercambian mediante el protocolo UDP. El principio general de funcionamiento del dispositivo al solicitar parámetros de red es el siguiente:

  1. El dispositivo (cliente) envía una solicitud de transmisión UDP (DHCPDISCOVER) a través de la red con la solicitud "bueno, que alguien me dé una dirección IP". Además, normalmente (pero no siempre) la solicitud se produce desde el puerto 68 (origen) y el destino es el puerto 67 (destino). Algunos dispositivos también envían paquetes desde el puerto 67. La dirección MAC del dispositivo cliente se incluye dentro del paquete DHCPDISCOVER.
  2. Todos los servidores DHCP ubicados en la red (y puede haber varios) forman una oferta DHCPOFFER con la configuración de red para el dispositivo que envió DHCPDISCOVER y también lo transmiten a través de la red. La identificación de a quién está destinado este paquete se basa en la dirección MAC del cliente proporcionada anteriormente en la solicitud DHCPDISCOVER.
  3. El cliente acepta paquetes con propuestas de configuración de red, selecciona el más atractivo (los criterios pueden ser diferentes, por ejemplo, el tiempo de entrega del paquete, el número de rutas intermedias) y realiza una "solicitud oficial" DHCPREQUEST con la configuración de red. desde el servidor DHCP que le guste. En este caso, el paquete va a un servidor DHCP específico.
  4. El servidor que recibió DHCPREQUEST envía un paquete en formato DHCPACK, en el que nuevamente enumera la configuración de red destinada a este cliente.

Servidor DHCP+Mysql en Python

Además, hay paquetes DHCPINFORM que provienen del cliente y cuyo propósito es informar al servidor DHCP que el "cliente está vivo" y está utilizando la configuración de red emitida. En la implementación de este servidor, estos paquetes se ignoran.

Formato de paquete

En general, una trama de paquete Ethernet se parece a esto:

Servidor DHCP+Mysql en Python

En nuestro caso, consideraremos solo los datos directamente del contenido del paquete UDP, sin encabezados de protocolo de capa OSI, es decir, la estructura DHCP:

DHCPDESCUBRIR

Entonces, el proceso de obtención de una dirección IP para un dispositivo comienza cuando el cliente DHCP envía una solicitud de transmisión desde el puerto 68 al 255.255.255.255:67. En este paquete, el cliente incluye su dirección MAC, así como exactamente lo que quiere recibir del servidor DHCP. La estructura del paquete se describe en la siguiente tabla.

Tabla de estructura de paquetes DHCPDISCOVER

Posición en el paquete
Nombre del valor
ejemplo
Introducción
Byte
Aclaración

1
Solicitud de arranque
1
Hexagonal
1
Tipo de mensaje. 1 - solicitud del cliente al servidor, 2 - respuesta del servidor al cliente

2
tipo de hardware
1
Hexagonal
1
Tipo de dirección de hardware, en este protocolo 1 - MAC

3
Longitud de las direcciones de hardware
6
Hexagonal
1
Longitud de la dirección MAC del dispositivo

4
El lúpulo
1
Hexagonal
1
Número de rutas intermedias

5
ID de transacción
23:cf:de:1d
Hexagonal
4
Identificador único de transacción. Generado por el cliente al comienzo de una operación de solicitud.

7
segundo transcurrido
0
Hexagonal
4
Tiempo en segundos desde el inicio del proceso de obtención de una dirección

9
Banderas de arranque
0
Hexagonal
2
Ciertos indicadores que se pueden configurar para indicar parámetros de protocolo

11
Dirección IP del cliente
0.0.0.0
Cadena
4
Dirección IP del cliente (si corresponde)

15
La dirección IP de tu cliente
0.0.0.0
Cadena
4
Dirección IP ofrecida por el servidor (si está disponible)

19
Dirección IP del siguiente servidor
0.0.0.0
Cadena
4
Dirección IP del servidor (si se conoce)

23
Dirección IP del agente de retransmisión
172.16.114.41
Cadena
4
Dirección IP del agente de retransmisión (por ejemplo, un conmutador)

27
Dirección MAC del cliente
14:d6:4d:a7:c9:55
Hexagonal
6
Dirección MAC del remitente del paquete (cliente)

31
Relleno de dirección de hardware del cliente
 
Hexagonal
10
Asiento reservado. Generalmente lleno de ceros

41
Nombre de host del servidor
 
Cadena
64
Nombre del servidor DHCP. Generalmente no se transmite

105
Nombre del archivo de arranque
 
Cadena
128
Nombre de archivo en el servidor utilizado por las estaciones sin disco al iniciar

235
galleta mágica
63: 82: 53: 63
Hexagonal
4
Número "mágico", según el cual, incl. Puedes determinar que este paquete pertenece al protocolo DHCP.

Opciones de DHCP. Puede ir en cualquier orden

236
Número de opción
53
Dic
1
Opción 53, que especifica el tipo de paquete DHCP

1 - DHCPDESCUBRIR
3 - SOLICITUD DHCP
2 - DHCPOFFER
5-DHCPACK
8 - DHCPINFORME

 
Longitud de la opción
1
Dic
1

 
Valor de la opción
1
Dic
1

 
Número de opción
50
Dic
1
¿Qué dirección IP quiere recibir el cliente?

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
172.16.134.61
Cadena
4

 
Número de opción
55
 
1
Parámetros de red solicitados por el cliente. La composición puede variar

01 — Máscara de red
03 - Puerta de enlace
06-DNS
oc — Nombre de host
0f - nombre de dominio de red
1c - dirección de solicitud de transmisión (transmisión)
42 - nombre del servidor TFTP
79 - Ruta estática sin clases

 
Longitud de la opción
8
 
1

 
Valor de la opción
01:03:06:0c:0f:1c:42:79
 
8

 
Número de opción
82
Dic
 
Opción 82, que transmite la dirección MAC del dispositivo repetidor y algunos valores adicionales.

La mayoría de las veces, este es el puerto del conmutador en el que se ejecuta el cliente DHCP final. Esta opción contiene parámetros adicionales. El primer byte es el número de la "subopción", el segundo es su longitud y luego su valor.

En este caso, en la opción 82, se anidan las subopciones:
ID del circuito del agente = 00:04:00:01:00:04, donde los dos últimos bytes son el puerto del cliente DHCP desde el que provino la solicitud

ID remoto del agente = 00:06:c8:be:19:93:11:48 - Dirección MAC del dispositivo repetidor DHCP

 
Longitud de la opción
18
Dic
 

 
Valor de la opción
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hexagonal
 

 
Fin del paquete
255
Dic
1
255 simboliza el final del paquete.

DHCPOFERTA

Tan pronto como el servidor recibe el paquete DHCPDISCOVER y ve que puede ofrecer al cliente algo del solicitado, genera una respuesta: DHCPDISCOVER. La respuesta se envía al puerto “de donde vino”, por difusión, porque En este momento, el cliente aún no tiene una dirección IP, por lo tanto sólo puede aceptar el paquete si se envía por difusión. El cliente reconoce que se trata de un paquete para él por su dirección MAC dentro del paquete, así como por el número de transacción que genera en el momento en que se crea el primer paquete.

Tabla de estructura de paquetes DHCPOFFER

Posición en el paquete
Nombre del valor (común)
ejemplo
Introducción
Byte
Aclaración

1
Solicitud de arranque
1
Hexagonal
1
Tipo de mensaje. 1 - solicitud del cliente al servidor, 2 - respuesta del servidor al cliente

2
tipo de hardware
1
Hexagonal
1
Tipo de dirección de hardware, en este protocolo 1 - MAC

3
Longitud de las direcciones de hardware
6
Hexagonal
1
Longitud de la dirección MAC del dispositivo

4
El lúpulo
1
Hexagonal
1
Número de rutas intermedias

5
ID de transacción
23:cf:de:1d
Hexagonal
4
Identificador único de transacción. Generado por el cliente al comienzo de una operación de solicitud.

7
segundo transcurrido
0
Hexagonal
4
Tiempo en segundos desde el inicio del proceso de obtención de una dirección

9
Banderas de arranque
0
Hexagonal
2
Ciertos indicadores que se pueden configurar para indicar parámetros de protocolo. En este caso, 0 significa el tipo de solicitud Unicast.

11
Dirección IP del cliente
0.0.0.0
Cadena
4
Dirección IP del cliente (si corresponde)

15
La dirección IP de tu cliente
172.16.134.61
Cadena
4
Dirección IP ofrecida por el servidor (si está disponible)

19
Dirección IP del siguiente servidor
0.0.0.0
Cadena
4
Dirección IP del servidor (si se conoce)

23
Dirección IP del agente de retransmisión
172.16.114.41
Cadena
4
Dirección IP del agente de retransmisión (por ejemplo, un conmutador)

27
Dirección MAC del cliente
14:d6:4d:a7:c9:55
Hexagonal
6
Dirección MAC del remitente del paquete (cliente)

31
Relleno de dirección de hardware del cliente
 
Hexagonal
10
Asiento reservado. Generalmente lleno de ceros

41
Nombre de host del servidor
 
Cadena
64
Nombre del servidor DHCP. Generalmente no se transmite

105
Nombre del archivo de arranque
 
Cadena
128
Nombre de archivo en el servidor utilizado por las estaciones sin disco al iniciar

235
galleta mágica
63: 82: 53: 63
Hexagonal
4
Número "mágico", según el cual, incl. Puedes determinar que este paquete pertenece al protocolo DHCP.

Opciones de DHCP. Puede ir en cualquier orden

236
Número de opción
53
Dic
1
Opción 53, que define el tipo de paquete DHCP 2 - DHCPOFFER

 
Longitud de la opción
1
Dic
1

 
Valor de la opción
2
Dic
1

 
Número de opción
1
Dic
1
Opción de ofrecer al cliente DHCP una máscara de red

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
255.255.224.0
Cadena
4

 
Número de opción
3
Dic
1
Opción para ofrecer al cliente DHCP una puerta de enlace predeterminada

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
172.16.12.1
Cadena
4

 
Número de opción
6
Dic
1
Opción para ofrecer DHCP al cliente DNS

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
8.8.8.8
Cadena
4

 
Número de opción
51
Dic
1
La vida útil de los parámetros de red emitidos en segundos, después de la cual el cliente DHCP debe solicitarlos nuevamente

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
86400
Dic
4

 
Número de opción
82
Dic
1
Opción 82, repite lo que vino en DHCPDISCOVER

 
Longitud de la opción
18
Dic
1

 
Valor de la opción
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dic
18

 
Fin del paquete
255
Dic
1
255 simboliza el final del paquete.

DHCPREQUEST

Después de que el cliente recibe DHCPOFFER, forma un paquete solicitando parámetros de red no a todos los servidores DHCP de la red, sino sólo a uno específico, cuya oferta DHCPOFFER le "gustó" más. Los criterios de "me gusta" pueden ser diferentes y depender de la implementación de DHCP del cliente. El destinatario de la solicitud se especifica mediante la dirección MAC del servidor DHCP. Además, el cliente puede enviar un paquete DHCPREQUEST sin generar primero DHCPDISCOVER, si la dirección IP del servidor ya se ha obtenido previamente.

Tabla de estructura de paquetes DHCPREQUEST

Posición en el paquete
Nombre del valor (común)
ejemplo
Introducción
Byte
Aclaración

1
Solicitud de arranque
1
Hexagonal
1
Tipo de mensaje. 1 - solicitud del cliente al servidor, 2 - respuesta del servidor al cliente

2
tipo de hardware
1
Hexagonal
1
Tipo de dirección de hardware, en este protocolo 1 - MAC

3
Longitud de las direcciones de hardware
6
Hexagonal
1
Longitud de la dirección MAC del dispositivo

4
El lúpulo
1
Hexagonal
1
Número de rutas intermedias

5
ID de transacción
23:cf:de:1d
Hexagonal
4
Identificador único de transacción. Generado por el cliente al comienzo de una operación de solicitud.

7
segundo transcurrido
0
Hexagonal
4
Tiempo en segundos desde el inicio del proceso de obtención de una dirección

9
Banderas de arranque
8000
Hexagonal
2
Ciertos indicadores que se pueden configurar para indicar parámetros de protocolo. En este caso, se establece “transmitir”

11
Dirección IP del cliente
0.0.0.0
Cadena
4
Dirección IP del cliente (si corresponde)

15
La dirección IP de tu cliente
172.16.134.61
Cadena
4
Dirección IP ofrecida por el servidor (si está disponible)

19
Dirección IP del siguiente servidor
0.0.0.0
Cadena
4
Dirección IP del servidor (si se conoce)

23
Dirección IP del agente de retransmisión
172.16.114.41
Cadena
4
Dirección IP del agente de retransmisión (por ejemplo, un conmutador)

27
Dirección MAC del cliente
14:d6:4d:a7:c9:55
Hexagonal
6
Dirección MAC del remitente del paquete (cliente)

31
Relleno de dirección de hardware del cliente
 
Hexagonal
10
Asiento reservado. Generalmente lleno de ceros

41
Nombre de host del servidor
 
Cadena
64
Nombre del servidor DHCP. Generalmente no se transmite

105
Nombre del archivo de arranque
 
Cadena
128
Nombre de archivo en el servidor utilizado por las estaciones sin disco al iniciar

235
galleta mágica
63: 82: 53: 63
Hexagonal
4
Número "mágico", según el cual, incl. Puedes determinar que este paquete pertenece al protocolo DHCP.

Opciones de DHCP. Puede ir en cualquier orden

236
Número de opción
53
Dic
3
Opción 53, que define el paquete DHCP tipo 3 - DHCPREQUEST

 
Longitud de la opción
1
Dic
1

 
Valor de la opción
3
Dic
1

 
Número de opción
61
Dic
1
ID de cliente: 01 (para Ehernet) + dirección MAC del cliente

 
Longitud de la opción
7
Dic
1

 
Valor de la opción
01:2c:ab:25:ff:72:a6
Hexagonal
7

 
Número de opción
60
Dic
 
"Identificador de clase de proveedor". En mi caso, informa la versión del cliente DHCP. Quizás otros dispositivos devuelvan algo diferente. Windows, por ejemplo, informa MSFT 5.0

 
Longitud de la opción
11
Dic
 

 
Valor de la opción
udhcp 0.9.8
Cadena
 

 
Número de opción
55
 
1
Parámetros de red solicitados por el cliente. La composición puede variar

01 — Máscara de red
03 - Puerta de enlace
06-DNS
oc — Nombre de host
0f - nombre de dominio de red
1c - dirección de solicitud de transmisión (transmisión)
42 - nombre del servidor TFTP
79 - Ruta estática sin clases

 
Longitud de la opción
8
 
1

 
Valor de la opción
01:03:06:0c:0f:1c:42:79
 
8

 
Número de opción
82
Dic
1
Opción 82, repite lo que vino en DHCPDISCOVER

 
Longitud de la opción
18
Dic
1

 
Valor de la opción
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dic
18

 
Fin del paquete
255
Dic
1
255 simboliza el final del paquete.

DHCPPACK

Como confirmación de que "sí, así es, esta es su dirección IP y no se la daré a nadie más" del servidor DHCP, se sirve un paquete en formato DHCPACK del servidor al cliente. Se envía por difusión como otros paquetes. Aunque, en el código siguiente para un servidor DHCP implementado en Python, por si acaso, duplico cualquier solicitud de transmisión enviando un paquete a una IP de cliente específica, si ya se conoce. Además, al servidor DHCP no le importa en absoluto si el paquete DHCPACK ha llegado al cliente. Si el cliente no recibe DHCPACK, después de un tiempo simplemente repite DHCPREQUEST

Tabla de estructura de paquetes DHCPACK

Posición en el paquete
Nombre del valor (común)
ejemplo
Introducción
Byte
Aclaración

1
Solicitud de arranque
2
Hexagonal
1
Tipo de mensaje. 1 - solicitud del cliente al servidor, 2 - respuesta del servidor al cliente

2
tipo de hardware
1
Hexagonal
1
Tipo de dirección de hardware, en este protocolo 1 - MAC

3
Longitud de las direcciones de hardware
6
Hexagonal
1
Longitud de la dirección MAC del dispositivo

4
El lúpulo
1
Hexagonal
1
Número de rutas intermedias

5
ID de transacción
23:cf:de:1d
Hexagonal
4
Identificador único de transacción. Generado por el cliente al comienzo de una operación de solicitud.

7
segundo transcurrido
0
Hexagonal
4
Tiempo en segundos desde el inicio del proceso de obtención de una dirección

9
Banderas de arranque
8000
Hexagonal
2
Ciertos indicadores que se pueden configurar para indicar parámetros de protocolo. En este caso, se establece “transmitir”

11
Dirección IP del cliente
0.0.0.0
Cadena
4
Dirección IP del cliente (si corresponde)

15
La dirección IP de tu cliente
172.16.134.61
Cadena
4
Dirección IP ofrecida por el servidor (si está disponible)

19
Dirección IP del siguiente servidor
0.0.0.0
Cadena
4
Dirección IP del servidor (si se conoce)

23
Dirección IP del agente de retransmisión
172.16.114.41
Cadena
4
Dirección IP del agente de retransmisión (por ejemplo, un conmutador)

27
Dirección MAC del cliente
14:d6:4d:a7:c9:55
Hexagonal
6
Dirección MAC del remitente del paquete (cliente)

31
Relleno de dirección de hardware del cliente
 
Hexagonal
10
Asiento reservado. Generalmente lleno de ceros

41
Nombre de host del servidor
 
Cadena
64
Nombre del servidor DHCP. Generalmente no se transmite

105
Nombre del archivo de arranque
 
Cadena
128
Nombre de archivo en el servidor utilizado por las estaciones sin disco al iniciar

235
galleta mágica
63: 82: 53: 63
Hexagonal
4
Número "mágico", según el cual, incl. Puedes determinar que este paquete pertenece al protocolo DHCP.

Opciones de DHCP. Puede ir en cualquier orden

236
Número de opción
53
Dic
3
Opción 53, que define el tipo de paquete DHCP 5 - DHCPACK

 
Longitud de la opción
1
Dic
1

 
Valor de la opción
5
Dic
1

 
Número de opción
1
Dic
1
Opción de ofrecer al cliente DHCP una máscara de red

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
255.255.224.0
Cadena
4

 
Número de opción
3
Dic
1
Opción para ofrecer al cliente DHCP una puerta de enlace predeterminada

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
172.16.12.1
Cadena
4

 
Número de opción
6
Dic
1
Opción para ofrecer DHCP al cliente DNS

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
8.8.8.8
Cadena
4

 
Número de opción
51
Dic
1
La vida útil de los parámetros de red emitidos en segundos, después de la cual el cliente DHCP debe solicitarlos nuevamente

 
Longitud de la opción
4
Dic
1

 
Valor de la opción
86400
Dic
4

 
Número de opción
82
Dic
1
Opción 82, repite lo que vino en DHCPDISCOVER

 
Longitud de la opción
18
Dic
1

 
Valor de la opción
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dic
18

 
Fin del paquete
255
Dic
1
255 simboliza el final del paquete.

Instalación

La instalación en realidad consiste en instalar los módulos de Python necesarios para el trabajo. Se supone que MySQL ya está instalado y configurado.

FreeBSD

paquete instalar python3 python3 -m asegurarpip pip3 instalar conector mysql

Ubuntu

sudo apt-get install python3 sudo apt-get install pip3 sudo pip3 install mysql-connector

Creamos una base de datos MySQL, cargamos el volcado pydhcp.sql en ella y configuramos el archivo de configuración.

Configuración

Todas las configuraciones del servidor están en un archivo xml. Archivo de referencia:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 servidor local prueba prueba pydhcp opción_8.8.8.8_hex:sw_port82:1:20 opción_22_hex:sw_port82:2:16 opción_18_hex:sw_mac:82:26 40 seleccione ip, máscara, enrutador, dns de los usuarios donde superior (mac) = superior ('{option_3_AgentRemoteId_hex}') y superior (puerto) = superior ('{option_1_AgentCircuitId_port_hex}') seleccione ip, máscara, enrutador, dns de los usuarios donde superior (mac) = superior ('{sw_mac}') y superior (puerto) = superior ('{sw_port82}') seleccione ip, máscara, enrutador, dns de los usuarios donde superior (mac) = superior ('{ClientMacAddress}') insertar en el historial (id,dt,mac,ip,comment) valores (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Ahora con más detalle sobre las etiquetas:

La sección dhcpserver describe la configuración básica para iniciar el servidor, a saber:

  • host: qué dirección IP escucha el servidor en el puerto 67
  • transmisión: qué ip es la transmisión para DHCPOFFER y DHCPACK
  • DHCPServer: ¿cuál es la ip del servidor DHCP?
  • LeaseTime tiempo de arrendamiento de la dirección IP emitida
  • ThreadLimit: cuántos subprocesos se ejecutan simultáneamente para procesar paquetes UDP entrantes en el puerto 67. Se supone que ayuda en proyectos de alta carga 😉
  • defaultMask,defaultRouter,defaultDNS: lo que se ofrece al suscriptor de forma predeterminada si se encuentra una IP en la base de datos, pero no se especifican parámetros adicionales para ella

sección mysql:

host, nombre de usuario, contraseña, nombre base: todo habla por sí solo. Una estructura aproximada de la base de datos está publicada en GitHub

Sección de consulta: las solicitudes para recibir OFERTA/ACK se describen aquí:

  • oferta_cuenta: la cantidad de líneas con solicitudes que devuelven un resultado como ip, máscara, enrutador, dns
  • oferta_n: cadena de consulta. Si la devolución está vacía, ejecuta la siguiente solicitud de oferta
  • History_sql: una consulta que escribe, por ejemplo, en el "historial de autorizaciones" de un suscriptor.

Las solicitudes pueden incluir cualquier variable de la sección de opciones u opciones del protocolo DHCP.

Sección de opciones. Aquí es donde se vuelve más interesante. Aquí podemos crear variables que podemos usar más adelante en la sección de consulta.

Por ejemplo:

option_82_hex:sw_port1:20:22

, esta línea de comando toma la línea completa que vino en la opción 82 de solicitud DHCP, en formato hexadecimal, en el rango de 20 a 22 bytes inclusive y la coloca en la nueva variable sw_port1 (puerto de conmutación de donde vino la solicitud)

option_82_hex:sw_mac:26:40

, define la variable sw_mac, tomando el hexadecimal del rango 26:40

Puede ver todas las opciones posibles que se pueden utilizar en las consultas iniciando el servidor con el modificador -d. Veremos algo como este registro:

--llegó un paquete DHCPINFORM al puerto 67, desde 0025224ad764 , b'x91xa5xe0xa3xa5xa9-x8fx8a' , ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764', 'ClientMacAddressByte': b'x00 7%"Jxd91 d' , 'HType': 'Ethernet', 'HostName': b'x5xa0xe3xa5xa9xa8-x8fx43a', 'ReqListDNS': Verdadero, 'ReqListDomainName': Verdadero, 'ReqListPerfowmRouterDiscover': Verdadero, 'ReqListRouter': Verdadero, 'ReqListStaticRoute': Verdadero, 'ReqListSubnetM preguntar': Verdadero, 'ReqListVendorSpecInfo': 0.0.0.0, 'RequestedIpAddress': '5.0', 'Proveedor': b'MSFT 0025224', 'chaddr': '764ad172.30.128.13', 'ciaddr': '00' , 'flags': b'x00x172.30.114.25', 'giaddr': '308', 'gpoz': 6, 'hlen': 1, 'hops': 82, 'htype': 'MAC', 'magic_cookie': b'cx12Sc ', 'op': 'DHCPINFORM', 'opción12': 53, 'opción53': 55, 'opción55': 60, 'opción60': 61, 'opción61': 82, 'opción82': 82, ' option_12_byte': b'x01x06x00x04x00x01x00x06x02x08x00x06' b'x00x1x9eXx2exb82xad', 'option_12010600040001000602080006001_hex': '589e2eb82ad', 'option_ 18_len': 82 12, 'option_01_str': "b'x06x00x04x00x01x00x06x02x08x00x06x00x1x9x2eXx768exb0.0.0.0xad'", 'resultado': Falso, 'segs': 001, 'siaddr': '589', 'sw_mac': '2e1eb06ad', 'sw_port89': '8', 'xidbyte': b'

En consecuencia, podemos incluir cualquier variable en {} y se usará en la consulta SQL.

Registremos para el historial que el cliente recibió la dirección IP:

Servidor DHCP+Mysql en Python

Servidor DHCP+Mysql en Python

Inicio del servidor

./pydhcpdb.py -d -c config.xml

— d modo de salida de consola DEBUG
-c archivo de configuración <nombre de archivo>

Debriefing

Y ahora más detalles sobre la implementación del servidor en Python. Es un dolor. Python se aprendió sobre la marcha. Muchos momentos están hechos al estilo de "guau, de alguna manera lo hice funcionar". No está optimizado en absoluto y se deja así principalmente debido a poca experiencia en el desarrollo de Python. Me detendré en los aspectos más interesantes de la implementación del servidor en "código".

Analizador de archivos de configuración XML

Se utiliza el módulo estándar de Python xml.dom. Parece simple, pero durante la implementación hubo una notable falta de documentación clara y ejemplos en la red usando este módulo.

    árbol = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") para elem en mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("username")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("contraseña")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basename")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") para elem en dconfig: gconfig["broadcast"]=elem.getElementsByTagName("broadcast")[0]. firstChild.data gconfig["dhcp_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["dhcp_LeaseTime"]=elem.getElementsByTagName("LeaseTime")[0].firstChild.data gconfig[" dhcp_ThreadLimit"]=int(elem.getElementsByTagName("ThreadLimit")[0].firstChild.data) gconfig["dhcp_Server"]=elem.getElementsByTagName("DHCPServer")[0].firstChild.data gconfig["dhcp_defaultMask"] =elem.getElementsByTagName("defaultMask")[0].firstChild.data gconfig["dhcp_defaultRouter"]=elem.getElementsByTagName("defaultRouter")[0].firstChild.data gconfig["dhcp_defaultDNS"]=elem.getElementsByTagName(" defaultDNS")[0].firstChild.data qconfig=tree.getElementsByTagName("query") para elem en qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data para num en range(int(gconfig["offer_count"])): gconfig["offer_"+str(num+1)]=elem.getElementsByTagName("offer_"+str(num+1))[0].firstChild.data gconfig ["history_sql"]=elem.getElementsByTagName("history_sql")[0].firstChild.data options=tree.getElementsByTagName("options") para elem en opciones: node=elem.getElementsByTagName("option") para opciones en nodo : opcionesMod.append(opciones.firstChild.data)

subprocesos múltiples

Curiosamente, el multiproceso en Python se implementa de forma muy clara y sencilla.

def PacketWork(data,addr): ... # implementación de analizar el paquete entrante y responder a él... while True: data, addr = udp_socket.recvfrom(1024) # esperando el paquete UDP thread = threading.Thread( target=PacketWork , args=(data,addr,)).start() # tal como vino: iniciamos la función PacketWork previamente definida en segundo plano con parámetros mientras threading.active_count() >gconfig["dhcp_ThreadLimit"]: tiempo. sleep(1) # si el número Ya hay más subprocesos ejecutándose que en la configuración, esperamos hasta que haya menos

Recibir/enviar paquete DHCP

Para interceptar paquetes UDP que llegan a través de la tarjeta de red, es necesario "levantar" el socket:

udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP) udp_socket.bind((gconfig["dhcp_host"],67))

, donde las banderas son:

  • AF_INET: significa que el formato de la dirección será IP: puerto. También puede haber AF_UNIX, donde la dirección viene dada por el nombre del archivo.
  • SOCK_DGRAM: significa que no aceptamos un "paquete sin procesar", sino uno que ya pasó a través del firewall y con un paquete parcialmente recortado. Aquellos. solo recibimos un paquete UDP sin el componente "físico" del envoltorio del paquete UDP. Si utiliza el indicador SOCK_RAW, también deberá analizar este "contenedor".

Enviar un paquete puede ser como una transmisión:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #cambiar el socket al modo de transmisión rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, y a la dirección “de donde vino el paquete”:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # cambia el socket al modo multiescucha rz=udp_socket.sendto(packetack, addr)

, donde SOL_SOCKET significa el "nivel de protocolo" para configurar opciones,

, opción SO_BROADCAST de que el paquete del casco se “transmite”

  La opción SO_REUSEADDR cambia el socket al modo "muchos oyentes". En teoría, en este caso no es necesario, pero en uno de los servidores FreeBSD en los que probé, el código no funcionaba sin esta opción.

Analizando un paquete DHCP

Aquí es donde realmente me gustó Python. Resulta que, desde el primer momento, te permite ser bastante flexible con el código de bytes. Permitiendo que se traduzca muy fácilmente a valores decimales, cadenas y hexadecimales, es decir, esto es lo que realmente necesitamos para comprender la estructura del paquete. Entonces, por ejemplo, puedes obtener un rango de bytes en HEX y solo bytes:

    res["xidhex"]=datos[4:8].hex() res["xidbyte"]=datos[4:8]

, empaqueta los bytes en una estructura:

res["banderas"]=pack('BB',datos[10],datos[11])

Obtener IP de la estructura:

res["ciaddr"]=socket.inet_ntoa(pack('BBBB',datos[12],datos[13],datos[14],datos[15]));

Y viceversa:

res=res+socket.inet_pton(socket.AF_INET, gconfig["dhcp_Server"])

Eso es todo por ahora 😉

Fuente: habr.com

Añadir un comentario