commit 992835bdc1919b983965d6c21841d84f7e0c572f Author: Marcel Peterkau Date: Thu Sep 11 09:58:51 2025 +0200 Initial commit: Simple DHCP Server mit Tkinter-GUI und Start-Skripten diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5dd5590 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +venv/ +__pycache__/ +*.pyc +*.pyo +*.pyd +.env +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3929d1 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# Python DHCP Tkinter Application + +This project is a simple DHCP server application built using Python and Tkinter. It provides a graphical user interface (GUI) for managing DHCP leases and clients. + +## Project Structure + +``` +python-dhcp-tk-app +├── src +│ ├── main.py # Entry point of the application +│ ├── dhcp_server.py # Contains the DHCPServer class +│ ├── gui.py # Defines the GUI layout +│ ├── utils.py # Utility functions for networking tasks +│ └── types +│ └── __init__.py # Custom types and data structures +├── requirements.txt # Project dependencies +└── README.md # Project documentation +``` + +## Requirements + +To run this project, you need to install the following dependencies: + +- tkinter +- (any additional libraries required for DHCP functionality) + +You can install the required packages using pip: + +``` +pip install -r requirements.txt +``` + +## Usage + +1. Run the application by executing the `main.py` file: + + ``` + python src/main.py + ``` + +2. The GUI will display a dropdown menu with available network interfaces. Select the desired interface. + +3. Enter the desired IP address and subnet mask in the provided fields. + +4. Use the "Start" button to start the DHCP server. The application will begin managing DHCP leases and display active clients in the list. + +5. To stop the DHCP server, click the "Stop" button. + +## Contributing + +Feel free to contribute to this project by submitting issues or pull requests. Your feedback and contributions are welcome! + +## License + +This project is licensed under the MIT License. See the LICENSE file for more details. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e976618 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +tkinter +scapy \ No newline at end of file diff --git a/src/dhcp_server.py b/src/dhcp_server.py new file mode 100644 index 0000000..03ff2d4 --- /dev/null +++ b/src/dhcp_server.py @@ -0,0 +1,35 @@ +class DHCPServer: + def __init__(self): + self.leases = {} + self.active_clients = [] + + def start(self, interface, ip_range, subnet): + # Start the DHCP server on the specified interface + pass + + def stop(self): + # Stop the DHCP server + pass + + def handle_request(self, request): + # Handle incoming DHCP requests + pass + + def add_lease(self, client_ip, client_mac): + # Add a new lease for a client + self.leases[client_mac] = client_ip + self.active_clients.append(client_mac) + + def remove_lease(self, client_mac): + # Remove a lease for a client + if client_mac in self.leases: + del self.leases[client_mac] + self.active_clients.remove(client_mac) + + def get_active_clients(self): + # Return a list of active clients + return self.active_clients + + def get_leases(self): + # Return the current leases + return self.leases \ No newline at end of file diff --git a/src/gui.py b/src/gui.py new file mode 100644 index 0000000..2e3b82f --- /dev/null +++ b/src/gui.py @@ -0,0 +1,68 @@ +from tkinter import Tk, Label, Button, Entry, StringVar, OptionMenu, Listbox, END +import psutil +from dhcp_server import DHCPServer + +class DHCPApp: + def __init__(self, master): + self.master = master + master.title("DHCP Server") + + self.interface_label = Label(master, text="Select Network Interface:") + self.interface_label.pack() + + self.interface_var = StringVar(master) + self.interfaces = self.get_network_interfaces() + self.interface_menu = OptionMenu(master, self.interface_var, *self.interfaces) + self.interface_menu.pack() + + self.ip_label = Label(master, text="IP Address:") + self.ip_label.pack() + self.ip_entry = Entry(master) + self.ip_entry.pack() + + self.subnet_label = Label(master, text="Subnet Mask:") + self.subnet_label.pack() + self.subnet_entry = Entry(master) + self.subnet_entry.pack() + + self.start_button = Button(master, text="Start DHCP Server", command=self.start_dhcp_server) + self.start_button.pack() + + self.stop_button = Button(master, text="Stop DHCP Server", command=self.stop_dhcp_server) + self.stop_button.pack() + + self.clients_label = Label(master, text="Active Clients:") + self.clients_label.pack() + + self.clients_listbox = Listbox(master) + self.clients_listbox.pack() + + self.dhcp_server = None + + def get_network_interfaces(self): + return psutil.net_if_addrs().keys() + + def start_dhcp_server(self): + ip = self.ip_entry.get() + subnet = self.subnet_entry.get() + interface = self.interface_var.get() + self.dhcp_server = DHCPServer(interface, ip, subnet) + self.dhcp_server.start() + self.update_clients_list() + + def stop_dhcp_server(self): + if self.dhcp_server: + self.dhcp_server.stop() + self.dhcp_server = None + self.clients_listbox.delete(0, END) + + def update_clients_list(self): + if self.dhcp_server: + self.clients_listbox.delete(0, END) + for client in self.dhcp_server.get_active_clients(): + self.clients_listbox.insert(END, client) + +if __name__ == "__main__": + root = Tk() + app = DHCPApp(root) + root.mainloop() \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..93f3edc --- /dev/null +++ b/src/main.py @@ -0,0 +1,69 @@ +import tkinter as tk +from tkinter import ttk +from dhcp_server import DHCPServer +import utils + +class DHCPApp: + def __init__(self, root): + self.root = root + self.root.title("Simple DHCP Server") + + self.server = None + + self.interface_label = tk.Label(root, text="Select Network Interface:") + self.interface_label.grid(row=0, column=0, padx=10, pady=10) + + self.interface_var = tk.StringVar() + self.interface_dropdown = ttk.Combobox(root, textvariable=self.interface_var) + self.interface_dropdown['values'] = utils.get_network_interfaces() + self.interface_dropdown.grid(row=0, column=1, padx=10, pady=10) + + self.ip_label = tk.Label(root, text="DHCP IP Range Start:") + self.ip_label.grid(row=1, column=0, padx=10, pady=10) + + self.ip_entry = tk.Entry(root) + self.ip_entry.grid(row=1, column=1, padx=10, pady=10) + + self.subnet_label = tk.Label(root, text="Subnet Mask:") + self.subnet_label.grid(row=2, column=0, padx=10, pady=10) + + self.subnet_entry = tk.Entry(root) + self.subnet_entry.grid(row=2, column=1, padx=10, pady=10) + + self.start_button = tk.Button(root, text="Start DHCP Server", command=self.start_server) + self.start_button.grid(row=3, column=0, padx=10, pady=10) + + self.stop_button = tk.Button(root, text="Stop DHCP Server", command=self.stop_server) + self.stop_button.grid(row=3, column=1, padx=10, pady=10) + + self.clients_label = tk.Label(root, text="Active Clients:") + self.clients_label.grid(row=4, column=0, padx=10, pady=10) + + self.clients_listbox = tk.Listbox(root, width=50) + self.clients_listbox.grid(row=5, column=0, columnspan=2, padx=10, pady=10) + + def start_server(self): + if not self.server: + ip_range = self.ip_entry.get() + subnet = self.subnet_entry.get() + interface = self.interface_var.get() + self.server = DHCPServer(interface, ip_range, subnet) + self.server.start() + self.update_clients() + + def stop_server(self): + if self.server: + self.server.stop() + self.server = None + self.clients_listbox.delete(0, tk.END) + + def update_clients(self): + if self.server: + self.clients_listbox.delete(0, tk.END) + for client in self.server.get_active_clients(): + self.clients_listbox.insert(tk.END, client) + +if __name__ == "__main__": + root = tk.Tk() + app = DHCPApp(root) + root.mainloop() \ No newline at end of file diff --git a/src/types/__init__.py b/src/types/__init__.py new file mode 100644 index 0000000..d5e1b4e --- /dev/null +++ b/src/types/__init__.py @@ -0,0 +1,8 @@ +class ClientLease: + def __init__(self, ip_address, mac_address, lease_time): + self.ip_address = ip_address + self.mac_address = mac_address + self.lease_time = lease_time + + def __repr__(self): + return f"ClientLease(ip_address={self.ip_address}, mac_address={self.mac_address}, lease_time={self.lease_time})" \ No newline at end of file diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..86363ea --- /dev/null +++ b/src/utils.py @@ -0,0 +1,29 @@ +def get_available_interfaces(): + import netifaces + return netifaces.interfaces() + +def format_ip_address(ip): + try: + parts = ip.split('.') + if len(parts) != 4: + raise ValueError("Invalid IP address format") + return '.'.join(str(int(part)) for part in parts) + except ValueError as e: + raise ValueError(f"Error formatting IP address: {e}") + +def validate_subnet_mask(mask): + valid_masks = [ + '255.255.255.255', '255.255.255.254', '255.255.255.252', + '255.255.255.248', '255.255.255.240', '255.255.255.224', + '255.255.255.192', '255.255.255.128', '255.255.255.0', + '255.255.254.0', '255.255.252.0', '255.255.248.0', + '255.255.240.0', '255.255.224.0', '255.255.192.0', + '255.255.128.0', '255.255.0.0', '255.254.0.0', + '255.252.0.0', '255.248.0.0', '255.240.0.0', + '255.224.0.0', '255.192.0.0', '255.128.0.0', + '255.0.0.0', '254.0.0.0', '252.0.0.0', + '248.0.0.0', '240.0.0.0', '224.0.0.0', + '192.0.0.0', '128.0.0.0', '0.0.0.0' + ] + if mask not in valid_masks: + raise ValueError("Invalid subnet mask") \ No newline at end of file diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..af25af8 --- /dev/null +++ b/start.bat @@ -0,0 +1,11 @@ +@echo off +if not exist venv ( + python -m venv venv +) +call venv\Scripts\activate +pip install --upgrade pip +pip install -r requirements.txt +tasklist /FI "IMAGENAME eq python.exe" | find /I "main.py" >nul +if errorlevel 1 ( + python src\main.py +) \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..a7a7173 --- /dev/null +++ b/start.sh @@ -0,0 +1,8 @@ +#!/bin/bash +if [ ! -d "venv" ]; then + python3 -m venv venv +fi +source venv/bin/activate +pip install --upgrade pip +pip install -r requirements.txt +pgrep -f "python src/main.py" > /dev/null || python src/main.py \ No newline at end of file