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:
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.
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.
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.
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
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:
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
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
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:
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:
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:
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: