Servidor DHCP + MySQL em Python

Servidor DHCP + MySQL em Python

O objetivo deste projeto foi:

  • Aprendendo sobre DHCP em uma rede IPv4
  • Aprendendo Python (um pouco mais do que do zero 😉)
  • substituição de servidor DB2DHCP (meu garfo), original aqui, que está se tornando cada vez mais difícil de montar para o novo sistema operacional. E eu não gosto que seja um binário que não tem como “mudar agora”
  • obter um servidor DHCP funcional com a capacidade de selecionar o endereço IP de um assinante usando o mac do assinante ou a combinação mac+porta do switch (Opção 82)
  • escrevendo outra bicicleta (Oh! esta é minha atividade favorita)
  • recebendo comentários sobre sua lateralidade no Habrahabr (ou melhor ainda, um convite) 😉

Resultado: funciona 😉 Testado em FreeBSD e Ubuntu OS. Teoricamente, o código pode funcionar em qualquer sistema operacional, porque Parece não haver ligações específicas no código.
Com cuidado! Há muito mais por vir.

Link para repositório para amadores "tocar vivo".

O processo de instalação, configuração e utilização o resultado do “estudo do hardware” é bem menor, e depois um pouco de teoria sobre o protocolo DHCP. Para mim. E para a história 😉

Um pouco de teoria

O que é DHCP

Este é um protocolo de rede que permite a um dispositivo descobrir seu endereço IP (e outros parâmetros como gateway, DNS, etc.) a partir de um servidor DHCP. Os pacotes são trocados usando o protocolo UDP. O princípio geral de funcionamento do dispositivo ao solicitar parâmetros de rede é o seguinte:

  1. O dispositivo (cliente) envia uma solicitação de transmissão UDP (DHCPDISCOVER) por toda a rede com a solicitação “bem, alguém me dê um endereço IP”. Além disso, normalmente (mas nem sempre) a solicitação ocorre na porta 68 (origem) e o destino é a porta 67 (destino). Alguns dispositivos também enviam pacotes da porta 67. O endereço MAC do dispositivo cliente está incluído no pacote DHCPDISCOVER.
  2. Todos os servidores DHCP localizados na rede (e pode haver vários deles) formam uma oferta DHCPOFFER com configurações de rede para o dispositivo que enviou DHCPDISCOVER, e também o transmitem pela rede. A identificação do destinatário deste pacote é baseada no endereço MAC do cliente fornecido anteriormente na solicitação DHCPDISCOVER.
  3. O cliente aceita pacotes com propostas de configurações de rede, seleciona o mais atrativo (os critérios podem ser diferentes, por exemplo, o tempo de entrega do pacote, a quantidade de rotas intermediárias) e faz uma “solicitação oficial” DHCPREQUEST com as configurações de rede do servidor DHCP que ele gosta. Neste caso, o pacote vai para um servidor DHCP específico.
  4. O servidor que recebeu o DHCPREQUEST envia um pacote no formato DHCPACK, no qual lista novamente as configurações de rede destinadas a este cliente

Servidor DHCP + MySQL em Python

Além disso, existem pacotes DHCPINFORM que vêm do cliente e cujo objetivo é informar ao servidor DHCP que o “cliente está ativo” e está usando as configurações de rede emitidas. Na implementação deste servidor, estes pacotes são ignorados.

Formato do pacote

Em geral, um quadro de pacote Ethernet se parece com isto:

Servidor DHCP + MySQL em Python

No nosso caso, consideraremos apenas os dados diretamente do conteúdo do pacote UDP, sem cabeçalhos de protocolo da camada OSI, ou seja, a estrutura DHCP:

DHCPDESCOBRIR

Assim, o processo de obtenção de um endereço IP para um dispositivo começa com o cliente DHCP enviando uma solicitação de broadcast da porta 68 para 255.255.255.255:67. Neste pacote, o cliente inclui seu endereço MAC, bem como exatamente o que deseja receber do servidor DHCP. A estrutura do pacote é descrita na tabela abaixo.

Tabela de estrutura de pacotes DHCPDISCOVER

Posição no pacote
Nome do valor
Exemplo
Introdução
Byte
Esclarecimento

1
Solicitação de inicialização
1
Feitiço
1
Tipo de mensagem. 1 – solicitação do cliente para o servidor, 2 – resposta do servidor para o cliente

2
Tipo de hardware
1
Feitiço
1
Tipo de endereço de hardware, neste protocolo 1 - MAC

3
Comprimento dos endereços de hardware
6
Feitiço
1
Comprimento do endereço MAC do dispositivo

4
hops
1
Feitiço
1
Número de rotas intermediárias

5
ID da transação
23:cf:de:1d
Feitiço
4
Identificador exclusivo da transação. Gerado pelo cliente no início de uma operação de solicitação

7
Segundo decorrido
0
Feitiço
4
Tempo em segundos desde o início do processo de obtenção de endereço

9
Sinalizadores de inicialização
0
Feitiço
2
Certos sinalizadores que podem ser definidos para indicar parâmetros de protocolo

11
Endereço IP do cliente
0.0.0.0
Linha
4
Endereço IP do cliente (se houver)

15
O endereço IP do seu cliente
0.0.0.0
Linha
4
Endereço IP oferecido pelo servidor (se disponível)

19
Próximo endereço IP do servidor
0.0.0.0
Linha
4
Endereço IP do servidor (se conhecido)

23
Endereço IP do agente de retransmissão
172.16.114.41
Linha
4
Endereço IP do agente de retransmissão (por exemplo, um switch)

27
Endereço MAC do cliente
14:d6:4d:a7:c9:55
Feitiço
6
Endereço MAC do remetente do pacote (cliente)

31
Preenchimento de endereço de hardware do cliente
 
Feitiço
10
Assento reservado. Geralmente preenchido com zeros

41
Nome do host do servidor
 
Linha
64
Nome do servidor DHCP. Geralmente não transmitido

105
Nome do arquivo de inicialização
 
Linha
128
Nome do arquivo no servidor usado por estações sem disco durante a inicialização

235
biscoito mágico
63: 82: 53: 63
Feitiço
4
Número “mágico”, segundo o qual, incl. você pode determinar que este pacote pertence ao protocolo DHCP

Opções de DHCP. Pode ir em qualquer ordem

236
Número da opção
53
Dez
1
Opção 53, que especifica o tipo de pacote DHCP

1 - DHCPDISCOVER
3 - SOLICITAÇÃO DE DHCP
2 - DHCPOFFER
5 - DHCPACK
8 - DHCPINFORM

 
Comprimento da opção
1
Dez
1

 
Valor da opção
1
Dez
1

 
Número da opção
50
Dez
1
Qual endereço IP o cliente deseja receber?

 
Comprimento da opção
4
Dez
1

 
Valor da opção
172.16.134.61
Linha
4

 
Número da opção
55
 
1
Parâmetros de rede solicitados pelo cliente. A composição pode variar

01 — Máscara de rede
03 – Portal
06 -DNS
oc — Nome do host
0f - nome de domínio da rede
1c - endereço da solicitação de transmissão (transmissão)
42 - Nome do servidor TFTP
79 - Rota Estática Sem Classe

 
Comprimento da opção
8
 
1

 
Valor da opção
01:03:06:0c:0f:1c:42:79
 
8

 
Número da opção
82
Dez
 
Opção 82, que transmite o endereço MAC do dispositivo repetidor e alguns valores adicionais.

Na maioria das vezes, esta é a porta do switch na qual o cliente DHCP final é executado. Esta opção contém parâmetros adicionais. O primeiro byte é o número da “subopção”, o segundo é o seu comprimento e depois o seu valor.

Neste caso, na opção 82, as subopções estão aninhadas:
ID do circuito do agente = 00:04:00:01:00:04, onde os dois últimos bytes são a porta do cliente DHCP de onde veio a solicitação

ID remoto do agente = 00:06:c8:be:19:93:11:48 - Endereço MAC do dispositivo repetidor DHCP

 
Comprimento da opção
18
Dez
 

 
Valor da opção
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Feitiço
 

 
Fim do pacote
255
Dez
1
255 simboliza o fim do pacote

OFERTA DHCP

Assim que o servidor recebe o pacote DHCPDISCOVER e percebe que pode oferecer ao cliente algo do solicitado, ele gera uma resposta para ele - DHCPDISCOVER. A resposta é enviada para o porto “de onde veio”, por broadcast, pois neste momento o cliente ainda não possui endereço IP, portanto só poderá aceitar o pacote se for enviado por broadcast. O cliente reconhece que se trata de um pacote para ele pelo seu endereço MAC dentro do pacote, bem como pelo número da transação que ele gera no momento da criação do primeiro pacote.

Tabela de estrutura de pacotes DHCPOFFER

Posição no pacote
Nome do valor (comum)
Exemplo
Introdução
Byte
Esclarecimento

1
Solicitação de inicialização
1
Feitiço
1
Tipo de mensagem. 1 – solicitação do cliente para o servidor, 2 – resposta do servidor para o cliente

2
Tipo de hardware
1
Feitiço
1
Tipo de endereço de hardware, neste protocolo 1 - MAC

3
Comprimento dos endereços de hardware
6
Feitiço
1
Comprimento do endereço MAC do dispositivo

4
hops
1
Feitiço
1
Número de rotas intermediárias

5
ID da transação
23:cf:de:1d
Feitiço
4
Identificador exclusivo da transação. Gerado pelo cliente no início de uma operação de solicitação

7
Segundo decorrido
0
Feitiço
4
Tempo em segundos desde o início do processo de obtenção de endereço

9
Sinalizadores de inicialização
0
Feitiço
2
Certos sinalizadores que podem ser definidos para indicar parâmetros de protocolo. Neste caso, 0 significa o tipo de solicitação Unicast

11
Endereço IP do cliente
0.0.0.0
Linha
4
Endereço IP do cliente (se houver)

15
O endereço IP do seu cliente
172.16.134.61
Linha
4
Endereço IP oferecido pelo servidor (se disponível)

19
Próximo endereço IP do servidor
0.0.0.0
Linha
4
Endereço IP do servidor (se conhecido)

23
Endereço IP do agente de retransmissão
172.16.114.41
Linha
4
Endereço IP do agente de retransmissão (por exemplo, um switch)

27
Endereço MAC do cliente
14:d6:4d:a7:c9:55
Feitiço
6
Endereço MAC do remetente do pacote (cliente)

31
Preenchimento de endereço de hardware do cliente
 
Feitiço
10
Assento reservado. Geralmente preenchido com zeros

41
Nome do host do servidor
 
Linha
64
Nome do servidor DHCP. Geralmente não transmitido

105
Nome do arquivo de inicialização
 
Linha
128
Nome do arquivo no servidor usado por estações sem disco durante a inicialização

235
biscoito mágico
63: 82: 53: 63
Feitiço
4
Número “mágico”, segundo o qual, incl. você pode determinar que este pacote pertence ao protocolo DHCP

Opções de DHCP. Pode ir em qualquer ordem

236
Número da opção
53
Dez
1
Opção 53, que define o tipo de pacote DHCP 2 - DHCPOFFER

 
Comprimento da opção
1
Dez
1

 
Valor da opção
2
Dez
1

 
Número da opção
1
Dez
1
Opção para oferecer ao cliente DHCP uma máscara de rede

 
Comprimento da opção
4
Dez
1

 
Valor da opção
255.255.224.0
Linha
4

 
Número da opção
3
Dez
1
Opção para oferecer ao cliente DHCP um gateway padrão

 
Comprimento da opção
4
Dez
1

 
Valor da opção
172.16.12.1
Linha
4

 
Número da opção
6
Dez
1
Opção para oferecer DHCP ao cliente DNS

 
Comprimento da opção
4
Dez
1

 
Valor da opção
8.8.8.8
Linha
4

 
Número da opção
51
Dez
1
A vida útil dos parâmetros de rede emitidos em segundos, após os quais o cliente DHCP deve solicitá-los novamente

 
Comprimento da opção
4
Dez
1

 
Valor da opção
86400
Dez
4

 
Número da opção
82
Dez
1
Opção 82, repete o que veio em DHCPDISCOVER

 
Comprimento da opção
18
Dez
1

 
Valor da opção
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18

 
Fim do pacote
255
Dez
1
255 simboliza o fim do pacote

SOLICITAÇÃO DE DHCP

Após o cliente receber o DHCPOFFER, ele forma um pacote solicitando parâmetros de rede não para todos os servidores DHCP da rede, mas apenas para um específico, cuja oferta DHCPOFFER ele mais “gostou”. Os critérios "like" podem ser diferentes e dependem da implementação do DHCP do cliente. O destinatário da solicitação é especificado usando o endereço MAC do servidor DHCP. Além disso, um pacote DHCPREQUEST pode ser enviado pelo cliente sem primeiro gerar DHCPDISCOVER, caso o endereço IP do servidor já tenha sido obtido anteriormente.

Tabela de estrutura de pacotes DHCPREQUEST

Posição no pacote
Nome do valor (comum)
Exemplo
Introdução
Byte
Esclarecimento

1
Solicitação de inicialização
1
Feitiço
1
Tipo de mensagem. 1 – solicitação do cliente para o servidor, 2 – resposta do servidor para o cliente

2
Tipo de hardware
1
Feitiço
1
Tipo de endereço de hardware, neste protocolo 1 - MAC

3
Comprimento dos endereços de hardware
6
Feitiço
1
Comprimento do endereço MAC do dispositivo

4
hops
1
Feitiço
1
Número de rotas intermediárias

5
ID da transação
23:cf:de:1d
Feitiço
4
Identificador exclusivo da transação. Gerado pelo cliente no início de uma operação de solicitação

7
Segundo decorrido
0
Feitiço
4
Tempo em segundos desde o início do processo de obtenção de endereço

9
Sinalizadores de inicialização
8000
Feitiço
2
Certos sinalizadores que podem ser definidos para indicar parâmetros de protocolo. Neste caso, “transmissão” é definida

11
Endereço IP do cliente
0.0.0.0
Linha
4
Endereço IP do cliente (se houver)

15
O endereço IP do seu cliente
172.16.134.61
Linha
4
Endereço IP oferecido pelo servidor (se disponível)

19
Próximo endereço IP do servidor
0.0.0.0
Linha
4
Endereço IP do servidor (se conhecido)

23
Endereço IP do agente de retransmissão
172.16.114.41
Linha
4
Endereço IP do agente de retransmissão (por exemplo, um switch)

27
Endereço MAC do cliente
14:d6:4d:a7:c9:55
Feitiço
6
Endereço MAC do remetente do pacote (cliente)

31
Preenchimento de endereço de hardware do cliente
 
Feitiço
10
Assento reservado. Geralmente preenchido com zeros

41
Nome do host do servidor
 
Linha
64
Nome do servidor DHCP. Geralmente não transmitido

105
Nome do arquivo de inicialização
 
Linha
128
Nome do arquivo no servidor usado por estações sem disco durante a inicialização

235
biscoito mágico
63: 82: 53: 63
Feitiço
4
Número “mágico”, segundo o qual, incl. você pode determinar que este pacote pertence ao protocolo DHCP

Opções de DHCP. Pode ir em qualquer ordem

236
Número da opção
53
Dez
3
Opção 53, que define o pacote DHCP tipo 3 - DHCPREQUEST

 
Comprimento da opção
1
Dez
1

 
Valor da opção
3
Dez
1

 
Número da opção
61
Dez
1
ID do cliente: 01 (para Ethernet) + endereço MAC do cliente

 
Comprimento da opção
7
Dez
1

 
Valor da opção
01:2c:ab:25:ff:72:a6
Feitiço
7

 
Número da opção
60
Dez
 
"Identificador de classe do fornecedor". No meu caso, ele informa a versão do cliente DHCP. Talvez outros dispositivos retornem algo diferente. O Windows, por exemplo, relata MSFT 5.0

 
Comprimento da opção
11
Dez
 

 
Valor da opção
udhcp 0.9.8
Linha
 

 
Número da opção
55
 
1
Parâmetros de rede solicitados pelo cliente. A composição pode variar

01 — Máscara de rede
03 – Portal
06 -DNS
oc — Nome do host
0f - nome de domínio da rede
1c - endereço da solicitação de transmissão (transmissão)
42 - Nome do servidor TFTP
79 - Rota Estática Sem Classe

 
Comprimento da opção
8
 
1

 
Valor da opção
01:03:06:0c:0f:1c:42:79
 
8

 
Número da opção
82
Dez
1
Opção 82, repete o que veio em DHCPDISCOVER

 
Comprimento da opção
18
Dez
1

 
Valor da opção
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18

 
Fim do pacote
255
Dez
1
255 simboliza o fim do pacote

DHCPACK

Como confirmação de que “sim, está certo, este é o seu endereço IP e não vou divulgá-lo a mais ninguém” do servidor DHCP, é servido um pacote no formato DHCPACK do servidor para o cliente. Ele é enviado por difusão como outros pacotes. Porém, no código abaixo para um servidor DHCP implementado em Python, por precaução, eu duplico qualquer solicitação de broadcast enviando um pacote para um IP de cliente específico, se já for conhecido. Além disso, o servidor DHCP não se importa se o pacote DHCPACK chegou ao cliente. Se o cliente não receber DHCPACK, depois de um tempo ele simplesmente repetirá DHCPREQUEST

Tabela de estrutura de pacotes DHCPACK

Posição no pacote
Nome do valor (comum)
Exemplo
Introdução
Byte
Esclarecimento

1
Solicitação de inicialização
2
Feitiço
1
Tipo de mensagem. 1 – solicitação do cliente para o servidor, 2 – resposta do servidor para o cliente

2
Tipo de hardware
1
Feitiço
1
Tipo de endereço de hardware, neste protocolo 1 - MAC

3
Comprimento dos endereços de hardware
6
Feitiço
1
Comprimento do endereço MAC do dispositivo

4
hops
1
Feitiço
1
Número de rotas intermediárias

5
ID da transação
23:cf:de:1d
Feitiço
4
Identificador exclusivo da transação. Gerado pelo cliente no início de uma operação de solicitação

7
Segundo decorrido
0
Feitiço
4
Tempo em segundos desde o início do processo de obtenção de endereço

9
Sinalizadores de inicialização
8000
Feitiço
2
Certos sinalizadores que podem ser definidos para indicar parâmetros de protocolo. Neste caso, “transmissão” é definida

11
Endereço IP do cliente
0.0.0.0
Linha
4
Endereço IP do cliente (se houver)

15
O endereço IP do seu cliente
172.16.134.61
Linha
4
Endereço IP oferecido pelo servidor (se disponível)

19
Próximo endereço IP do servidor
0.0.0.0
Linha
4
Endereço IP do servidor (se conhecido)

23
Endereço IP do agente de retransmissão
172.16.114.41
Linha
4
Endereço IP do agente de retransmissão (por exemplo, um switch)

27
Endereço MAC do cliente
14:d6:4d:a7:c9:55
Feitiço
6
Endereço MAC do remetente do pacote (cliente)

31
Preenchimento de endereço de hardware do cliente
 
Feitiço
10
Assento reservado. Geralmente preenchido com zeros

41
Nome do host do servidor
 
Linha
64
Nome do servidor DHCP. Geralmente não transmitido

105
Nome do arquivo de inicialização
 
Linha
128
Nome do arquivo no servidor usado por estações sem disco durante a inicialização

235
biscoito mágico
63: 82: 53: 63
Feitiço
4
Número “mágico”, segundo o qual, incl. você pode determinar que este pacote pertence ao protocolo DHCP

Opções de DHCP. Pode ir em qualquer ordem

236
Número da opção
53
Dez
3
Opção 53, que define o tipo de pacote DHCP 5 - DHCPACK

 
Comprimento da opção
1
Dez
1

 
Valor da opção
5
Dez
1

 
Número da opção
1
Dez
1
Opção para oferecer ao cliente DHCP uma máscara de rede

 
Comprimento da opção
4
Dez
1

 
Valor da opção
255.255.224.0
Linha
4

 
Número da opção
3
Dez
1
Opção para oferecer ao cliente DHCP um gateway padrão

 
Comprimento da opção
4
Dez
1

 
Valor da opção
172.16.12.1
Linha
4

 
Número da opção
6
Dez
1
Opção para oferecer DHCP ao cliente DNS

 
Comprimento da opção
4
Dez
1

 
Valor da opção
8.8.8.8
Linha
4

 
Número da opção
51
Dez
1
A vida útil dos parâmetros de rede emitidos em segundos, após os quais o cliente DHCP deve solicitá-los novamente

 
Comprimento da opção
4
Dez
1

 
Valor da opção
86400
Dez
4

 
Número da opção
82
Dez
1
Opção 82, repete o que veio em DHCPDISCOVER

 
Comprimento da opção
18
Dez
1

 
Valor da opção
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dez
18

 
Fim do pacote
255
Dez
1
255 simboliza o fim do pacote

Instalação

A instalação na verdade consiste em instalar os módulos python necessários para o trabalho. Presume-se que o MySQL já esteja instalado e configurado.

FreeBSD

pkg instalar python3 python3 -m garantirpip pip3 instalar conector mysql

Ubuntu

sudo apt-get instalar python3 sudo apt-get instalar pip3 sudo pip3 instalar conector mysql

Criamos um banco de dados MySQL, carregamos o dump pydhcp.sql nele e configuramos o arquivo de configuração.

Configuração

Todas as configurações do servidor estão em um arquivo xml. Arquivo de referência:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 host local teste teste pydhcp opção_8.8.8.8_hex:sw_port82:1:20 opção_22_hex:sw_port82:2:16 opção_18_hex:sw_mac:82:26 40 selecione ip,mask,router,dns dos usuários onde upper(mac)=upper('{option_3_AgentRemoteId_hex}') e Upper(port)=upper('{option_1_AgentCircuitId_port_hex}') selecione ip,mask,router,dns dos usuários onde upper(mac)=upper('{sw_mac}') e upper(port)=upper('{sw_port82}') selecione ip,mask,router,dns dos usuários onde upper(mac)=upper('{ClientMacAddress}') inserir no histórico (id,dt,mac,ip,comment) valores (null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Agora com mais detalhes sobre as tags:

A seção dhcpserver descreve as configurações básicas para iniciar o servidor, a saber:

  • host - qual endereço IP o servidor escuta na porta 67
  • broadcast - qual ip é o broadcast para DHCPOFFER e DHCPACK
  • DHCPServer - qual é o ip do servidor DHCP
  • LeaseTime tempo de locação do endereço IP emitido
  • ThreadLimit - quantos threads estão sendo executados simultaneamente para processar pacotes UDP recebidos na porta 67. Supõe-se que ajude em projetos de alta carga 😉
  • defaultMask,defaultRouter,defaultDNS - o que é oferecido ao assinante por padrão se um IP for encontrado no banco de dados, mas parâmetros adicionais não forem especificados para ele

seção mysql:

host, nome de usuário, senha, nome de base - tudo fala por si. Uma estrutura aproximada do banco de dados é publicada em GitHub

Seção de consulta: as solicitações para recebimento de OFERTA/ACK são descritas aqui:

  • offer_count — o número de linhas com solicitações que retornam um resultado como ip,mask,router,dns
  • oferta_n — string de consulta. Se return estiver vazio, executa a seguinte solicitação de oferta
  • history_sql - uma consulta que grava, por exemplo, no “histórico de autorização” de um assinante

As solicitações podem incluir quaisquer variáveis ​​da seção de opções ou opções do protocolo DHCP.

Seção de opções. É aqui que fica mais interessante. Aqui podemos criar variáveis ​​que podemos usar posteriormente na seção de consulta.

Por exemplo:

option_82_hex:sw_port1:20:22

, esta linha de comando pega toda a linha que veio na opção 82 da solicitação DHCP, em formato hexadecimal, no intervalo de 20 a 22 bytes inclusive e coloca na nova variável sw_port1 (porta do switch de onde veio a solicitação)

option_82_hex:sw_mac:26:40

, defina a variável sw_mac, pegando o hexadecimal do intervalo 26:40

Você pode ver todas as opções possíveis que podem ser usadas em consultas iniciando o servidor com a opção -d. Veremos algo assim:

-Um pacote dhcpinform chegou na porta 67, de 0025224ad764, b'x91XA5XE0XA3XA5XA9-x8fx8a ', (' 172.30.114.25 ', 68) {' clientmacaddress ':' 0025224 '', 'CustermacdRESS': '764' '. , 'HType': 'Ethernet', 'HostName': b'x00xa7xe91xa5xa0xa3-x5fx9a', 'ReqListDNS': Verdadeiro, 'ReqListDomainName': Verdadeiro, 'ReqListPerfowmRouterDiscover': Verdadeiro, 'ReqListRouter': Verdadeiro, 'ReqListStaticRoute': Verdadeiro, 'ReqListSubnetM perguntar ': Verdadeiro, 'ReqListVendorSpecInfo': 8, 'RequestedIpAddress': '8', 'Fornecedor': b'MSFT 43', 'chaddr': '0.0.0.0ad5.0', 'ciaddr': '0025224' , 'flags': b'x764x172.30.128.13', 'giaddr': '00', 'gpoz': 00, 'hlen': 172.30.114.25, 'hops': 308, 'htype': 'MAC', 'magic_cookie': b'cx6Sc ', 'op': 'DHCPINFORM', 'opção1': 82, 'opção12': 12, 'opção53': 53, 'opção55': 55, 'opção60': 60, 'opção61': 61, ' opção_82_byte': b'x82x82x12x01x06x00x04x00x01x00x06x02' b'x08x00x06eXx00exb1xad', 'option_9_hex': '2e82eb12010600040001000602080006001ad', 'opção_ 589_len': 2 82, 'option_18_str': "b'x82x12x01x06x00x04x00x01x00x06x02x08x00x06x00eXx1exb9xad'", 'resultado': Falso, 'segundos': 2, 'siaddr': '768', 'sw_mac': '0.0.0.0e001eb589ad', 'sw_port2': '1', 'xidbyte': b'

Assim, podemos agrupar qualquer variável em {} e ela será usada na consulta SQL.

Vamos registrar no histórico que o cliente recebeu o endereço IP:

Servidor DHCP + MySQL em Python

Servidor DHCP + MySQL em Python

Início do servidor

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

— d modo de saída do console DEBUG
-c arquivo de configuração <nome do arquivo>

Discussão

E agora mais detalhes sobre a implementação do servidor em Python. É uma dor. Python foi aprendido na hora. Muitos momentos são feitos no estilo “uau, de alguma forma eu fiz funcionar”. Não foi nada otimizado e foi deixado desta forma principalmente devido à pouca experiência em desenvolvimento em Python. Vou me debruçar sobre os aspectos mais interessantes da implementação do servidor em “código”.

Analisador de arquivo de configuração XML

O módulo Python padrão xml.dom é usado. Parece simples, mas durante a implementação houve uma notável falta de documentação clara e exemplos na rede usando este módulo.

    tree = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") para elem em mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("nome de usuário")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("senha")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basename")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") para elem em 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 em qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data para num in 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 nas opções: node=elem.getElementsByTagName("option") para opções no nó : opçõesMod.append(options.firstChild.data)

Multithreading

Curiosamente, o multithreading em Python é implementado de forma muito clara e simples.

def PacketWork(data,addr): ... # implementação de análise do pacote recebido e resposta a ele ... while True: data, addr = udp_socket.recvfrom(1024) # aguardando o pacote UDP thread = threading.Thread( target=PacketWork , args=(data,addr,)).start() # como veio - lançamos a função PacketWork definida anteriormente em segundo plano com parâmetros enquanto threading.active_count() >gconfig["dhcp_ThreadLimit"]: time. sleep(1) # se o número Já existem mais threads em execução do que nas configurações, esperamos até que haja menos deles

Receber/enviar pacote DHCP

Para interceptar pacotes UDP que passam pela placa de rede, você precisa “levantar” o soquete:

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

, onde as bandeiras são:

  • AF_INET - significa que o formato do endereço será IP: porta. Também pode haver AF_UNIX - onde o endereço é dado pelo nome do arquivo.
  • SOCK_DGRAM - significa que não aceitamos um “pacote bruto”, mas sim um que já passou pelo firewall, e com um pacote parcialmente cortado. Aqueles. recebemos apenas um pacote UDP sem o componente “físico” do wrapper do pacote UDP. Se você usar o sinalizador SOCK_RAW, também precisará analisar esse “wrapper”.

O envio de um pacote pode ser como uma transmissão:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #mudar o soquete para o modo de transmissão rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, e para o endereço “de onde veio o pacote”:

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # muda o soquete para o modo multi-ouvinte rz=udp_socket.sendto(packetack, addr)

, onde SOL_SOCKET significa o “nível de protocolo” para definir opções,

, SO_BROADCAST opção de que o pacote do capacete seja “transmitido”

  A opção SO_REUSEADDR muda o soquete para o modo “muitos ouvintes”. Em teoria é desnecessário neste caso, mas em um dos servidores FreeBSD em que testei o código não funcionou sem esta opção.

Analisando um pacote DHCP

Foi aqui que eu realmente gostei do Python. Acontece que ele permite que você seja bastante flexível com o bytecode. Permitindo que seja facilmente traduzido em valores decimais, strings e hexadecimais - ou seja, é disso que realmente precisamos para entender a estrutura do pacote. Assim, por exemplo, você pode obter um intervalo de bytes em HEX e apenas bytes:

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

, empacote os bytes em uma estrutura:

res["flags"]=pacote('BB',dados[10],dados[11])

Obtenha IP da estrutura:

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

E vice-versa:

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

Por enquanto é tudo 😉

Fonte: habr.com

Adicionar um comentário