core,transports: remove global object

This commit is contained in:
Indexyz 2018-02-12 16:43:43 +08:00 committed by Micooz
parent 69a3d34c2f
commit 48c3a2d70e
34 changed files with 289 additions and 245 deletions

@ -194,19 +194,19 @@ describe('Config#init', () => {
log_max_days: 30
};
it('should globals set correctly', () => {
Config.init(clientConf);
expect(__LOCAL_PROTOCOL__).toBe('tcp');
expect(__LOCAL_HOST__).toBe('localhost');
expect(__LOCAL_PORT__).toBe(1080);
expect(__IS_CLIENT__).toBe(true);
expect(__IS_SERVER__).toBe(false);
expect(__SERVERS__.length).toBe(1);
expect(__TIMEOUT__).toBe(600 * 1e3);
expect(__WORKERS__).toBe(0);
expect(__LOG_LEVEL__).toBe('warn');
expect(__LOG_PATH__.endsWith('blinksocks.log')).toBe(true);
expect(__LOG_MAX_DAYS__).toBe(30);
it('should ctx set correctly', () => {
const ctx = Config.init(clientConf);
expect(ctx.LOCAL_PROTOCOL).toBe('tcp');
expect(ctx.LOCAL_HOST).toBe('localhost');
expect(ctx.LOCAL_PORT).toBe(1080);
expect(ctx.IS_CLIENT).toBe(true);
expect(ctx.IS_SERVER).toBe(false);
expect(ctx.SERVERS.length).toBe(1);
expect(ctx.TIMEOUT).toBe(600 * 1e3);
expect(ctx.WORKERS).toBe(0);
expect(ctx.LOG_LEVEL).toBe('warn');
expect(ctx.LOG_PATH.endsWith('blinksocks.log')).toBe(true);
expect(ctx.LOG_MAX_DAYS).toBe(30);
});
});
@ -224,10 +224,10 @@ describe('Config#initServer', () => {
};
it('should globals set correctly', () => {
Config.init(serverConf);
expect(__TRANSPORT__).toBe('tls');
expect(__TLS_CERT__).toBeDefined();
expect(__TLS_KEY__).toBeDefined();
const ctx = Config.init(serverConf);
expect(ctx.TRANSPORT).toBe('tls');
expect(ctx.TLS_CERT).toBeDefined();
expect(ctx.TLS_KEY).toBeDefined();
});
});

@ -17,78 +17,80 @@ function loadFileSync(file) {
export class Config {
static init(json) {
const ctx = {};
const {protocol, hostname, port, query} = url.parse(json.service);
global.__LOCAL_PROTOCOL__ = protocol.slice(0, -1);
global.__LOCAL_HOST__ = hostname;
global.__LOCAL_PORT__ = +port;
ctx.LOCAL_PROTOCOL = protocol.slice(0, -1);
ctx.LOCAL_HOST = hostname;
ctx.LOCAL_PORT = +port;
if (json.servers !== undefined) {
global.__SERVERS__ = json.servers.filter((server) => !!server.enabled);
global.__IS_CLIENT__ = true;
global.__IS_SERVER__ = false;
ctx.SERVERS = json.servers.filter((server) => !!server.enabled);
ctx.IS_CLIENT = true;
ctx.IS_SERVER = false;
} else {
global.__IS_CLIENT__ = false;
global.__IS_SERVER__ = true;
ctx.IS_CLIENT = false;
ctx.IS_SERVER = true;
}
Config.initLogger(json);
Config.initLogger(ctx, json);
if (__IS_SERVER__) {
Config.initServer(json);
if (ctx.IS_SERVER) {
Config.initServer(ctx, json);
}
if (__IS_CLIENT__ && __LOCAL_PROTOCOL__ === 'tcp') {
if (ctx.IS_CLIENT && ctx.LOCAL_PROTOCOL === 'tcp') {
const {forward} = qs.parse(query);
const {hostname, port} = url.parse('tcp://' + forward);
global.__FORWARD_HOST__ = hostname;
global.__FORWARD_PORT__ = +port;
ctx.FORWARD_HOST = hostname;
ctx.FORWARD_PORT = +port;
}
global.__TIMEOUT__ = (json.timeout !== undefined) ? json.timeout * 1e3 : 600 * 1e3;
global.__REDIRECT__ = (json.redirect !== '') ? json.redirect : null;
global.__WORKERS__ = (json.workers !== undefined) ? json.workers : 0;
global.__DNS_EXPIRE__ = (json.dns_expire !== undefined) ? json.dns_expire * 1e3 : DNS_DEFAULT_EXPIRE;
ctx.TIMEOUT = (json.timeout !== undefined) ? json.timeout * 1e3 : 600 * 1e3;
ctx.REDIRECT = (json.redirect !== '') ? json.redirect : null;
ctx.WORKERS = (json.workers !== undefined) ? json.workers : 0;
ctx.DNS_EXPIRE = (json.dns_expire !== undefined) ? json.dns_expire * 1e3 : DNS_DEFAULT_EXPIRE;
// dns
if (json.dns !== undefined && json.dns.length > 0) {
global.__DNS__ = json.dns;
ctx.DNS = json.dns;
dns.setServers(json.dns);
}
// dns-cache
DNSCache.init(__DNS_EXPIRE__);
DNSCache.init(ctx.DNS_EXPIRE);
return ctx;
}
static initServer(server) {
static initServer(ctx, server) {
// service
const {protocol, hostname, port} = url.parse(server.service);
global.__TRANSPORT__ = protocol.slice(0, -1);
global.__SERVER_HOST__ = hostname;
global.__SERVER_PORT__ = +port;
ctx.TRANSPORT = protocol.slice(0, -1);
ctx.SERVER_HOST = hostname;
ctx.SERVER_PORT = +port;
// preload tls_cert or tls_key
if (__TRANSPORT__ === 'tls') {
if (ctx.TRANSPORT === 'tls') {
logger.info(`[config] loading ${server.tls_cert}`);
global.__TLS_CERT__ = loadFileSync(server.tls_cert);
if (__IS_SERVER__) {
ctx.TLS_CERT = loadFileSync(server.tls_cert);
if (ctx.IS_SERVER) {
logger.info(`[config] loading ${server.tls_key}`);
global.__TLS_KEY__ = loadFileSync(server.tls_key);
ctx.TLS_KEY = loadFileSync(server.tls_key);
}
}
global.__KEY__ = server.key;
global.__PRESETS__ = server.presets;
global.__UDP_PRESETS__ = server.presets;
ctx.KEY = server.key;
ctx.PRESETS = server.presets;
ctx.UDP_PRESETS = server.presets;
// mux
global.__MUX__ = !!server.mux;
if (__IS_CLIENT__) {
global.__MUX_CONCURRENCY__ = server.mux_concurrency || 10;
ctx.MUX = !!server.mux;
if (ctx.IS_CLIENT) {
ctx.MUX_CONCURRENCY = server.mux_concurrency || 10;
}
// remove unnecessary presets
if (__MUX__) {
global.__PRESETS__ = __PRESETS__.filter(
if (ctx.MUX) {
ctx.PRESETS = ctx.PRESETS.filter(
({name}) => !IPresetAddressing.isPrototypeOf(getPresetClassByName(name))
);
}
@ -103,7 +105,7 @@ export class Config {
}
}
static initLogger(json) {
static initLogger(ctx, json) {
// log_path & log_level
const absolutePath = path.resolve(process.cwd(), json.log_path || '.');
let isFile = false;
@ -114,12 +116,12 @@ export class Config {
}
// log_path, log_level, log_max_days
global.__LOG_PATH__ = isFile ? absolutePath : path.join(absolutePath, `bs-${__IS_CLIENT__ ? 'client' : 'server'}.log`);
global.__LOG_LEVEL__ = (json.log_level !== undefined) ? json.log_level : 'info';
global.__LOG_MAX_DAYS__ = (json.log_max_days !== undefined) ? json.log_max_days : 0;
ctx.LOG_PATH = isFile ? absolutePath : path.join(absolutePath, `bs-${ctx.IS_CLIENT ? 'client' : 'server'}.log`);
ctx.LOG_LEVEL = (json.log_level !== undefined) ? json.log_level : 'info';
ctx.LOG_MAX_DAYS = (json.log_max_days !== undefined) ? json.log_max_days : 0;
logger.configure({
level: __LOG_LEVEL__,
level: ctx.LOG_LEVEL,
transports: [
new (winston.transports.Console)({
colorize: true,
@ -128,9 +130,9 @@ export class Config {
new (require('winston-daily-rotate-file'))({
json: false,
eol: os.EOL,
filename: __LOG_PATH__,
level: __LOG_LEVEL__,
maxDays: __LOG_MAX_DAYS__
filename: ctx.LOG_PATH,
level: ctx.LOG_LEVEL,
maxDays: ctx.LOG_MAX_DAYS
})
]
});

@ -35,8 +35,10 @@ export class Hub {
_udpRelays = null; // LRU cache
_ctx = null;
constructor(config) {
Config.init(config);
this._ctx = Config.init(config);
this._onConnection = this._onConnection.bind(this);
this._udpRelays = LRU({
max: 500,
@ -48,14 +50,14 @@ export class Hub {
terminate(callback) {
// relays
this._udpRelays.reset();
if (__MUX__) {
if (this._ctx.MUX) {
this._muxRelays.forEach((relay) => relay.destroy());
this._muxRelays.clear();
}
this._tcpRelays.forEach((relay) => relay.destroy());
this._tcpRelays.clear();
// balancer
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
Balancer.destroy();
logger.info(`[balancer-${this._wkId}] stopped`);
}
@ -71,8 +73,8 @@ export class Hub {
if (this._tcpServer !== null) {
this.terminate();
}
if (__IS_CLIENT__) {
Balancer.start(__SERVERS__);
if (this._ctx.IS_CLIENT) {
Balancer.start(this._ctx.SERVERS);
logger.info(`[balancer-${this._wkId}] started`);
this._switchServer();
}
@ -85,7 +87,7 @@ export class Hub {
}
async _createServer() {
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
this._tcpServer = await this._createServerOnClient();
} else {
this._tcpServer = await this._createServerOnServer();
@ -96,30 +98,30 @@ export class Hub {
async _createServerOnClient() {
return new Promise((resolve, reject) => {
let server = null;
switch (__LOCAL_PROTOCOL__) {
switch (this._ctx.LOCAL_PROTOCOL) {
case 'tcp':
server = tcp.createServer({forwardHost: __FORWARD_HOST__, forwardPort: __FORWARD_PORT__});
server = tcp.createServer({forwardHost: this._ctx.FORWARD_HOST, forwardPort: this._ctx.FORWARD_PORT});
break;
case 'socks':
case 'socks5':
case 'socks4':
case 'socks4a':
server = socks.createServer({bindAddress: __LOCAL_HOST__, bindPort: __LOCAL_PORT__});
server = socks.createServer({bindAddress: this._ctx.LOCAL_HOST, bindPort: this._ctx.LOCAL_PORT});
break;
case 'http':
case 'https':
server = http.createServer();
break;
default:
return reject(Error(`unsupported protocol: "${__LOCAL_PROTOCOL__}"`));
return reject(Error(`unsupported protocol: "${this._ctx.LOCAL_PROTOCOL}"`));
}
const address = {
host: __LOCAL_HOST__,
port: __LOCAL_PORT__
host: this._ctx.LOCAL_HOST,
port: this._ctx.LOCAL_PORT
};
server.on('proxyConnection', this._onConnection);
server.listen(address, () => {
const service = `${__LOCAL_PROTOCOL__}://${__LOCAL_HOST__}:${__LOCAL_PORT__}`;
const service = `${this._ctx.LOCAL_PROTOCOL}://${this._ctx.LOCAL_HOST}:${this._ctx.LOCAL_PORT}`;
logger.info(`[hub-${this._wkId}] blinksocks client is running at ${service}`);
resolve(server);
});
@ -129,15 +131,15 @@ export class Hub {
async _createServerOnServer() {
return new Promise((resolve, reject) => {
const address = {
host: __LOCAL_HOST__,
port: __LOCAL_PORT__
host: this._ctx.LOCAL_HOST,
port: this._ctx.LOCAL_PORT
};
const onListening = (server) => {
const service = `${__LOCAL_PROTOCOL__}://${__LOCAL_HOST__}:${__LOCAL_PORT__}`;
const service = `${this._ctx.LOCAL_PROTOCOL}://${this._ctx.LOCAL_HOST}:${this._ctx.LOCAL_PORT}`;
logger.info(`[hub-${this._wkId}] blinksocks server is running at ${service}`);
resolve(server);
};
switch (__LOCAL_PROTOCOL__) {
switch (this._ctx.LOCAL_PROTOCOL) {
case 'tcp': {
const server = net.createServer();
server.on('connection', this._onConnection);
@ -158,13 +160,13 @@ export class Hub {
break;
}
case 'tls': {
const server = tls.createServer({key: [__TLS_KEY__], cert: [__TLS_CERT__]});
const server = tls.createServer({key: [this._ctx.TLS_KEY], cert: [this._ctx.TLS_CERT]});
server.on('secureConnection', this._onConnection);
server.listen(address, () => onListening(server));
break;
}
default:
return reject(Error(`unsupported protocol: "${__LOCAL_PROTOCOL__}"`));
return reject(Error(`unsupported protocol: "${this._ctx.LOCAL_PROTOCOL}"`));
}
});
}
@ -178,7 +180,7 @@ export class Hub {
const {address, port} = rinfo;
let proxyRequest = null;
let packet = msg;
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
const parsed = socks.parseSocks5UdpRequest(msg);
if (parsed === null) {
logger.warn(`[hub] [${address}:${port}] drop invalid udp packet: ${dumpHex(msg)}`);
@ -217,7 +219,7 @@ export class Hub {
})(server.close);
// monkey patch for Socket.send() to meet Socks5 protocol
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
server.send = ((send) => (data, port, host, isSs, ...args) => {
let packet = null;
if (isSs) {
@ -230,8 +232,8 @@ export class Hub {
})(server.send);
}
server.bind({address: __LOCAL_HOST__, port: __LOCAL_PORT__}, () => {
const service = `udp://${__LOCAL_HOST__}:${__LOCAL_PORT__}`;
server.bind({address: this._ctx.LOCAL_HOST, port: this._ctx.LOCAL_PORT}, () => {
const service = `udp://${this._ctx.LOCAL_HOST}:${this._ctx.LOCAL_PORT}`;
logger.info(`[hub-${this._wkId}] blinksocks udp server is running at ${service}`);
resolve(server);
});
@ -240,7 +242,7 @@ export class Hub {
_onConnection(socket, proxyRequest = null) {
logger.verbose(`[hub] [${socket.remoteAddress}:${socket.remotePort}] connected`);
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
this._switchServer();
}
const context = {
@ -253,8 +255,8 @@ export class Hub {
};
let muxRelay = null, cid = null;
if (__MUX__) {
if (__IS_CLIENT__) {
if (this._ctx.MUX) {
if (this._ctx.IS_CLIENT) {
cid = makeConnID();
muxRelay = this._getMuxRelayOnClient(context, cid);
context.muxRelay = muxRelay;
@ -267,8 +269,8 @@ export class Hub {
const relay = this._createRelay(context);
// setup association between relay and muxRelay
if (__MUX__) {
if (__IS_CLIENT__) {
if (this._ctx.MUX) {
if (this._ctx.IS_CLIENT) {
relay.id = cid; // NOTE: this cid will be used in mux preset
muxRelay.addSubRelay(relay);
} else {
@ -314,25 +316,25 @@ export class Hub {
_createRelay(context, isMux = false) {
const props = {
context: context,
transport: __TRANSPORT__,
presets: __PRESETS__
transport: this._ctx.TRANSPORT,
presets: this._ctx.PRESETS
};
if (isMux) {
return new MuxRelay(props);
return new MuxRelay(props, this._ctx);
}
if (__MUX__) {
if (__IS_CLIENT__) {
return new Relay({...props, transport: 'mux', presets: []});
if (this._ctx.MUX) {
if (this._ctx.IS_CLIENT) {
return new Relay({...props, transport: 'mux', presets: []}, this._ctx);
} else {
return new MuxRelay(props);
return new MuxRelay(props, this._ctx);
}
} else {
return new Relay(props);
return new Relay(props, this._ctx);
}
}
_createUdpRelay(context) {
return new Relay({transport: 'udp', context, presets: __UDP_PRESETS__});
return new Relay({transport: 'udp', context, presets: this._ctx.UDP_PRESETS}, this._ctx);
}
_selectMuxRelay() {
@ -341,7 +343,7 @@ export class Hub {
if (concurrency < 1) {
return null;
}
if (concurrency < __MUX_CONCURRENCY__ && getRandomInt(0, 1) === 0) {
if (concurrency < this._ctx.MUX_CONCURRENCY && getRandomInt(0, 1) === 0) {
return null;
}
return relays.get([...relays.keys()][getRandomInt(0, concurrency - 1)]);
@ -351,7 +353,7 @@ export class Hub {
const server = Balancer.getFastest();
if (server) {
Config.initServer(server);
logger.info(`[balancer-${this._wkId}] use server: ${__SERVER_HOST__}:${__SERVER_PORT__}`);
logger.info(`[balancer-${this._wkId}] use server: ${this._ctx.SERVER_HOST}:${this._ctx.SERVER_PORT}`);
}
}

@ -5,12 +5,12 @@ import {kebabCase} from '../utils';
const staticPresetCache = new Map(/* 'ClassName': <preset> */);
function createPreset(name, params = {}) {
function createPreset(name, params = {}, ctx) {
const ImplClass = getPresetClassByName(name);
const createOne = () => {
ImplClass.checkParams(params);
ImplClass.onInit(params);
return new ImplClass(params);
ImplClass.checkParams(params, ctx);
ImplClass.onInit(params, ctx);
return new ImplClass(params, ctx);
};
let preset = null;
if (IPresetStatic.isPrototypeOf(ImplClass)) {
@ -32,13 +32,16 @@ function createPreset(name, params = {}) {
export class Middleware extends EventEmitter {
_impl = null;
_ctx = null;
constructor(preset) {
constructor(preset, ctx) {
super();
console.log(this._ctx)
this._ctx = ctx;
this.onPresetNext = this.onPresetNext.bind(this);
this.onPresetBroadcast = this.onPresetBroadcast.bind(this);
this.onPresetFail = this.onPresetFail.bind(this);
this._impl = createPreset(preset.name, preset.params || {});
this._impl = createPreset(preset.name, preset.params || {}, this._ctx);
this._impl.next = this.onPresetNext;
this._impl.broadcast = this.onPresetBroadcast;
this._impl.fail = this.onPresetFail;
@ -105,7 +108,7 @@ export class Middleware extends EventEmitter {
// clientXXX, serverXXX
const nextLifeCycleHook = (buf/* , isReverse = false */) => {
const args = {buffer: buf, next, broadcast, direct, fail};
const ret = __IS_CLIENT__ ? this._impl[`client${type}`](args, extraArgs) : this._impl[`server${type}`](args, extraArgs);
const ret = this._ctx.IS_CLIENT ? this._impl[`client${type}`](args, extraArgs) : this._impl[`server${type}`](args, extraArgs);
if (ret instanceof Buffer) {
next(ret);
}

@ -28,7 +28,7 @@ export class MuxRelay extends Relay {
'tls': [TlsInbound, TlsOutbound],
'ws': [WsInbound, WsOutbound],
};
const [Inbound, Outbound] = __IS_CLIENT__ ? [MuxInbound, mapping[transport][1]] : [mapping[transport][0], MuxOutbound];
const [Inbound, Outbound] = this._globalCtx.IS_CLIENT ? [MuxInbound, mapping[transport][1]] : [mapping[transport][0], MuxOutbound];
return {Inbound, Outbound};
}
@ -121,7 +121,7 @@ export class MuxRelay extends Relay {
logger.error(`[mux-${this.id}] fail to dispatch data frame(size=${data.length}), no such sub connection(cid=${cid})`);
return;
}
if (__IS_CLIENT__ || relay.isOutboundReady()) {
if (this._globalCtx.IS_CLIENT || relay.isOutboundReady()) {
relay.decode(data);
} else {
// TODO: find a way to avoid using relay._pendingFrames

@ -20,6 +20,8 @@ export class Pipe extends EventEmitter {
_destroyed = false;
_presets = null;
_ctx = null;
get destroyed() {
return this._destroyed;
@ -29,8 +31,9 @@ export class Pipe extends EventEmitter {
return this._presets;
}
constructor({presets, isUdp = false}) {
constructor({presets, isUdp = false}, ctx) {
super();
this._ctx = ctx;
this.broadcast = this.broadcast.bind(this);
this.onReadProperty = this.onReadProperty.bind(this);
this.createMiddlewares(presets);
@ -140,7 +143,7 @@ export class Pipe extends EventEmitter {
}
_createMiddleware(preset) {
const middleware = new Middleware(preset);
const middleware = new Middleware(preset, this._ctx);
this._attachEvents(middleware);
// set readProperty()
const impl = middleware.getImplement();

@ -54,6 +54,8 @@ export class Relay extends EventEmitter {
_destroyed = false;
_globalCtx = null;
get id() {
return this._id;
}
@ -63,8 +65,9 @@ export class Relay extends EventEmitter {
this._ctx.cid = id;
}
constructor({transport, context, presets = []}) {
constructor({transport, context, presets = []}, ctx) {
super();
this._globalCtx = ctx;
this.updatePresets = this.updatePresets.bind(this);
this.onBroadcast = this.onBroadcast.bind(this);
this.onEncoded = this.onEncoded.bind(this);
@ -82,8 +85,8 @@ export class Relay extends EventEmitter {
};
// bounds
const {Inbound, Outbound} = this.getBounds(transport);
const inbound = new Inbound({context: this._ctx});
const outbound = new Outbound({context: this._ctx});
const inbound = new Inbound({context: this._ctx, globalContext: this._globalCtx});
const outbound = new Outbound({context: this._ctx, globalContext: this._globalCtx});
this._inbound = inbound;
this._outbound = outbound;
// outbound
@ -127,7 +130,7 @@ export class Relay extends EventEmitter {
if (transport === 'udp') {
[Inbound, Outbound] = [UdpInbound, UdpOutbound];
} else {
[Inbound, Outbound] = __IS_CLIENT__ ? [TcpInbound, mapping[transport][1]] : [mapping[transport][0], TcpOutbound];
[Inbound, Outbound] = this._globalCtx.IS_CLIENT ? [TcpInbound, mapping[transport][1]] : [mapping[transport][0], TcpOutbound];
}
return {Inbound, Outbound};
}
@ -164,7 +167,7 @@ export class Relay extends EventEmitter {
if (type === CONNECT_TO_REMOTE) {
const remote = `${this._remoteInfo.host}:${this._remoteInfo.port}`;
const target = `${action.payload.host}:${action.payload.port}`;
if (__MUX__ && __IS_CLIENT__ && this._transport !== 'udp') {
if (this._globalCtx.MUX && this._globalCtx.IS_CLIENT && this._transport !== 'udp') {
logger.info(`[relay-${this.id}] [${remote}] request over mux-${this._ctx.muxRelay.id}: ${target}`);
return;
}
@ -193,7 +196,7 @@ export class Relay extends EventEmitter {
type: CONNECTION_CREATED,
payload: {transport, ...this._remoteInfo}
});
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
this._pipe.broadcast(null, {
type: CONNECT_TO_REMOTE,
payload: {...proxyRequest, keepAlive: true} // keep previous connection alive, don't re-connect
@ -204,7 +207,7 @@ export class Relay extends EventEmitter {
}
onEncoded(buffer) {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
this._outbound.write(buffer);
} else {
this._inbound.write(buffer);
@ -212,7 +215,7 @@ export class Relay extends EventEmitter {
}
onDecoded(buffer) {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
this._inbound.write(buffer);
} else {
this._outbound.write(buffer);
@ -268,7 +271,7 @@ export class Relay extends EventEmitter {
* create pipes for both data forward and backward
*/
createPipe(presets) {
const pipe = new Pipe({presets, isUdp: this._transport === 'udp'});
const pipe = new Pipe({presets, isUdp: this._transport === 'udp'}, this._globalCtx);
pipe.on('broadcast', this.onBroadcast.bind(this)); // if no action were caught by presets
pipe.on(`post_${PIPE_ENCODE}`, this.onEncoded);
pipe.on(`post_${PIPE_DECODE}`, this.onDecoded);
@ -291,6 +294,7 @@ export class Relay extends EventEmitter {
this._remoteInfo = null;
this._proxyRequest = null;
this._destroyed = true;
this._globalCtx = null;
}
}

@ -118,11 +118,11 @@ export default class AeadRandomCipherPreset extends IPreset {
}
}
static onInit({method, info = DEFAULT_INFO, factor = DEFAULT_FACTOR}) {
static onInit({method, info = DEFAULT_INFO, factor = DEFAULT_FACTOR}, {KEY}) {
AeadRandomCipherPreset.cipherName = method;
AeadRandomCipherPreset.info = Buffer.from(info);
AeadRandomCipherPreset.factor = factor;
AeadRandomCipherPreset.rawKey = Buffer.from(__KEY__);
AeadRandomCipherPreset.rawKey = Buffer.from(KEY);
AeadRandomCipherPreset.keySaltSize = ciphers[method];
}

@ -76,6 +76,8 @@ export default class AutoConfPreset extends IPreset {
_header = null;
_ctx = null;
static suites = [];
static checkParams({suites}) {
@ -84,6 +86,11 @@ export default class AutoConfPreset extends IPreset {
}
}
constructor(_, ctx) {
super();
this._ctx = ctx;
}
static async onInit({suites: uri}) {
logger.info(`[auto-conf] loading suites from: ${uri}`);
let suites = [];
@ -111,7 +118,7 @@ export default class AutoConfPreset extends IPreset {
createRequestHeader(suites) {
const sid = crypto.randomBytes(2);
const utc = ntb(getCurrentTimestampInt(), 4, BYTE_ORDER_LE);
const key = EVP_BytesToKey(Buffer.from(__KEY__).toString('base64') + hash('md5', sid).toString('base64'), 16, 16);
const key = EVP_BytesToKey(Buffer.from(this._ctx.KEY).toString('base64') + hash('md5', sid).toString('base64'), 16, 16);
const cipher = crypto.createCipheriv('rc4', key, NOOP);
const enc_utc = cipher.update(utc);
const request_hmac = hmac('md5', key, Buffer.concat([sid, enc_utc]));
@ -149,7 +156,7 @@ export default class AutoConfPreset extends IPreset {
}
const sid = buffer.slice(0, 2);
const request_hmac = buffer.slice(6, 22);
const key = EVP_BytesToKey(Buffer.from(__KEY__).toString('base64') + hash('md5', sid).toString('base64'), 16, 16);
const key = EVP_BytesToKey(Buffer.from(this._ctx.KEY).toString('base64') + hash('md5', sid).toString('base64'), 16, 16);
const hmac_calc = hmac('md5', key, buffer.slice(0, 6));
if (!hmac_calc.equals(request_hmac)) {
return fail(`unexpected hmac of client request, dump=${dumpHex(buffer)}`);

@ -78,6 +78,8 @@ export default class BaseAuthPreset extends IPresetAddressing {
_port = null; // buffer
_ctx = null;
static checkParams({method = DEFAULT_HASH_METHOD}) {
const methods = Object.keys(HMAC_METHODS);
if (!methods.includes(method)) {
@ -85,17 +87,18 @@ export default class BaseAuthPreset extends IPresetAddressing {
}
}
static onInit({method = DEFAULT_HASH_METHOD}) {
static onInit({method = DEFAULT_HASH_METHOD}, {KEY}) {
BaseAuthPreset.hmacMethod = method;
BaseAuthPreset.hmacLen = HMAC_METHODS[method];
BaseAuthPreset.hmacKey = EVP_BytesToKey(__KEY__, 16, 16);
BaseAuthPreset.hmacKey = EVP_BytesToKey(KEY, 16, 16);
}
constructor() {
constructor(_, ctx) {
super();
this._ctx = ctx;
const {hmacKey: key} = BaseAuthPreset;
const iv = hash('md5', Buffer.from(__KEY__ + 'base-auth'));
if (__IS_CLIENT__) {
const iv = hash('md5', Buffer.from(ctx.KEY + 'base-auth'));
if (ctx.IS_CLIENT) {
this._cipher = crypto.createCipheriv('aes-128-cfb', key, iv);
} else {
this._decipher = crypto.createDecipheriv('aes-128-cfb', key, iv);
@ -111,7 +114,7 @@ export default class BaseAuthPreset extends IPresetAddressing {
}
onNotified(action) {
if (__IS_CLIENT__ && action.type === CONNECT_TO_REMOTE) {
if (this._ctx.IS_CLIENT && action.type === CONNECT_TO_REMOTE) {
const {host, port} = action.payload;
this._host = Buffer.from(host);
this._port = numberToBuffer(port);

@ -120,7 +120,7 @@ export class IPreset {
* check params passed to the preset, if any errors, should throw directly
* @param params
*/
static checkParams(params) {
static checkParams(params, ctx) {
}
@ -128,7 +128,7 @@ export class IPreset {
* you can make some cache in this function
* @param params
*/
static onInit(params) {
static onInit(params, ctx) {
}

@ -126,13 +126,13 @@ export default class SsAeadCipherPreset extends IPreset {
}
}
static onInit({method}) {
static onInit({method}, {KEY}) {
const [keySize, saltSize, nonceSize] = ciphers[method];
SsAeadCipherPreset.cipherName = method;
SsAeadCipherPreset.keySize = keySize;
SsAeadCipherPreset.saltSize = saltSize;
SsAeadCipherPreset.nonceSize = nonceSize;
SsAeadCipherPreset.evpKey = EVP_BytesToKey(__KEY__, keySize, 16);
SsAeadCipherPreset.evpKey = EVP_BytesToKey(KEY, keySize, 16);
SsAeadCipherPreset.isUseLibSodium = Object.keys(libsodium_functions).includes(method);
}

@ -73,6 +73,8 @@ export default class SsBasePreset extends IPresetAddressing {
_headSize = 0;
_ctx = null;
get headSize() {
return this._headSize;
}
@ -83,8 +85,13 @@ export default class SsBasePreset extends IPresetAddressing {
this._port = null;
}
constructor(_, ctx) {
super();
this._ctx = ctx;
}
onNotified(action) {
if (__IS_CLIENT__ && action.type === CONNECT_TO_REMOTE) {
if (this._ctx.IS_CLIENT && action.type === CONNECT_TO_REMOTE) {
const {host, port} = action.payload;
const type = getHostType(host);
this._atyp = type;

@ -97,14 +97,14 @@ export default class SsStreamCipherPreset extends IPreset {
return this._iv;
}
constructor({method}) {
constructor({method}, {KEY}) {
super();
const [keySize, ivSize] = ciphers[method];
const iv = crypto.randomBytes(ivSize);
this._algorithm = ['rc4-md5', 'rc4-md5-6'].includes(method) ? 'rc4' : method;
this._keySize = keySize;
this._ivSize = ivSize;
this._key = EVP_BytesToKey(__KEY__, keySize, ivSize);
this._key = EVP_BytesToKey(KEY, keySize, ivSize);
this._iv = method === 'rc4-md5-6' ? iv.slice(0, 6) : iv;
}

@ -102,8 +102,8 @@ export default class SsrAuthAes128Preset extends IPreset {
_adBuf = null;
static onInit() {
SsrAuthAes128Preset.userKey = EVP_BytesToKey(__KEY__, 16, 16);
static onInit({KEY}) {
SsrAuthAes128Preset.userKey = EVP_BytesToKey(KEY, 16, 16);
SsrAuthAes128Preset.clientId = crypto.randomBytes(4);
SsrAuthAes128Preset.connectionId = getRandomInt(0, 0x00ffffff);
}

@ -143,13 +143,16 @@ export default class SsrAuthChainPreset extends IPreset {
_adBuf = null;
_ctx = null;
static onInit() {
SsrAuthChainPreset.clientId = crypto.randomBytes(4);
SsrAuthChainPreset.connectionId = getRandomInt(0, 0x00ffffff);
}
constructor() {
constructor(_, ctx) {
super();
this._ctx = ctx;
this._rngClient = xorshift128plus();
this._rngServer = xorshift128plus();
this._adBuf = new AdvancedBuffer({getPacketLength: this.onReceiving.bind(this)});
@ -232,17 +235,17 @@ export default class SsrAuthChainPreset extends IPreset {
createChunks(buffer) {
const userKey = this._userKey;
const max_payload_size = __IS_CLIENT__ ? 2800 : (this._tcpMss - this._overhead);
const max_payload_size = this._ctx.IS_CLIENT ? 2800 : (this._tcpMss - this._overhead);
return getChunks(buffer, max_payload_size).map((payload) => {
let _payload = payload;
if (__IS_SERVER__ && this._encodeChunkId === 1) {
if (this._ctx.IS_SERVER && this._encodeChunkId === 1) {
_payload = Buffer.concat([ntb(this._tcpMss, 2, BYTE_ORDER_LE), payload]);
}
const rc4_enc_payload = this._cipher.update(_payload);
const hash = __IS_CLIENT__ ? this._lastClientHash : this._lastServerHash;
const hash = this._ctx.IS_CLIENT ? this._lastClientHash : this._lastServerHash;
const size = rc4_enc_payload.length ^ hash.slice(-2).readUInt16LE(0);
// generate two pieces of random bytes
const rng = __IS_CLIENT__ ? this._rngClient : this._rngServer;
const rng = this._ctx.IS_CLIENT ? this._rngClient : this._rngServer;
const random_bytes_len = this.getRandomBytesLengthForTcp(hash, _payload.length, rng);
const random_bytes = crypto.randomBytes(random_bytes_len);
const random_divide_pos = random_bytes_len > 0 ? rng.next().mod(8589934609).mod(random_bytes_len).toNumber() : 0;
@ -253,7 +256,7 @@ export default class SsrAuthChainPreset extends IPreset {
const hmac_key = Buffer.concat([userKey, ntb(this._encodeChunkId, 4, BYTE_ORDER_LE)]);
const chunk_hmac = hmac('md5', hmac_key, chunk);
chunk = Buffer.concat([chunk, chunk_hmac.slice(0, 2)]);
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
this._lastClientHash = chunk_hmac;
} else {
this._lastServerHash = chunk_hmac;
@ -350,9 +353,9 @@ export default class SsrAuthChainPreset extends IPreset {
if (buffer.length < 2 || this._adBuf === null) {
return; // too short to get size
}
const hash = __IS_CLIENT__ ? this._lastServerHash : this._lastClientHash;
const hash = this._ctx.IS_CLIENT ? this._lastServerHash : this._lastClientHash;
const payload_len = buffer.readUInt16LE(0) ^ hash.readUInt16LE(14);
const rng = __IS_CLIENT__ ? this._rngServer : this._rngClient;
const rng = this._ctx.IS_CLIENT ? this._rngServer : this._rngClient;
const random_bytes_len = this.getRandomBytesLengthForTcp(hash, payload_len, rng);
const chunk_size = 2 + random_bytes_len + payload_len + 2;
if (chunk_size >= 4096) {
@ -376,9 +379,9 @@ export default class SsrAuthChainPreset extends IPreset {
return fail(`unexpected chunk hmac, chunk=${dumpHex(chunk)}`);
}
// drop random_bytes, get encrypted payload
const hash = __IS_CLIENT__ ? this._lastServerHash : this._lastClientHash;
const hash = this._ctx.IS_CLIENT ? this._lastServerHash : this._lastClientHash;
const payload_len = chunk.readUInt16LE(0) ^ hash.readUInt16LE(14);
const rng = __IS_CLIENT__ ? this._rngServer : this._rngClient;
const rng = this._ctx.IS_CLIENT ? this._rngServer : this._rngClient;
const random_bytes_len = this.getRandomBytesLengthForTcp(hash, payload_len, rng);
let enc_payload = null;
if (random_bytes_len > 0) {
@ -390,12 +393,12 @@ export default class SsrAuthChainPreset extends IPreset {
// decrypt payload
let payload = this._decipher.update(enc_payload);
// update hash
if (__IS_CLIENT__) {
if (this._ctx.IS_CLIENT) {
this._lastServerHash = new_hash;
} else {
this._lastClientHash = new_hash;
}
if (__IS_CLIENT__ && this._decodeChunkId === 1) {
if (this._ctx.IS_CLIENT && this._decodeChunkId === 1) {
this._tcpMss = payload.readUInt16LE(0);
payload = payload.slice(2);
}

@ -29,6 +29,13 @@ export default class TrackerPreset extends IPreset {
_targetHost;
_targetPort;
_ctx = null;
constructor(_, ctx) {
super();
this._ctx = ctx;
}
onNotified({type, payload}) {
switch (type) {
case CONNECTION_CREATED: {
@ -95,7 +102,7 @@ export default class TrackerPreset extends IPreset {
if (strs.length > TRACK_MAX_SIZE) {
strs = strs.slice(0, perSize).concat([' ... ']).concat(strs.slice(-perSize));
}
const summary = __IS_CLIENT__ ? `out/in = ${up}/${dp}, ${ub}b/${db}b` : `in/out = ${dp}/${up}, ${db}b/${ub}b`;
const summary = this._ctx.IS_CLIENT ? `out/in = ${up}/${dp}, ${ub}b/${db}b` : `in/out = ${dp}/${up}, ${db}b/${ub}b`;
logger.info(`[tracker:${this._transport}] summary(${summary}) abstract(${strs.join(' ')})`);
}

@ -192,6 +192,8 @@ export default class V2rayVmessPreset extends IPresetAddressing {
_cipherNonce = 0;
_decipherNonce = 0;
_ctx = null;
static checkParams({id, security = 'aes-128-gcm'}) {
if (Buffer.from(id.split('-').join(''), 'hex').length !== 16) {
throw Error('id is not a valid uuid');
@ -202,9 +204,9 @@ export default class V2rayVmessPreset extends IPresetAddressing {
}
}
static onInit({id, security = 'aes-128-gcm'}) {
static onInit({id, security = 'aes-128-gcm'}, {IS_CLIENT}) {
V2rayVmessPreset.uuid = Buffer.from(id.split('-').join(''), 'hex');
if (__IS_CLIENT__) {
if (IS_CLIENT) {
V2rayVmessPreset.security = securityTypes[security];
}
setInterval(() => V2rayVmessPreset.updateAuthCache(), 1e3);
@ -231,8 +233,9 @@ export default class V2rayVmessPreset extends IPresetAddressing {
this.userHashCache = newItems;
}
constructor() {
constructor(_, ctx) {
super();
this._ctx = ctx;
this._adBuf = new AdvancedBuffer({getPacketLength: this.onReceiving.bind(this)});
this._adBuf.on('data', this.onChunkReceived.bind(this));
}
@ -254,7 +257,7 @@ export default class V2rayVmessPreset extends IPresetAddressing {
}
onNotified(action) {
if (__IS_CLIENT__ && action.type === CONNECT_TO_REMOTE) {
if (this._ctx.IS_CLIENT && action.type === CONNECT_TO_REMOTE) {
const {host, port} = action.payload;
const type = getAddrType(host);
this._atyp = type;
@ -269,7 +272,7 @@ export default class V2rayVmessPreset extends IPresetAddressing {
beforeOut({buffer}) {
if (!this._isHeaderSent) {
this._isHeaderSent = true;
const header = __IS_CLIENT__ ? this.createRequestHeader() : this.createResponseHeader();
const header = this._ctx.IS_CLIENT ? this.createRequestHeader() : this.createResponseHeader();
const chunks = this.getBufferChunks(buffer);
return Buffer.concat([header, ...chunks]);
} else {

@ -5,10 +5,12 @@ import EventEmitter from 'events';
class Bound extends EventEmitter {
_ctx = null;
_globalCtx = null;
constructor({context}) {
constructor({context, globalContext}) {
super();
this._ctx = context;
this._globalCtx = globalContext;
}
get ctx() {

@ -7,7 +7,7 @@ export class MuxInbound extends Inbound {
constructor(props) {
super(props);
this.onDrain = this.onDrain.bind(this);
if (__IS_SERVER__) {
if (this._globalCtx.IS_SERVER) {
const inbound = this.ctx.muxRelay.getInbound();
inbound.on('drain', this.onDrain);
} else {
@ -20,7 +20,7 @@ export class MuxInbound extends Inbound {
}
get bufferSize() {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const totalBufferSize = 0;
// const subRelays = this.ctx.thisRelay.getSubRelays();
// if (subRelays) {
@ -70,7 +70,7 @@ export class MuxInbound extends Inbound {
}
write(buffer) {
if (__IS_SERVER__) {
if (this._globalCtx.IS_SERVER) {
const {muxRelay, cid} = this.ctx;
muxRelay.encode(buffer, {cid});
}
@ -83,7 +83,7 @@ export class MuxInbound extends Inbound {
close() {
const doClose = () => {
if (__IS_SERVER__) {
if (this._globalCtx.IS_SERVER) {
const {muxRelay, cid} = this.ctx;
const inbound = muxRelay.getInbound();
if (inbound) {
@ -112,7 +112,7 @@ export class MuxOutbound extends Outbound {
constructor(props) {
super(props);
this.onDrain = this.onDrain.bind(this);
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const outbound = this.ctx.muxRelay.getOutbound();
outbound.on('drain', this.onDrain);
} else {
@ -121,7 +121,7 @@ export class MuxOutbound extends Outbound {
}
get bufferSize() {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const outbound = this.ctx.muxRelay.getOutbound();
if (outbound) {
return outbound.bufferSize;
@ -148,7 +148,7 @@ export class MuxOutbound extends Outbound {
}
write(buffer) {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const {muxRelay, proxyRequest, cid} = this.ctx;
if (this._isFirstFrame) {
this._isFirstFrame = false;
@ -166,7 +166,7 @@ export class MuxOutbound extends Outbound {
close() {
const doClose = () => {
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const {muxRelay, cid} = this.ctx;
const outbound = muxRelay.getOutbound();
if (outbound) {

@ -35,7 +35,7 @@ export class TcpInbound extends Inbound {
this._socket.on('timeout', this.onTimeout);
this._socket.on('end', this.onHalfClose);
this._socket.on('close', this.onClose);
this._socket.setTimeout && this._socket.setTimeout(__TIMEOUT__);
this._socket.setTimeout && this._socket.setTimeout(this._globalCtx.TIMEOUT);
}
}
@ -62,7 +62,7 @@ export class TcpInbound extends Inbound {
}
onReceive(buffer) {
const direction = __IS_CLIENT__ ? PIPE_ENCODE : PIPE_DECODE;
const direction = this._globalCtx.IS_CLIENT ? PIPE_ENCODE : PIPE_DECODE;
this.ctx.pipe.feed(direction, buffer);
// throttle receiving data to reduce memory grow:
// https://github.com/blinksocks/blinksocks/issues/60
@ -85,7 +85,7 @@ export class TcpInbound extends Inbound {
}
onTimeout() {
logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${__TIMEOUT__ / 1e3}s`);
logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${this._globalCtx.TIMEOUT / 1e3}s`);
this.onClose();
}
@ -153,16 +153,16 @@ export class TcpInbound extends Inbound {
logger.error(`[${this.name}] [${this.remote}] preset "${name}" fail to process: ${message}`);
// close connection directly on client side
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
logger.warn(`[${this.name}] [${this.remote}] connection closed`);
this.onClose();
}
// for server side, redirect traffic if "redirect" is set, otherwise, close connection after a random timeout
if (__IS_SERVER__ && !__MUX__) {
if (__REDIRECT__) {
if (this._globalCtx.IS_SERVER && !this._globalCtx.MUX) {
if (this._globalCtx.REDIRECT) {
const {orgData} = action.payload;
const [host, port] = __REDIRECT__.split(':');
const [host, port] = this._globalCtx.REDIRECT.split(':');
logger.warn(`[${this.name}] [${this.remote}] connection is redirecting to: ${host}:${port}`);
@ -189,11 +189,11 @@ export class TcpInbound extends Inbound {
}
onPresetPauseRecv() {
__IS_SERVER__ && (this._socket && this._socket.pause())
this._globalCtx.IS_SERVER && (this._socket && this._socket.pause())
}
onPresetResumeRecv() {
__IS_SERVER__ && (this._socket && this._socket.resume());
this._globalCtx.IS_SERVER && (this._socket && this._socket.resume());
}
}
@ -237,7 +237,7 @@ export class TcpOutbound extends Outbound {
}
onReceive(buffer) {
const direction = __IS_CLIENT__ ? PIPE_DECODE : PIPE_ENCODE;
const direction = this._globalCtx.IS_CLIENT ? PIPE_DECODE : PIPE_ENCODE;
this.ctx.pipe.feed(direction, buffer);
// throttle receiving data to reduce memory grow:
// https://github.com/blinksocks/blinksocks/issues/60
@ -260,7 +260,7 @@ export class TcpOutbound extends Outbound {
}
onTimeout() {
logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${__TIMEOUT__ / 1e3}s`);
logger.warn(`[${this.name}] [${this.remote}] timeout: no I/O on the connection for ${this._globalCtx.TIMEOUT / 1e3}s`);
this.onClose();
}
@ -318,17 +318,17 @@ export class TcpOutbound extends Outbound {
const {host, port, keepAlive, onConnected} = action.payload;
if (!keepAlive || !this._socket) {
try {
if (__IS_SERVER__) {
if (this._globalCtx.IS_SERVER) {
await this.connect({host, port});
}
if (__IS_CLIENT__) {
await this.connect({host: __SERVER_HOST__, port: __SERVER_PORT__});
if (this._globalCtx.IS_CLIENT) {
await this.connect({host: this._globalCtx.SERVER_HOST, port: this._globalCtx.SERVER_PORT});
}
this._socket.on('connect', () => {
if (typeof onConnected === 'function') {
onConnected((buffer) => {
if (buffer) {
const type = __IS_CLIENT__ ? PIPE_ENCODE : PIPE_DECODE;
const type = this._globalCtx.IS_CLIENT ? PIPE_ENCODE : PIPE_DECODE;
this.ctx.pipe.feed(type, buffer, {cid: this.ctx.proxyRequest.cid, host, port});
}
});
@ -345,11 +345,11 @@ export class TcpOutbound extends Outbound {
}
onPresetPauseSend() {
__IS_SERVER__ && (this._socket && this._socket.pause());
this._globalCtx.IS_SERVER && (this._socket && this._socket.pause());
}
onPresetResumeSend() {
__IS_SERVER__ && (this._socket && this._socket.resume());
this._globalCtx.IS_SERVER && (this._socket && this._socket.resume());
}
async connect({host, port}) {
@ -364,7 +364,7 @@ export class TcpOutbound extends Outbound {
this._socket.on('timeout', this.onTimeout);
this._socket.on('data', this.onReceive);
this._socket.on('drain', this.onDrain);
this._socket.setTimeout(__TIMEOUT__);
this._socket.setTimeout(this._globalCtx.TIMEOUT);
}
async _connect({host, port}) {

@ -29,7 +29,7 @@ export class TlsOutbound extends TcpOutbound {
// overwrite _connect of tcp outbound using tls.connect()
async _connect({host, port}) {
logger.info(`[tls:outbound] [${this.remote}] connecting to tls://${host}:${port}`);
return tls.connect({host, port, ca: [__TLS_CERT__]});
return tls.connect({host, port, ca: [this._globalCtx.TLS_CERT]});
}
}

@ -18,7 +18,7 @@ export class UdpInbound extends Inbound {
}
onReceive(buffer, rinfo) {
const type = __IS_CLIENT__ ? PIPE_ENCODE : PIPE_DECODE;
const type = this._globalCtx.IS_CLIENT ? PIPE_ENCODE : PIPE_DECODE;
this._rinfo = rinfo;
this.ctx.pipe.feed(type, buffer);
}
@ -51,7 +51,7 @@ export class UdpInbound extends Inbound {
logger.warn(`[udp:inbound] [${this.remote}]:`, err);
}
};
if (__IS_CLIENT__) {
if (this._globalCtx.IS_CLIENT) {
const isSs = this.ctx.pipe.presets.some(({name}) => ['ss-base'].includes(name));
this._socket.send(buffer, port, address, isSs, onSendError);
} else {
@ -85,7 +85,7 @@ export class UdpOutbound extends Outbound {
}
onReceive(buffer) {
const type = __IS_CLIENT__ ? PIPE_DECODE : PIPE_ENCODE;
const type = this._globalCtx.IS_CLIENT ? PIPE_DECODE : PIPE_ENCODE;
this.ctx.pipe.feed(type, buffer);
}
@ -121,11 +121,11 @@ export class UdpOutbound extends Outbound {
onConnectToRemote(action) {
const {host, port, onConnected} = action.payload;
if (__IS_CLIENT__) {
this._targetHost = __SERVER_HOST__;
this._targetPort = __SERVER_PORT__;
if (this._globalCtx.IS_CLIENT) {
this._targetHost = this._globalCtx.SERVER_HOST;
this._targetPort = this._globalCtx.SERVER_PORT;
}
if (__IS_SERVER__) {
if (this._globalCtx.IS_SERVER) {
this._targetHost = host;
this._targetPort = port;
if (typeof onConnected === 'function') {

@ -3,17 +3,15 @@ import {getPresetClassByName} from '../../src/presets';
import {PIPE_ENCODE, PIPE_DECODE} from '../../src/constants';
import {Middleware} from '../../src/core/middleware';
export function setGlobals(obj) {
Object.assign(global, obj);
}
export class PresetRunner extends EventEmitter {
_ctx = null;
constructor({name, params = {}}, globals = {}) {
constructor({name, params = {}}, context = {}) {
super();
setGlobals(globals);
this._ctx = context;
getPresetClassByName(name).checkParams(params);
this.middleware = new Middleware({name, params});
this.middleware = new Middleware({name, params}, context);
}
notify(action) {
@ -34,7 +32,7 @@ export class PresetRunner extends EventEmitter {
this.middleware.on('fail', reject);
this.middleware.on('broadcast', (name, action) => this.emit('broadcast', action));
this.middleware.write({
direction: __IS_CLIENT__ ? PIPE_ENCODE : PIPE_DECODE,
direction: this._ctx.IS_CLIENT ? PIPE_ENCODE : PIPE_DECODE,
buffer: data,
direct: resolve,
isUdp
@ -52,7 +50,7 @@ export class PresetRunner extends EventEmitter {
this.middleware.on('fail', reject);
this.middleware.on('broadcast', (name, action) => this.emit('broadcast', action));
this.middleware.write({
direction: __IS_CLIENT__ ? PIPE_DECODE : PIPE_ENCODE,
direction: this._ctx.IS_CLIENT ? PIPE_DECODE : PIPE_ENCODE,
buffer: data,
direct: resolve,
isUdp

@ -14,8 +14,8 @@ test('running on both client and server', async () => {
acl: path.join(__dirname, 'acl.txt')
}
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
await sleep(20);

@ -7,9 +7,9 @@ test('running on client and server', async () => {
method: 'aes-128-gcm'
}
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
const packet_1 = await runner.forward('12');

@ -5,9 +5,9 @@ test('tcp relay on client and server', async () => {
let runner = new PresetRunner({
name: 'base-auth'
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
// client
@ -36,9 +36,9 @@ test('tcp relay on client and server', async () => {
runner = new PresetRunner({
name: 'base-auth'
}, {
__KEY__: 'secret',
__IS_CLIENT__: false,
__IS_SERVER__: true
KEY: 'secret',
IS_CLIENT: false,
IS_SERVER: true
});
runner.on('broadcast', (action) => {
@ -61,9 +61,9 @@ test('udp relay on client and server', async () => {
let runner = new PresetRunner({
name: 'base-auth'
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
// client
@ -86,9 +86,9 @@ test('udp relay on client and server', async () => {
runner = new PresetRunner({
name: 'base-auth'
}, {
__KEY__: 'secret',
__IS_CLIENT__: false,
__IS_SERVER__: true
KEY: 'secret',
IS_CLIENT: false,
IS_SERVER: true
});
runner.on('broadcast', (action) => {

@ -4,8 +4,8 @@ test('running on both client and server', async () => {
const runner = new PresetRunner({
name: 'obfs-random-padding'
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
const chunk = await runner.forward('12');

@ -7,9 +7,9 @@ test('tcp relay on client and server', async () => {
method: 'aes-128-gcm'
}
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
const packet_1 = await runner.forward('12');
@ -38,9 +38,9 @@ test('udp relay on client and server', async () => {
method: 'aes-128-gcm'
}
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
const packet = await runner.forwardUdp('12');

@ -5,8 +5,8 @@ test('running on client', async () => {
const runner = new PresetRunner({
name: 'ss-base'
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
runner.notify({
@ -40,8 +40,8 @@ test('running on server', async () => {
const runner = new PresetRunner({
name: 'ss-base'
}, {
__IS_CLIENT__: false,
__IS_SERVER__: true
IS_CLIENT: false,
IS_SERVER: true
});
runner.on('broadcast', (action) => {

@ -7,9 +7,9 @@ test('tcp relay on client and server', async () => {
method: 'aes-128-ctr'
}
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
// should add 16 more bytes at the beginning
@ -35,9 +35,9 @@ test('udp relay on client and server', async () => {
method: 'rc4-md5-6'
}
}, {
__KEY__: 'secret',
__IS_CLIENT__: true,
__IS_SERVER__: false
KEY: 'secret',
IS_CLIENT: true,
IS_SERVER: false
});
expect(await runner.forwardUdp('1')).toHaveLength(6 + 1);

@ -13,8 +13,8 @@ test('running on both client and server', async () => {
save_interval: 1
}
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
runner.notify({type: CONNECTION_CREATED});

@ -5,8 +5,8 @@ test('tcp relay on client and server', async () => {
const runner = new PresetRunner({
name: 'tracker'
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
const actionPayload = {
@ -33,8 +33,8 @@ test('udp relay on client and server', async () => {
const runner = new PresetRunner({
name: 'tracker'
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
expect(await runner.forwardUdp('12')).toMatchSnapshot();

@ -9,8 +9,8 @@ test('running on client', async () => {
security: 'aes-128-gcm'
}
}, {
__IS_CLIENT__: true,
__IS_SERVER__: false
IS_CLIENT: true,
IS_SERVER: false
});
runner.notify({
@ -40,8 +40,8 @@ test('running on server', async () => {
id: 'a3482e88-686a-4a58-8126-99c9df64b7bf'
}
}, {
__IS_CLIENT__: false,
__IS_SERVER__: true
IS_CLIENT: false,
IS_SERVER: true
});
// fail on wrong data