Skip to content
This repository was archived by the owner on Sep 9, 2021. It is now read-only.

Conversation

Mr-Shpinks
Copy link

Инструкция по использованию

Запустить скрипт командой python3 dhcp_server.py с нужными аргументами. Для использования порта 67 необходимо запускать программу с правами суперпользователя: sudo python3 dhcp_server.py. Возможные аргументы:

  -h, --help       show this help message and exit
  --ip IP          ip address at wich server will receive messages
  --port PORT      port at wich server will receive messages
  --mask MASK      subnet mask
  --router ROUTER  router address
  --domain DOMAIN  domain name server
  -d D             show details: 1 to show all incoming and outcoming messages

По дефолту сервер запускается по адресу 0.0.0.0, порт 67.

Описание используемого протокола.

Структура DHCP-сообщения, в скобках указана длина поля в октетах (байтах):

   0               1               2               3
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     op (1)    |   htype (1)   |   hlen (1)    |   hops (1)    |
   +---------------+---------------+---------------+---------------+
   |                            xid (4)                            |
   +-------------------------------+-------------------------------+
   |           secs (2)            |           flags (2)           |
   +-------------------------------+-------------------------------+
   |                          ciaddr  (4)                          |
   +---------------------------------------------------------------+
   |                          yiaddr  (4)                          |
   +---------------------------------------------------------------+
   |                          siaddr  (4)                          |
   +---------------------------------------------------------------+
   |                          giaddr  (4)                          |
   +---------------------------------------------------------------+
   |                                                               |
   |                          chaddr  (16)                         |
   |                                                               |
   |                                                               |
   +---------------------------------------------------------------+
   |                                                               |
   |                          sname   (64)                         |
   +---------------------------------------------------------------+
   |                                                               |
   |                          file    (128)                        |
   +---------------------------------------------------------------+
   |                                                               |
   |                          options (variable)                   |
   +---------------------------------------------------------------+
   FIELD      OCTETS       DESCRIPTION
   -----      ------       -----------

   op            1  Message op code / message type.
                    1 = BOOTREQUEST, 2 = BOOTREPLY
   htype         1  Hardware address type, see ARP section in "Assigned
                    Numbers" RFC; e.g., '1' = 10mb ethernet.
   hlen          1  Hardware address length (e.g.  '6' for 10mb
                    ethernet).
   hops          1  Client sets to zero, optionally used by relay agents
                    when booting via a relay agent.
   xid           4  Transaction ID, a random number chosen by the
                    client, used by the client and server to associate
                    messages and responses between a client and a
                    server.
   secs          2  Filled in by client, seconds elapsed since client
                    began address acquisition or renewal process.
   flags         2  Flags (see figure 2).
   ciaddr        4  Client IP address; only filled in if client is in
                    BOUND, RENEW or REBINDING state and can respond
                    to ARP requests.
   yiaddr        4  'your' (client) IP address.
   siaddr        4  IP address of next server to use in bootstrap;
                    returned in DHCPOFFER, DHCPACK by server.
   giaddr        4  Relay agent IP address, used in booting via a
                    relay agent.
   chaddr       16  Client hardware address.
   sname        64  Optional server host name, null terminated string.
   file        128  Boot file name, null terminated string; "generic"
                    name or null in DHCPDISCOVER, fully qualified
                    directory-path name in DHCPOFFER.
   options     var  Optional parameters field.  See the options
                    documents for a list of defined options.

В данной программе поля sname и file не заполняются. При приеме и отправке сообщений используются следующие опции (помимо pad option, end option и magic cookie):
Subnet Mask:

    Code   Len        Subnet Mask
   +-----+-----+-----+-----+-----+-----+
   |  1  |  4  |  m1 |  m2 |  m3 |  m4 |
   +-----+-----+-----+-----+-----+-----+

Router Option:


    Code   Len         Address 1               Address 2
   +-----+-----+-----+-----+-----+-----+-----+-----+--
   |  3  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
   +-----+-----+-----+-----+-----+-----+-----+-----+--

Domain Name Server Option:

    Code   Len         Address 1               Address 2
   +-----+-----+-----+-----+-----+-----+-----+-----+--
   |  6  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
   +-----+-----+-----+-----+-----+-----+-----+-----+--

DHCP Message Type:


           Value   Message Type
           -----   ------------
             1     DHCPDISCOVER
             2     DHCPOFFER
             3     DHCPREQUEST
             4     DHCPDECLINE
             5     DHCPACK
             6     DHCPNAK
             7     DHCPRELEASE

    Code   Len  Type
   +-----+-----+-----+
   |  53 |  1  | 1-7 |
   +-----+-----+-----+

Server Identifier:

    Code   Len            Address
   +-----+-----+-----+-----+-----+-----+
   |  54 |  4  |  a1 |  a2 |  a3 |  a4 |
   +-----+-----+-----+-----+-----+-----+

IP Address Lease Time:


    Code   Len         Lease Time
   +-----+-----+-----+-----+-----+-----+
   |  51 |  4  |  t1 |  t2 |  t3 |  t4 |
   +-----+-----+-----+-----+-----+-----+

Requested IP Address:

    Code   Len          Address
   +-----+-----+-----+-----+-----+-----+
   |  50 |  4  |  a1 |  a2 |  a3 |  a4 |
   +-----+-----+-----+-----+-----+-----+

Данные опции были выбраны исходя из того, с какими опциями ходят пакеты у меня по сети на машине с ubuntu 20. Подразумевается использование только одного роутера и одного сервера имен. Важным моментом является то, что механизм аренды адресов реализован тривиально, не по RFC-стандарту. Предлагаемый/назначаемый адрес отсчитывается от адреса сервера, назначенные адреса хранятся в простом массиве, адрес выдается на максимальное время. Можно было бы создать базу данных и реализовать аренду по всем правилам стандарта, но мне показалось, что это уже выходит за рамки курса. Может быть, я был неправ.
Сервер умеет принимать сообщения типа DHCPDISCOVER, DHCPREQUEST, DHCPRELEASE и DHCPDECLINE и отвечать DHCPOFFER и DHCPACK.
Сервер проверялся в основном работой с клиентом dhclient. С проверкой сервера возникли некоторые трудности. Например, DHCPDISCOVER от клиента dhclient не воспринимался сервером, хотя все сообщения DHCPREQUEST приходили. Для проверки работы с DHCPDISCOVER потребовалось использовать утилиту nmap:
sudo nmap --script broadcast-dhcp-discover
Вывод утилиты:

| broadcast-dhcp-discover: 
|   Response 1 of 1: 
|     IP Offered: 192.168.0.103
|     DHCP Message Type: DHCPOFFER
|     Server Identifier: 192.168.0.1
|     IP Address Lease Time: 2h00m00s
|     Subnet Mask: 255.255.255.0
|     Router: 192.168.0.1
|_    Domain Name Server: 192.168.0.1

Здесь видно, что предложение поступило от стандартного сервера, а не от моего, хотя сервер реагирует и отправляет сообщение по соответствующему адресу:

DHCP server starting at 0.0.0.0 : 67
MESSAGE RECEIVED FROM:  ('192.168.0.104', 68)
MESSAGE TYPE: 1
DHCPDISCOVER ACCEPTED
SENDING DHCPOFFER TO  ('192.168.0.104', 68)
extracted xid:  b'l\x1c\xf5\t'
extracted flags:  b'\x80\x00'
extracted ciaddr:  b'\x00\x00\x00\x00'
extracted giaddr:  b'\x00\x00\x00\x00'
extracted chaddr:  b'\xde\xad\xc0\xde\xca\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
offered yiaddr:  [0, 0, 0, 1]

Для проверки DHCPREQUEST можно использовать dhclient, но ситуация примерно та же:
sudo dhclient -s 0.0.0.0 -v
Вывод dhclient:

Listening on LPF/wlp3s0/6c:71:d9:56:cf:93
Sending on   LPF/wlp3s0/6c:71:d9:56:cf:93
Listening on LPF/enp4s0/60:a4:4c:72:5b:2c
Sending on   LPF/enp4s0/60:a4:4c:72:5b:2c
Sending on   Socket/fallback
DHCPREQUEST for 192.168.0.104 on wlp3s0 to 0.0.0.0 port 67 (xid=0x35243577)
DHCPDISCOVER on enp4s0 to 0.0.0.0 port 67 interval 3 (xid=0xa7a118)

Реакция сервера:

MESSAGE RECEIVED FROM:  ('127.0.0.1', 68)
MESSAGE TYPE: 3
DHCPREQUEST ACCEPTED
SENDING DHCPACK TO  ('127.0.0.1', 68)
extracted xid:  b'w5$5'
extracted flags:  b'\x00\x00'
extracted ciaddr:  b'\x00\x00\x00\x00'
extracted giaddr:  b'\x00\x00\x00\x00'
extracted chaddr:  b'lq\xd9V\xcf\x93\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
yiaddr to assign:  [192, 168, 0, 104]

Здесь назначаемый адрес был взят из поля Requested IP Address опций поступившего DHCPREQUEST.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Вторая лабораторная Реальные UDP протоколы Зачтено
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants