DHCP + Mysql server in Python



The purpose of this project was:

  • Learning DHCP over an IPv4 Network
  • Learning Python (a little more than from scratch;))
  • replacing the DB2DHCP server (my fork), the original here , which is harder and harder to assemble under the new OS. Yes, and I do not 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 subscriber's mac or a bunch of mac switches + port (Option 82)
  • writing another bike (Oh! this is my favorite pastime)
  • getting Lyuli about his squint on Habrahabr (or better invite);)

Result: it works;) Tested on FreeBSD and Ubuntu OS. Theoretically, the code can be asked to work under any OS, because there are no specific bindings in the code.
Caution! A lot further.

Link to the repository for fans to "touch alive . "

The process of installing, configuring, and using the result of the "study of the hardware" is much lower, and then a little theory on the DHCP protocol. For yourself. And for the story;)

A bit of theory


What is DHCP?


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

  1. The device (client) sends out a UDP broadcast request (DHCPDISCOVER) across the network with the request, "Well, someone, give me an IP address." And usually (but not always) the request is from port 68 (source), and the destination is port 67 (destination). Some devices also send packets from port 67. 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) form for the device that sent DHCPDISCOVER a DHCPOFFER sentence with network settings, and it also broadcasts it over the network. Identification to whom this packet is intended goes to the MAC address of the client provided earlier in the DHCPDISCOVER request.
  3. The client receives packets with offers of network settings, selects the most attractive (the criteria can be different, for example, by the time of packet delivery, the number of intermediate routes), and makes the DHCP server “officially request” DHCPREQUEST with network settings. In this case, the packet goes to a specific DHCP server.
  4. The server that received DHCPREQUEST sends a DHCPACK packet in which it once again lists the network settings for this client



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 issued network settings. In the implementation of this server, these packets are ignored.

Packet format



In general, the frame of the Ethernet packet looks something like this:



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

DHCPDISCOVER


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

DHCPDISCOVER packet structure table
Package PositionValue NameExampleRepresentationByteExplanation
1Boot request1Hex1Type of message. 1 - request from client to server, 2 - response from server to client
2Hardware type1Hex1Type of hardware address, in this protocol 1 - MAC
3Hardware adrees length6Hex1Device MAC Address Length
4Hops1Hex1Number of intermediate routes
5Transaction id23: cf: de: 1dHex4Unique Transaction Identifier. Generated by the client at the beginning of the request operation
7Second elapsed0Hex4Time in seconds since the beginning of the process of obtaining the address
9Bootp flags0Hex2Some flags that can be set as an indication of protocol parameters
elevenClient IP address0.0.0.0Line4Client IP address (if any)
fifteenYour client IP address0.0.0.0Line4IP address proposed by the server (if any)
19Next server IP address0.0.0.0Line4Server IP address (if known)
23Relay agent IP address172.16.114.41Line4Relay agent IP address (for example, a switch)
27Client MAC address14: d6: 4d: a7: c9: 55Hex6MAC address of the sender of the packet (client)
31Client hardware address padding Hex10Reserved place. Usually zeros
41Server host name Line64The name of the DHCP server. Usually not transmitted
105Boot file name Line128The file name on the server used by diskless stations during boot
235Magic cookie63: 82: 53: 63Hex4The "magic" number, by which incl. you can determine that this packet belongs to the DHCP protocol
DHCP options. Can go in any order
236Option number53Dec1Option 53 specifying the type of packet DHCP

1 - DHCPDISCOVER
3 - DHCPREQUEST
2 - DHCPOFFER
5 - DHCPACK
8 - DHCPINFORM
 Option length1Dec1
 Option value1Dec1
 Option numberfiftyDec1What IP address does the client want to receive
 Option length4Dec1
 Option value172.16.134.61Line4
 Option number55 1The network parameters requested by the client. The composition can be different

01 - Network mask
03 - Gateway
06 - DNS
oc - Host name
0f - network domain name
1c - broadcast request (broadcast) address
42 - TFTP server name
79 - Classless Static Route
 Option length8 1
 Option value01: 03: 06: 0c: 0f: 1c: 42: 79 8
 Option number82Dec Option 82, in which the MAC address of the repeater device and some additional values ​​are transmitted.

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

In this case, option 82 contains the following options:
Agent Circuit ID = 00: 04: 00: 01: 00: 04, where the last two bytes are the DHCP client port from which the

Agent Remote ID = 00: 06: c8: be: 19: 93: 11: 48 - MAC address of the DHCP relay device
 Option length18Dec 
 Option value01:06
00: 04: 00: 01: 00: 04
02:08
00: 06: c8: be: 19: 93: 11: 48
Hex 
 End of package255Dec1255 symbolizes the end of the package


DHCPOFFER


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

DHCPOFFER packet structure table
Package PositionName of value (common)ExampleRepresentationByteExplanation
1Boot request1Hex1Type of message. 1 - request from client to server, 2 - response from server to client
2Hardware type1Hex1Type of hardware address, in this protocol 1 - MAC
3Hardware adrees length6Hex1Device MAC Address Length
4Hops1Hex1Number of intermediate routes
5Transaction id23: cf: de: 1dHex4Unique Transaction Identifier. Generated by the client at the beginning of the request operation
7Second elapsed0Hex4Time in seconds since the beginning of the process of obtaining the address
9Bootp flags0Hex2Some flags that can be set as an indication of protocol parameters. In this case, 0 means the Unicast request type
elevenClient IP address0.0.0.0Line4Client IP address (if any)
fifteenYour client IP address172.16.134.61Line4IP address proposed by the server (if any)
19Next server IP address0.0.0.0Line4Server IP address (if known)
23Relay agent IP address172.16.114.41Line4Relay agent IP address (for example, a switch)
27Client MAC address14: d6: 4d: a7: c9: 55Hex6MAC address of the sender of the packet (client)
31Client hardware address padding Hex10Reserved place. Usually zeros
41Server host name Line64The name of the DHCP server. Usually not transmitted
105Boot file name Line128The file name on the server used by diskless stations during boot
235Magic cookie63: 82: 53: 63Hex4The "magic" number, by which incl. you can determine that this packet belongs to the DHCP protocol
DHCP options. Can go in any order
236Option number53Dec1Option 53 specifying the type of DHCP 2 packet - DHCPOFFER
 Option length1Dec1
 Option value2Dec1
 Option number1Dec1Option offering DHCP client network mask
 Option length4Dec1
 Option value255.255.224.0Line4
 Option number3Dec1Option offering DHCP client default gateway
 Option length4Dec1
 Option value172.16.12.1Line4
 Option number6Dec1Option offering DHCP to the DNS client
 Option length4Dec1
 Option value8.8.8.8Line4
 Option number51Dec1The lifetime of the issued network parameters in seconds, after which the DHCP client must request them again
 Option length4Dec1
 Option value86400Dec4
 Option number82Dec1Option 82, repeats what came in DHCPDISCOVER
 Option length18Dec1
 Option value01: 08: 00: 06: 00
01: 01: 00: 00: 01
02: 06: 00: 03: 0f
26: 4d: ec
Dec18
 End of package255Dec1255 symbolizes the end of the package


DHCPREQUEST


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

DHCPREQUEST packet structure table
Package PositionName of value (common)ExampleRepresentationByteExplanation
1Boot request1Hex1Type of message. 1 - request from client to server, 2 - response from server to client
2Hardware type1Hex1Type of hardware address, in this protocol 1 - MAC
3Hardware adrees length6Hex1Device MAC Address Length
4Hops1Hex1Number of intermediate routes
5Transaction id23: cf: de: 1dHex4Unique Transaction Identifier. Generated by the client at the beginning of the request operation
7Second elapsed0Hex4Time in seconds since the beginning of the process of obtaining the address
9Bootp flags8000Hex2Some flags that can be set as an indication of protocol parameters. In this case, “Broadcast”
elevenClient IP address0.0.0.0Line4Client IP address (if any)
fifteenYour client IP address172.16.134.61Line4IP address proposed by the server (if any)
19Next server IP address0.0.0.0Line4Server IP address (if known)
23Relay agent IP address172.16.114.41Line4Relay agent IP address (for example, a switch)
27Client MAC address14: d6: 4d: a7: c9: 55Hex6MAC address of the sender of the packet (client)
31Client hardware address padding Hex10Reserved place. Usually zeros
41Server host name Line64The name of the DHCP server. Usually not transmitted
105Boot file name Line128The file name on the server used by diskless stations during boot
235Magic cookie63: 82: 53: 63Hex4The "magic" number, by which incl. you can determine that this packet belongs to the DHCP protocol
DHCP options. Can go in any order
236Option number53Dec3Option 53 specifying the type of DHCP 3 packet - DHCPREQUEST
 Option length1Dec1
 Option value3Dec1
 Option number61Dec1Client ID: 01 (for Ehernet) + MAC address of the client
 Option length7Dec1
 Option value01: 2c: ab: 25: ff: 72: a6Hex7
 Option number60Dec "Vendor class identifier." In my case, the version of the DHCP client is reported. Perhaps other devices return something else. Windows for example reports MSFT 5.0
 Option lengthelevenDec 
 Option valueudhcp 0.9.8Line 
 Option number55 1Запрашиваемые клиентом сетевые параметры. Состав может быть различным

01 — Маска сети
03 — Шлюз
06 — DNS
oc — Имя хоста
0f — имя домена сети
1c — адрес широковещательного запроса (бродкаста)
42 — имя сервера TFTP
79 — Classless Static Route
 Длина опции8 1
 Значение опции01:03:06:0c:0f:1c:42:79 8
 Номер опции82Dec1Опция 82, повторяет то что пришло в DHCPDISCOVER
 Длина опции18Dec1
 Значение опции01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec18
 Окончание пакета255Dec1255 символизирует окончание пакета


DHCPACK


As a confirmation of the fact that “yes, it’s your IP address, and I won’t give it to anyone else” from the DHCP server, there is a packet in DHCPACK format from the server to the client. It is the same as the rest of the packets sent broadcast. Although, in the below code of the DHCP server 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 DHCPACK, then after a while it simply repeats DHCPREQUEST

DHCPACK Packet Structure Table
Package PositionName of value (common)ExampleRepresentationByteExplanation
1Boot request2Hex1Type of message. 1 - request from client to server, 2 - response from server to client
2Hardware type1Hex1Type of hardware address, in this protocol 1 - MAC
3Hardware adrees length6Hex1Длина MAC адреса устройства
4Hops1Hex1Количество промежуточных маршрутов
5Transaction ID23:cf:de:1dHex4Уникальный идентификатор транзакции. Генерирует клиент в начале операции запроса
7Second elapsed0Hex4Время в секундах с начала процесса получения адреса
9Bootp flags8000Hex2Некие флаги, которые могут устанавливаться, в качестве указания параметров протокол. В данном случае выставлено «бродкаст»
11Client IP address0.0.0.0Строка4IP адрес клиента (если есть)
15Your client IP address172.16.134.61Строка4IP адрес предложенный сервером (если есть)
19Next server IP address0.0.0.0Строка4IP адрес сервера (если известен)
23Relay agent IP address172.16.114.41Строка4IP адрес агента ретрансляции (например свича)
27Client MAC address14:d6:4d:a7:c9:55Hex6MAC адрес отправителя пакета (клиента)
31Client hardware address padding Hex10Зарезервированное место. Обычно забито нулями
41Server host name Строка64Имя сервера DHCP. Обычно не передается
105Boot file name Строка128Имя файла на сервере, используемое бездисковыми станциями при загрузке
235Magic cookie63:82:53:63Hex4«Магическое» число, по которому в т.ч. можно определить, что этот пакет — принадлежит протоколу DHCP
Опции DHCP. Могут идти в любом порядке
236Номер опции53Dec3Опция 53, определяющая тип пакета DHCP 5 — DHCPACK
 Длина опции1Dec1
 Значение опции5Dec1
 Номер опции1Dec1Опция предлагающая DHCP клиенту маску сети
 Длина опции4Dec1
 Значение опции255.255.224.0Строка4
 Номер опции3Dec1Опция предлагающая DHCP клиенту шлюз по умолчанию
 Длина опции4Dec1
 Значение опции172.16.12.1Строка4
 Номер опции6Dec1Опция предлагающая DHCP клиенту DNS
 Длина опции4Dec1
 Значение опции8.8.8.8Строка4
 Номер опции51Dec1Время жизни выданных сетевых параметров в секундах, через которое DHCP клиент должен запросить их снова
 Длина опции4Dec1
 Значение опции86400Dec4
 Номер опции82Dec1Опция 82, повторяет то что пришло в DHCPDISCOVER
 Длина опции18Dec1
 Значение опции01:08:00:06:00
01:01:00:00:01
02:06:00:03:0f
26:4d:ec
Dec18
 Окончание пакета255Dec1255 symbolizes the end of the package



Installation


Installation actually consists of installing the python modules necessary for the job. 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 the MySQL database, fill in the dump pydhcp.sql, configure the configuration file.

Configuration


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

0.0.0.0255.255.255.255192.168.0.7186001255.255.255.0192.168.0.18.8.8.8localhosttesttestpydhcp3select ip, mask, router, dns from users where upper (mac) = upper ('{option_82_AgentRemoteId_hex}') and upper (port) = upper ('{option_82_AgentCircuitId_port_hex}')select ip, mask, router, dns from users where upper (mac) = upper ('{sw_mac}') and upper (port) = upper ('{sw_port2}')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 in more detail by tags:

The dhcpserver section describes the basic settings for starting the server, namely:
  • host - which ip address the server is listening on port 67
  • broadcast - which ip is a Broadcast for DHCPOFFER and DHCPACK
  • DHCPServer - what is the ip of the DHCP server
  • LeaseTime lease time of the issued ip address
  • ThreadLimit - how many threads are simultaneously running to process incoming UDP packets on port 67. It is assumed that this will help on highly loaded projects;)
  • defaultMask, defaultRouter, defaultDNS - what is offered to the subscriber by default if IP is found in the database, but no additional parameters are specified for him

The mysql section:

host, username, password, basename - everything speaks for itself. An exemplary database structure is available on GitHub.

Query section: This section describes the queries for obtaining OFFER / ACK:

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

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

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

For instance:

option_82_hex:sw_port1:20:22

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

option_82_hex:sw_mac:26:40

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

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

- the DHCPINFORM packet came on port 67, from 0025224ad764, b '\ x91 \ xa5 \ xe0 \ xa3 \ xa5 \ xa9- \ x8f \ x8a', ('172.30.114.25', 68)
{'ClientMacAddress': '0025224ad764',
 'ClientMacAddressByte': b'\x00%"J\xd7d',
 'HType': 'Ethernet',
 'HostName': b'\x91\xa5\xe0\xa3\xa5\xa9-\x8f\x8a',
 'ReqListDNS': True,
 'ReqListDomainName': True,
 'ReqListPerfowmRouterDiscover': True,
 'ReqListRouter': True,
 'ReqListStaticRoute': True,
 'ReqListSubnetMask': True,
 'ReqListVendorSpecInfo': 43,
 'RequestedIpAddress': '0.0.0.0',
 'Vendor': b'MSFT 5.0',
 'chaddr': '0025224ad764',
 'ciaddr': '172.30.128.13',
 'flags': b'\x00\x00',
 'giaddr': '172.30.114.25',
 'gpoz': 308,
 'hlen': 6,
 'hops': 1,
 'htype': 'MAC',
 'magic_cookie': b'c\x82Sc',
 'op': 'DHCPINFORM',
 'option12': 12,
 'option53': 53,
 'option55': 55,
 'option60': 60,
 'option61': 61,
 'option82': 82,
 'option_82_byte': b'\x12\x01\x06\x00\x04\x00\x01\x00\x06\x02\x08\x00'
                   b'\x06\x00\x1eX\x9e\xb2\xad',
 'option_82_hex': '12010600040001000602080006001e589eb2ad',
 'option_82_len': 18,
 'option_82_str': "b'\\x12\\x01\\x06\\x00\\x04\\x00\\x01\\x00\\x06\\x02\\x08\\x00\\x06\\x00\\x1eX\\x9e\\xb2\\xad'",
 'result': False,
 'secs': 768,
 'siaddr': '0.0.0.0',
 'sw_mac': '001e589eb2ad',
 'sw_port1': '06',
 'xidbyte': b'<\x89}\x8c',
 'xidhex': '3c897d8c',
 'yiaddr': '0.0.0.0'}

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

Let us capture for history that the client received the IP address:





Server start


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

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

Debriefing


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

XML configuration file parser


The standard Python module xml.dom is used. It seems to be simple, but during the 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 the analysis of the received package, and the answer to it
...
while True:
    data, addr = udp_socket.recvfrom (1024) # wait for UDP packet
    thread = threading.Thread (target = PacketWork, args = (data, addr,)). start () # as it came - run the PacketWork function defined earlier in the background with parameters
    while threading.active_count ()> gconfig ["dhcp_ThreadLimit"]:
       time.sleep (1) # if the number of already running threads is greater than in the settings, wait until they become less


Receive / send DHCP packet


In order to intercept UDP packets coming 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 AF_UNIX - where the address is given by the file name.
  • SOCK_DGRAM - means that we are accepting not a “raw packet”, but already passed through a firewall, and with partially cut off packet. Those. we get only the UDP packet without the “physical” component of the UDP packet wrapper. If you use the SOCK_RAW flag, you will still need 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 Broadcast mode
                    rz = udp_socket.sendto (packetack, (gconfig ["broadcast"], 68))

, and to the address, "where did the package come from":
                        udp_socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # switch the socket to the "many listeners" mode
                        rz = udp_socket.sendto (packetack, addr)

where SOL_SOCKET means “protocol level” for setting options

,, SO_BROADCAST option that the package is a Broadcast helmet

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

DHCP packet parsing


This is where I really liked Python. It turns out of the "box" it allows you to quite easily deal with the bytecode. Allowing it to be very simple to translate to decimal values, 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 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 ;)

Also popular now: