
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:
- 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.
- 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.
- 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.
- 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 DHCPDISCOVERPosisi Paket | Nama Nilai | Contoh | Kiriman | Byte | Penjelasan |
1 | Permintaan boot | 1 | Hex | 1 | Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien |
2 | Jenis perangkat keras | 1 | Hex | 1 | Jenis alamat perangkat keras, dalam protokol ini 1 - MAC |
3 | Panjang alamat perangkat keras | 6 | Hex | 1 | Panjang Alamat MAC Perangkat |
4 | Hop | 1 | Hex | 1 | Jumlah rute perantara |
5 | ID transaksi | 23: cf: de: 1d | Hex | 4 | Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan |
7 | Kedua berlalu | 0 | Hex | 4 | Waktu dalam detik sejak awal proses mendapatkan alamat |
9 | Bendera bootp | 0 | Hex | 2 | Beberapa flag yang dapat diatur sebagai indikasi parameter protokol |
11 | Alamat IP klien | 0.0.0.0 | Tali | 4 | Alamat IP klien (jika ada) |
15 | Alamat IP klien Anda | 0.0.0.0 | Tali | 4 | Alamat IP yang diajukan oleh server (jika ada) |
19 | Alamat IP server berikutnya | 0.0.0.0 | Tali | 4 | Alamat IP server (jika diketahui) |
23 | Relay alamat IP agen | 172.16.114.41 | Tali | 4 | Relay alamat IP agen (misalnya, switch) |
27 | Alamat MAC klien | 14: d6: 4d: a7: c9: 55 | Hex | 6 | Alamat MAC dari pengirim paket (klien) |
31 | Padding alamat perangkat keras klien | | Hex | 10 | Tempat yang dipesan. Biasanya nol |
41 | Nama host server | | Tali | 64 | Nama server DHCP. Biasanya tidak ditransmisikan |
105 | Nama file boot | | Tali | 128 | Nama file di server yang digunakan oleh stasiun tanpa disk saat boot |
235 | Cookie ajaib | 63: 82: 53: 63 | Hex | 4 | Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP |
Opsi DHCP. Bisa masuk dalam urutan apa pun |
236 | Nomor opsi | 53 | Desember | 1 | Opsi 53 menentukan jenis paket DHCP
1 - DHCPDISCOVER 3 - DHCPREQUEST 2 - DHCPOFFER 5 - DHCPACK 8 - DHCPINFORM |
| Panjang opsi | 1 | Desember | 1 |
| Nilai opsi | 1 | Desember | 1 |
| Nomor opsi | 50 | Desember | 1 | Alamat IP apa yang ingin diterima oleh klien |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 172.16.134.61 | Tali | 4 |
| Nomor opsi | 55 | | 1 | Parameter 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 opsi | 8 | | 1 |
| Nilai opsi | 01: 03: 06: 0c: 0f: 1c: 42: 79 | | 8 |
| Nomor opsi | 82 | Desember | | Opsi 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 opsi | 18 | Desember | |
| Nilai opsi | 01:06 00: 00: 00: 01: 00: 04 02:08 00: 06: c8: menjadi: 19: 93: 11: 48 | Hex | |
| Paket akhir | 255 | Desember | 1 | 255 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 DHCPOFFERPosisi Paket | Nama nilai (umum) | Contoh | Kiriman | Byte | Penjelasan |
1 | Permintaan boot | 1 | Hex | 1 | Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien |
2 | Jenis perangkat keras | 1 | Hex | 1 | Jenis alamat perangkat keras, dalam protokol ini 1 - MAC |
3 | Panjang alamat perangkat keras | 6 | Hex | 1 | Panjang Alamat MAC Perangkat |
4 | Hop | 1 | Hex | 1 | Jumlah rute perantara |
5 | ID transaksi | 23: cf: de: 1d | Hex | 4 | Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan |
7 | Kedua berlalu | 0 | Hex | 4 | Waktu dalam detik sejak awal proses mendapatkan alamat |
9 | Bendera bootp | 0 | Hex | 2 | Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, 0 berarti jenis permintaan Unicast |
11 | Alamat IP klien | 0.0.0.0 | Tali | 4 | Alamat IP klien (jika ada) |
15 | Alamat IP klien Anda | 172.16.134.61 | Tali | 4 | Alamat IP yang diajukan oleh server (jika ada) |
19 | Alamat IP server berikutnya | 0.0.0.0 | Tali | 4 | Alamat IP server (jika diketahui) |
23 | Relay alamat IP agen | 172.16.114.41 | Tali | 4 | Relay alamat IP agen (misalnya, switch) |
27 | Alamat MAC klien | 14: d6: 4d: a7: c9: 55 | Hex | 6 | Alamat MAC dari pengirim paket (klien) |
31 | Padding alamat perangkat keras klien | | Hex | 10 | Tempat yang dipesan. Biasanya nol |
41 | Nama host server | | Tali | 64 | Nama server DHCP. Biasanya tidak ditransmisikan |
105 | Nama file boot | | Tali | 128 | Nama file di server yang digunakan oleh stasiun tanpa disk saat boot |
235 | Cookie ajaib | 63: 82: 53: 63 | Hex | 4 | Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP |
Opsi DHCP. Bisa masuk dalam urutan apa pun |
236 | Nomor opsi | 53 | Desember | 1 | Opsi 53 menentukan jenis paket DHCP 2 - DHCPOFFER |
| Panjang opsi | 1 | Desember | 1 |
| Nilai opsi | 2 | Desember | 1 |
| Nomor opsi | 1 | Desember | 1 | Opsi menawarkan topeng jaringan klien DHCP |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 255.255.224.0 | Tali | 4 |
| Nomor opsi | 3 | Desember | 1 | Opsi menawarkan gateway default klien DHCP |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 172.16.12.1 | Tali | 4 |
| Nomor opsi | 6 | Desember | 1 | Opsi yang menawarkan DHCP ke klien DNS |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 8.8.8.8 | Tali | 4 |
| Nomor opsi | 51 | Desember | 1 | Masa pakai parameter jaringan yang dikeluarkan dalam hitungan detik, setelah itu klien DHCP harus memintanya lagi |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 86400 | Desember | 4 |
| Nomor opsi | 82 | Desember | 1 | Opsi 82, ulangi apa yang datang di DHCPDISCOVER |
| Panjang opsi | 18 | Desember | 1 |
| Nilai opsi | 01:00: 00: 06: 00 01: 00: 00: 00: 01 02: 00: 00: 03: 0f 26: 4d: ec | Desember | 18 |
| Paket akhir | 255 | Desember | 1 | 255 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 DHCPREQUESTPosisi Paket | Nama nilai (umum) | Contoh | Kiriman | Byte | Penjelasan |
1 | Permintaan boot | 1 | Hex | 1 | Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien |
2 | Jenis perangkat keras | 1 | Hex | 1 | Jenis alamat perangkat keras, dalam protokol ini 1 - MAC |
3 | Panjang alamat perangkat keras | 6 | Hex | 1 | Panjang Alamat MAC Perangkat |
4 | Hop | 1 | Hex | 1 | Jumlah rute perantara |
5 | ID transaksi | 23: cf: de: 1d | Hex | 4 | Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan |
7 | Kedua berlalu | 0 | Hex | 4 | Waktu dalam detik sejak dimulainya proses |
9 | Bendera bootp | 8000 | Hex | 2 | Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, "Siaran" |
11 | Alamat IP klien | 0.0.0.0 | Tali | 4 | Alamat IP klien (jika ada) |
15 | Alamat IP klien Anda | 172.16.134.61 | Tali | 4 | Alamat IP yang diajukan oleh server (jika ada) |
19 | Alamat IP server berikutnya | 0.0.0.0 | Tali | 4 | Alamat IP server (jika diketahui) |
23 | Relay alamat IP agen | 172.16.114.41 | Tali | 4 | Relay alamat IP agen (misalnya, switch) |
27 | Alamat MAC klien | 14: d6: 4d: a7: c9: 55 | Hex | 6 | Alamat MAC dari pengirim paket (klien) |
31 | Padding alamat perangkat keras klien | | Hex | 10 | Tempat yang dipesan. Biasanya nol |
41 | Nama host server | | Tali | 64 | Nama server DHCP. Biasanya tidak ditransmisikan |
105 | Nama file boot | | Tali | 128 | Nama file di server yang digunakan oleh stasiun tanpa disk saat boot |
235 | Cookie ajaib | 63: 82: 53: 63 | Hex | 4 | Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP |
Opsi DHCP. Bisa masuk dalam urutan apa pun |
236 | Nomor opsi | 53 | Desember | 3 | Opsi 53 menentukan jenis paket DHCP 3 - DHCPREQUEST |
| Panjang opsi | 1 | Desember | 1 |
| Nilai opsi | 3 | Desember | 1 |
| Nomor opsi | 61 | Desember | 1 | ID Klien: 01 (untuk Ehernet) + alamat MAC klien |
| Panjang opsi | 7 | Desember | 1 |
| Nilai opsi | 01: 2c: ab: 25: ff: 72: a6 | Hex | 7 |
| Nomor opsi | 60 | Desember | | "Pengidentifikasi kelas vendor." Dalam kasus saya, versi klien DHCP dilaporkan. Mungkin perangkat lain mengembalikan sesuatu yang lain. Windows misalnya melaporkan MSFT 5.0 |
| Panjang opsi | 11 | Desember | |
| Nilai opsi | udhcp 0.9.8 | Tali | |
| Nomor opsi | 55 | | 1 | Parameter 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 opsi | 8 | | 1 |
| Nilai opsi | 01: 03: 06: 0c: 0f: 1c: 42: 79 | | 8 |
| Nomor opsi | 82 | Desember | 1 | Opsi 82, ulangi apa yang datang di DHCPDISCOVER |
| Panjang opsi | 18 | Desember | 1 |
| Nilai opsi | 01:00: 00: 06: 00 01: 00: 00: 00: 01 02: 00: 00: 03: 0f 26: 4d: ec | Desember | 18 |
| Paket akhir | 255 | Desember | 1 | 255 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 DHCPACKPosisi Paket | Nama nilai (umum) | Contoh | Kiriman | Byte | Penjelasan |
1 | Permintaan boot | 2 | Hex | 1 | Jenis pesan. 1 - permintaan dari klien ke server, 2 - respons dari server ke klien |
2 | Jenis perangkat keras | 1 | Hex | 1 | Jenis alamat perangkat keras, dalam protokol ini 1 - MAC |
3 | Panjang alamat perangkat keras | 6 | Hex | 1 | Panjang Alamat MAC Perangkat |
4 | Hop | 1 | Hex | 1 | Jumlah rute perantara |
5 | ID transaksi | 23: cf: de: 1d | Hex | 4 | Pengidentifikasi Transaksi Unik. Dihasilkan oleh klien pada awal operasi permintaan |
7 | Kedua berlalu | 0 | Hex | 4 | Waktu dalam detik sejak awal proses mendapatkan alamat |
9 | Bendera bootp | 8000 | Hex | 2 | Beberapa flag yang dapat diatur sebagai indikasi parameter protokol. Dalam hal ini, "Siaran" |
11 | Alamat IP klien | 0.0.0.0 | Tali | 4 | Alamat IP klien (jika ada) |
15 | Alamat IP klien Anda | 172.16.134.61 | Tali | 4 | Alamat IP yang diajukan oleh server (jika ada) |
19 | Alamat IP server berikutnya | 0.0.0.0 | Tali | 4 | Alamat IP server (jika diketahui) |
23 | Relay alamat IP agen | 172.16.114.41 | Tali | 4 | Relay alamat IP agen (misalnya, switch) |
27 | Alamat MAC klien | 14: d6: 4d: a7: c9: 55 | Hex | 6 | Alamat MAC dari pengirim paket (klien) |
31 | Padding alamat perangkat keras klien | | Hex | 10 | Tempat yang dipesan. Biasanya nol |
41 | Nama host server | | Tali | 64 | Nama server DHCP. Biasanya tidak ditransmisikan |
105 | Nama file boot | | Tali | 128 | Nama file di server yang digunakan oleh stasiun tanpa disk saat boot |
235 | Cookie ajaib | 63: 82: 53: 63 | Hex | 4 | Angka "ajaib", dimana termasuk Anda dapat menentukan bahwa paket ini milik protokol DHCP |
Opsi DHCP. Bisa masuk dalam urutan apa pun |
236 | Nomor opsi | 53 | Desember | 3 | Opsi 53 menentukan paket DHCP tipe 5 - DHCPACK |
| Panjang opsi | 1 | Desember | 1 |
| Nilai opsi | 5 | Desember | 1 |
| Nomor opsi | 1 | Desember | 1 | Opsi menawarkan topeng jaringan klien DHCP |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 255.255.224.0 | Tali | 4 |
| Nomor opsi | 3 | Desember | 1 | Opsi menawarkan gateway default klien DHCP |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 172.16.12.1 | Tali | 4 |
| Nomor opsi | 6 | Desember | 1 | Opsi yang menawarkan DHCP ke klien DNS |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 8.8.8.8 | Tali | 4 |
| Nomor opsi | 51 | Desember | 1 | Masa pakai parameter jaringan yang dikeluarkan dalam hitungan detik, setelah itu klien DHCP harus memintanya lagi |
| Panjang opsi | 4 | Desember | 1 |
| Nilai opsi | 86400 | Desember | 4 |
| Nomor opsi | 82 | Desember | 1 | Opsi 82, ulangi apa yang datang di DHCPDISCOVER |
| Panjang opsi | 18 | Desember | 1 |
| Nilai opsi | 01:00: 00: 06: 00 01: 00: 00: 00: 01 02: 00: 00: 03: 0f 26: 4d: ec | Desember | 18 |
| Paket akhir | 255 | Desember | 1 | 255 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
GitHubBagian 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;)