尝试给 ssh 写一个 ProxyCommand
1 的实现的过程中发现:
- 如果是使用
ssh -W
,它可以顺利从终端中读取密码; - 如果是我自己的程序,则只能读取到主 ssh 发来的“版本号”。
我百思不得其解,不知问题在哪。 实际例子如下:
1 2 |
|
换成我自己的测试程序(从标准输入读取密码):
1 2 3 4 5 6 7 8 9 10 11 |
|
编译成 ./test
后尝试执行一下:
1 2 3 |
|
有点儿意外,但是读了上面 ProxyCommand
的原理文章后,又觉得没有那么奇怪:
启用 ProxyCommand
后,主 ssh 进程确实是通过 stdin/stdout
和 ProxyCommand 通信的,所以读取到版本号字符串理所当然。
翻源代码
但是 ssh -W
是怎么绕过标准输入并从终端读取到密码的呢?
然后我跑去看了一下 openssh 的源代码有没有对此种情形的 ssh 进行特殊处理,答案是:没有。
但是,在读密码函数处发现“奇怪”的地方,它读 /dev/tty
了:
75 76 77 78 79 80 81 82 83 84 85 86 87 |
|
答案揭晓:先读 /dev/tty
,不成功才读 stdin
。
至于 /dev/tty
是个什么东西?简单答约:当前进程的控制终端(键盘?),不管 stdin/stdout 有没有被重定向。
一些结论
输入来源 | 能否获取到终端用户的输入 | 举例 |
---|---|---|
os.Stdin |
❌ 不一定,因为可能被重定向 | 被 SSH 主进程用作数据通道以交换数据 |
/dev/tty |
✅ 一定连接到终端/键盘输入 | 不管标准输入是否被重定向,都能读取 |