协议无关流量路由:基于目标主机名的多域名转发与识别方案咨询
Hey there! Great question—let’s break down exactly how to achieve what you’re looking for, covering both DNS routing and Node.js server-side hostname detection before protocol identification.
1. Custom DNS Setup to Route Traffic to Your Server
First, you need to make sure requests to target1.com, target2.com, etc., resolve to your server.com IP. Here are two reliable ways to do this:
Local Hosts File (Quick Testing)
For testing on your own machine, edit your system’shostsfile (e.g.,/etc/hostson Linux/macOS,C:\Windows\System32\drivers\etc\hostson Windows) and add lines like:[your-server-ip] target1.com [your-server-ip] target2.comThis forces your local system to resolve those domains directly to your server.
Self-Hosted DNS Server (Production-Grade)
For broader use (e.g., for your network or public users), set up a DNS server likednsmasqor BIND. Configure it to return your server’s IP fortarget1.comandtarget2.comwhile leaving other domains to resolve normally. This way, any device using your DNS will send traffic for those targets to your server.
2. Identifying Target Hostnames in Node.js Before Protocol Detection
The key here is leveraging Server Name Indication (SNI)—a TLS extension that sends the target hostname during the initial TLS handshake, before any application-layer protocol (like HTTP) is detected. Since you mentioned handling arbitrary protocols, SNI is your best bet for TLS traffic (which covers most modern services).
Example: Node.js TLS Server with SNI Detection
Here’s how to capture the hostname early using Node.js’s tls module:
const tls = require('tls'); const net = require('net'); const fs = require('fs'); // SSL certificate (use a valid one or self-signed for testing) const options = { key: fs.readFileSync('server-key.pem'), cert: fs.readFileSync('server-cert.pem'), // SNI callback runs BEFORE protocol negotiation SNICallback: (servername, cb) => { console.log(`Received request for hostname: ${servername}`); // You can use this servername to decide routing logic upfront cb(null, tls.createSecureContext(options)); } }; // Create TLS server that handles incoming connections const server = tls.createServer(options, (socket) => { const hostname = socket.servername; // Access hostname here too // Route traffic based on hostname let target; switch(hostname) { case 'target1.com': target = '192.168.1.100:8080'; // Internal IP/port break; case 'target2.com': target = 'internal-service.local:3000'; break; default: socket.end('Unknown hostname'); return; } // Forward traffic to internal target const proxySocket = net.connect(target, () => { socket.pipe(proxySocket).pipe(socket); }); proxySocket.on('error', (err) => { console.error(`Proxy error: ${err}`); socket.end('Internal service unavailable'); }); }); server.listen(443, () => { console.log('TLS server listening on port 443'); });
Handling Non-TLS (Raw TCP) Traffic
For non-TLS traffic, there’s no standard way to get the hostname before protocol detection—since raw TCP doesn’t include hostname metadata. If you absolutely need to handle this, your best bet is to:
- Assume the traffic uses an application protocol that sends a Host header (like HTTP), and parse that early (but this requires detecting the protocol first, which you wanted to avoid).
- Use port-based routing as a fallback, but you mentioned avoiding port dependencies, so this is a last resort.
3. Routing Traffic to Internal Addresses
Once you’ve captured the hostname via SNI, you can use Node.js’s net module to create a proxy connection to your internal IP/hostname, as shown in the code example above. This acts as a reverse proxy, forwarding the incoming traffic to the correct internal service while maintaining the original connection.
Bonus: Capture All Incoming Traffic
If you want your Node.js server to handle traffic on any port (not just 443), you can use iptables (Linux) or pf (macOS) to forward all incoming traffic to a single port your server listens on. For example, on Linux:
iptables -t nat -A PREROUTING -p tcp --dport 1:65535 -j REDIRECT --to-port 443
This redirects all TCP traffic to port 443, where your Node.js server can process it.
内容的提问来源于stack exchange,提问作者Thomas McFarlane

