用 bash 编写 TCP 服务器

Spe*_*omb 7 bash tcp

所以,我最近发现了如何通过/dev/tcp/hostname/port文件发送 TCP 数据包,但我的主要问题是我如何接收它们。我想制作一个可以托管 TCP 服务器的 bash 脚本,以及另一个作为 TCP 客户端的脚本。一些帮助会很棒。我还想指出,我这样做是作为一种学习体验,这就是为什么我不使用sshtelnet作为执行我想要的任务的方式。

mik*_*erv 8

根据这个,没有。你不能这样做,因为bash不尝试bind(2)套接字,而只是尝试connect(2).

您可以通过以下几种方式启动netcat服务器:

(我使用nmap'sncat因为GNUnc自 2004 年以来没有看到更新)


local $ :|{  ncat -l 9999 --keep-open --allow localhost |
local >      PS1='ncat $ '  PS2='ncat > ' dash +m -i 2>&1
local >   }  1<>/dev/fd/0
[1] + Running  : | { ncat -l 9999 --keep-open --allow localhost | PS1='ncat $ ' PS2='ncat > ' dash +m -i 2>&1; } 1<>/dev/fd/0
Run Code Online (Sandbox Code Playgroud)

:|在那里借用了管道 -dash写出来并ncat读取它,因为:null 命令肯定不需要它。有时比mkfifo.

无论如何,关键是ncat写入的所有内容都通过管道传输到dash的标准输入,而dash写入的所有内容都通过管道传输到ncat的标准输入。不是bash,我知道,但我会做到的。但请注意,至少,该+m选项。


local $ ncat localhost 9999
ncat $ echo $0 $$
dash 31231
ncat $ ls -l /dev/fd/[012]
lr-x------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/0 -> pipe:[3563412]
l-wx------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/1 -> pipe:[3567682]
l-wx------ 1 mikeserv mikeserv 64 Dec 11 23:28 /dev/fd/2 -> pipe:[3567682]
ncat $ ^C
local $ 
Run Code Online (Sandbox Code Playgroud)

我必须使用 ,+m因为一个-monitored 作业控制的 shell - 通常默认情况下为交互式 shell 设置为 on -i- 会尝试从其控制终端读取并发送一个SIGTTIN- 默认情况下会自动挂起它,或者否则(如果它试图忽略或阻止它)杀死它。


[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | dash -i 2>&1; } 1<>/dev/fd/0
Run Code Online (Sandbox Code Playgroud)

但是这里没有终端——这些只是管道,正如你在ls输出中看到的那样——所以-m监控是不行的。

bash碰巧,即使readline禁用了它,它的初始交互式终端关联似乎也不那么灵活。


[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | bash --noediting +m -i 2>&1 ; } 1<>/dev/fd/0
Run Code Online (Sandbox Code Playgroud)

那么该怎么办?好吧,我们需要一个伪终端。类似于我们在模拟器中拥有的东西。


local $ ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/0 -> /dev/pts/0
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/1 -> /dev/pts/0
lrwx------ 1 mikeserv mikeserv 64 Dec 11 23:30 /dev/fd/2 -> /dev/pts/0
Run Code Online (Sandbox Code Playgroud)

我们可以从/dev/ptmxlinux 系统上的主设备获取一个(尽管tty如果您不想先chown成为该组的成员,您的用户可能需要成为该组的成员)。如果我们< open(2)使用 ptmx 设备,将创建一个新的伪终端,如果我们之后创建unlockpt(3)了新的设备文件,我们就可以读取和写入它。

前段时间我了解到使用 shell 并没有真正简单的方法来做到这一点,所以我为它编写了一个小 C 程序。您会在该链接中找到一些解释和简单的构建说明(实际上只是复制/粘贴到 shell 提示中) - 这是pts我在下面使用的程序。


local $ { 9>&- setsid -c -- bash <> "$({ pts && 
local >   >&9  ncat -l 9999 -k --allow localhost
local > } <&9  &)" 2>&0 >&2 ; } 9<> /dev/ptmx
local $
Run Code Online (Sandbox Code Playgroud)

有一个在伪终端上bash作为会话领导者启动,它pts解锁并命名其标准输出 - 替代<>重定向中的标准bash。但是,显然什么都没有发生,因为所有的 i/o 都在别处 - 到新的伪终端 - 唯一的链接是ncat在端口 9999 上启动的服务器。-i这里bash不需要交互式开关 -将自动在它自己的 pty。


local $ ncat localhost 9999
[mikeserv@desktop ~]$ echo hey
echo hey
hey
[mikeserv@desktop ~]$ ls -l /dev/fd/[012]
ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/0 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/1 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 00:27 /dev/fd/2 -> /dev/pts/4
[mikeserv@desktop ~]$ ^[[A^[[A
Run Code Online (Sandbox Code Playgroud)

好吧,我们快到了。所以我们肯定有一个 socketized- bash,但可能你注意到那里奇怪的双回声,最后一个提示中有趣的转义实际上是我按下了 ^up 箭头键。这里的问题是我们有两层伪终端——我的ncat客户端运行stty echo的一层设置为与服务器运行的一层相同。并且因为客户端是面向行的,并且每个输入换行符刷新一次输出,并且还根据默认stty echoctl设置打印 ctrl-char 转义符,所以bash根本不会收到 ^up 箭头键,我们只看到有趣的小逃亡。

好的。我们也可以处理。


local $ ncatsh()(
local >    ${2+":"} set  localhost "${1:?ncatsh(): No port number provided!}"
local >    stty="   stty -F'$(tty)'" || unset stty
local >    trap " ${stty- ncat '${1##*\'*}' '${2##*\'*}' </dev/null} \
local >           ${stty+$(for a in -g 'raw -echo isig intr "^A" quit "" susp ""'
local >                    do  eval "$stty $a";done)}
local >             trap - 0 1 2; exit"    0 1 2
local >    ncat  "$@"
local > )
Run Code Online (Sandbox Code Playgroud)

该函数将检查它的标准输入是否是一个终端——你的本地终端——如果不是,它只会将输入传递给ncat客户端。但如果是这样,它会trap退出发出EXITHANGUPINTERRUPT信号以恢复其标准的终端状态。这是一件好事,因为它也会在调用标准输入之前改变该状态ncat

本地回声被禁用,本地终端设置为原始模式 - 因此每次按键都会ncat立即发送到服务器。事实上,所有特殊的本地模式键都被禁用,除了本地intr - 通常是CTRL+C,但在这里配置为CTRL+A- 因为CTRL+C将由bash服务器解释。

我会再做ls一次,但只需按 ^up 箭头然后RETURN


local $ ncatsh 9999

[mikeserv@desktop ~]$ ls -l /dev/fd/[012]
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/0 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/1 -> /dev/pts/4
lrwx------ 1 mikeserv mikeserv 64 Dec 12 01:00 /dev/fd/2 -> /dev/pts/4
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$ ^C
[mikeserv@desktop ~]$
local $
Run Code Online (Sandbox Code Playgroud)

你在那里看不到它,因为按下时本地回显被禁用,但我按下CTRL+A中断会话并返回本地提示,此时所有本地终端配置都恢复到权限。该bash服务器遗体,不过,ncatsh 9999会带我右后卫,如果我将它。

  • 哇。我还没有那么高级。除了游戏服务器之外,没有人真正为我所描述的内容制作工具,这有点愚蠢。 (2认同)
  • 我必须在此忽略添加评论工具提示,并为这些宝石向您表示衷心的***感谢***。我只是偶然发现了这一点(同时仔细检查了 bash 的 /dev/tcp 是否可以绑定())并学到了五十个新东西。我喜欢使用 shell,这太棒了!再次感谢! (2认同)

ger*_* d. 3

为了简化您的工作,请尝试使用“netcat”工具。它可以用作服务器或客户端,并且能够发送和接收任意数据。

那就不用费心处理低级的东西了..

#server listening on port 8000/tcp
$>netcat -l 8000

#client sending stuff to localhost 8000/tcp
$>netcat localhost 8000
blah
Run Code Online (Sandbox Code Playgroud)