This project implements a custom networking environment that demonstrates how several core networking protocols work together in one complete system.
The project includes:
- A DNS server with local cache and manual domain registration
- A DHCP server that dynamically assigns IP addresses and network settings
- An application server that serves content over HTTP/TCP and Reliable UDP (RUDP)
- A GUI client built with PyQt6 + Qt WebEngine
The project is designed for learning and demonstration. It shows how a client can receive network configuration, resolve a domain name, connect to an application server, and load application content.
The components can work together like this:
- The DNS server translates domain names such as
my-app.homeinto IP addresses. - The DHCP server can provide the client with an IP address, DNS server address, and lease information.
- The application server serves pages and media over TCP and RUDP.
- The GUI client connects to the server and displays the application.
High-level flow:
GUI Client
|
| HTTP / RUDP
v
Application Server
|
| registers domain in DNS
v
DNS Server
|
| if not in cache
v
External DNS (Google 8.8.8.8)
The DNS server resolves domain names to IP addresses.
- Listens for DNS queries on UDP port
53 - Maintains a local cache named
DNS_RECORDS - If a domain exists in the cache, returns the cached IP address
- If a domain does not exist in the cache, forwards the query to Google DNS (
8.8.8.8) - Stores external results in the cache for a limited time
- Supports manual registration of domain names through an admin UDP port (
5354)
The DNS server code contains these main parts:
encode_dns_name(domain)converts a regular domain string into DNS wire formatdecode_dns_name(data, offset)decodes a domain name from a DNS packetbuild_dns_query(domain)builds a DNS query packet for an external DNS serverget_ip(response)extracts the first IPv4 address from a DNS responsequery_external_dns(domain)asks Google DNS for a domain if it is not cached locallybuild_dns_response(data, ip, domain)creates a DNS response packet to send back to the clienthandle_client(sock, data, addr)processes one incoming DNS requestadmin_listener_thread()listens for manual registration commands
The DNS server supports admin commands over UDP on port 5354.
Supported command:
REGISTER <domain> <ip>
Example:
REGISTER my-app.home 192.168.1.50
This adds a permanent entry to the local DNS cache.
The DNS server supports a --host argument:
python dns.py --host 127.0.0.1or:
python dns.py --host 0.0.0.0127.0.0.1means the DNS server is only accessible from the same computer0.0.0.0means the DNS server listens on all local network interfaces
The DHCP server dynamically assigns IP addresses and network settings to clients.
- Allocates an IP from a configured address pool
- Sends the DNS server address to the client
- Sends lease duration information
- Tracks used and available addresses
It demonstrates how a client can receive automatic network configuration instead of hardcoding IP settings manually.
The application server provides the actual web application content.
- HTTP communication over TCP
- Reliable UDP communication over RUDP
- Controller-based routing
- Automatic DNS registration using the DNS admin port
- Serving of HTML, CSS, JavaScript, and media files
Examples:
HomeControllerWatchControllerMediaControllerJsControllerCssController
When the application server starts:
- It optionally registers its domain in the DNS server
- It starts the TCP server
- It starts the RUDP server
- It waits for client connections
UDP alone does not guarantee delivery, order, or retransmission.
RUDP adds reliability on top of UDP.
- Handshake
- Acknowledgements (ACK)
- Retransmissions on timeout
- Sliding window
- Basic congestion-style control with
window_sizeandssthresh - Segmentation of large responses into smaller packets
This allows the server to send data more reliably while still using UDP.
The client is built with:
PyQt6PyQt6-WebEngine
- Opens the graphical interface
- Connects to the application server
- Displays HTML/CSS/JS content
- Allows interaction with the project like a mini browser
Because the GUI needs to render web content inside the desktop application.
A typical structure for the repository looks like this:
NetworksProject/
│
├── server.py
├── dns.py
├── client_dns.py
├── dhcp_server.py
├── start_dhcp.py
├── requirements.txt
│
├── Client/
│ ├── Client_GUI.py
│ ├── client_TCP.py
│ ├── client_rudp.py
│ ├── Client_DHCP.py
│
├── Controller/
│ ├── HomeController.py
│ ├── WatchController.py
│ ├── MediaController.py
│ ├── JsController.py
│ └── CssController.py
│
├── Model/
├── View/
└── RUDP/
You need:
- Python 3.10+
pipgit(optional, but recommended)
Supported operating systems:
- Windows
- Linux (Ubuntu / Debian / WSL)
Download Python from:
https://www.python.org/downloads/
During installation, enable:
Add Python to PATH
Clone the repository:
git clone https://github.com/yoavnach/NetworksProject.git
cd NetworksProjectOr download the project as ZIP and extract it.
python -m venv venvActivate it.
PowerShell:
venv\Scripts\Activate.ps1CMD:
venv\Scripts\activatepip install -r requirements.txtsudo apt update
sudo apt install -y \
python3 python3-venv python3-pip git \
libnss3 libxkbfile1 libxkbcommon-x11-0 libglu1-mesa libglib2.0-0 \
libasound2t64 libgtk-3-0 libgbm1 libxss1 libatk-bridge2.0-0 \
libxcb-cursor0 libxcb-shape0 libxcb-xfixes0 libxcb-icccm4 \
libxcb-image0 libxcb-keysyms1 libxcb-render-util0 \
libxcb-xinerama0 libxcb-xinput0These are mainly required for Qt WebEngine.
python3 -m venv --copies venvActivate it:
source venv/bin/activatepip install -r requirements.txtIf your DHCP code uses raw sockets or privileged ports, you may need:
sudo setcap cap_net_raw,cap_net_bind_service+ep ./venv/bin/python3Verify:
getcap ./venv/bin/python3The project can run in two main modes.
In this mode, all services listen only on the local machine.
Use:
127.0.0.1
- Development
- Debugging
- Running everything on one computer
Very easy to test.
Other devices on the network cannot connect.
In this mode, services listen on all available network interfaces.
Use:
0.0.0.0
- Testing across multiple devices
- LAN demonstration
- Running client and server on different machines
Other computers on the same network can connect using the host machine IP address.
You may need firewall changes and correct network configuration.
This is the easiest way to run the project.
Windows or Linux:
python dns.py --host 127.0.0.1Expected output:
DNS Server is running on 127.0.0.1:53...
Waiting for requests...
python DHCP/dhcp_main.py --dns 127.0.0.1If your DHCP server script is named differently, use that file instead.
Example output:
Server is running on port 6767. Press Ctrl+C to stop.
python server.py --host 127.0.0.1 --tcp_port 80 --udp_port 8080 --dns 127.0.0.1 --domain my-app.homeWhat this does:
- Starts the TCP server on port
80 - Starts the RUDP server on port
8080 - Registers
my-app.homein the DNS server at127.0.0.1
Expected output includes something like:
[server] listening on 127.0.0.1:80
[server] RUDP listening on 127.0.0.1:8080
Windows:
python -m Client.Client_GUILinux:
QT_QPA_PLATFORM=xcb QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" python3 -m Client.Client_GUIThis opens the graphical client.
Use this mode when the server should accept connections from other machines on the same network.
python dns.py --host 0.0.0.0This makes the DNS server listen on all local network interfaces.
python DHCP/dhcp_main.py --dns <DNS_SERVER_IP>Replace <DNS_SERVER_IP> with the real IP of the machine running dns.py.
The DHCP server typically detects the local subnet and prepares a dynamic range.
python server.py --host 0.0.0.0 --tcp_port 80 --udp_port 8080 --dns <DNS_SERVER_IP> --domain my-app.homeReplace <DNS_SERVER_IP> with the real IP of the machine running dns.py.
Example:
python server.py --host 0.0.0.0 --tcp_port 80 --udp_port 8080 --dns 192.168.1.20 --domain my-app.homeWhat happens here:
- The TCP server listens on all interfaces
- The RUDP server listens on all interfaces
- The application server detects its real local IP and registers that IP in the DNS server
On the client machine:
Windows:
python -m Client.Client_GUILinux:
QT_QPA_PLATFORM=xcb QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" python3 -m Client.Client_GUIMake sure the client points to the correct DNS / server settings if they are configurable in your project.
Local only:
python dns.py --host 127.0.0.1LAN:
python dns.py --host 0.0.0.0127.0.0.1→ same computer only0.0.0.0→ all interfaces
Port 53 is a privileged / standard DNS port.
- On Windows, you may need to run as Administrator
- On Linux, you may need
sudoor extra privileges
Example on Linux:
sudo python3 dns.py --host 0.0.0.0If port 53 is already occupied by another DNS service, stop that service or change the port in code.
python DHCP/dhcp_main.pyor on Linux:
python3 DHCP/dhcp_main.pyIf your OS blocks raw sockets or low ports, run with suitable privileges.
Localhost:
python server.py --host 127.0.0.1 --tcp_port 80 --udp_port 8080 --dns 127.0.0.1 --domain my-app.homeLAN:
python server.py --host 0.0.0.0 --tcp_port 80 --udp_port 8080 --dns 192.168.1.20 --domain my-app.home--host→ which interface to bind to--tcp_port→ TCP / HTTP port--udp_port→ RUDP port--dns→ IP address of the DNS server admin/register target--domain→ domain name to register for this server
Windows:
python -m Client.Client_GUILinux:
QT_QPA_PLATFORM=xcb QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" python3 -m Client.Client_GUITo run the full environment, use this order:
- Start the DNS server
- Start the DHCP server (if used)
- Start the application server
- Start the GUI client
This ensures that DNS and network configuration are already available when the application server and client start.
Use:
- DNS →
127.0.0.1 - Application server →
127.0.0.1 - Client → same computer
Commands:
python dns.py --host 127.0.0.1
python DHCP/dhcp_main.py --dns 127.0.0.1
python server.py --host 127.0.0.1 --tcp_port 80 --udp_port 8080 --dns 127.0.0.1 --domain my-app.home
python -m Client.Client_GUIOn server machine:
python dns.py --host 0.0.0.0
python DHCP/dhcp_main.py --dns 192.168.1.20
python server.py --host 0.0.0.0 --tcp_port 80 --udp_port 8080 --dns 192.168.1.20 --domain my-app.homeOn client machine:
python -m Client.Client_GUIReplace 192.168.1.20 with the actual server machine IP.
netstat -ano | findstr :53
netstat -ano | findstr :80sudo lsof -i :53
sudo lsof -i :80If a port is already in use, stop the existing service or change the port in your code.
Port 53 may require elevated permissions.
Run terminal as Administrator.
Use sudo if needed:
sudo python3 dns.py --host 0.0.0.0If your DHCP implementation uses raw sockets or restricted networking features, run:
sudo setcap cap_net_raw,cap_net_bind_service+ep ./venv/bin/python3Install the required Qt / XCB dependencies from the installation section.
For debugging missing libraries:
ldd ./venv/lib/python3.12/site-packages/PyQt6/Qt6/plugins/platforms/libqxcb.so | grep "not found"Run the GUI with:
QT_QPA_PLATFORM=xcb QTWEBENGINE_CHROMIUM_FLAGS="--disable-gpu" python3 -m Client.Client_GUIIf a domain is not in the local cache, the DNS server forwards the request to 8.8.8.8.
If that fails:
- check internet connection
- check firewall rules
- verify that outbound UDP is allowed
This project demonstrates how several networking components can work together in a realistic environment.
It includes:
- DNS resolution
- DHCP configuration
- TCP-based HTTP serving
- Reliable UDP transport
- A GUI application client
The system can run either:
- locally on one machine using
127.0.0.1 - across a local network using
0.0.0.0
This makes it useful both for development and for network demonstrations.