DHCP+Mysql server in Python

DHCP+Mysql server in Python

The aim of this project was:

  • Learning DHCP when working on an IPv4 network
  • Learning Python (a little more than from scratch 😉 )
  • server replacement DB2DHCP (my fork), original here, which is becoming more and more difficult to assemble for a new OS. Yes, and I don’t like that the binary, which is not possible to “change right now”
  • obtaining a working DHCP server with the ability to select the subscriber's IP address by the subscriber's mac or a bunch of mac switch + port (Option 82)
  • writing another bike (Oh! this is my favorite thing to do)
  • getting lyuli about your club hand on Habrahabr (or better, an invite) 😉

Result: works 😉 Tested on FreeBSD and Ubuntu. Theoretically, the code can be asked to work under any OS, because. there are no specific bindings in the code.
Carefully! Much further.

Link to repository for fans "touch alive".

The process of installing, configuring and using the result of the “materiel study” is much lower, and then a little theory on the DHCP protocol. For myself. And for history

A bit of theory

What is DHCP

This is a network protocol that allows the device to find out its IP address (well, other parameters like the gateway, DNS, etc.) from the DHCP server. Packets are exchanged using the UDP protocol. The general principle of operation of the device when requesting network parameters is as follows:

  1. The device (client) sends out a broadcast UDP request (DHCPDISCOVER) to the entire network with the request "well, someone give me an IP address." Moreover, usually (but not always) the request comes from port 68 (source), and the destination is port 67 (destination). Some devices send packets from port 67 as well. Inside the DHCPDISCOVER packet, the MAC address of the client device is included.
  2. All DHCP servers located on the network (and there may be several of them) form a DHCPOFFER offer with network settings for the device that sent DHCPDISCOVER, and also broadcast it over the network. The identity of who this packet is for comes from the MAC address of the client provided earlier in the DHCPDISCOVER request.
  3. The client accepts packets with offers of network settings, selects the most attractive one (the criteria may be different, for example, including the time of packet delivery, the number of intermediate routes), and makes an “official request” DHCPREQUEST with network settings from the DHCP server he likes. In this case, the packet is already going to a specific DHCP server.
  4. The server that received the DHCPREQUEST sends a DHCPACK format packet, in which it once again lists the network settings intended for this client.

DHCP+Mysql server in Python

In addition, there are DHCPINFORM packets that come from the client, and the purpose of which is to inform the DHCP server that the “client is alive” and uses the given network settings. In this server's implementation, these packets are ignored.

Packet Format

In general, an Ethernet packet frame looks something like this:

DHCP+Mysql server in Python

In our case, we will consider only the data directly from the contents of the UDP packet, without the OSI level protocol headers, namely the DHCP structure:

DHCPDISCOVER

So, the process of obtaining an IP address for a device begins with the DHCP client sending a broadcast request from port 68 to 255.255.255.255:67. In this packet, the client includes its MAC address, as well as what exactly it wants to receive from the DHCP server. The package structure is described in the form of a table below.

DHCPDISCOVER Packet Structure Table

Position in the package
Value name
Example
Performance
Byte
Clarification

1
boot request
1
Hex
1
Message type. 1 - request from client to server, 2 - response from server to client

2
hardware type
1
Hex
1
Type of hardware address, in this protocol 1 - MAC

3
hardware address length
6
Hex
1
Device MAC address length

4
Hops
1
Hex
1
Number of intermediate routes

5
Transaction ID
23:cf:de:1d
Hex
4
The unique ID of the transaction. Generates a client at the start of a request operation

7
Second elapsed
0
Hex
4
Time in seconds since the beginning of the address acquisition process

9
bootp flags
0
Hex
2
Some flags that can be set to indicate protocol options

11
client IP address
0.0.0.0
Line
4
client IP address (if any)

15
Your client IP address
0.0.0.0
Line
4
IP address suggested by the server (if any)

19
Next server IP address
0.0.0.0
Line
4
Server IP address (if known)

23
relay agent IP address
172.16.114.41
Line
4
IP address of the relay agent (for example, a switch)

27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC address of the packet sender (client)

31
Client hardware address padding
 
Hex
10
Reserved place. Usually filled with zeros

41
server host name
 
Line
64
Name of the DHCP server. Usually not transmitted

105
Boot file name
 
Line
128
Server file name used by diskless stations when booting

235
magic cookie
63: 82: 53: 63
Hex
4
"Magic" number, according to which, incl. you can determine that this packet belongs to the DHCP protocol

DHCP options. Can go in any order

236
Option number
53
Dec
1
Option 53 specifying the DHCP packet type

1 - DHCPDISCOVER
3 - DHCP REQUEST
2 - DHCPOFFER
5 - DHCPACK
8 - DHCPINFORM

 
Option Length
1
Dec
1

 
Option value
1
Dec
1

 
Option number
50
Dec
1
What IP address does the client want to receive

 
Option Length
4
Dec
1

 
Option value
172.16.134.61
Line
4

 
Option number
55
 
1
The network parameters requested by the client. Composition may vary

01 - Netmask
03 - Gateway
06 - DNS
oc - Hostname
0f - network domain name
1c - address of the broadcast request (broadcast)
42 - TFTP server name
79 - Classless Static Route

 
Option Length
8
 
1

 
Option value
01:03:06:0c:0f:1c:42:79
 
8

 
Option number
82
Dec
 
Option 82, which transmits the MAC address of the repeater device and some additional values.

Most often - the port of the switch on which the end DHCP client works. Additional parameters are “embedded” in this option. The first byte is the number of the “suboption”, the second is its length, then its value.

In this case, in option 82, the following sub-options are nested:
Agent Circuit ID = 00:04:00:01:00:04, where the last two bytes are the port of the DHCP client from which the request came

Agent Remote ID = 00:06:c8:be:19:93:11:48 - MAC address of the DHCP relay device

 
Option Length
18
Dec
 

 
Option value
01:06
00:04:00:01:00:04
02:08
00:06:c8:be:19:93:11:48
Hex
 

 
End of package
255
Dec
1
255 symbolizes the end of the packet

DHCPOFFER

As soon as the server receives a DHCPDISCOVER packet and if it sees that it can offer something to the client from the requested one, then it forms a response for it - DHCPDISCOVER. The response is sent to the port "where it came from", by broadcasting, because at this point, the client does not yet have an IP address, so it can only receive a packet if it is broadcast. The client recognizes that this is a packet for him by his MAC address inside the packet, as well as the transaction number that he generates at the time of the creation of the first packet.

DHCPOFFER Packet Structure Table

Position in the package
Value name (common)
Example
Performance
Byte
Clarification

1
boot request
1
Hex
1
Message type. 1 - request from client to server, 2 - response from server to client

2
hardware type
1
Hex
1
Type of hardware address, in this protocol 1 - MAC

3
hardware address length
6
Hex
1
Device MAC address length

4
Hops
1
Hex
1
Number of intermediate routes

5
Transaction ID
23:cf:de:1d
Hex
4
The unique ID of the transaction. Generates a client at the start of a request operation

7
Second elapsed
0
Hex
4
Time in seconds since the beginning of the address acquisition process

9
bootp flags
0
Hex
2
Some flags that can be set to indicate protocol options. In this case, 0 means the request type is Unicast

11
client IP address
0.0.0.0
Line
4
client IP address (if any)

15
Your client IP address
172.16.134.61
Line
4
IP address suggested by the server (if any)

19
Next server IP address
0.0.0.0
Line
4
Server IP address (if known)

23
relay agent IP address
172.16.114.41
Line
4
IP address of the relay agent (for example, a switch)

27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC address of the packet sender (client)

31
Client hardware address padding
 
Hex
10
Reserved place. Usually filled with zeros

41
server host name
 
Line
64
Name of the DHCP server. Usually not transmitted

105
Boot file name
 
Line
128
Server file name used by diskless stations when booting

235
magic cookie
63: 82: 53: 63
Hex
4
"Magic" number, according to which, incl. you can determine that this packet belongs to the DHCP protocol

DHCP options. Can go in any order

236
Option number
53
Dec
1
Option 53 specifying DHCP packet type 2 - DHCPOFFER

 
Option Length
1
Dec
1

 
Option value
2
Dec
1

 
Option number
1
Dec
1
Option to offer the DHCP client a netmask

 
Option Length
4
Dec
1

 
Option value
255.255.224.0
Line
4

 
Option number
3
Dec
1
Option to offer the DHCP client a default gateway

 
Option Length
4
Dec
1

 
Option value
172.16.12.1
Line
4

 
Option number
6
Dec
1
Option to offer DHCP to DNS client

 
Option Length
4
Dec
1

 
Option value
8.8.8.8
Line
4

 
Option number
51
Dec
1
Time to live for issued network parameters in seconds, after which the DHCP client must request them again

 
Option Length
4
Dec
1

 
Option value
86400
Dec
4

 
Option number
82
Dec
1
Option 82, repeats what came in DHCPDISCOVER

 
Option Length
18
Dec
1

 
Option value
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
End of package
255
Dec
1
255 symbolizes the end of the packet

DHCPREQUEST

After the client receives a DHCPOFFER, it forms a packet with a request for network parameters not to all DHCP servers on the network, but only to one specific one, whose DHCPOFFER proposal he “liked” the most. The "liked" criteria can be different and depend on the implementation of the DHCP client. The recipient of the request is specified using the MAC address of the DHCP server. Also, the DHCPREQUEST packet can be sent by the client without the formation of a DHCPDISCOVER earlier, if the IP address from the server has already been previously received.

DHCPREQUEST Packet Structure Table

Position in the package
Value name (common)
Example
Performance
Byte
Clarification

1
boot request
1
Hex
1
Message type. 1 - request from client to server, 2 - response from server to client

2
hardware type
1
Hex
1
Type of hardware address, in this protocol 1 - MAC

3
hardware address length
6
Hex
1
Device MAC address length

4
Hops
1
Hex
1
Number of intermediate routes

5
Transaction ID
23:cf:de:1d
Hex
4
The unique ID of the transaction. Generates a client at the start of a request operation

7
Second elapsed
0
Hex
4
Time in seconds since the beginning of the address acquisition process

9
bootp flags
8000
Hex
2
Some flags that can be set as an indication of protocol options. In this case, "broadcast" is set

11
client IP address
0.0.0.0
Line
4
client IP address (if any)

15
Your client IP address
172.16.134.61
Line
4
IP address suggested by the server (if any)

19
Next server IP address
0.0.0.0
Line
4
Server IP address (if known)

23
relay agent IP address
172.16.114.41
Line
4
IP address of the relay agent (for example, a switch)

27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC address of the packet sender (client)

31
Client hardware address padding
 
Hex
10
Reserved place. Usually filled with zeros

41
server host name
 
Line
64
Name of the DHCP server. Usually not transmitted

105
Boot file name
 
Line
128
Server file name used by diskless stations when booting

235
magic cookie
63: 82: 53: 63
Hex
4
"Magic" number, according to which, incl. you can determine that this packet belongs to the DHCP protocol

DHCP options. Can go in any order

236
Option number
53
Dec
3
Option 53 DHCP Packet Type 3 - DHCPREQUEST

 
Option Length
1
Dec
1

 
Option value
3
Dec
1

 
Option number
61
Dec
1
Client ID: 01 (for Ethernet) + client MAC address

 
Option Length
7
Dec
1

 
Option value
01:2c:ab:25:ff:72:a6
Hex
7

 
Option number
60
Dec
 
Vendor class identifier. In my case, it tells the version of the DHCP client. Perhaps other devices return something different. Windows for example reports MSFT 5.0

 
Option Length
11
Dec
 

 
Option value
udhcp 0.9.8
Line
 

 
Option number
55
 
1
The network parameters requested by the client. Composition may vary

01 - Netmask
03 - Gateway
06 - DNS
oc - Hostname
0f - network domain name
1c - address of the broadcast request (broadcast)
42 - TFTP server name
79 - Classless Static Route

 
Option Length
8
 
1

 
Option value
01:03:06:0c:0f:1c:42:79
 
8

 
Option number
82
Dec
1
Option 82, repeats what came in DHCPDISCOVER

 
Option Length
18
Dec
1

 
Option value
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
End of package
255
Dec
1
255 symbolizes the end of the packet

DHCPACK

As confirmation that “yes, this is your IP address, and I won’t give it out to anyone else” from the DHCP server, a packet in the DHCPACK format from the server to the client is served. It is the same as the rest of the packets sent broadcast. Although, in the DHCP server code below implemented in Python, just in case, I duplicate any broadcast request by sending a packet to a specific client IP if it is already known. Moreover, the DHCP server does not care at all whether the DHCPACK packet has reached the client. If the client does not receive a DHCPACK, then after a while it simply repeats the DHCPREQUEST

DHCPACK Packet Structure Table

Position in the package
Value name (common)
Example
Performance
Byte
Clarification

1
boot request
2
Hex
1
Message type. 1 - request from client to server, 2 - response from server to client

2
hardware type
1
Hex
1
Type of hardware address, in this protocol 1 - MAC

3
hardware address length
6
Hex
1
Device MAC address length

4
Hops
1
Hex
1
Number of intermediate routes

5
Transaction ID
23:cf:de:1d
Hex
4
The unique ID of the transaction. Generates a client at the start of a request operation

7
Second elapsed
0
Hex
4
Time in seconds since the beginning of the address acquisition process

9
bootp flags
8000
Hex
2
Some flags that can be set as an indication of protocol options. In this case, "broadcast" is set

11
client IP address
0.0.0.0
Line
4
client IP address (if any)

15
Your client IP address
172.16.134.61
Line
4
IP address suggested by the server (if any)

19
Next server IP address
0.0.0.0
Line
4
Server IP address (if known)

23
relay agent IP address
172.16.114.41
Line
4
IP address of the relay agent (for example, a switch)

27
Client MAC address
14:d6:4d:a7:c9:55
Hex
6
MAC address of the packet sender (client)

31
Client hardware address padding
 
Hex
10
Reserved place. Usually filled with zeros

41
server host name
 
Line
64
Name of the DHCP server. Usually not transmitted

105
Boot file name
 
Line
128
Server file name used by diskless stations when booting

235
magic cookie
63: 82: 53: 63
Hex
4
"Magic" number, according to which, incl. you can determine that this packet belongs to the DHCP protocol

DHCP options. Can go in any order

236
Option number
53
Dec
3
Option 53 specifying DHCP packet type 5 - DHCPACK

 
Option Length
1
Dec
1

 
Option value
5
Dec
1

 
Option number
1
Dec
1
Option to offer the DHCP client a netmask

 
Option Length
4
Dec
1

 
Option value
255.255.224.0
Line
4

 
Option number
3
Dec
1
Option to offer the DHCP client a default gateway

 
Option Length
4
Dec
1

 
Option value
172.16.12.1
Line
4

 
Option number
6
Dec
1
Option to offer DHCP to DNS client

 
Option Length
4
Dec
1

 
Option value
8.8.8.8
Line
4

 
Option number
51
Dec
1
Time to live for issued network parameters in seconds, after which the DHCP client must request them again

 
Option Length
4
Dec
1

 
Option value
86400
Dec
4

 
Option number
82
Dec
1
Option 82, repeats what came in DHCPDISCOVER

 
Option Length
18
Dec
1

 
Option value
01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec
18

 
End of package
255
Dec
1
255 symbolizes the end of the packet

Installation

Installation actually consists in installing the python modules necessary for work. It is assumed that MySQL is already installed and configured.

FreeBSD

pkg install python3 python3 -m ensurepip pip3 install mysql-connector

Ubuntu

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

We create a MySQL database, upload the pydhcp.sql dump into it, and set up the configuration file.

Configuration

All server settings are in the xml file. Reference file:

1.0 0.0.0.0 255.255.255.255 192.168.0.71 8600 1 255.255.255.0 192.168.0.1 localhost test test pydhcp option_8.8.8.8_hex:sw_port82:1:20 option_22_hex:sw_port82:2:16 option_18_hex:sw_mac:82:26 40 select ip,mask,router,dns from users where upper(mac)=upper('{option_3_AgentRemoteId_hex}') and upper(port)=upper('{option_1_AgentCircuitId_port_hex}') select ip,mask,router,dns from users where upper(mac)=upper('{sw_mac}') and upper(port)=upper('{sw_port82}') select ip,mask,router,dns from users where upper(mac)=upper('{ClientMacAddress}') insert into history (id,dt,mac,ip,comment) values ​​(null,now(),'{ClientMacAddress}','{RequestedIpAddress}','DHCPACK/INFORM')

Now for the tags:

The dhcpserver section describes the basic settings for starting the server, namely:

  • host - what ip address the server is listening on port 67
  • broadcast - which ip is broadcast for DHCPOFFER and DHCPACK
  • DHCPServer - what is the ip of the DHCP server
  • LeaseTime lease time of the given ip address
  • ThreadLimit - how many threads are simultaneously running to process incoming UDP packets on port 67. It is supposed to help on highly loaded projects 😉
  • defaultMask,defaultRouter,defaultDNS - what is offered to the subscriber by default if the IP is found in the database, but additional parameters are not specified for it

mysql section:

host, username, password, basename - everything speaks for itself. An example database structure is posted at GitHub

The query section: requests for receiving OFFER/ACK are described here:

  • offer_count - the number of lines with requests that return a result of the form ip, mask, router, dns
  • offer_n - query string. If return is empty, then executes the following offer request
  • history_sql - write a request, for example, to the "authorization history" for the subscriber

Any variables from the options section or options from the DHCP protocol can participate in requests.

options section. Here it is more interesting. Here we can create variables that we can use later in the query section.

For example:

option_82_hex:sw_port1:20:22

, this line-command take the entire line that came in the DHCP request for option 82, in hex format, in the range from 20 to 22 bytes inclusive and put it in a new variable sw_port1 (the port of the switch where the request came from)

option_82_hex:sw_mac:26:40

, define the variable sw_mac, taking hex from the range 26:40

You can see all possible options that can be used in queries by starting the server with the -d switch. We will see something like this log:

-- DHCPINFORM packet arrived on port 67, from 0025224ad764 , b'x91xa5xe0xa3xa5xa9-x8fx8a' , ('172.30.114.25', 68) {'ClientMacAddress': '0025224ad764', 'ClientMacAddressByte': b'x00 7%"Jxd91d', ' HType': 'Ethernet', 'HostName': b'x5xa0xe3xa5xa9xa8-x8fx43a', 'ReqListDNS': True, 'ReqListDomainName': True, 'ReqListPerfowmRouterDiscover': True, 'ReqListRouter': True, 'ReqListStaticRoute': True, 'ReqL istSubnetMask ': True, 'ReqListVendorSpecInfo': 0.0.0.0, 'RequestedIpAddress': '5.0', 'Vendor': 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', 'option12': 53, 'option53': 55, 'option55': 60, 'option60': 61, 'option61': 82, 'option82': 82, 'option_12_byte': b'x01x06x00x04x00x01x00x06x02x08x00x06' b'x00x1x9eXx2exb82xad', 'option_12010600040001000602080006001_hex': '589e2eb82ad', 'option_18_len' : 82, 'option_12_str': "b'x01x06x00x04x00x01x00x06x02x08x00x06x00x1x9eXx2exb768xad'", 'result': False, 'secs': 0.0.0.0, 'siaddr': '001', 'sw_mac': '589e2eb1ad', 'sw_port06': '89', 'xidbyte': b'

Accordingly, we can wrap any variable in {} and it will be used in the SQL query.

Let's record for history that the IP address the client received:

DHCP+Mysql server in Python

DHCP+Mysql server in Python

Server start

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

- d console output mode DEBUG
- c <filename> configuration file

Debriefing

And now more about the implementation of the server in Python. It is a pain. Python was learned on the fly. Many moments are made in the style: "wow, somehow I did what works." Not optimized at all, and left in this form mainly due to little experience in python development. I will dwell on the most interesting aspects of the implementation of the server in the "code".

XML configuration file parser

The standard Python module xml.dom is used. It seems to be simple, but during implementation, there was a noticeable lack of sensible documentation and examples on the network using this module.

    tree = minidom.parse(gconfig["config_file"]) mconfig=tree.getElementsByTagName("mysql") for elem in mconfig: gconfig["mysql_host"]=elem.getElementsByTagName("host")[0].firstChild.data gconfig["mysql_username"]=elem.getElementsByTagName("username")[0].firstChild.data gconfig["mysql_password"]=elem.getElementsByTagName("password")[0].firstChild.data gconfig["mysql_basename"] =elem.getElementsByTagName("basename")[0].firstChild.data dconfig=tree.getElementsByTagName("dhcpserver") for elem in 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") for elem in qconfig: gconfig["offer_count"]=elem.getElementsByTagName("offer_count")[0].firstChild.data for 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") for elem in options: node=elem.getElementsByTagName("option") for options in node : optionsMod.append(options.firstChild.data)

Multithreading

Oddly enough, multithreading in Python is implemented very clearly and simply.

def PacketWork(data,addr): ... # implementation of parsing an incoming packet and answering it ... while True: data, addr = udp_socket.recvfrom(1024) # waiting for a UDP packet thread = threading.Thread(target=PacketWork , args=(data,addr,)).start() # as it came - we start the previously defined PacketWork function in the background with parameters while threading.active_count() >gconfig["dhcp_ThreadLimit"]: time.sleep(1) # if number there are more already running threads than in the settings, we wait until there are fewer of them

Receiving/sending a DHCP packet

In order to intercept UDP packets going through the network card, you need to "raise" the socket:

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

where the flags are:

  • AF_INET - means that the address format will be IP:port. Maybe also AF_UNIX - where the address is given by the file name.
  • SOCK_DGRAM - means that we are not receiving a “raw packet”, but one that has already passed through the firewall, and with a partially cut packet. Those. we get only the UDP packet without the "physical" component of the wrapper of the UDP packet. If you use the SOCK_RAW flag, then it will also be necessary to parse this “wrapper”.

Sending a packet can be like a broadcast:

                    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #switch the socket to send broadcast mode rz=udp_socket.sendto(packetack, (gconfig["broadcast"],68))

, and to the address "where the package came from":

                        udp_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # switch socket to "many listeners" mode rz=udp_socket.sendto(packetack, addr)

, where SOL_SOCKET means "protocol layer" for setting options,

, SO_BROADCAST option that the helmet package is "broadcasted"

  ,SO_REUSEADDR option switches the socket to "many listeners" mode. In theory, it is unnecessary in this case, but on one of the FreeBSD servers on which I tested, the code did not work without this option.

Parsing a DHCP packet

This is where I really liked Python. It turns out out of the "box" that it allows you to quite freely deal with the bytecode. Allowing it to be very easy to convert to decimals, strings and hex - i.e. what we actually need to understand the structure of the package. So for example, you can get a range of bytes in HEX and just bytes:

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

, pack the bytes into a structure:

res["flags"]=pack('BB',data[10],data[11])

Get IP from structure:

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

And vice versa:

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

That's all 😉

Source: habr.com

Add a comment