|
||
---|---|---|
.. | ||
architecture.png | ||
README.md |
Architecture
Proxy Protocols
To take over data send and receive of applications, we must find a widely used proxy protocol. Http/Socks5/Socks4/Socks4a are ideal, they only work on the client side, so don't worry about being attacked.
Pipe
Pipe is a duplex facility for dealing with data streaming. A pipe is created once a connection was open.
Pipe puts all middlewares in cascade(both upstream and downstream), feeds original data to the first middleware from time to time and gathers processed data from the last layer of all middlewares.
Middleware
Middleware is a class which used for processing input data to output data from/to different middlewares. There are four kind of middlewares:
- FrameMiddleware
The lowest layer in the middleware stack. It packs data from application, or unpacks data from CryptoMiddleware.
- CryptoMiddleware
The second layer in the middleware stack. It encrypts data from FrameMiddleware, or decrypts data from ProtocolMiddleware.
- ProtocolMiddleware
The third layer in the middleware stack. It encapsulates data with additional headers from CryptoMiddleware, or decapsulates data from ObfsMiddleware.
The additional headers may be used for AEAD or other needs.
- ObfsMiddleware
The last layer in the middleware stack. It encapsulates data with obfuscation headers from ProtocolMiddleware, or decapsulates data from network.
Preset
Preset is the implement of middleware, for examples you can check out src/presets, there are several built-in presets already:
- frame/*: implement for FrameMiddleware
- crypto/*: implement for CryptoMiddleware
- protocol/*: implement for ProtocolMiddleware
- obfs/*: implement for ObfsMiddleware
Custom Preset
A typical preset must implement four methods of IPreset interface:
// custom.js
export default class CustomPreset extends IPreset {
clientOut({buffer/* , next, broadcast, fail */}) {
// next(buffer); async
return buffer; // sync
}
serverIn({buffer/* , next, broadcast, fail */}) {
return buffer;
}
serverOut({buffer/* , next, broadcast, fail */}) {
return buffer;
}
clientIn({buffer/* , next, broadcast, fail */}) {
return buffer;
}
}
METHODS | DESCRIPTION |
---|---|
clientOut | client will send data to server |
serverIn | server received data from client |
serverOut | server will send back data to client |
clientIn | client received data from server |
NOTE:
server*
are used on the server side whileclient*
are used on the client side.
Every method gets an object which contains three parameters you need:
PARAM | DESCRIPTION |
---|---|
buffer | output from the previous middleware |
next | call it with a new buffer once async process done |
broadcast | call it with an action to notify other middlewares |
fail | call it once handshake failed, connection will be closed in random seconds |
Action passed to broadcast is an object which requires a type
field:
// action
{
type: <string>,
payload: <any>
}
Once a method broadcast, all other middlewares will receive the action in onNotified(action) immediately:
// custom.js
export default class CustomPreset extends IPreset {
/**
* how to deal with the action, return false to ignore
* @returns {boolean}
*/
onNotified(/* action */) {
return false;
}
// ...
}
Hooks
There are two hooks available:
// custom.js
export default class CustomPreset extends IPreset {
beforeOut({buffer/* , next, broadcast, fail */}) {
return buffer;
}
beforeIn({buffer/* , next, broadcast, fail */}) {
return buffer;
}
// ...
}
METHODS | DESCRIPTION |
---|---|
beforeOut | pre-process before *Out() |
beforeIn | pre-process before *In() |