99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import * as plugins from '../../plugins.js';
|
|
|
|
/**
|
|
* WrappedSocket wraps a regular net.Socket to provide transparent access
|
|
* to the real client IP and port when behind a proxy using PROXY protocol.
|
|
*
|
|
* This is the FOUNDATION for all PROXY protocol support and must be implemented
|
|
* before any protocol parsing can occur.
|
|
*
|
|
* This implementation uses a Proxy to delegate all properties and methods
|
|
* to the underlying socket while allowing override of specific properties.
|
|
*/
|
|
export class WrappedSocket {
|
|
public readonly socket: plugins.net.Socket;
|
|
private realClientIP?: string;
|
|
private realClientPort?: number;
|
|
|
|
// Make TypeScript happy by declaring the Socket methods that will be proxied
|
|
[key: string]: any;
|
|
|
|
constructor(
|
|
socket: plugins.net.Socket,
|
|
realClientIP?: string,
|
|
realClientPort?: number
|
|
) {
|
|
this.socket = socket;
|
|
this.realClientIP = realClientIP;
|
|
this.realClientPort = realClientPort;
|
|
|
|
// Create a proxy that delegates everything to the underlying socket
|
|
return new Proxy(this, {
|
|
get(target, prop, receiver) {
|
|
// Override specific properties
|
|
if (prop === 'remoteAddress') {
|
|
return target.remoteAddress;
|
|
}
|
|
if (prop === 'remotePort') {
|
|
return target.remotePort;
|
|
}
|
|
if (prop === 'socket') {
|
|
return target.socket;
|
|
}
|
|
if (prop === 'realClientIP') {
|
|
return target.realClientIP;
|
|
}
|
|
if (prop === 'realClientPort') {
|
|
return target.realClientPort;
|
|
}
|
|
if (prop === 'isFromTrustedProxy') {
|
|
return target.isFromTrustedProxy;
|
|
}
|
|
if (prop === 'setProxyInfo') {
|
|
return target.setProxyInfo.bind(target);
|
|
}
|
|
|
|
// For all other properties/methods, delegate to the underlying socket
|
|
const value = target.socket[prop as keyof plugins.net.Socket];
|
|
if (typeof value === 'function') {
|
|
return value.bind(target.socket);
|
|
}
|
|
return value;
|
|
},
|
|
set(target, prop, value) {
|
|
// Set on the underlying socket
|
|
(target.socket as any)[prop] = value;
|
|
return true;
|
|
}
|
|
}) as any;
|
|
}
|
|
|
|
/**
|
|
* Returns the real client IP if available, otherwise the socket's remote address
|
|
*/
|
|
get remoteAddress(): string | undefined {
|
|
return this.realClientIP || this.socket.remoteAddress;
|
|
}
|
|
|
|
/**
|
|
* Returns the real client port if available, otherwise the socket's remote port
|
|
*/
|
|
get remotePort(): number | undefined {
|
|
return this.realClientPort || this.socket.remotePort;
|
|
}
|
|
|
|
/**
|
|
* Indicates if this connection came through a trusted proxy
|
|
*/
|
|
get isFromTrustedProxy(): boolean {
|
|
return !!this.realClientIP;
|
|
}
|
|
|
|
/**
|
|
* Updates the real client information (called after parsing PROXY protocol)
|
|
*/
|
|
setProxyInfo(ip: string, port: number): void {
|
|
this.realClientIP = ip;
|
|
this.realClientPort = port;
|
|
}
|
|
} |