A high-performance TCP port forwarder for Windows with optional IP whitelisting and verbose logging capabilities.
- ✅ Forward TCP traffic from a local port to any remote host:port
- ✅ Optional IP whitelisting for enhanced security
- ✅ Port 445 / SMB takeover mode (disables SMB and frees port 445 for relaying)
- ✅ Supports up to 100 concurrent connections
- ✅ Bidirectional data forwarding with real-time statistics
- ✅ Verbose mode for debugging rejected connections
- ✅ Aggressive TCP keepalive settings for dead connection detection
- ✅ Low-latency forwarding (Nagle's algorithm disabled)
- ✅ Graceful shutdown handling (Ctrl+C)
- ✅ Thread-safe connection management
- Windows operating system
- Visual Studio (for compilation) or MinGW-w64
- Winsock2 library (included with Windows SDK)
cl PortForwarder.c /Fe:PortForwarder.exe ws2_32.libgcc PortForwarder.c -o PortForwarder.exe -lws2_32PortForwarder.exe <local_port> <remote_host> <remote_port> [allowed_ip] [-v]
<local_port>- Local port to listen on (1-65535)<remote_host>- Remote hostname or IP address to forward traffic to<remote_port>- Remote port to forward traffic to (1-65535)[allowed_ip]- Optional - Only accept connections from this IP address[-v]- Optional - Enable verbose mode (show rejected connections)
Forward local port 8080 to remote server 192.168.1.100 port 80:
PortForwarder.exe 8080 192.168.1.100 80Only accept connections from 192.168.1.50:
PortForwarder.exe 8080 192.168.1.100 80 192.168.1.50Show rejected connection attempts:
PortForwarder.exe 8080 192.168.1.100 80 192.168.1.50 -vPortForwarder.exe 3306 database.example.com 3306PortForwarder.exe 2222 10.0.0.50 22 192.168.1.100Listen on SMB port 445 and forward to a remote SMB endpoint. When 445 is the
local port the tool first frees the port from Windows' built-in SMB server:
PortForwarder.exe 445 10.0.0.50 445 192.168.1.100When the local port is 445, before binding the tool will automatically:
- Verify privileges — confirm the process is running elevated (administrator). If not, it aborts with a clear message.
- Show the current holder — identify the PID/process currently bound to
port 445 (normally
System, PID 4, via thesrvnetkernel driver). - Disable SMB and free the port — stop
LanmanServerand thesrv2/srvnetdrivers (recursively stopping any dependent services), printing each step for visibility. - Verify and bind — confirm port 445 is free, then bind and forward as usual.
Example output:
[445] === Port 445 / SMB takeover ===
[445] Privilege check: running elevated (administrator). OK
[445] Port 445 currently held by PID 4 (System (kernel / srvnet))
[445] Disabling SMB server and releasing port 445...
[445] Stopping 'LanmanServer'...
[445] service 'LanmanServer' stopped
[445] Stopping 'srv2'...
[445] service 'srv2' stopped
[445] Stopping 'srvnet'...
[445] service 'srvnet' stopped
[445] Port 445 is now free. Proceeding to bind.
[445] (Restore SMB later with: net start LanmanServer)
⚠️ Stopping these services disables file/printer sharing on the host for the duration of the engagement. Restore it afterwards withnet start LanmanServer(the drivers restart on demand or at next boot). Use only on systems you are authorized to test.
- Access services running in containers or VMs
- Forward ports from WSL2 to Windows host
- Test webhook endpoints locally
- Bridge different network segments
- Bypass firewall restrictions (authorized use only)
- Access internal services from DMZ
- Secure database connections with IP whitelisting
- Tunnel database traffic through jump hosts
- Expose local databases for remote development
- Monitor and analyze TCP traffic patterns
- Test IP-based access controls
- Audit connection attempts with verbose mode
The forwarder provides detailed logging:
[INFO] Configuration:
Local port: 8080
Remote host: 192.168.1.100
Remote port: 80
Allowed IP: 192.168.1.50 (filtered mode)
Verbose: OFF
[INFO] Listening on port 8080...
[INFO] Press Ctrl+C to stop
[INFO] New connection from 192.168.1.50:54321 ACCEPTED
[INFO] Connected to remote 192.168.1.100:80
[INFO] Connection established, forwarding traffic...
[INFO] Closing connection (Sent: 1024 bytes, Received: 2048 bytes, Total: 3072 bytes)
When -v flag is enabled, rejected connections are also logged:
[INFO] Connection from 192.168.1.99:54322 REJECTED (IP not allowed)
- Buffer Size: 8KB buffers for efficient data transfer
- TCP_NODELAY: Disabled Nagle's algorithm for lower latency
- Keepalive: Aggressive settings (10s initial, 1s interval) to detect dead connections
- Thread Pool: Up to 100 concurrent connections with dedicated forwarding threads
- Non-blocking Accept: Timeout-based select() for responsive shutdown
Each connection spawns a dedicated forwarding thread that:
- Establishes connection to remote host
- Sets socket options (timeouts, keepalive, TCP_NODELAY)
- Uses select() for bidirectional forwarding
- Tracks bytes transferred in each direction
- Gracefully closes both sockets on termination
The forwarder handles common network errors gracefully:
WSAECONNRESET- Connection reset by peerWSAECONNABORTED- Connection abortedWSAENETRESET- Network caused disconnectWSAETIMEDOUT- Connection timed out
- Critical sections protect the connection array
- Volatile
runningflag for clean shutdown - Thread synchronization during cleanup
- IP Whitelisting: Use the
[allowed_ip]parameter in production to restrict access - No Encryption: This forwarder does not encrypt traffic. Use with SSH tunnels or VPNs for sensitive data
- Authentication: No built-in authentication. Ensure the remote service has proper security
- Firewall: Configure Windows Firewall to restrict access to the listening port
- Logging: Disable verbose mode in production to avoid log file bloat
- Resource Limits: 100 connection limit prevents resource exhaustion
[ERROR] bind() failed: 10048
Solution: Another application is using the port. Choose a different local port or stop the conflicting service.
[ERROR] connect() to remote failed: 10061
Solution: Verify the remote host is reachable and the service is running on the specified port.
[ERROR] bind() failed: 10013
Solution: Ports below 1024 may require administrator privileges. Run as Administrator or use a higher port number.
[INFO] Connection from X.X.X.X:XXXXX REJECTED (IP not allowed)
Solution: Enable verbose mode (-v) to see rejected IPs, or remove IP filtering.
Press Ctrl+C to gracefully stop the forwarder. It will:
- Stop accepting new connections
- Wait for active connections to complete (up to 5 seconds)
- Close all sockets
- Clean up resources
- Display cleanup confirmation
- Windows Only: Uses Winsock2 API (not portable to Linux/macOS)
- IPv4 Only: Currently supports IPv4 addresses only
- Single IP Filter: Only one allowed IP address can be specified
- No Load Balancing: Traffic is forwarded to a single remote endpoint
- No Traffic Inspection: Raw TCP forwarding without content analysis
- No Bandwidth Limiting: No built-in throttling or QoS
Potential features for future versions:
- IPv6 support
- Multiple IP whitelist/blacklist
- SSL/TLS encryption wrapper
- Traffic statistics dashboard
- Configuration file support
- Bandwidth limiting
- Round-robin load balancing
- Connection rate limiting
- Cross-platform support (Linux/macOS)
This software is provided as-is for educational and legitimate network administration purposes. Use responsibly and in compliance with applicable laws and regulations.
Contributions are welcome! Please ensure:
- Code follows the existing style
- Changes are well-tested on Windows
- Comments explain complex logic
- README is updated for new features
For issues, questions, or feature requests, please open an issue on the project repository.
You can also support my work on Patreon