@ -6,9 +6,6 @@ var local;
var isPiped = ! process . stdin . isTTY ;
var localAddress ;
var localPort ;
var rejectUnauthorized ;
var servername ;
var sshProxy ;
function usage ( ) {
console . info ( "" ) ;
@ -20,127 +17,220 @@ function usage() {
console . info ( "" ) ;
}
function parseFlags ( ) {
process . argv . some ( function ( arg , i ) {
function parseFlags ( argv ) {
var args = argv . slice ( ) ;
var flags = { } ;
args . sort ( function ( a , b ) {
if ( '-' === a [ 0 ] ) {
if ( '-' === b [ 0 ] ) {
return 0 ;
}
return 1 ;
}
if ( '-' === b [ 0 ] ) {
return - 1 ;
}
return 0 ;
} ) ;
args . some ( function ( arg , i ) {
if ( /^-k|--?insecure$/ . test ( arg ) ) {
rejectUnauthorized = false ;
process . argv . splice ( i , 1 ) ;
flags . rejectUnauthorized = false ;
args . splice ( i , 1 ) ;
return true ;
}
} ) ;
process . argv . some ( function ( arg , i ) {
args . some ( function ( arg , i ) {
if ( /^--?servername$/ . test ( arg ) ) {
servername = process . argv [ i + 1 ] ;
if ( ! servername || /^-/ . test ( servername ) ) {
flags . servername = args [ i + 1 ] ;
if ( ! flags . servername || /^-/ . test ( flags . servername ) ) {
usage ( ) ;
process . exit ( 2 ) ;
}
process . argv . splice ( i , 2 ) ;
args . splice ( i , 2 ) ;
return true ;
}
} ) ;
process . argv . some ( function ( arg , i ) {
args . some ( function ( arg , i ) {
if ( /^--?p(ort)?$/ . test ( arg ) ) {
flags . port = args [ i + 1 ] ;
if ( ! flags . port || /^-/ . test ( flags . port ) ) {
usage ( ) ;
process . exit ( 201 ) ;
}
args . splice ( i , 2 ) ;
return true ;
}
} ) ;
args . some ( function ( arg , i ) {
if ( /^--?ssh$/ . test ( arg ) ) {
sshProxy = true ;
process . argv . splice ( i , 1 ) ;
process . argv [ 3 ] = '$' ;
flags . wrapSsh = true ;
args . splice ( i , 1 ) ;
return true ;
}
} ) ;
return {
flags : flags
, args : args
} ;
}
parseFlags ( ) ;
var sclient = require ( '../' ) ;
remote = ( process . argv [ 2 ] || '' ) . split ( ':' ) ;
local = ( process . argv [ 3 ] || '' ) . split ( ':' ) ;
function testRemote ( opts ) {
var emitter = new ( require ( 'events' ) . EventEmitter ) ( ) ;
if ( 'ssh' === remote [ 0 ] ) {
sshProxy = true ;
remote = local ;
local = [ '$' ] ;
} else if ( 'ssh' === local [ 0 ] ) {
sshProxy = true ;
local [ 0 ] = '$' ;
sclient . _ test ( opts ) . then ( function ( ) {
// connected successfully (and closed)
sclient . _ listen ( emitter , opts ) ;
} ) . catch ( function ( err ) {
// did not connect succesfully
sclient . _ listen ( emitter , opts ) ;
console . warn ( "[warn] '" + opts . remoteAddr + ":" + opts . remotePort
+ "' may not be accepting connections: " , err . toString ( ) , '\n' ) ;
} ) ;
emitter . once ( 'listening' , function ( opts ) {
console . info ( '[listening] ' + opts . remoteAddr + ":" + opts . remotePort
+ " <= " + opts . localAddress + ":" + opts . localPort ) ;
if ( opts . command ) {
var args = [
opts . remoteUser + 'localhost'
, '-p' , opts . localPort
// we're _inverse_ proxying ssh, so we must alias the serveranem and ignore the IP
, '-o' , 'HostKeyAlias=' + opts . remoteAddr
, '-o' , 'CheckHostIP=no'
] ;
var spawn = require ( 'child_process' ) . spawn ;
if ( 'rsync' === opts . command ) {
var remote = args . shift ( ) + ':' + opts . remotePath ;
args = [ remote , '-e' , 'ssh ' + args . join ( ' ' ) ] ;
}
args = args . concat ( opts . args ) ;
var child = spawn ( opts . command , args , { stdio : 'inherit' } ) ;
child . on ( 'exit' , function ( ) {
console . info ( 'closing...' ) ;
} ) ;
child . on ( 'close' , function ( ) {
opts . server . close ( ) ;
} ) ;
}
} ) ;
emitter . on ( 'connect' , function ( sock ) {
console . info ( '[connect] ' + sock . localAddress . replace ( '::1' , 'localhost' ) + ":" + sock . localPort
+ " => " + opts . remoteAddr + ":" + opts . remotePort ) ;
} ) ;
emitter . on ( 'remote-error' , function ( err ) {
console . error ( '[error] (remote) ' + err . toString ( ) ) ;
} ) ;
emitter . on ( 'local-error' , function ( err ) {
console . error ( '[error] (local) ' + err . toString ( ) ) ;
} ) ;
}
// arg 0 is node
// arg 1 is sclient
// arg 2 is remote
// arg 3 is local
if ( 4 !== process . argv . length ) {
if ( isPiped ) {
local = [ '|' ] ;
function main ( ) {
var cmd = parseFlags ( process . argv ) ;
var binParam ;
var remoteUser ;
// Re-arrange argument order for ssh
if ( cmd . flags . wrapSsh ) {
cmd . args . splice ( 3 , 0 , 'ssh' ) ;
} else if ( - 1 !== [ 'ssh' , 'rsync' ] . indexOf ( ( cmd . args [ 2 ] || '' ) . split ( ':' ) [ 0 ] ) ) {
cmd . flags . wrapSsh = true ;
binParam = cmd . args . splice ( 2 , 1 ) ;
cmd . args . splice ( 3 , 0 , binParam [ 0 ] ) ;
}
remoteUser = ( cmd . args [ 2 ] || '' ) . split ( '@' ) ;
if ( remoteUser [ 1 ] ) {
// has 'user@' in front
remote = ( remoteUser [ 1 ] || '' ) . split ( ':' ) ;
remoteUser = remoteUser [ 0 ] + '@' ;
} else {
// no 'user@' in front
remote = ( remoteUser [ 0 ] || '' ) . split ( ':' ) ;
remoteUser = '' ;
}
local = ( cmd . args [ 3 ] || '' ) . split ( ':' ) ;
if ( - 1 !== [ 'ssh' , 'rsync' ] . indexOf ( local [ 0 ] ) ) {
cmd . flags . wrapSsh = true ;
}
if ( cmd . flags . wrapSsh ) {
process . argv = cmd . args ;
} else if ( 4 !== cmd . args . length ) {
// arg 0 is node
// arg 1 is sclient
// arg 2 is remote
// arg 3 is local (or ssh or rsync)
if ( isPiped ) {
local = [ '|' ] ;
} else {
usage ( ) ;
process . exit ( 1 ) ;
}
}
// Check for the first argument (what to connect to)
if ( ! remote [ 0 ] ) {
usage ( ) ;
process . exit ( 1 ) ;
return ;
}
}
// Check for the first argument (what to connect to)
if ( ! remote [ 0 ] ) {
usage ( ) ;
return ;
}
if ( ! local [ 0 ] ) {
usage ( ) ;
return ;
}
if ( ! local [ 0 ] ) {
usage ( ) ;
return ;
}
if ( local [ 0 ] === String ( parseInt ( local [ 0 ] , 10 ) ) ) {
localPort = parseInt ( local [ 0 ] , 10 ) ;
localAddress = 'localhost' ;
} else {
localAddress = local [ 0 ] ; // potentially '-' or '|' or '$'
localPort = parseInt ( local [ 1 ] , 10 ) ;
}
// check if it looks like a port number
if ( local [ 0 ] === String ( parseInt ( local [ 0 ] , 10 ) ) ) {
localPort = parseInt ( local [ 0 ] , 10 ) ;
localAddress = 'localhost' ;
} else {
localAddress = local [ 0 ] ; // potentially '-' or '|' or '$'
localPort = parseInt ( local [ 1 ] , 10 ) ;
}
var rparts = remote [ 0 ] . split ( '@' ) ;
var username = rparts [ 1 ] ? ( rparts [ 0 ] + '@' ) : '' ;
var opts = {
remoteAddr : rparts [ 1 ] || rparts [ 0 ]
, remotePort : remote [ 1 ] || 443
, localAddress : localAddress
, localPort : localPort
, rejectUnauthorized : rejectUnauthorized
, servername : servername
, stdin : null
, stdout : null
} ;
if ( '-' === localAddress || '|' === localAddress ) {
opts . stdin = process . stdin ;
opts . stdout = process . stdout ;
// no need for port
} else if ( '$' === localAddress ) {
sshProxy = true ;
opts . localAddress = 'localhost' ;
opts . localPort = 0 ; // choose at random
} else if ( ! localPort ) {
usage ( ) ;
return ;
}
var opts = {
remoteUser : remoteUser
, remoteAddr : remote [ 0 ]
, remotePort : remote [ 1 ] || 443
, localAddress : localAddress
, localPort : localPort
, rejectUnauthorized : cmd . flags . rejectUnauthorized
, servername : cmd . flags . servername
, stdin : null
, stdout : null
} ;
var emitter = require ( '../' ) ( opts ) ;
emitter . once ( 'listening' , function ( opts ) {
var port = opts . localPort ;
console . info ( '[listening] ' + opts . remoteAddr + ":" + opts . remotePort
+ " <= " + opts . localAddress + ":" + opts . localPort ) ;
if ( sshProxy ) {
// TODO choose at random and connect to ssh after test
var spawn = require ( 'child_process' ) . spawn ;
var ssh = spawn ( 'ssh' , [
username + 'localhost'
, '-p' , port
// we're _inverse_ proxying ssh, so we must alias the serveranem and ignore the IP
, '-o' , 'HostKeyAlias=' + opts . remoteAddr
, '-o' , 'CheckHostIP=no'
] , { stdio : 'inherit' } ) ;
ssh . on ( 'exit' , function ( ) {
console . info ( 'shutting down...' ) ;
} ) ;
ssh . on ( 'close' , function ( ) {
opts . server . close ( ) ;
} ) ;
if ( '-' === localAddress || '|' === localAddress ) {
opts . stdin = process . stdin ;
opts . stdout = process . stdout ;
// no need for port
} else if ( - 1 !== [ 'ssh' , 'rsync' ] . indexOf ( localAddress ) ) {
cmd . flags . wrapSsh = true ;
opts . localAddress = 'localhost' ;
opts . localPort = local [ 1 ] || 0 ; // choose at random
opts . command = localAddress ;
opts . args = cmd . args . slice ( 4 ) ; // node, sclient, ssh, addr
if ( 'rsync' === opts . command ) {
opts . remotePath = opts . remotePort ;
opts . remotePort = 0 ;
}
if ( ! opts . remotePort ) {
opts . remotePort = cmd . flags . port || 443 ;
}
} else if ( ! localPort ) {
usage ( ) ;
return ;
}
} ) ;
testRemote ( opts ) ;
}
main ( ) ;