# NetPenetrate **Repository Path**: zli/NetPenetrate ## Basic Information - **Project Name**: NetPenetrate - **Description**: 两台内网的PC通过p2p穿透互联 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-29 - **Last Updated**: 2026-07-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # NetPenetrate NetPenetrate is a small one-to-one P2P IP tunnel prototype. It uses a public UDP pairing server only to match two clients with the same UUID and exchange their observed UDP endpoints. Application traffic is never relayed by the server. Clients create a virtual tunnel interface and exchange raw IPv4 packets over a UDP P2P channel. ## Defaults - Pairing server: UDP `7000` - Virtual network: `10.66.0.0/30` - First client in a UUID room: `10.66.0.1` - Second client in a UUID room: `10.66.0.2` - Payload: IPv4 packets carried over UDP - GUI: tkinter ## Files - `server.py` - UDP pairing server - `client.py` - tkinter client - `netpenetrate/protocol.py` - control and data packet helpers - `netpenetrate/server_core.py` - in-memory UUID room logic - `netpenetrate/client_core.py` - client runtime, punching, and forwarding - `netpenetrate/tun.py` - Linux TUN and Windows Wintun adapter code ## Run the server Linux or Windows: ```bash python server.py --host 0.0.0.0 --port 7000 ``` The server does not need administrator privileges when using port `7000`. ## Run the client on Linux Linux clients need root privileges and `/dev/net/tun`. If `pkexec` is available in a graphical session, the client tries to request elevation automatically. ```bash python3 client.py ``` Enter the public server address, UDP port `7000`, and the same UUID on both clients. The first client receives `10.66.0.1`; the second receives `10.66.0.2`. ## Run the client on Windows Windows clients require Wintun. If the client is not already elevated, it requests Administrator privileges through UAC at startup. 1. Install Wintun or place `wintun.dll` beside `client.py` or in `PATH`. 2. Run: ```powershell python client.py ``` The client creates or opens a Wintun adapter named `NetPenetrate`. ## Saved client settings The client saves settings when you click **Start** and restores them on the next launch. The saved values include: - server host - server UDP port - UUID - persistent client ID - preferred virtual IP role - integrity key - advanced timing parameters The persistent client ID lets the pairing server recognize the same client after a restart, which avoids stale entries filling a UUID room. The preferred virtual IP role is learned after the first successful assignment and sent back to the server on future starts. The server keeps the same virtual IP when that role is available, so restarting clients in a different order is less likely to swap `10.66.0.1` and `10.66.0.2`. Configuration is stored in: - Windows: `%APPDATA%\NetPenetrate\config.json` - Linux: `~/.config/netpenetrate/config.json`, or `$XDG_CONFIG_HOME/netpenetrate/config.json` ## Advanced timing The client exposes several timing parameters in the GUI: - `服务端心跳` - how often the client refreshes its endpoint with the pairing server. Default: `5s`. - `对端保活` - how often a connected client sends UDP punch keepalives to the peer. Default: `2s`. - `断线判定` - how long without inbound peer control packets or tunnel data before the client marks the P2P path stale. Default: `30s`. - `重试打洞` - after the first immediate reconnect request, how often a stale client asks the server again to coordinate a fresh punch. Default: `10s`. - `换UDP端口` - how long a stale client waits before rebuilding the local UDP socket to get a fresh local port and NAT mapping. Default: `60s`. Set it equal to `断线判定` to renew the UDP port immediately when the path is marked stale. Before `Socket Reset` is reached, reconnect requests do not ask clients to refresh their UDP sockets. If this retry-only punch succeeds, the log prints: ```text P2P reconnected before UDP socket reset; retry-only punch worked ``` For unstable NATs, try `对端保活=1`, `断线判定=45`, `换UDP端口=90`. For quieter logs and fewer reconnects, increase `断线判定` and `换UDP端口`. ## Diagnostics and HMAC The client shows a diagnostics panel with: - local UDP socket - peer endpoint - seconds since the last peer packet - HMAC status - tunnel packet and byte counters - peer control packet counters - HMAC failures, dropped packets, UDP errors, socket resets, and reconnects - stale peer control packets ignored during reconnect - current punch interval and mode (`Punch Int`) Punch send/receive events are logged for every packet during debugging. Use `Punch Int` and `Ctrl Tx/Rx` in diagnostics to verify whether the configured peer keepalive interval is taking effect. The `Integrity Key` field is optional. When both clients use the same non-empty key, tunnel data packets are sent as: ```text NPDH1 + nonce + IPv4 packet + HMAC-SHA256 ``` When the key is empty, the client uses the legacy unauthenticated format: ```text NPDT1 + IPv4 packet ``` Peer-to-peer control messages are also HMAC-signed while the key is enabled, including punch and punch_ack packets. Server control messages remain unsigned because the pairing server does not know the integrity key. Instead, clients send the server a short key ID derived from the key; rooms are isolated by both key ID and UUID, so two groups can reuse the same UUID with different integrity keys without being paired together. HMAC detects modified or mismatched peer packets, but it does not encrypt the traffic. ## Usage After both clients show `connected`, client A can access services on client B by connecting to B's virtual IP, for example: ```bash curl http://10.66.0.2:8080/ ``` Likewise, client B can connect to client A: ```bash curl http://10.66.0.1:8080/ ``` ## SOCKS5 exit and LAN sharing The client can optionally expose a SOCKS5 proxy without changing the existing P2P tunnel behavior. To let client A use client B's network: 1. On B, enable **SOCKS5 Proxy -> Exit**. 2. Select the outbound source IP. Use `Auto` to let the OS choose the default route, or select a specific local IPv4 address to force that network interface. 3. Keep the exit port at `1080`, or set another port. 4. Start both clients and wait for the tunnel assignment. 5. On A, configure the application or browser to use SOCKS5: ```text Host: B virtual IP, for example 10.66.0.1 Port: 1080 DNS: remote / proxy DNS ``` To let a LAN device C use B's network through A: 1. On B, enable **Exit** as above. 2. On A, enable **LAN Share**. 3. Select A's LAN IP, for example `192.168.1.20`. 4. Set the LAN Share port, for example `1080`. 5. Make sure A's **Exit Port** field matches B's exit port; this is the upstream SOCKS5 port used by the LAN share forwarder. 6. On C, configure SOCKS5: ```text Host: A LAN IP, for example 192.168.1.20 Port: A LAN Share port, for example 1080 DNS: remote / proxy DNS ``` The GUI shows `Open: host:port` next to each proxy mode after the listener is started. The listeners are off by default and stop together with the client. ## Important limits - This is P2P only. If NAT punching fails, the connection fails. There is no relay fallback. - If an established P2P path goes stale, clients ask the pairing server to coordinate a fresh punch burst. The server still relays only control messages, not tunnel traffic. - When a P2P path goes stale, the reconnect request asks both clients to refresh their local UDP socket, get fresh public endpoints through the pairing server, and punch again. - UDP is used for punching and carrying tunnel packets. - IPv4 packets are forwarded generically. TCP, UDP, and ICMP may work if the operating system, firewall, and service binding allow them. - There is no encryption and no authentication by design. Use it only in trusted and authorized environments. - SOCKS5 proxy mode is unauthenticated. Bind LAN Share only to the intended LAN address and make sure the local firewall policy matches who should be allowed to use it. - Services must listen on `0.0.0.0` or on the assigned tunnel IP to be reachable. Services bound only to `127.0.0.1` or only to another interface IP may not accept connections through the tunnel. - The Windows Wintun path is implemented with `ctypes`, but it still depends on a compatible installed `wintun.dll` and elevated network configuration rights. ## Development checks ```bash python -m unittest discover -s tests python -m py_compile server.py client.py netpenetrate/*.py ```