それで、私は最近、TCPパケットを/dev/tcp/hostname/port
ファイルですが、ここでの主な問題は、それらを受け取る方法です。 TCPサーバーをホストできるbashスクリプトと、TCPクライアントとして別のスクリプトを作成します。いくつかの助けが必要です。また、私はこれを学習体験として行っていることに注意してください。そのため、必要なタスクを実行する方法としてssh
またはtelnet
を使用していません。
this によれば、いいえ。 bash
は bind(2)
ソケットを試行せず、 connect(2)
を試行するだけなので、これを行うことはできません。
netcat
サーバーを起動する方法をいくつか紹介します。
(私は nmap
のncat
を使用します-- GNU nc
は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
私はそこで:|
パイプを借りています-:
nullコマンドには確かに必要がないため、dash
がそれに書き込み、ncat
がそれを読み取ります。 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 $
+m
を使用する必要があるのは、-m
onitoredジョブ制御シェル--i
nteractive Shellのデフォルトで通常オンに設定されているように、その制御端末から読み取ろうとするためです。 SIGTTIN
が送信されます-デフォルトで自動的に一時停止します。それ以外の場合は(無視またはブロックしようとした場合)強制終了します。
[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | dash -i 2>&1; } 1<>/dev/fd/0
しかし、ここにはターミナルはありません-ls
の出力でわかるように、これらは単なるパイプです-したがって、-m
onitoringは実行できません。
bash
は、たとえ発生しても、readline
が無効になっていても、最初のインタラクティブな端末の関連付けに関して柔軟ではないようです。
[1] + Stopped(SIGTTIN) : | { ncat -l 9999 | bash --noediting +m -i 2>&1 ; } 1<>/dev/fd/0
じゃあ何をすればいいの?まあ、私たちは疑似端末が必要です。エミュレータにあるようなもの。
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
Linuxシステムの/dev/ptmx
マスターデバイスから取得できます(ただし、最初にtty
を使用したくない場合は、ユーザーがchown
グループのメンバーである必要があります。 )。 <
open(2)
ptmxデバイスの場合、新しい疑似端末が作成され、その後 unlockpt(3)
新しいデバイスファイルでは、読み書きできます。
少し前に、シェルでこれを行う簡単な方法はないことを知ったので、 私はそのための小さなCプログラムを作成しました です。いくつかの説明と簡単なビルド手順(実際にはシェルプロンプトへのコピー/貼り付け)がそのリンクにあります。これは、以下で使用するpts
プログラムです。
local $ { 9>&- setsid -c -- bash <> "$({ pts &&
local > >&9 ncat -l 9999 -k --allow localhost
local > } <&9 &)" 2>&0 >&2 ; } 9<> /dev/ptmx
local $
bash
が疑似ターミナルでセッションリーダーとして開始され、pts
がロック解除し、その標準出力に名前を付けます。これは、bash
のリダイレクトで<>
標準の代わりに使用されます。ただし、すべてのI/Oが別の場所(新しい疑似端末)に移動し、ポート9999で開始されたncat
サーバーが唯一のリンクであるため、何も起こりません。ここでは、-i
nteractiveスイッチは必要ありません- 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
まあ、もうすぐそこです。つまり、確実にsocketized -bash
を取得しましたが、おそらく奇妙なダブルエコーがあり、最後のプロンプトでの面白いエスケープは、実際には^上矢印キーを押すことです。ここでの問題は、2つのレベルの疑似端末があることです-私のncat
クライアントが実行されるものは、サーバーが実行されるものと同じstty echo
に設定されます。また、クライアント側の端末は行指向であり、入力改行ごとに1回出力をフラッシュし、デフォルトのstty echoctl
設定に従ってctrl-charエスケープも出力しているため、bash
は^上矢印キーをまったく受け取りません、そして私たちは面白い小さなエスケープだけを見ます。
OK。それにも対応できます。
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 > )
その関数は、その標準入力がターミナル(ローカルターミナル)であるかどうかをチェックし、そうでない場合は、ncat
クライアントへの入力をパススルーするだけです。しかし、そうであればtrap
[〜#〜] exit [〜#〜]、[〜#〜] hangup [〜#〜]、および[〜#〜] interrupt [〜#〜]シグナルは、終了時に標準でターミナル状態を復元します。標準入力でncat
を呼び出す前に状態を変更するので、これは良いことです。
ローカルエコーは無効になり、ローカルターミナルはそれ以外の場合はrawモードに設定されるため、キーを押すたびにncat
サーバーにすぐに送信されます。実際、すべての特別なローカルモードキーは無効になっています例外ローカルintr-通常CTRL+C
、ただしここではCTRL+A
に設定されています-CTRL+C
は、bash
サーバーによって解釈されます。
もう一度ls
を行いますが、^上矢印キーを押してから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 $
ローカルエコーが押されていると無効になっているため、そこには表示されませんが、CTRL+A
を押してセッションを中断し、ローカルプロンプトに戻ります。その時点で、すべてのローカル端末構成が権利に復元されます。ただし、bash
サーバーは残ります。そうすれば、ncatsh 9999
がすぐに戻ってきます。
bash
の仮想/dev/tcp/Host/port
ファイル(最初はksh機能)はconnectソケットからTCPポートへのソケット)にのみ使用できます。
リスニングソケットを作成したり、ソケットを受け入れたりするなど、さらに多くのことを実行したい場合は、リダイレクトではできません。
zsh
はzsh/net/tcp
モジュールとztcp
組み込み。
zmodload zsh/net/tcp
handle-connection() (
IFS= read -ru4 line || exit
print -r "Got: $line"
print -ru4 "Hello $line"
ztcp -c 4
)
ztcp -l -d 3 1234 # create a TCP listening socket on port 1234 on fd 3
while ztcp -ad4 3 # accept connection on fd 4
do handle-connection & exec 4>&-
done
バインドするアドレスやリッスンキューのサイズを指定したり、一方向のみをシャットダウンしたり、ソケットオプションを設定したりすることはできませんが、UDPやSCTPは実行できません(UNIXでも実行できます)。ただし、zsocket
コマンドを使用したドメインソケット)。
より洗練されたものが必要な場合、またはzshがない場合は、socat
を使用できます。たとえば、ここではbash
エクスポート関数を使用します。
handle_connection() {
IFS= read -r line &&
printf 'Hello %s\n' "$line"
}
export -f handle_connection
socat tcp-listen:1234,reuseaddr,fork 'exec:bash -c handle_connection'
socat
を使用すると、可能性は無限です。詳細については、manページを参照してください。
たとえば、サーバーがシェルセッションを生成する場合:
socat tcp-listen:1234,reuseaddr,fork exec:bash,pty,ctty,setsid,stderr,sane
クライアント側では、次のように接続します。
socat -,raw,echo=0 tcp:Host:1234
仕事を楽にするために、「netcat」ツールを使用してみてください。サーバーまたはクライアントとして使用でき、任意のデータを送受信できます。
低レベルのものを気にする必要はありません。
#server listening on port 8000/tcp
$>netcat -l 8000
#client sending stuff to localhost 8000/tcp
$>netcat localhost 8000
blah
最も簡単な方法は、次のように独自のxinetd
サービスを作成することです。
/etc/services
:
...
foo 500/tcp
...
/etc/xinetd.d/foo
:
service foo
{
disable = no
bind = 127.0.0.1
socket_type = stream
protocol = tcp
log_on_failure += USERID
server = /usr/local/lib/foo.sh
user = il
instances = UNLIMITED
wait = no
log_on_success =
}
/usr/local/lib/foo.sh
:
read ...
...
echo ...
したがって、シェルスクリプトは、stdin/stdoutがソケットに直接接続されているクライアント接続ごとに実行されます。