【问题标题】:Closing connections via s_client in a shell script在 shell 脚本中通过 s_client 关闭连接
【发布时间】:2013-04-13 08:12:15
【问题描述】:

我正在尝试在 shell 脚本中建立与 IMAP 服务器的连接。虽然我可以连接并发出命令,但适当地关闭连接似乎是不可能的。

这是我正在使用的测试命令:

openssl s_client -crlf -connect server:993 <<EOF
01 login USERNAME PASSWORD
02 LIST "" "*"
03 logout
EOF

因为一旦输入用完连接就会关闭,这发生在接收到任何输出之前,所以我永远不会收到所需的数据。

如果我添加选项-ign_eof 选项,它会忽略输入结束以保持连接打开,输出将根据需要返回。但是在连接关闭之后...

* BYE Logging out
03 OK Logout completed.

...s_client 保持活动状态,因此执行永远不会返回到脚本。

是否有解决方案会在服务器关闭连接时导致 s_client 终止?

或者是否有使用标准工具的替代方法?该脚本将在 Mac OS X、Debian 和 Redhat 衍生版本以及可能的 Android 终端仿真器上运行,因此我希望使用相当标准的工具来实现可移植性,而不是使用专门的软件包。

更新:我想出了一个我并不完全满意的答案,但它确实有效。它使用一个脚本将命令传送到 openssl,但随后进入一个无限循环以保持标准输入打开,直到它接收到一个告诉它退出的信号。这是我的测试脚本:

#!/bin/sh

if [ "$1" = "doit" ]; then
   trap "echo \"04 logout\"; exit" SIGUSR1
   echo "00 login USERNAME PASSWORD"
   echo "01 SELECT PID-$$"
   echo "02 SELECT FOLDER"
   echo "03 FETCH 1:* (BODY[HEADER.FIELDS (Subject)])"
   while :; do :; done
fi

MYFLAG=
$0 doit | openssl s_client -crlf -connect server:993 2>/dev/null | while read LINE; do
   LINE=`echo "$LINE" | tr -d '\r'`
   [ "${LINE:0:4}" = "* OK" ] && MYFLAG=Y 
   [ "${LINE:0:33}" = "01 NO Mailbox doesn't exist: PID-" ] && PID="${LINE##*PID-}"
   [ "$MYFLAG" ] && echo "$LINE"
   [ "$PID" -a "$LINE" = "03 OK Fetch completed." ] && kill -USR1 $PID
done
echo "Finished."

脚本使用参数调用自身以输出通过管道传输到 openssl 的 IMAP 命令,openssl 的输出通过管道传输到 read 循环中,以便对其进行处理。 MYFLAG 变量只是用来隐藏 openssl 输出的信息,只是回显服务器连接的输出。

我选择了一个包含脚本第二个实例的 PID 的虚拟文件夹名称作为将其传回的一种方式,显然临时文件会更好,但对于测试,我想保持所有内容自包含并能够看看发生了什么。

一旦显示获取信息并且服务器返回 OK 响应,它会向脚本的第二个实例发送 SIGUSR1 信号,然后发送注销消息并退出,关闭 stdin 导致 s_client 断开连接。

最初我在初始回显集中包含了04 logout 命令,但是当我这样做时,读取循环只显示到提取输出然后停止,它甚至没有显示操作的 OK 状态,虽然一切都收到了。

我还需要使用tr 去除尾随回车符,但如果我通过管道将 openssl 的输出通过管道传输,则读取循环不会收到任何内容。

【问题讨论】:

    标签: bash openssl


    【解决方案1】:

    您可以通过将输入定时到 openssl 来解决此问题。 我能想到的最简单的方法是使用一个将输入回显到标准输出的函数:

    #!/bin/sh
    
    imapscript () {
    echo '01 login USER PASSWD'
    echo '02 LIST "" "*"'
    echo '03 logout'
    while sleep 1; do
      echo "04 logout"
    done
    }
    
    imapscript | openssl s_client -crlf -connect server:993
    

    【讨论】:

    • 我有一个类似的想法,使用脚本来回显命令,但随后我有一个无限循环来保持连接处于活动状态,直到收到输入,然后我可以终止该脚本。我已经用我的测试脚本更新了这个问题。
    • 不确定我的解决方案有什么问题 - 我在 debian 和 OSX 上进行了测试,它的文件夹列表很好,然后退出;无需发送信号并终止,因为一旦服务器关闭连接并且您尝试发送一些东西(那是循环中的echo - 放任何你喜欢的东西,我只使用04 logout,因为它让我们更清楚真的很想做),s_client会因为socket关闭而退出。
    • 已经能够充分测试您的想法,这实际上要好得多。我不确定我做了什么不同,但是当我尝试这样的事情之前它有时会在FETCH 1:* (BODY[HEADER.FIELDS (Subject)])的结果中途关闭连接。您的解决方案似乎每次都有效,这正是我想要的。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 2012-12-14
    • 2015-02-09
    相关资源
    最近更新 更多