371 lines
9.1 KiB
JavaScript
371 lines
9.1 KiB
JavaScript
'use strict'
|
|
|
|
const assert = require('./assert-compat.js')
|
|
const { inspect } = require('util')
|
|
|
|
const { fixture, mustCall, mustCallAtLeast, setup: setup_ } = require('./common.js')
|
|
|
|
const debug = false
|
|
|
|
const clientCfg = { username: 'foo', password: 'bar' }
|
|
const serverCfg = { hostKeys: [fixture('ssh_host_rsa_key')] }
|
|
|
|
{
|
|
const { client, server } = setup_('Exec with OpenSSH agent forwarding', {
|
|
client: {
|
|
...clientCfg,
|
|
agent: '/path/to/agent'
|
|
},
|
|
server: serverCfg,
|
|
|
|
debug
|
|
})
|
|
|
|
server.on(
|
|
'connection',
|
|
mustCall((conn) => {
|
|
conn
|
|
.on(
|
|
'authentication',
|
|
mustCall((ctx) => {
|
|
ctx.accept()
|
|
})
|
|
)
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
conn.on(
|
|
'session',
|
|
mustCall((accept, reject) => {
|
|
let sawAuthAgent = false
|
|
accept()
|
|
.on(
|
|
'auth-agent',
|
|
mustCall((accept, reject) => {
|
|
sawAuthAgent = true
|
|
accept && accept()
|
|
})
|
|
)
|
|
.on(
|
|
'exec',
|
|
mustCall((accept, reject, info) => {
|
|
assert(sawAuthAgent, 'Expected auth-agent before exec')
|
|
assert(info.command === 'foo --bar', `Wrong exec command: ${info.command}`)
|
|
const stream = accept()
|
|
stream.exit(100)
|
|
stream.end()
|
|
conn.end()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
|
|
client.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
client.exec(
|
|
'foo --bar',
|
|
{ agentForward: true },
|
|
mustCall((err, stream) => {
|
|
assert(!err, `Unexpected exec error: ${err}`)
|
|
stream.resume()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
}
|
|
|
|
{
|
|
const { client, server } = setup_('OpenSSH forwarded UNIX socket connection', {
|
|
client: clientCfg,
|
|
server: {
|
|
...serverCfg,
|
|
ident: 'OpenSSH_7.1'
|
|
},
|
|
|
|
debug
|
|
})
|
|
|
|
const socketPath = '/foo'
|
|
const events = []
|
|
const expected = [
|
|
['client', 'openssh_forwardInStreamLocal'],
|
|
['server', '[email protected]', { socketPath }],
|
|
['client', 'forward callback'],
|
|
['client', 'unix connection', { socketPath }],
|
|
['client', 'socket data', '1'],
|
|
['server', 'socket data', '2'],
|
|
['client', 'socket end'],
|
|
['server', '[email protected]', { socketPath }],
|
|
['client', 'cancel callback']
|
|
]
|
|
|
|
server.on(
|
|
'connection',
|
|
mustCall((conn) => {
|
|
conn
|
|
.on(
|
|
'authentication',
|
|
mustCall((ctx) => {
|
|
ctx.accept()
|
|
})
|
|
)
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
conn.once(
|
|
'request',
|
|
mustCall((accept, reject, name, info) => {
|
|
events.push(['server', name, info])
|
|
assert(name === '[email protected]', `Wrong request name: ${name}`)
|
|
accept()
|
|
conn.openssh_forwardOutStreamLocal(
|
|
socketPath,
|
|
mustCall((err, ch) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
ch.write('1')
|
|
ch.on(
|
|
'data',
|
|
mustCallAtLeast((data) => {
|
|
events.push(['server', 'socket data', data.toString()])
|
|
ch.close()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
|
|
conn.on(
|
|
'request',
|
|
mustCall((accept, reject, name, info) => {
|
|
events.push(['server', name, info])
|
|
assert(
|
|
name === '[email protected]',
|
|
`Wrong request name: ${name}`
|
|
)
|
|
accept()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
|
|
client
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
// request forwarding
|
|
events.push(['client', 'openssh_forwardInStreamLocal'])
|
|
client.openssh_forwardInStreamLocal(
|
|
socketPath,
|
|
mustCall((err) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
events.push(['client', 'forward callback'])
|
|
})
|
|
)
|
|
client.on(
|
|
'unix connection',
|
|
mustCall((info, accept, reject) => {
|
|
events.push(['client', 'unix connection', info])
|
|
const stream = accept()
|
|
stream
|
|
.on(
|
|
'data',
|
|
mustCallAtLeast((data) => {
|
|
events.push(['client', 'socket data', data.toString()])
|
|
stream.write('2')
|
|
})
|
|
)
|
|
.on(
|
|
'end',
|
|
mustCall(() => {
|
|
events.push(['client', 'socket end'])
|
|
client.openssh_unforwardInStreamLocal(
|
|
socketPath,
|
|
mustCall((err) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
events.push(['client', 'cancel callback'])
|
|
client.end()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
.on(
|
|
'close',
|
|
mustCall(() => {
|
|
assert.deepStrictEqual(
|
|
events,
|
|
expected,
|
|
'Events mismatch\n' + `Actual:\n${inspect(events)}\n` + `Expected:\n${inspect(expected)}`
|
|
)
|
|
})
|
|
)
|
|
}
|
|
|
|
{
|
|
const { client, server } = setup_('OpenSSH UNIX socket connection', {
|
|
client: clientCfg,
|
|
server: {
|
|
...serverCfg,
|
|
ident: 'OpenSSH_8.0'
|
|
},
|
|
|
|
debug
|
|
})
|
|
|
|
const socketPath = '/foo/bar/baz'
|
|
const response = 'Hello World'
|
|
|
|
server.on(
|
|
'connection',
|
|
mustCall((conn) => {
|
|
conn
|
|
.on(
|
|
'authentication',
|
|
mustCall((ctx) => {
|
|
ctx.accept()
|
|
})
|
|
)
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
conn.on(
|
|
'openssh.streamlocal',
|
|
mustCall((accept, reject, info) => {
|
|
assert.deepStrictEqual(info, { socketPath }, `Wrong info: ${inspect(info)}`)
|
|
|
|
const stream = accept()
|
|
stream
|
|
.on(
|
|
'close',
|
|
mustCall(() => {
|
|
client.end()
|
|
})
|
|
)
|
|
.end(response)
|
|
stream.resume()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
|
|
client.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
client.openssh_forwardOutStreamLocal(
|
|
socketPath,
|
|
mustCall((err, stream) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
let buf = ''
|
|
stream
|
|
.on(
|
|
'data',
|
|
mustCallAtLeast((data) => {
|
|
buf += data
|
|
})
|
|
)
|
|
.on(
|
|
'close',
|
|
mustCall(() => {
|
|
assert(buf === response, `Wrong response: ${inspect(buf)}`)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
}
|
|
|
|
{
|
|
const { client, server } = setup_('OpenSSH 5.x workaround for binding on port 0', {
|
|
client: clientCfg,
|
|
server: {
|
|
...serverCfg,
|
|
ident: 'OpenSSH_5.3'
|
|
},
|
|
|
|
debug
|
|
})
|
|
|
|
const boundAddr = 'good'
|
|
const boundPort = 1337
|
|
const tcpInfo = {
|
|
destIP: boundAddr,
|
|
destPort: boundPort,
|
|
srcIP: 'remote',
|
|
srcPort: 12345
|
|
}
|
|
|
|
server.on(
|
|
'connection',
|
|
mustCall((conn) => {
|
|
conn
|
|
.on(
|
|
'authentication',
|
|
mustCall((ctx) => {
|
|
ctx.accept()
|
|
})
|
|
)
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
conn.on(
|
|
'request',
|
|
mustCall((accept, reject, name, info) => {
|
|
assert(name === 'tcpip-forward', `Unexpected request: ${name}`)
|
|
assert(info.bindAddr === boundAddr, `Wrong addr: ${info.bindAddr}`)
|
|
assert(info.bindPort === 0, `Wrong port: ${info.bindPort}`)
|
|
accept(boundPort)
|
|
conn.forwardOut(
|
|
boundAddr,
|
|
0,
|
|
tcpInfo.srcIP,
|
|
tcpInfo.srcPort,
|
|
mustCall((err, ch) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
client.end()
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
|
|
client
|
|
.on(
|
|
'ready',
|
|
mustCall(() => {
|
|
// request forwarding
|
|
client.forwardIn(
|
|
boundAddr,
|
|
0,
|
|
mustCall((err, port) => {
|
|
assert(!err, `Unexpected error: ${err}`)
|
|
assert(port === boundPort, `Bad bound port: ${port}`)
|
|
})
|
|
)
|
|
})
|
|
)
|
|
.on(
|
|
'tcp connection',
|
|
mustCall((details, accept, reject) => {
|
|
assert.deepStrictEqual(details, tcpInfo, `Wrong tcp details: ${inspect(details)}`)
|
|
accept()
|
|
})
|
|
)
|
|
}
|