test-openssh.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. 'use strict';
  2. const assert = require('assert');
  3. const { inspect } = require('util');
  4. const {
  5. fixture,
  6. mustCall,
  7. mustCallAtLeast,
  8. setup: setup_,
  9. } = require('./common.js');
  10. const debug = false;
  11. const clientCfg = { username: 'foo', password: 'bar' };
  12. const serverCfg = { hostKeys: [ fixture('ssh_host_rsa_key') ] };
  13. {
  14. const { client, server } = setup_(
  15. 'Exec with OpenSSH agent forwarding',
  16. {
  17. client: {
  18. ...clientCfg,
  19. agent: '/path/to/agent',
  20. },
  21. server: serverCfg,
  22. debug,
  23. },
  24. );
  25. server.on('connection', mustCall((conn) => {
  26. conn.on('authentication', mustCall((ctx) => {
  27. ctx.accept();
  28. })).on('ready', mustCall(() => {
  29. conn.on('session', mustCall((accept, reject) => {
  30. let sawAuthAgent = false;
  31. accept().on('auth-agent', mustCall((accept, reject) => {
  32. sawAuthAgent = true;
  33. accept && accept();
  34. })).on('exec', mustCall((accept, reject, info) => {
  35. assert(sawAuthAgent, 'Expected auth-agent before exec');
  36. assert(info.command === 'foo --bar',
  37. `Wrong exec command: ${info.command}`);
  38. const stream = accept();
  39. stream.exit(100);
  40. stream.end();
  41. conn.end();
  42. }));
  43. }));
  44. }));
  45. }));
  46. client.on('ready', mustCall(() => {
  47. client.exec('foo --bar', { agentForward: true }, mustCall((err, stream) => {
  48. assert(!err, `Unexpected exec error: ${err}`);
  49. stream.resume();
  50. }));
  51. }));
  52. }
  53. {
  54. const { client, server } = setup_(
  55. 'OpenSSH forwarded UNIX socket connection',
  56. {
  57. client: clientCfg,
  58. server: {
  59. ...serverCfg,
  60. ident: 'OpenSSH_7.1',
  61. },
  62. debug,
  63. },
  64. );
  65. const socketPath = '/foo';
  66. const events = [];
  67. const expected = [
  68. ['client', 'openssh_forwardInStreamLocal'],
  69. ['server', 'streamlocal-forward@openssh.com', { socketPath }],
  70. ['client', 'forward callback'],
  71. ['client', 'unix connection', { socketPath }],
  72. ['client', 'socket data', '1'],
  73. ['server', 'socket data', '2'],
  74. ['client', 'socket end'],
  75. ['server', 'cancel-streamlocal-forward@openssh.com', { socketPath }],
  76. ['client', 'cancel callback']
  77. ];
  78. server.on('connection', mustCall((conn) => {
  79. conn.on('authentication', mustCall((ctx) => {
  80. ctx.accept();
  81. })).on('ready', mustCall(() => {
  82. conn.once('request', mustCall((accept, reject, name, info) => {
  83. events.push(['server', name, info]);
  84. assert(name === 'streamlocal-forward@openssh.com',
  85. `Wrong request name: ${name}`);
  86. accept();
  87. conn.openssh_forwardOutStreamLocal(socketPath,
  88. mustCall((err, ch) => {
  89. assert(!err, `Unexpected error: ${err}`);
  90. ch.write('1');
  91. ch.on('data', mustCallAtLeast((data) => {
  92. events.push(['server', 'socket data', data.toString()]);
  93. ch.close();
  94. }));
  95. }));
  96. conn.on('request', mustCall((accept, reject, name, info) => {
  97. events.push(['server', name, info]);
  98. assert(name === 'cancel-streamlocal-forward@openssh.com',
  99. `Wrong request name: ${name}`);
  100. accept();
  101. }));
  102. }));
  103. }));
  104. }));
  105. client.on('ready', mustCall(() => {
  106. // request forwarding
  107. events.push(['client', 'openssh_forwardInStreamLocal']);
  108. client.openssh_forwardInStreamLocal(socketPath, mustCall((err) => {
  109. assert(!err, `Unexpected error: ${err}`);
  110. events.push(['client', 'forward callback']);
  111. }));
  112. client.on('unix connection', mustCall((info, accept, reject) => {
  113. events.push(['client', 'unix connection', info]);
  114. const stream = accept();
  115. stream.on('data', mustCallAtLeast((data) => {
  116. events.push(['client', 'socket data', data.toString()]);
  117. stream.write('2');
  118. })).on('end', mustCall(() => {
  119. events.push(['client', 'socket end']);
  120. client.openssh_unforwardInStreamLocal(socketPath,
  121. mustCall((err) => {
  122. assert(!err, `Unexpected error: ${err}`);
  123. events.push(['client', 'cancel callback']);
  124. client.end();
  125. }));
  126. }));
  127. }));
  128. })).on('close', mustCall(() => {
  129. assert.deepStrictEqual(
  130. events,
  131. expected,
  132. 'Events mismatch\n'
  133. + `Actual:\n${inspect(events)}\n`
  134. + `Expected:\n${inspect(expected)}`
  135. );
  136. }));
  137. }
  138. {
  139. const { client, server } = setup_(
  140. 'OpenSSH UNIX socket connection',
  141. {
  142. client: clientCfg,
  143. server: {
  144. ...serverCfg,
  145. ident: 'OpenSSH_8.0',
  146. },
  147. debug,
  148. },
  149. );
  150. const socketPath = '/foo/bar/baz';
  151. const response = 'Hello World';
  152. server.on('connection', mustCall((conn) => {
  153. conn.on('authentication', mustCall((ctx) => {
  154. ctx.accept();
  155. })).on('ready', mustCall(() => {
  156. conn.on('openssh.streamlocal', mustCall((accept, reject, info) => {
  157. assert.deepStrictEqual(
  158. info,
  159. { socketPath },
  160. `Wrong info: ${inspect(info)}`
  161. );
  162. const stream = accept();
  163. stream.on('close', mustCall(() => {
  164. client.end();
  165. })).end(response);
  166. stream.resume();
  167. }));
  168. }));
  169. }));
  170. client.on('ready', mustCall(() => {
  171. client.openssh_forwardOutStreamLocal(socketPath, mustCall((err, stream) => {
  172. assert(!err, `Unexpected error: ${err}`);
  173. let buf = '';
  174. stream.on('data', mustCallAtLeast((data) => {
  175. buf += data;
  176. })).on('close', mustCall(() => {
  177. assert(buf === response, `Wrong response: ${inspect(buf)}`);
  178. }));
  179. }));
  180. }));
  181. }
  182. {
  183. const { client, server } = setup_(
  184. 'OpenSSH 5.x workaround for binding on port 0',
  185. {
  186. client: clientCfg,
  187. server: {
  188. ...serverCfg,
  189. ident: 'OpenSSH_5.3',
  190. },
  191. debug,
  192. },
  193. );
  194. const boundAddr = 'good';
  195. const boundPort = 1337;
  196. const tcpInfo = {
  197. destIP: boundAddr,
  198. destPort: boundPort,
  199. srcIP: 'remote',
  200. srcPort: 12345,
  201. };
  202. server.on('connection', mustCall((conn) => {
  203. conn.on('authentication', mustCall((ctx) => {
  204. ctx.accept();
  205. })).on('ready', mustCall(() => {
  206. conn.on('request', mustCall((accept, reject, name, info) => {
  207. assert(name === 'tcpip-forward', `Unexpected request: ${name}`);
  208. assert(info.bindAddr === boundAddr, `Wrong addr: ${info.bindAddr}`);
  209. assert(info.bindPort === 0, `Wrong port: ${info.bindPort}`);
  210. accept(boundPort);
  211. conn.forwardOut(boundAddr,
  212. 0,
  213. tcpInfo.srcIP,
  214. tcpInfo.srcPort,
  215. mustCall((err, ch) => {
  216. assert(!err, `Unexpected error: ${err}`);
  217. client.end();
  218. }));
  219. }));
  220. }));
  221. }));
  222. client.on('ready', mustCall(() => {
  223. // request forwarding
  224. client.forwardIn(boundAddr, 0, mustCall((err, port) => {
  225. assert(!err, `Unexpected error: ${err}`);
  226. assert(port === boundPort, `Bad bound port: ${port}`);
  227. }));
  228. })).on('tcp connection', mustCall((details, accept, reject) => {
  229. assert.deepStrictEqual(
  230. details,
  231. tcpInfo,
  232. `Wrong tcp details: ${inspect(details)}`
  233. );
  234. accept();
  235. }));
  236. }