Mercurial > public > mercurial-scm > hg
comparison tests/sshprotoext.py @ 36215:464bedc0fdb4
wireprotoserver: handle SSH protocol version 2 upgrade requests
This commit teaches the SSH server to recognize the "upgrade"
request line that clients send when they wish to switch the
channel to version 2 of the SSH protocol.
Servers don't honor upgrade requests unless an experimental config
option is set.
Since the built-in server now supports upgrade requests, our test
server to test the handshake has been deleted. Existing tests
use the built-in server and their output doesn't change.
The upgrade is handled in our state machine. The end result is a bit
wonky, as the server transitions back to version 1 state immediately
after upgrading. But this will change as soon as version 2 has an
actual protocol that differs from version 1.
Tests demonstrating that the new server is a bit more strict about
the upgrade handshake have been added.
Differential Revision: https://phab.mercurial-scm.org/D2204
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 12 Feb 2018 16:33:54 -0800 |
parents | 3b3a987bbbaa |
children | b4d85bc122bd |
comparison
equal
deleted
inserted
replaced
36214:3b3a987bbbaa | 36215:464bedc0fdb4 |
---|---|
53 rsp = wireproto.dispatch(self._repo, proto, b'between') | 53 rsp = wireproto.dispatch(self._repo, proto, b'between') |
54 wireprotoserver._sshv1respondbytes(self._fout, rsp.data) | 54 wireprotoserver._sshv1respondbytes(self._fout, rsp.data) |
55 | 55 |
56 super(prehelloserver, self).serve_forever() | 56 super(prehelloserver, self).serve_forever() |
57 | 57 |
58 class upgradev2server(wireprotoserver.sshserver): | |
59 """Tests behavior for clients that issue upgrade to version 2.""" | |
60 def serve_forever(self): | |
61 name = wireprotoserver.SSHV2 | |
62 l = self._fin.readline() | |
63 assert l.startswith(b'upgrade ') | |
64 token, caps = l[:-1].split(b' ')[1:] | |
65 assert caps == b'proto=%s' % name | |
66 | |
67 # Filter hello and between requests. | |
68 l = self._fin.readline() | |
69 assert l == b'hello\n' | |
70 l = self._fin.readline() | |
71 assert l == b'between\n' | |
72 l = self._fin.readline() | |
73 assert l == b'pairs 81\n' | |
74 self._fin.read(81) | |
75 | |
76 # Send the upgrade response. | |
77 proto = wireprotoserver.sshv1protocolhandler(self._ui, self._fin, | |
78 self._fout) | |
79 self._fout.write(b'upgraded %s %s\n' % (token, name)) | |
80 servercaps = wireproto.capabilities(self._repo, proto) | |
81 rsp = b'capabilities: %s' % servercaps.data | |
82 self._fout.write(b'%d\n' % len(rsp)) | |
83 self._fout.write(rsp) | |
84 self._fout.write(b'\n') | |
85 self._fout.flush() | |
86 | |
87 super(upgradev2server, self).serve_forever() | |
88 | |
89 def performhandshake(orig, ui, stdin, stdout, stderr): | 58 def performhandshake(orig, ui, stdin, stdout, stderr): |
90 """Wrapped version of sshpeer._performhandshake to send extra commands.""" | 59 """Wrapped version of sshpeer._performhandshake to send extra commands.""" |
91 mode = ui.config(b'sshpeer', b'handshake-mode') | 60 mode = ui.config(b'sshpeer', b'handshake-mode') |
92 if mode == b'pre-no-args': | 61 if mode == b'pre-no-args': |
93 ui.debug(b'sending no-args command\n') | 62 ui.debug(b'sending no-args command\n') |
116 | 85 |
117 if servermode == b'banner': | 86 if servermode == b'banner': |
118 wireprotoserver.sshserver = bannerserver | 87 wireprotoserver.sshserver = bannerserver |
119 elif servermode == b'no-hello': | 88 elif servermode == b'no-hello': |
120 wireprotoserver.sshserver = prehelloserver | 89 wireprotoserver.sshserver = prehelloserver |
121 elif servermode == b'upgradev2': | |
122 wireprotoserver.sshserver = upgradev2server | |
123 elif servermode: | 90 elif servermode: |
124 raise error.ProgrammingError(b'unknown server mode: %s' % servermode) | 91 raise error.ProgrammingError(b'unknown server mode: %s' % servermode) |
125 | 92 |
126 peermode = ui.config(b'sshpeer', b'mode') | 93 peermode = ui.config(b'sshpeer', b'mode') |
127 | 94 |