proxy-chain
Version:
Node.js implementation of a proxy server (think Squid) with support for SSL, authentication, upstream proxy chaining, and protocol tunneling.
208 lines • 7.9 kB
TypeScript
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
/// <reference types="node" />
import { Buffer } from 'node:buffer';
import type dns from 'node:dns';
import { EventEmitter } from 'node:events';
import http from 'node:http';
import { URL } from 'node:url';
import type { HandlerOpts as CustomResponseOpts } from './custom_response';
import type { Socket } from './socket';
export declare const SOCKS_PROTOCOLS: string[];
export type ConnectionStats = {
srcTxBytes: number;
srcRxBytes: number;
trgTxBytes: number | null;
trgRxBytes: number | null;
};
type HandlerOpts = {
server: Server;
id: number;
srcRequest: http.IncomingMessage;
srcResponse: http.ServerResponse | null;
srcHead: Buffer | null;
trgParsed: URL | null;
upstreamProxyUrlParsed: URL | null;
ignoreUpstreamProxyCertificate: boolean;
isHttp: boolean;
customResponseFunction?: CustomResponseOpts['customResponseFunction'] | null;
customConnectServer?: http.Server | null;
localAddress?: string;
ipFamily?: number;
dnsLookup?: typeof dns['lookup'];
customTag?: unknown;
};
export type PrepareRequestFunctionOpts = {
connectionId: number;
request: http.IncomingMessage;
username: string;
password: string;
hostname: string;
port: number;
isHttp: boolean;
};
export type PrepareRequestFunctionResult = {
customResponseFunction?: CustomResponseOpts['customResponseFunction'];
customConnectServer?: http.Server | null;
requestAuthentication?: boolean;
failMsg?: string;
upstreamProxyUrl?: string | null;
ignoreUpstreamProxyCertificate?: boolean;
localAddress?: string;
ipFamily?: number;
dnsLookup?: typeof dns['lookup'];
customTag?: unknown;
};
type Promisable<T> = T | Promise<T>;
export type PrepareRequestFunction = (opts: PrepareRequestFunctionOpts) => Promisable<undefined | PrepareRequestFunctionResult>;
/**
* Represents the proxy server.
* It emits the 'requestFailed' event on unexpected request errors, with the following parameter `{ error, request }`.
* It emits the 'connectionClosed' event when connection to proxy server is closed, with parameter `{ connectionId, stats }`.
*/
export declare class Server extends EventEmitter {
port: number;
host?: string;
prepareRequestFunction?: PrepareRequestFunction;
authRealm: unknown;
verbose: boolean;
server: http.Server;
lastHandlerId: number;
stats: {
httpRequestCount: number;
connectRequestCount: number;
};
connections: Map<number, Socket>;
/**
* Initializes a new instance of Server class.
* @param options
* @param [options.port] Port where the server will listen. By default 8000.
* @param [options.prepareRequestFunction] Custom function to authenticate proxy requests,
* provide URL to upstream proxy or potentially provide a function that generates a custom response to HTTP requests.
* It accepts a single parameter which is an object:
* ```
* {
* connectionId: symbol,
* request: http.IncomingMessage,
* username: string,
* password: string,
* hostname: string,
* port: number,
* isHttp: boolean,
* }
* ```
* and returns an object (or promise resolving to the object) with following form:
* ```
* {
* requestAuthentication: boolean,
* upstreamProxyUrl: string,
* customResponseFunction: Function,
* }
* ```
* If `upstreamProxyUrl` is a falsy value, no upstream proxy is used.
* If `prepareRequestFunction` is not set, the proxy server will not require any authentication
* and will not use any upstream proxy.
* If `customResponseFunction` is set, it will be called to generate a custom response to the HTTP request.
* It should not be used together with `upstreamProxyUrl`.
* @param [options.authRealm] Realm used in the Proxy-Authenticate header and also in the 'Server' HTTP header. By default it's `ProxyChain`.
* @param [options.verbose] If true, the server will output logs
*/
constructor(options?: {
port?: number;
host?: string;
prepareRequestFunction?: PrepareRequestFunction;
verbose?: boolean;
authRealm?: unknown;
});
log(connectionId: unknown, str: string): void;
onClientError(err: NodeJS.ErrnoException, socket: Socket): void;
/**
* Assigns a unique ID to the socket and keeps the register up to date.
* Needed for abrupt close of the server.
*/
registerConnection(socket: Socket): void;
/**
* Handles incoming sockets, useful for error handling
*/
onConnection(socket: Socket): void;
/**
* Converts known errors to be instance of RequestError.
*/
normalizeHandlerError(error: NodeJS.ErrnoException): NodeJS.ErrnoException;
/**
* Handles normal HTTP request by forwarding it to target host or the upstream proxy.
*/
onRequest(request: http.IncomingMessage, response: http.ServerResponse): Promise<void>;
/**
* Handles HTTP CONNECT request by setting up a tunnel either to target host or to the upstream proxy.
* @param request
* @param socket
* @param head The first packet of the tunneling stream (may be empty)
*/
onConnect(request: http.IncomingMessage, socket: Socket, head: Buffer): Promise<void>;
/**
* Prepares handler options from a request.
* @see {prepareRequestHandling}
*/
getHandlerOpts(request: http.IncomingMessage): HandlerOpts;
/**
* Calls `this.prepareRequestFunction` with normalized options.
* @param request
* @param handlerOpts
*/
callPrepareRequestFunction(request: http.IncomingMessage, handlerOpts: HandlerOpts): Promise<PrepareRequestFunctionResult>;
/**
* Authenticates a new request and determines upstream proxy URL using the user function.
* Returns a promise resolving to an object that can be used to run a handler.
* @param request
*/
prepareRequestHandling(request: http.IncomingMessage): Promise<HandlerOpts>;
/**
* Sends a HTTP error response to the client.
* @param request
* @param error
*/
failRequest(request: http.IncomingMessage, error: NodeJS.ErrnoException): void;
/**
* Sends a simple HTTP response to the client and forcibly closes the connection.
* This invalidates the ServerResponse instance (if present).
* We don't know the state of the response anyway.
* Writing directly to the socket seems to be the easiest solution.
* @param socket
* @param statusCode
* @param headers
* @param message
*/
sendSocketResponse(socket: Socket, statusCode?: number, caseSensitiveHeaders?: {}, message?: string): void;
/**
* Starts listening at a port specified in the constructor.
*/
listen(callback?: (error: NodeJS.ErrnoException | null) => void): Promise<void>;
/**
* Gets array of IDs of all active connections.
*/
getConnectionIds(): number[];
/**
* Gets data transfer statistics of a specific proxy connection.
*/
getConnectionStats(connectionId: number): ConnectionStats | undefined;
/**
* Forcibly close a specific pending proxy connection.
*/
closeConnection(connectionId: number): void;
/**
* Forcibly closes pending proxy connections.
*/
closeConnections(): void;
/**
* Closes the proxy server.
* @param closeConnections If true, pending proxy connections are forcibly closed.
*/
close(closeConnections: boolean, callback?: (error: NodeJS.ErrnoException | null) => void): Promise<void>;
}
export {};
//# sourceMappingURL=server.d.ts.map