2017-01-31 23:11:36 +00:00
const socks = require ( 'socksv5' ) ;
2018-09-09 19:42:34 +00:00
const Promise = require ( 'bluebird' ) ;
2018-09-09 05:45:12 +00:00
const { Server } = socks ;
2017-01-31 23:11:36 +00:00
2018-09-09 05:45:12 +00:00
class SOCKSServer extends Server {
2018-09-09 19:42:34 +00:00
async listen ( ) {
return await new Promise ( ( resolve , reject ) => {
let args = Array . from ( arguments ) ;
let inner _func = super . listen ;
args . push ( ( ) => {
let args = Array . from ( arguments ) ;
resolve . apply ( args ) ;
} ) ;
inner _func . apply ( this , args ) ;
} ) ;
}
2018-09-10 03:44:24 +00:00
authenticate _user ( username , password , callback ) {
2018-09-10 17:03:02 +00:00
let deny _un = this . proxy _by _name . deny _unidentified _users ;
2018-09-10 03:44:24 +00:00
// No username and deny unindentifed then deny
if ( ! username && deny _un ) callback ( false ) ;
// Otherwise if there is no username allow
else if ( ! username ) callback ( true ) ;
this . logger . verbose ( ` [socks]: connected attempted to instance " ${ username } " ` ) ;
let instance = this . tor _pool . instance _by _name ( username ) ;
// If a username is specified but no instances match that username deny
if ( ! instance )
return callback ( false ) ;
// Otherwise allow
2018-09-10 17:03:02 +00:00
callback ( true , true ) ;
2018-09-10 03:44:24 +00:00
}
2018-09-10 02:26:55 +00:00
constructor ( tor _pool , logger , proxy _by _name ) {
2017-02-26 21:07:47 +00:00
let handleConnection = ( info , accept , deny ) => {
2017-01-31 23:11:36 +00:00
let inbound _socket = accept ( true ) ;
2018-09-10 03:44:24 +00:00
let instance ;
if ( inbound _socket . user )
2018-09-10 17:03:02 +00:00
instance = this . tor _pool . instance _by _name ( inbound _socket . user ) ;
2018-09-10 03:44:24 +00:00
let outbound _socket ;
2017-01-31 23:11:36 +00:00
let buffer = [ ] ;
2017-03-26 01:14:46 +00:00
let onInboundData = ( data ) => buffer . push ( data )
let onClose = ( error ) => {
inbound _socket && inbound _socket . end ( ) ;
outbound _socket && outbound _socket . end ( ) ;
2017-03-26 01:02:56 +00:00
2017-03-26 01:14:46 +00:00
inbound _socket = outbound _socket = buffer = void ( 0 ) ;
2017-03-26 01:02:56 +00:00
2017-03-26 01:14:46 +00:00
if ( error )
this . logger . error ( ` [socks]: an error occured: ${ error . message } ` )
} ;
2017-03-26 01:02:56 +00:00
2017-03-26 01:14:46 +00:00
if ( ! inbound _socket ) return ;
2017-03-26 01:02:56 +00:00
2017-03-26 01:14:46 +00:00
inbound _socket . on ( 'close' , onClose ) ;
inbound _socket . on ( 'data' , onInboundData ) ;
inbound _socket . on ( 'error' , onClose ) ;
2017-03-26 01:02:56 +00:00
2017-03-26 01:14:46 +00:00
let connect = ( tor _instance ) => {
2018-09-10 17:03:02 +00:00
let source = { hostname : info . srcAddr , port : info . srcPort , proto : 'socks' , by _name : Boolean ( instance ) } ;
2017-03-26 01:14:46 +00:00
let socks _port = tor _instance . socks _port ;
2018-09-10 17:03:02 +00:00
this . emit ( 'instance-connection' , tor _instance , source ) ;
this . logger . verbose ( ` [socks]: ${ source . hostname } : ${ source . port } → 127.0.0.1: ${ socks _port } ${ tor _instance . definition . Name ? ' (' + tor _instance . definition . Name + ')' : '' } → ${ info . dstAddr } : ${ info . dstPort } ` )
2017-03-26 01:02:56 +00:00
2018-08-09 17:42:11 +00:00
socks . connect ( {
host : info . dstAddr ,
port : info . dstPort ,
proxyHost : '127.0.0.1' ,
proxyPort : socks _port ,
localDNS : false ,
auths : [ socks . auth . None ( ) ]
} , ( $outbound _socket ) => {
outbound _socket = $outbound _socket ;
outbound _socket && outbound _socket . on ( 'close' , onClose ) ;
inbound _socket && inbound _socket . removeListener ( 'data' , onInboundData ) ;
inbound _socket && inbound _socket . on ( 'data' , ( data ) => {
outbound _socket && outbound _socket . write ( data ) ;
} ) ;
outbound _socket && outbound _socket . on ( 'data' , ( data ) => {
inbound _socket && inbound _socket . write ( data ) ;
} ) ;
outbound _socket && outbound _socket . on ( 'error' , onClose ) ;
while ( buffer && buffer . length && outbound _socket ) {
outbound _socket . write ( buffer . shift ( ) ) ;
}
2017-03-26 01:02:56 +00:00
} ) ;
2017-01-31 23:11:36 +00:00
} ;
2018-09-10 03:44:24 +00:00
if ( instance ) {
if ( instance . ready ) {
connect ( instance ) ;
}
else {
this . logger . debug ( ` [socks]: a connection has been attempted to " ${ instance . instance _name } ", but it is not live... waiting for the instance to come online ` ) ;
instance . once ( 'ready' , ( ( ) => connect ( instance ) ) ) ;
}
}
else if ( this . tor _pool . instances . length ) {
connect ( this . tor _pool . next ( ) ) ;
2017-03-26 01:02:56 +00:00
} else {
2018-09-09 19:42:34 +00:00
this . logger . debug ( ` [socks]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online ` ) ;
2018-09-10 03:44:24 +00:00
this . tor _pool . once ( 'instance_created' , connect ) ;
2017-03-26 01:02:56 +00:00
}
2017-02-26 21:07:47 +00:00
} ;
super ( handleConnection ) ;
2017-01-31 23:11:36 +00:00
2018-09-10 03:44:24 +00:00
let auth = socks . auth . None ( ) ;
2018-09-10 17:03:02 +00:00
if ( proxy _by _name ) {
auth = socks . auth . UserPassword ( this . authenticate _user . bind ( this ) ) ;
2018-09-10 02:26:55 +00:00
}
this . useAuth ( auth ) ;
2018-09-10 17:03:02 +00:00
this . logger = logger || require ( './winston-silent-logger' ) ;
this . tor _pool = tor _pool ;
this . proxy _by _name = proxy _by _name ;
this . logger . debug ( ` [socks]: connecting to a specific instance by name has ben turned ${ proxy _by _name ? 'on' : 'off' } ` ) ;
2017-01-31 23:11:36 +00:00
}
} ;
module . exports = SOCKSServer ;