.. | ||
README.md |
Guideline
Proxy Application Data
+----------------+ HTTP/SOCKS +---------------------+
| applications |---------------->| blniksocks client |
+----------------+ +---------------------+
To take over data send and receive of applications, blinksocks implemented socks4(a)/socks5/HTTP protocols in src/proxies.
References
Hub
+----------+ +-----------+
| Conn_1 |<---+ +--->| Relay_1 |
+----------+ | +-------+ | +-----------+
| ... |<---+--->| Hub |<---+--->| ... |
+----------+ | +-------+ | +-----------+
| Conn_N |<---+ +--->| Relay_N |
+----------+ +-----------+
Hub
gathers connections from apps or clients, for each connection, it also creates an associate relay.
Relay
+-----------------------------------------------+
| Relay |
| +-----------+ +----------+ |
---->| Inbound |->| Pipe | |
| +-----------+ |----------| |
| | Preset | |
| |----------| |
| | Preset | |
| |----------| +------------+ |
| | ... |->| Outbound |---->
| +----------+ +------------+ |
+-----------------------------------------------+
Relay handle both inbound and outbound endpoints, the type of inbound or outbound can be different. Once a relay created, it also creates an associate pipe.
Pipe
Pipe is a director which handle a list of preset, transmit data from the previous preset to the next.
Similar to TCP/IP protocol stack, you can define your own protocol in each layer. Application data are processed step by step from the lowest layer to the top. Preset here act as specific layers in the stack.
Here is the original shadowsocks
protocol implementation constructed by the following preset list:
{
...
"presets": [
{"name": "ss-base", "params": {}},
{"name": "ss-stream-cipher", "params": {"method": "aes-256-cfb"}}
]
...
}
Pipe process data from ss-base
to ss-stream-cipher
:
+--------+----------------------------------------+
| IV | PAYLOAD |
+--------+----------------------------------------+ <-------+
| 16 | Variable | |
+--------+----------------------------------------+ |
|
{"name": "ss-stream-cipher", "params": {"method": "aes-256-cfb"}}
|
+------+----------+----------+-----------+ |
| ATYP | DST.ADDR | DST.PORT | PAYLOAD | |
+------+----------+----------+-----------+ <-------+
| 1 | Variable | 2 | Variable | |
+------+----------+----------+-----------+ |
|
{"name": "ss-base", "params": {}}
|
+-----------+ |
| DATA | |
Application Data -----> +-----------+ --------+
| Variable |
+-----------+
Preset
Preset implements a specific protocol, for examples you can check out src/presets.
Custom Preset
To custom a preset, create a class then extends IPreset interface:
// custom.js
import {IPreset} from './defs';
export default class CustomPreset extends IPreset {
// implement some of the methods you need
}
You are probably want to know the destination host and port when write your own preset, an action CONNECT_TO_REMOTE
will be emitted once pipe created, then you can access to them via action.payload
:
import {IPreset, CONNECT_TO_REMOTE} from './defs';
export default class CustomPreset extends IPreset {
onNotified(action) {
if (__IS_CLIENT__ && action.type === CONNECT_TO_REMOTE) {
// host and port are obtained from HTTP/SOCKS protocol
const {host, port} = action.payload;
// ...
}
}
// ...
}
Next, you can implement some of the following methods to control data flow:
METHODS | DESCRIPTION |
---|---|
clientOut | client received data from application, and ready to forward data to server |
serverIn | server received data from client, and ready to forward data to real destination |
serverOut | server received data from real destination, and ready to backward data to client |
clientIn | client received data from server, and ready to backward data to application |
beforeOut | before calling clientOut() or serverOut() |
beforeIn | before calling clientIn() or serverIn() |
Hint:
server*()
are running on the server side whileclient*()
are running on the client side.before*()
are running on both sides.
Every method gets an object which contains several parameters you may need:
PARAM | DESCRIPTION |
---|---|
buffer | output from the previous preset |
next(buffer, isReverse) | transmit processed buffer to the next preset. If isReverse is true, send data back to the previous preset |
broadcast(action) | broadcast an action to other presets |
direct(buffer, isReverse) | ignore the following presets, finish piping |
fail(message) | report an error message when the preset fail to process |
Check Parameters
Your presets may require several parameters, and you can validate them in constructor(params)
(every time a connection created)
or static checkParams(params)
(only once):
import {IPreset} from './defs';
export default class CustomPreset extends IPreset {
/**
* check params passed to the preset, if any errors, should throw directly
* @param params
*/
static checkParams(params) {
}
}
Performance Improvements
You can initialize some shared/immutable data among connections in static onInit(params)
to improve performance:
import {IPreset} from './defs';
export default class CustomPreset extends IPreset {
/**
* you can make some cache in this function
* @param params
*/
static onInit(params) {
}
}
Presets Decoupling
When communicate with other presets, you can pass an action to broadcast().
Action is a plain object which only requires a type
field:
// action
{
type: <string>,
...
}
When broadcast, all other presets will receive the action in onNotified(action) immediately:
import {IPreset} from './defs';
export default class CustomPreset extends IPreset {
/**
* how to deal with the action, return false/undefined to ignore
* @returns {boolean}
*/
onNotified(/* action */) {
return false;
}
// ...
}
NOTE:
onNotified
is synchronous.
Access User Configuration
You can access user configuration directly from global
in your preset:
import {IPreset} from './defs';
export default class CustomPreset extends IPreset {
constructor() {
super();
console.log(__KEY__);
}
}
available items
NAME |
---|
__IS_SERVER__ |
__IS_CLIENT__ |
__LOCAL_HOST__ |
__LOCAL_PORT__ |
__LOCAL_PROTOCOL__ |
__DSTADDR__ |
__SERVER_HOST__ |
__SERVER_PORT__ |
__SERVERS__ |
__KEY__ |
__PRESETS__ |
__DNS__ |
__DNS_EXPIRE__ |
__TRANSPORT__ |
__TLS_CERT__ |
__TLS_KEY__ |
__TIMEOUT__ |
__REDIRECT__ |
__LOG_PATH__ |
__LOG_LEVEL__ |
__LOG_MAX_DAYS__ |
__WORKERS__ |