|
|
|
|
|
const net = require('net'); |
|
|
const { parseDestinationIP, parseDestinationPort, isValidIPv4Packet } = require('../utils/ipUtils'); |
|
|
const { parseTCPHeader, constructTCPPacket, isSYNPacket, isFINPacket, isRSTPacket } = require('../utils/tcpUtils'); |
|
|
const { decryptPacket, encryptPacket } = require('./authService'); |
|
|
const { createProtectedTCPConnection, createProtectedUDPSocket, sendICMPPacketViaSystem, isLocalAddress } = require('./networkService'); |
|
|
|
|
|
|
|
|
const clientIdentifiers = new WeakMap(); |
|
|
|
|
|
|
|
|
const clientSockets = new WeakMap(); |
|
|
|
|
|
|
|
|
const clientConnections = new WeakMap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getProtocolName(protocol) { |
|
|
switch (protocol) { |
|
|
case 1: return 'ICMP'; |
|
|
case 6: return 'TCP'; |
|
|
case 17: return 'UDP'; |
|
|
default: return 'Unknown'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleICMPPacket(packet, destinationIP, clientId, ws) { |
|
|
console.log(`处理ICMP数据包,目标IP: ${destinationIP}`); |
|
|
try { |
|
|
await sendICMPPacketViaSystem(destinationIP, packet); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('处理ICMP数据包时出错:', error.message); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleControlMessage(message, ws) { |
|
|
const { type, id } = message; |
|
|
|
|
|
if (!clientSockets.has(ws)) { |
|
|
clientSockets.set(ws, new Map()); |
|
|
} |
|
|
const sockets = clientSockets.get(ws); |
|
|
|
|
|
if (type === 'connect') { |
|
|
const { host, port } = message; |
|
|
console.log(`[Server] Connect request: ${id} -> ${host}:${port}`); |
|
|
|
|
|
if (sockets.has(id)) { |
|
|
console.warn(`[Server] Socket ${id} already exists`); |
|
|
return; |
|
|
} |
|
|
|
|
|
try { |
|
|
const socket = new net.Socket(); |
|
|
socket.setNoDelay(true); |
|
|
|
|
|
socket.connect(port, host, () => { |
|
|
console.log(`[Server] Connected: ${id} -> ${host}:${port}`); |
|
|
if (ws.readyState === 1) { |
|
|
ws.send(JSON.stringify({ type: 'connected', id })); |
|
|
} |
|
|
}); |
|
|
|
|
|
socket.on('data', (data) => { |
|
|
if (ws.readyState === 1) { |
|
|
ws.send(JSON.stringify({ |
|
|
type: 'data', |
|
|
id, |
|
|
payload: data.toString('base64') |
|
|
})); |
|
|
} |
|
|
}); |
|
|
|
|
|
socket.on('close', () => { |
|
|
console.log(`[Server] Socket Closed: ${id}`); |
|
|
if (sockets.has(id)) { |
|
|
sockets.delete(id); |
|
|
if (ws.readyState === 1) { |
|
|
try { |
|
|
ws.send(JSON.stringify({ type: 'close', id })); |
|
|
} catch (e) { } |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
socket.on('error', (err) => { |
|
|
console.error(`[Server] Socket Error ${id}:`, err.message); |
|
|
if (sockets.has(id)) { |
|
|
sockets.delete(id); |
|
|
if (ws.readyState === 1) { |
|
|
try { |
|
|
ws.send(JSON.stringify({ type: 'close', id })); |
|
|
} catch (e) { } |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
sockets.set(id, socket); |
|
|
|
|
|
} catch (e) { |
|
|
console.error(`[Server] Connection Failed ${id}:`, e); |
|
|
if (ws.readyState === 1) { |
|
|
ws.send(JSON.stringify({ type: 'close', id })); |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (type === 'data') { |
|
|
const socket = sockets.get(id); |
|
|
if (socket && !socket.destroyed) { |
|
|
const payload = Buffer.from(message.payload, 'base64'); |
|
|
socket.write(payload); |
|
|
} else { |
|
|
|
|
|
if (ws.readyState === 1) { |
|
|
ws.send(JSON.stringify({ type: 'close', id })); |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (type === 'close') { |
|
|
console.log(`[Server] Close request: ${id}`); |
|
|
const socket = sockets.get(id); |
|
|
if (socket) { |
|
|
socket.destroy(); |
|
|
sockets.delete(id); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleTCPPacket(packet, destinationIP, clientId, ws) { |
|
|
console.warn('[Server] Legacy handleTCPPacket called. This should not happen with new Split-TCP.'); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleUDPPacket(packet, destinationIP, clientId, ws) { |
|
|
|
|
|
console.log(`处理UDP数据包,目标IP: ${destinationIP}`); |
|
|
|
|
|
|
|
|
const headerLength = (packet[0] & 0x0F) * 4; |
|
|
if (packet.length < headerLength + 4) return; |
|
|
const destinationPort = (packet[headerLength + 2] << 8) + packet[headerLength + 3]; |
|
|
|
|
|
const client = createProtectedUDPSocket(); |
|
|
client.on('message', (msg, rinfo) => { |
|
|
try { |
|
|
const encryptedResponse = encryptPacket(msg, clientId); |
|
|
if (ws.readyState === 1) { |
|
|
ws.send(encryptedResponse); |
|
|
} |
|
|
} catch (error) { } |
|
|
}); |
|
|
|
|
|
client.send(packet, 0, packet.length, destinationPort, destinationIP, (err) => { |
|
|
|
|
|
}); |
|
|
setTimeout(() => client.close(), 5000); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function setClientIdentifier(ws, clientId) { |
|
|
clientIdentifiers.set(ws, clientId); |
|
|
} |
|
|
|
|
|
function getClientIdentifier(ws) { |
|
|
return clientIdentifiers.get(ws); |
|
|
} |
|
|
|
|
|
function cleanupClientConnections(ws) { |
|
|
clientIdentifiers.delete(ws); |
|
|
if (clientSockets.has(ws)) { |
|
|
const sockets = clientSockets.get(ws); |
|
|
for (const [id, socket] of sockets.entries()) { |
|
|
if (!socket.destroyed) socket.destroy(); |
|
|
} |
|
|
clientSockets.delete(ws); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function forwardPacket(packet, ws) { |
|
|
try { |
|
|
if (!isValidIPv4Packet(packet)) return; |
|
|
const destinationIP = parseDestinationIP(packet); |
|
|
const protocol = packet[9]; |
|
|
const clientId = getClientIdentifier(ws); |
|
|
|
|
|
if (!clientId) return; |
|
|
|
|
|
switch (protocol) { |
|
|
case 1: await handleICMPPacket(packet, destinationIP, clientId, ws); break; |
|
|
case 6: await handleTCPPacket(packet, destinationIP, clientId, ws); break; |
|
|
case 17: await handleUDPPacket(packet, destinationIP, clientId, ws); break; |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('转发数据包时出错:', error.message); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleIncomingPacket(data, ws) { |
|
|
|
|
|
try { |
|
|
const clientId = getClientIdentifier(ws); |
|
|
if (clientId) { |
|
|
const decryptedPacket = decryptPacket(data, clientId); |
|
|
await forwardPacket(decryptedPacket, ws); |
|
|
} |
|
|
} catch (e) { |
|
|
console.error(e); |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
forwardPacket, |
|
|
handleIncomingPacket, |
|
|
handleControlMessage, |
|
|
setClientIdentifier, |
|
|
getClientIdentifier, |
|
|
cleanupClientConnections, |
|
|
handleICMPPacket, |
|
|
handleTCPPacket, |
|
|
handleUDPPacket, |
|
|
getProtocolName |
|
|
}; |