DHCP + server Mysql dengan Python



Tujuan dari proyek ini adalah:

  • Mempelajari DHCP melalui Jaringan IPv4
  • Belajar Python (sedikit lebih banyak dari awal;))
  • mengganti server DB2DHCP (garpu saya), yang asli di sini , yang lebih sulit dan lebih sulit untuk dirakit di bawah OS baru. Ya, dan saya tidak suka biner itu, yang tidak mungkin untuk "berubah sekarang"
  • mendapatkan server DHCP yang berfungsi dengan kemampuan untuk memilih alamat IP pelanggan oleh mac pelanggan atau sekelompok switch mac + port (Opsi 82)
  • menulis sepeda lain (Oh! ini hobi favorit saya)
  • mendapatkan luli tentang juling Anda di Habrahabr (atau undangan yang lebih baik);)

Hasil: berfungsi;) Diuji pada FreeBSD dan OS Ubuntu. Secara teoritis, kode dapat diminta untuk bekerja di bawah OS apa pun, karena tidak ada ikatan khusus dalam kode.
Perhatian Lebih jauh.

Tautan ke repositori untuk penggemar untuk "menyentuh hidup-hidup . "

Proses menginstal, mengkonfigurasi, dan menggunakan hasil "studi perangkat keras" jauh lebih rendah, dan kemudian sedikit teori tentang protokol DHCP. Untuk diriku sendiri Dan untuk ceritanya;)

Sedikit teori


Apa itu DHCP?


Ini adalah protokol jaringan yang memungkinkan perangkat untuk mengetahui alamat IP-nya (well, parameter lain seperti gateway, DNS, dll.) Dari server DHCP. Paket dipertukarkan melalui UDP. Prinsip umum pengoperasian perangkat saat meminta parameter jaringan adalah sebagai berikut:

  1. Perangkat (klien) mengirimkan permintaan siaran UDP (DHCPDISCOVER) di seluruh jaringan dengan permintaan, "Baiklah, seseorang, beri saya alamat IP." Dan biasanya (tetapi tidak selalu) permintaan dari port 68 (sumber), dan tujuannya adalah port 67 (tujuan). Beberapa perangkat juga mengirim paket dari port 67. Di dalam paket DHCPDISCOVER, alamat MAC perangkat klien disertakan.
  2. Semua server DHCP yang terletak di jaringan (dan mungkin ada beberapa) formulir untuk perangkat yang mengirim DHCPDISCOVER kalimat DHCPOFFER dengan pengaturan jaringan, dan juga menyiarkannya melalui jaringan. Identifikasi kepada siapa paket ini dimaksudkan pergi ke alamat MAC dari klien yang diberikan sebelumnya dalam permintaan DHCPDISCOVER.
  3. Klien menerima paket dengan penawaran pengaturan jaringan, memilih yang paling menarik (kriteria dapat berbeda, misalnya, pada saat pengiriman paket, jumlah rute perantara), dan membuat server DHCP "secara resmi meminta" DHCPREQUEST dengan pengaturan jaringan. Dalam hal ini, paket tersebut menuju ke server DHCP tertentu.
  4. Server yang menerima DHCPREQUEST mengirimkan paket DHCPACK di mana ia sekali lagi mencantumkan pengaturan jaringan untuk klien ini



Selain itu, ada paket DHCPINFORM yang berasal dari klien, dan tujuannya adalah untuk memberi tahu server DHCP bahwa "klien masih hidup" dan menggunakan pengaturan jaringan yang dikeluarkan. Dalam implementasi server ini, paket-paket ini diabaikan.

Format paket



Secara umum, frame paket Ethernet terlihat seperti ini:



Dalam kasus kami, kami hanya akan mempertimbangkan data secara langsung dari isi paket UDP, tanpa header protokol layer OSI, yaitu struktur DHCP:

DHCPDISCOVER


Jadi, proses mendapatkan alamat IP untuk perangkat dimulai dengan fakta bahwa klien DHCP mengirim permintaan siaran dari port 68 ke 255.255.255.255:255. Dalam paket ini, klien menyertakan alamat MAC-nya, serta apa yang ingin diterima dari server DHCP. Struktur paket dijelaskan dalam tabel di bawah ini.

Tabel struktur paket DHCPDISCOVER
Posisi PaketNama NilaiContohKirimanBytePenjelasan
1Permintaan boot1Hex1Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien
2Jenis perangkat keras1Hex1Jenis alamat perangkat keras, dalam protokol ini 1 - MAC
3Panjang alamat perangkat keras6Hex1Panjang Alamat MAC Perangkat
4Hop1Hex1Jumlah rute perantara
5ID transaksi23: cf: de: 1dHex4Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan
7Kedua berlalu0Hex4Waktu dalam detik sejak awal proses mendapatkan alamat
9Bendera bootp0Hex2Beberapa flag yang dapat diatur sebagai indikasi parameter protokol
11Alamat IP klien0.0.0.0Tali4Alamat IP klien (jika ada)
15Alamat IP klien Anda0.0.0.0Tali4Alamat IP yang diajukan oleh server (jika ada)
19Alamat IP server berikutnya0.0.0.0Tali4Alamat IP server (jika diketahui)
23Relay alamat IP agen172.16.114.41Tali4Relay alamat IP agen (misalnya, switch)
27Alamat MAC klien14: d6: 4d: a7: c9: 55Hex6Alamat MAC dari pengirim paket (klien)
31Padding alamat perangkat keras klienHex10Tempat yang dipesan. Biasanya nol
41Nama host serverTali64Nama server DHCP. Biasanya tidak ditransmisikan
105Nama file bootTali128Nama file di server yang digunakan oleh stasiun tanpa disk saat boot
235Cookie ajaib63: 82: 53: 63Hex4Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP
Opsi DHCP. Bisa masuk dalam urutan apa pun
236Nomor opsi53Desember1Opsi 53 menentukan jenis paket DHCP

1 - DHCPDISCOVER
3 - DHCPREQUEST
2 - DHCPOFFER
5 - DHCPACK
8 - DHCPINFORM
Panjang opsi1Desember1
Nilai opsi1Desember1
Nomor opsi50Desember1Alamat IP apa yang ingin diterima oleh klien
Panjang opsi4Desember1
Nilai opsi172.16.134.61Tali4
Nomor opsi551Parameter jaringan yang diminta oleh klien. Komposisi mungkin berbeda

01 - Netmask
03 - Gateway
06 - DNS
oc - nama host
0f - nama domain jaringan
1c - alamat permintaan siaran (Siaran)
42 - Nama server TFTP
79 - Rute Statis Tanpa Kelas
Panjang opsi81
Nilai opsi01: 03: 06: 0c: 0f: 1c: 42: 798
Nomor opsi82DesemberOpsi 82, di mana alamat MAC perangkat repeater dan beberapa nilai tambahan dikirimkan.

Paling sering, port switch di mana DHCP end client berjalan. Opsi tambahan adalah "tertanam" dalam opsi ini. Byte pertama adalah nomor dari "suboption", yang kedua adalah panjangnya, dan kemudian nilainya.

Dalam hal ini, dalam opsi 82, suboplikasi bersarang:
ID Sirkuit Agen = 00: 04: 00: 01: 00: 04, dengan dua byte terakhir adalah port klien DHCP dari mana permintaan tersebut berasal

ID Remote Agen = 00: 06: c8: be: 19: 93: 11: 48 - Alamat MAC pada perangkat relai DHCP
Panjang opsi18Desember
Nilai opsi01:06
00: 00: 00: 01: 00: 04
02:08
00: 06: c8: menjadi: 19: 93: 11: 48
Hex
Paket akhir255Desember1255 melambangkan akhir paket


DHCPOFFER


Segera setelah server menerima paket DHCPDISCOVER dan jika ia melihat bahwa ia dapat menawarkan sesuatu kepada klien dari yang diminta, maka ia membentuk respons untuknya - DHCPOFFER. Jawabannya dikirim ke port "dari tempat asalnya", Siaran, karena pada saat ini, klien belum memiliki alamat IP, oleh karena itu, ia dapat menerima paket hanya jika dikirim siaran. Klien mengakui bahwa itu adalah paket untuknya oleh MAC di alamatnya di dalam paket, serta nomor transaksi yang ia hasilkan pada saat pembuatan paket pertama.

Tabel struktur paket DHCPOFFER
Posisi PaketNama nilai (umum)ContohKirimanBytePenjelasan
1Permintaan boot1Hex1Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien
2Jenis perangkat keras1Hex1Jenis alamat perangkat keras, dalam protokol ini 1 - MAC
3Panjang alamat perangkat keras6Hex1Panjang Alamat MAC Perangkat
4Hop1Hex1Jumlah rute perantara
5ID transaksi23: cf: de: 1dHex4Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan
7Kedua berlalu0Hex4Waktu dalam detik sejak awal proses mendapatkan alamat
9Bendera bootp0Hex2Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, 0 berarti jenis permintaan Unicast
11Alamat IP klien0.0.0.0Tali4Alamat IP klien (jika ada)
15Alamat IP klien Anda172.16.134.61Tali4Alamat IP yang diajukan oleh server (jika ada)
19Alamat IP server berikutnya0.0.0.0Tali4Alamat IP server (jika diketahui)
23Relay alamat IP agen172.16.114.41Tali4Relay alamat IP agen (misalnya, switch)
27Alamat MAC klien14: d6: 4d: a7: c9: 55Hex6Alamat MAC dari pengirim paket (klien)
31Padding alamat perangkat keras klienHex10Tempat yang dipesan. Biasanya nol
41Nama host serverTali64Nama server DHCP. Biasanya tidak ditransmisikan
105Nama file bootTali128Nama file di server yang digunakan oleh stasiun tanpa disk saat boot
235Cookie ajaib63: 82: 53: 63Hex4Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP
Opsi DHCP. Bisa masuk dalam urutan apa pun
236Nomor opsi53Desember1Opsi 53 menentukan jenis paket DHCP 2 - DHCPOFFER
Panjang opsi1Desember1
Nilai opsi2Desember1
Nomor opsi1Desember1Opsi menawarkan topeng jaringan klien DHCP
Panjang opsi4Desember1
Nilai opsi255.255.224.0Tali4
Nomor opsi3Desember1Opsi menawarkan gateway default klien DHCP
Panjang opsi4Desember1
Nilai opsi172.16.12.1Tali4
Nomor opsi6Desember1Opsi yang menawarkan DHCP ke klien DNS
Panjang opsi4Desember1
Nilai opsi8.8.8.8Tali4
Nomor opsi51Desember1Masa pakai parameter jaringan yang dikeluarkan dalam hitungan detik, setelah itu klien DHCP harus memintanya lagi
Panjang opsi4Desember1
Nilai opsi86400Desember4
Nomor opsi82Desember1Opsi 82, ulangi apa yang datang di DHCPDISCOVER
Panjang opsi18Desember1
Nilai opsi01:00: 00: 06: 00
01: 00: 00: 00: 01
02: 00: 00: 03: 0f
26: 4d: ec
Desember18
Paket akhir255Desember1255 melambangkan akhir paket


DHCPREQUEST


Setelah klien menerima DHCPOFFER, ia membentuk sebuah paket dengan permintaan parameter jaringan tidak untuk semua server DHCP di jaringan, tetapi hanya untuk satu server tertentu, yang proposal DHCPOFFER-nya paling “disukai”. Kriteria untuk "suka" bisa berbeda dan tergantung pada implementasi klien DHCP. Penerima permintaan ditunjukkan menggunakan alamat MAC dari server DHCP. Juga, paket DHCPREQUEST dapat dikirim oleh klien tanpa membentuk DHCPDISCOVER sebelumnya, jika alamat IP server sebelumnya diterima sebelumnya.

Tabel struktur paket DHCPREQUEST
Posisi PaketNama nilai (umum)ContohKirimanBytePenjelasan
1Permintaan boot1Hex1Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien
2Jenis perangkat keras1Hex1Jenis alamat perangkat keras, dalam protokol ini 1 - MAC
3Panjang alamat perangkat keras6Hex1Panjang Alamat MAC Perangkat
4Hop1Hex1Jumlah rute perantara
5ID transaksi23: cf: de: 1dHex4Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan
7Kedua berlalu0Hex4Waktu dalam detik sejak dimulainya proses
9Bendera bootp8000Hex2Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, "Siaran"
11Alamat IP klien0.0.0.0Tali4Alamat IP klien (jika ada)
15Alamat IP klien Anda172.16.134.61Tali4Alamat IP yang diajukan oleh server (jika ada)
19Alamat IP server berikutnya0.0.0.0Tali4Alamat IP server (jika diketahui)
23Relay alamat IP agen172.16.114.41Tali4Relay alamat IP agen (misalnya, switch)
27Alamat MAC klien14: d6: 4d: a7: c9: 55Hex6Alamat MAC dari pengirim paket (klien)
31Padding alamat perangkat keras klienHex10Tempat yang dipesan. Biasanya nol
41Nama host serverTali64Nama server DHCP. Biasanya tidak ditransmisikan
105Nama file bootTali128Nama file di server yang digunakan oleh stasiun tanpa disk saat boot
235Cookie ajaib63: 82: 53: 63Hex4Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP
Opsi DHCP. Bisa masuk dalam urutan apa pun
236Nomor opsi53Desember3Opsi 53 menentukan jenis paket DHCP 3 - DHCPREQUEST
Panjang opsi1Desember1
Nilai opsi3Desember1
Nomor opsi61Desember1ID Klien: 01 (untuk Ehernet) + alamat MAC klien
Panjang opsi7Desember1
Nilai opsi01: 2c: ab: 25: ff: 72: a6Hex7
Nomor opsi60Desember"Pengidentifikasi kelas vendor." Dalam kasus saya, versi klien DHCP dilaporkan. Mungkin perangkat lain mengembalikan sesuatu yang lain. Windows misalnya melaporkan MSFT 5.0
Panjang opsi11Desember
Nilai opsiudhcp 0.9.8Tali
Nomor opsi551Parameter jaringan yang diminta oleh klien. Komposisi mungkin berbeda

01 - Netmask
03 - Gateway
06 - DNS
oc - nama host
0f - nama domain jaringan
1c - alamat permintaan siaran (Siaran)
42 - Nama server TFTP
79 - Rute Statis Tanpa Kelas
Panjang opsi81
Nilai opsi01: 03: 06: 0c: 0f: 1c: 42: 798
Nomor opsi82Desember1Opsi 82, ulangi apa yang datang di DHCPDISCOVER
Panjang opsi18Desember1
Nilai opsi01:00: 00: 06: 00
01: 00: 00: 00: 01
02: 00: 00: 03: 0f
26: 4d: ec
Desember18
Paket akhir255Desember1255 melambangkan akhir paket


DHCPACK


Sebagai konfirmasi fakta bahwa "ya, itu adalah alamat IP Anda, dan saya tidak akan memberikannya kepada orang lain" dari server DHCP, ada paket dalam format DHCPACK dari server ke klien. Itu sama dengan sisa paket yang dikirim siaran. Meskipun, dalam kode di bawah ini server DHCP diimplementasikan dalam Python, untuk berjaga-jaga, saya menduplikasi permintaan siaran dengan mengirimkan paket ke IP klien tertentu, jika sudah diketahui. Selain itu, server DHCP tidak peduli sama sekali apakah paket DHCPACK telah mencapai klien. Jika klien tidak menerima DHCPACK, maka setelah beberapa saat ia hanya mengulangi DHCPREQUEST

Tabel Struktur Paket DHCPACK
Posisi PaketNama nilai (umum)ContohKirimanBytePenjelasan
1Permintaan boot2Hex1Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien
2Jenis perangkat keras1Hex1Jenis alamat perangkat keras, dalam protokol ini 1 - MAC
3Panjang alamat perangkat keras6Hex1Panjang Alamat MAC Perangkat
4Hop1Hex1Jumlah rute perantara
5ID transaksi23: cf: de: 1dHex4Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan
7Kedua berlalu0Hex4Waktu dalam detik sejak awal proses mendapatkan alamat
9Bendera bootp8000Hex2Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, "Siaran"
11Alamat IP klien0.0.0.0Tali4Alamat IP klien (jika ada)
15Alamat IP klien Anda172.16.134.61Tali4Alamat IP yang diajukan oleh server (jika ada)
19Alamat IP server berikutnya0.0.0.0Tali4Alamat IP server (jika diketahui)
23Relay alamat IP agen172.16.114.41Tali4Relay alamat IP agen (misalnya, switch)
27Alamat MAC klien14: d6: 4d: a7: c9: 55Hex6Alamat MAC dari pengirim paket (klien)
31Padding alamat perangkat keras klienHex10Tempat yang dipesan. Biasanya nol
41Nama host serverTali64Nama server DHCP. Biasanya tidak ditransmisikan
105Nama file bootTali128Nama file di server yang digunakan oleh stasiun tanpa disk saat boot
235Cookie ajaib63: 82: 53: 63Hex4Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP
Opsi DHCP. Bisa masuk dalam urutan apa pun
236Nomor opsi53Desember3Opsi 53 menentukan paket DHCP tipe 5 - DHCPACK
Panjang opsi1Desember1
Nilai opsi5Desember1
Nomor opsi1Desember1Opsi menawarkan topeng jaringan klien DHCP
Panjang opsi4Desember1
Nilai opsi255.255.224.0Tali4
Nomor opsi3Desember1Opsi menawarkan gateway default klien DHCP
Panjang opsi4Desember1
Nilai opsi172.16.12.1Tali4
Nomor opsi6Desember1Opsi yang menawarkan DHCP ke klien DNS
Panjang opsi4Desember1
Nilai opsi8.8.8.8Tali4
Nomor opsi51Desember1Masa pakai parameter jaringan yang dikeluarkan dalam hitungan detik, setelah itu klien DHCP harus memintanya lagi
Panjang opsi4Desember1
Nilai opsi86400Desember4
Nomor opsi82Desember1Opsi 82, ulangi apa yang datang di DHCPDISCOVER
Panjang opsi18Desember1
Nilai opsi01:00: 00: 06: 00
01: 00: 00: 00: 01
02: 00: 00: 03: 0f
26: 4d: ec
Desember18
Paket akhir255Desember1255 melambangkan akhir paket



Instalasi


Instalasi sebenarnya terdiri dari pemasangan modul python yang diperlukan untuk pekerjaan itu. Diasumsikan bahwa MySQL sudah diinstal dan dikonfigurasi.

Freebsd


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

Ubuntu


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

Kami membuat database MySQL, mengisi pydhcp.sql dump, mengkonfigurasi file konfigurasi.

Konfigurasi


Semua pengaturan server dalam format file xml. File referensi:

  <? xml version = "1.0"?>
 <config>
     <dhcpserver>
	 <host> 0.0.0.0 </host>
         <broadcast> 255.255.255.255 </broadcast>
         <DHCPServer> 192.168.0.71 </DHCPServer>
	 <LeaseTime> 8600 </LeaseTime>
	 <ThreadLimit> 1 </ThreadLimit>
         <defaultMask> 255.255.255.0 </defaultMask>
         <defaultRouter> 192.168.0.1 </defaultRouter>
         <defaultDNS> 8.8.8.8 </defaultDNS>
     </dhcpserver>
     <mysql>
         <host> localhost </host>
	 <username> test </username>
	 <password> test </password>
	 <basename> pydhcp </basename>
     </mysql>
     <options>
        <option> option_82_hex: sw_port1: 20:22 </option>       
        <option> option_82_hex: sw_port2: 16:18 </option>       
        <option> option_82_hex: sw_mac: 26: 40 </option>
     </options>    
     <query>
         <offer_count> 3 </offer_count>
	 <offer_1> pilih ip, mask, router, dns dari pengguna di mana atas (mac) = atas ('{option_82_AgentRemoteId_hex}') dan atas (port) = atas ('{option_82_AgentCircuitId_port_hex}') </offer_1>
         <offer_2> pilih ip, mask, router, dns dari pengguna di mana atas (mac) = atas ('{sw_mac}') dan atas (port) = atas ('{sw_port2}') </offer_2>
         <offer_3> pilih ip, mask, router, dns dari pengguna di mana atas (mac) = atas ('{ClientMacAddress}') </offer_3>
	 <history_sql> masukkan nilai history (id, dt, mac, ip, comment) (null, now (), '{ClientMacAddress}', '{RequestedIpAddress}', 'DHCPACK / INFORM') </history_sql>
     </query>
 </config> 

Sekarang dengan lebih detail pada tag:

Bagian dhcpserver menjelaskan pengaturan dasar untuk memulai server, yaitu:
  • host - alamat ip yang didengarkan server pada port 67
  • broadcast - ip mana yang merupakan Broadcast untuk DHCPOFFER dan DHCPACK
  • DHCPServer - apa ip dari server DHCP
  • Waktu sewa LeaseTime dari alamat ip yang dikeluarkan
  • ThreadLimit - berapa banyak utas yang secara bersamaan berjalan untuk memproses paket UDP yang masuk pada port 67. Diasumsikan bahwa ini akan membantu proyek yang sangat dimuat;)
  • defaultMask, defaultRouter, defaultDNS - apa yang ditawarkan kepada pelanggan secara default jika IP ditemukan dalam database, tetapi tidak ada parameter tambahan yang ditentukan untuknya

Bagian Mysql:

host, nama pengguna, kata sandi, nama kecil - semuanya berbicara sendiri. Contoh struktur basis data yang diposting di GitHub

Bagian Permintaan: Bagian ini menjelaskan permintaan untuk PENAWARAN / ACK:

  • offer_count - jumlah baris dengan permintaan yang mengembalikan hasil dari form ip, mask, router, dns
  • offer_n adalah string kueri. Jika pengembalian kosong, maka permintaan penawaran berikut dijalankan
  • history_sql - permintaan penulisan, misalnya, ke "riwayat otorisasi" oleh pelanggan

Setiap variabel dari bagian opsi atau opsi dari protokol DHCP dapat berpartisipasi dalam permintaan.

Opsi bagian. Ini dia sudah lebih menarik. Di sini kita bisa membuat variabel yang bisa kita gunakan nanti di bagian permintaan.

Sebagai contoh:

option_82_hex:sw_port1:20:22 

, baris ini adalah perintah untuk mengambil seluruh baris yang datang dalam permintaan DHCP dari opsi 82, dalam format hex, dalam kisaran dari 20 hingga 22 byte, termasuk dan memasukkannya ke dalam variabel baru sw_port1 (port switch tempat permintaan itu berasal)

 option_82_hex:sw_mac:26:40 

, tentukan variabel sw_mac, ambil hex dari kisaran 26:40

Anda bisa melihat semua opsi yang memungkinkan yang bisa digunakan dalam kueri dengan memulai server dengan saklar -d. Kami akan melihat sesuatu seperti log ini:

  - paket DHCPINFORM datang pada port 67, dari 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': Benar,
  'ReqListDomainName': Benar,
  'ReqListPerfowmRouterDiscover': Benar,
  'ReqListRouter': Benar,
  'ReqListStaticRoute': Benar,
  'ReqListSubnetMask': Benar,
  '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,
  'hop': 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 '",
  'hasil': Salah,
  'dtk': 768,
  'siaddr': '0.0.0.0',
  'sw_mac': '001e589eb2ad',
  'sw_port1': '06',
  'xidbyte': b '<\ x89} \ x8c',
  'xidhex': '3c897d8c',
  'yiaddr': '0.0.0.0'} 

Karenanya, kita dapat membungkus variabel apa pun dalam {} dan itu akan digunakan dalam kueri SQL.

Mari kita tinjau riwayat bahwa klien menerima alamat IP:





Server mulai


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

- Mode keluaran d ke konsol DEBUG
- file konfigurasi c <file_name>

Tanya jawab


Dan sekarang lebih pada implementasi server dengan Python. Ini menyakitkan. Python dipelajari dengan cepat. Banyak momen dibuat dengan gaya: "wow, aku entah bagaimana melakukan apa yang berhasil." Tidak dioptimalkan sama sekali, dan dibiarkan dalam bentuk ini terutama karena pengalaman kecil pengembangan python. Saya akan mengingat saat-saat paling menarik dari implementasi server dalam "kode".

Pengurai file konfigurasi XML


Modul Python standar xml.dom digunakan. Tampaknya sederhana, tetapi selama implementasi ada kurangnya dokumentasi dan contoh yang masuk akal di jaringan menggunakan modul ini.

  tree = minidom.parse (gconfig ["config_file"])
     mconfig = tree.getElementsByTagName ("mysql")
     untuk elem di 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")
     untuk elem di 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 ("permintaan")
     untuk elem di qconfig:  
         gconfig ["offer_count"] = elem.getElementsByTagName ("offer_count") [0] .firstChild.data                          
         untuk num dalam kisaran (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")       
     untuk opsi elem:          
         simpul = elem.getElementsByTagName ("option")
         untuk opsi di simpul:
             optionsMod.append (options.firstChild.data) 

Multithreading


Anehnya, multithreading dengan Python diimplementasikan dengan sangat jelas dan sederhana.

  def PacketWork (data, addr): 
 ...
 # Implementasi analisis paket yang diterima, dan jawabannya
 ...


 sementara Benar:
     data, addr = udp_socket.recvfrom (1024) # tunggu paket UDP
     utas = threading.Thread (target = PacketWork, args = (data, addr,)). start () # ketika datang - jalankan fungsi PacketWork yang ditentukan sebelumnya di latar belakang dengan parameter
     saat threading.active_count ()> gconfig ["dhcp_ThreadLimit"]:
        time.sleep (1) # jika jumlah utas yang sudah berjalan lebih besar dari pada pengaturan, tunggu sampai menjadi kurang 


Terima / kirim paket DHCP


Untuk mencegat paket UDP yang datang melalui kartu jaringan, Anda perlu "menaikkan" soket:
  udp_socket = socket.socket (socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
 udp_socket.bind ((gconfig ["dhcp_host"], 67)) 

di mana bendera berada:

  • AF_INET - artinya format alamat adalah IP: port. Mungkin AF_UNIX - di mana alamatnya diberikan oleh nama file.
  • SOCK_DGRAM - berarti kami menerima bukan "paket mentah", tetapi sudah melewati firewall, dan dengan paket yang terpotong sebagian. Yaitu kita hanya mendapatkan paket UDP tanpa komponen "fisik" dari bungkus paket UDP. Jika Anda menggunakan bendera SOCK_RAW, Anda masih harus mengurai "pembungkus" ini juga.

Mengirim paket bisa seperti Siaran:

  udp_socket.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # alihkan soket ke mode Broadcast
                     rz = udp_socket.sendto (packetack, (gconfig ["broadcast"], 68)) 

, dan ke alamat, "dari mana paket itu berasal":
  udp_socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # alihkan soket ke mode "banyak pendengar"
                         rz = udp_socket.sendto (paket, addr) 

di mana SOL_SOCKET berarti "tingkat protokol" untuk opsi pengaturan,

Opsi SO_BROADCAST adalah paket helm Siaran

Opsi SO_REUSEADDR mengalihkan soket ke mode multi-pendengar. Secara teori, tidak perlu dalam kasus ini, tetapi pada salah satu server FreeBSD yang saya uji, kode tidak berfungsi tanpa opsi ini.

Penguraian paket DHCP


Di sinilah saya sangat menyukai Python. Ternyata dari "kotak" itu memungkinkan Anda untuk dengan mudah menangani bytecode. Mengizinkannya menjadi sangat sederhana untuk diterjemahkan ke nilai desimal, string, dan hex - yaitu. apa yang sebenarnya kita butuhkan untuk memahami struktur paket. Jadi misalnya, Anda bisa mendapatkan rentang byte dalam HEX dan hanya byte:

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

, kemas byte ke dalam struktur:

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

Dapatkan IP dari struktur:

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


Dan sebaliknya:

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

Itu saja;)

Source: https://habr.com/ru/post/id445338/


All Articles