質問(TL;DR)
リモート転送用にポート(-R
オプションとも呼ばれる)が動的に割り当てられている場合、リモートシステムのスクリプト(たとえば、から始まる.bashrc
)がOpenSSHでどのポートを選択するかを決定しますか?
背景
私はOpenSSH(両端)を使用して他の複数のユーザーと共有する中央サーバーに接続します。私のリモートセッション(現在)の場合は、X、cup、およびpulseaudioを渡したいと思います。
最も簡単な方法は、-X
このオプションを使用してXを渡すことです。割り当てられたXアドレスは環境変数に保存されDISPLAY
、ほとんどの場合、対応するTCPポートを確認できます。しかし、XlibはDISPLAY
。
カップとパルスオーディオにも同様のメカニズムが必要です。これら2つのサービスの基本は、それぞれCUPS_SERVER
環境変数との形で存在しますPULSE_SERVER
。使用例は次のとおりです。
ssh -X -R12345:localhost:631 -R54321:localhost:4713 datserver
export CUPS_SERVER=localhost:12345
lowriter #and I can print using my local printer
lpr -P default -o Duplex=DuplexNoTumble minutes.pdf #printing through the tunnel
lpr -H localhost:631 -P default -o Duplex=DuplexNoTumble minutes.pdf #printing remotely
mpg123 mp3s/van_halen/jump.mp3 #annoy co-workers
PULSE_SERVER=localhost:54321 mpg123 mp3s/van_halen/jump.mp3 #listen to music through the tunnel
問題はそれを設定CUPS_SERVER
してPULSE_SERVER
正しく設定することです。
ポート転送が多いため、動的ポート割り当てが必要です。静的ポート割り当てはオプションではありません。
0
OpenSSHには、リモート転送用のバインドポートを指定して(-R
オプション)、リモートサーバーにポートを動的に割り当てるメカニズムがあります。次のコマンドを使用して、OpenSSHはカップとパルス転送用のポートを動的に割り当てます。
ssh -X -R0:localhost:631 -R0:localhost:4713 datserver
このコマンドを使用すると、次のものがssh
印刷されますSTDERR
。
Allocated port 55710 for remote forward to 127.0.0.1:4713
Allocated port 41273 for remote forward to 127.0.0.1:631
私が欲しい情報があります!最終的に私は以下を生成したいと思います。
export CUPS_SERVER=localhost:41273
export PULSE_SERVER=localhost:55710
ところで、「ポート割り当て済み...」メッセージがローカルコンピュータに生成され、リモートSTDERR
コンピュータからアクセスできない場所に送信されました。奇妙なことは、OpenSSHがポート転送に関する情報を取得する方法がないようです。
その情報を取得し、それをシェルスクリプトに入れて完全に設定CUPS_SERVER
し、PULSE_SERVER
リモートホストに配置するにはどうすればよいですか?
行き止まりの路地
私が見つけることができる唯一の簡単な方法は、sshd
ログから情報を読むことができるまで長い情報を追加することです。これは、root以外のユーザーが合理的にアクセスできるよりもはるかに多くの情報を公開するため、実現可能ではありません。
内部構造の良い表現を印刷する追加のエスケープシーケンスをサポートするためにOpenSSHをパッチするつもりですがpermitted_opens
、それが私が望むものであっても、まだサーバーからクライアント側のエスケープシーケンスにアクセスするスクリプトを作成することはできません。横。
もっと良い方法があります。
次の方法は非常に不安定なようで、ユーザーごとに1つのSSHセッションに制限されています。しかし、私には複数の同時セッションが必要で、他のユーザーにはより多くのセッションが必要です。しかし試してみました...
星が正しく並べ替えられたら、鶏の1〜2匹を犠牲にしてsshd
私のユーザーとして起動するのではなく、代わりに成功したログイン後に権限を放棄して次のことを悪用する可能性があります。
私のユーザーに属するすべてのリスニングソケットのポート番号のリストを取得します。
netstat -tlpen | grep ${UID} | sed -e 's/^.*:\([0-9]\+\) .*$/\1/'
私のユーザーが開始したプロセスに属するすべてのリスニングソケットのポート番号のリストを取得します。
lsof -u ${UID} 2>/dev/null | grep LISTEN | sed -e 's/.*:\([0-9]\+\) (LISTEN).*$/\1/'
最初のセットにはあるが2番目のセットにはないすべてのポートが転送されたポートである可能性が高く、実際にセットを引くとそれぞれ、
41273
およびXが生成されます。55710
6010
6010
DISPLAY
Xで識別されたポートを使用してください。41273
lpstat -h localhost:41273 -a
リターンのためカップポートです0
。55710
pactl -s localhost:55710 stat
リターンのためパルスポートです0
。 (私のクライアントのホスト名も印刷します!)
(集合減算を実行するには、sort -u
上記のコマンドラインからの出力を保存し、それを使用してcomm
減算を実行します。)
Pulseaudioを使用すると、クライアントを識別でき、すべての意図と目的のために、分離する必要があるSSHセッションを分離するためのアンカーポイントとして機能します。しかし、バインドする方法41273
と同じプロセス55710
が見つかりませんでした。この情報は、root以外のユーザーには公開されません。私が読みたい列には1つだけが表示されます(この特定の例では)。非常に近い...6010
sshd
netstat
-
PID/Program name
2339/54
答え1
残念ながら、以前はあなたの質問を見つけることができませんでしたが、ちょうどkamil-maciorowskiから本当に良い答えを受けました。
https://unix.stackexchange.com/a/584505/251179
要約すると、最初にデフォルト接続を確立し、それをバックグラウンドにしたままにしてから、2番目のコマンドを実行してポート転送を要求/設定するように-O *ctl_cmd*
設定します。forward
ssh -fNMS /path/to/socket user@server
port="$(ssh -S /path/to/socket -O forward -R 0:localhost:22 placeholder)"
$port
これにより、ローカルコンピュータとバックグラウンド接続が提供されます。
その後、$port
ローカルで使用したり、ssh
同じ制御ソケットを使用できるリモートサーバーでコマンドを再実行したりできます。
フラグは次のとおりです。
- - F= sshにバックグラウンドエントリをリクエストしてください。
- -N= リモートコマンドを実行しないでください。
- -中=接続共有のためにクライアントを「マスター」モードに切り替えます。
- -S= 共有接続に使用される制御ソケットの位置。
- - モールド= 基本プロセスでアクティブな接続の再利用を制御します。
私の場合、接続を確認するためにいくつかの項目を追加しました。
#!/bin/bash
#--------------------------------------------------
# Setup
#--------------------------------------------------
set -u;
tunnel_user="user";
tunnel_host="1.1.1.1";
local_port="22";
local_name="my-name";
path_key="$HOME/.ssh/tunnel_ed25519";
path_lock="/tmp/tunnel.${tunnel_host}.pid"
path_port="/tmp/tunnel.${tunnel_host}.port"
path_log="/tmp/tunnel.${tunnel_host}.log"
path_socket="/tmp/tunnel.${tunnel_host}.socket"
#--------------------------------------------------
# Key file
#--------------------------------------------------
if [ ! -f "${path_key}" ]; then
ssh-keygen -q -t ed25519 -f "${path_key}" -N "";
/usr/local/bin/tunnel-client-key.sh
# Sends the public key to a central server, also run via cron, so it can be added to ~/.ssh/authorized_keys
# curl -s --form-string "pass=${pass}" --form-string "name=$(local_name)" -F "key=@${path_key}.pub" "https://example.com/key/";
fi
#--------------------------------------------------
# Lock
#--------------------------------------------------
if [ -e "${path_lock}" ]; then
c=$(pgrep -F "${path_lock}" 2>/dev/null | wc -l);
# MacOS 10.15.4 does not support "-c" to count processes, or the full "--pidfile" flag.
else
c=0;
fi
if [[ "${c}" -gt 0 ]]; then
if tty -s; then
echo "Already running";
fi;
exit;
fi;
echo "$$" > "${path_lock}";
#--------------------------------------------------
# Port forward
#--------------------------------------------------
retry=0;
while true; do
#--------------------------------------------------
# Log cleanup
#--------------------------------------------------
if [ ! -f "${path_log}" ]; then
touch "${path_log}";
fi
tail -n 30 "${path_log}" > "${path_log}.tmp";
mv "${path_log}.tmp" "${path_log}";
#--------------------------------------------------
# Exit old sockets
#--------------------------------------------------
if [ -S "${path_socket}" ]; then
echo "$(date) : Exit" >> "${path_log}";
ssh -S "${path_socket}" -O exit placeholder;
fi
#--------------------------------------------------
# Lost lock
#--------------------------------------------------
if [ ! -e "${path_lock}" ] || ! grep -q "$$" "${path_lock}"; then
echo "$(date) : Lost Lock" >> "${path_log}";
exit;
fi
#--------------------------------------------------
# Master connection
#--------------------------------------------------
echo "$(date) : Connect ${retry}" >> "${path_log}";
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes -fNTMS "${path_socket}" -i "${path_key}" "${tunnel_user}@${tunnel_host}" >> "${path_log}" 2>&1;
#--------------------------------------------------
# Setup and keep checking the port forwarding
#--------------------------------------------------
old_port=0;
while ssh -S "${path_socket}" -O check placeholder 2>/dev/null; do
new_port=$(ssh -S "${path_socket}" -O forward -R "0:localhost:${local_port}" placeholder 2>&1);
if [[ "${new_port}" -gt 0 ]]; then
retry=0;
if [[ "${new_port}" -ne "${old_port}" ]]; then
ssh -i "${path_key}" "${tunnel_user}@${tunnel_host}" "tunnel.port.sh '${new_port}' '${local_name}'" >> "${path_log}" 2>&1;
# Tell remote server what the port is, and local_name.
# Don't use socket, it used "-N"; if done, a lost connection keeps sshd running on the remote host, even with ClientAliveInterval/ClientAliveCountMax.
echo "$(date) : ${new_port}" >> "${path_log}";
echo "${new_port}" > "${path_port}";
old_port="${new_port}";
sleep 1;
else
sleep 300; # Looks good, check again in 5 minutes.
fi
else # Not a valid port number (0, empty string, number followed by an error message, etc?)
ssh -S "${path_socket}" -O exit placeholder 2>/dev/null;
fi
done
#--------------------------------------------------
# Cleanup
#--------------------------------------------------
if [ ! -f "${path_port}" ]; then
rm "${path_port}";
fi
echo "$(date) : Disconnected" >> "${path_log}";
#--------------------------------------------------
# Delay before next re-try
#--------------------------------------------------
retry=$((retry+1));
if [[ $retry -gt 10 ]]; then
sleep 180; # Too many connection failures, try again in 3 minutes
else
sleep 5;
fi
done
答え2
ローカルクライアントにパイプを作成し、stderrをそのパイプにリダイレクトして同じ結果を得ました。このパイプもsshの入力にリダイレクトされました。失敗する可能性のある既知のポートを想定するために複数のSSH接続は必要ありません。これにより、ログインバナーと「割り当てられたポート###...」テキストがリモートホストにリダイレクトされます。
getsshport.sh
リダイレクトされた入力を読み取り、ポートを確認するリモートホストで実行される単純なスクリプトがホストにあります。このスクリプトが終了しない限り、SSHリモート転送は開いたままです。
地域側
mkfifo pipe
ssh -R "*:0:localhost:22" user@remotehost "~/getsshport.sh" 3>&1 1>&2 2>&3 < pipe | cat > pipe
3>&1 1>&2 2>&3
stderrをcatにパイプすることができ、sshのすべての一般的な出力がstderrに表示されるようにstderrとstdoutを置き換えるのは少しトリックです。
リモート側~/getsshport.sh
#!/bin/sh
echo "Connection from $SSH_CLIENT"
while read line
do
echo "$line" # echos everything sent back to the client
echo "$line" | sed -n "s/Allocated port \([0-9]*\) for remote forward to \(.*\)\:\([0-9]*\).*/client port \3 is on local port \1/p" >> /tmp/allocatedports
done
sshを介して送信する前に、「割り当てられたポート」メッセージをローカルに送信しようとしましたが、grep
パイプがstdinで開かれるのを待つsshブロックのように見えます。 grepは何かを受け取るまで書き込み用にパイプを開かないので、デフォルトではデッドロックが発生します。cat
しかし、同じ動作をするようには思えず、即時書き込みのためにパイプを開くと、sshは接続を開くことができます。
これはリモート側でも同じ問題です。なぜread
stdinの代わりにgrepを1行ずつ実行するのですか?そうしないと、SSHトンネルが閉じるまで「/tmp/allocationports」が記録されず、目的全体が失われます。
sshのstderrを同様のコマンドにパイプすることをお勧めします~/getsshport.sh
。コマンドを指定しないと、パイプのバナーテキストやその他のエントリがリモートシェルで実行されるためです。
答え3
両方持ってください(バージョン履歴参照、このバージョンSCPサーバー側の観点から見ると、もう少し簡単です。これが効果があります。ポイントは次のとおりです。
- ポート情報が利用可能な時期を検出する方法をサーバーに通知する環境変数をクライアントからサーバーに渡し、それを取得して使用します。
- ポート情報が利用可能になったら、それをクライアントからサーバーにコピーし、サーバーがそれを取得できるようにし(上記のパート1の助けを借りて)使用します。
まず、リモート側で設定するには環境変数転送を有効にする必要があります。SSHD構成:
sudo yourfavouriteeditor /etc/ssh/sshd_config
含まれている行を見つけてAcceptEnv
追加します(まだ追加していない場合は、右側のMY_PORT_FILE
セクションの下に追加)。Host
私にとって、その行は次のとおりです。
AcceptEnv LANG LC_* MY_PORT_FILE
再起動を忘れないでくださいSSHDこれを効果的にするため。
また、次のスクリプトが正常に動作するようにmkdir ~/portfiles
リモート側で実行してみてください!
その後、ローカルでスクリプトフラグメント
- stderrリダイレクト用の一時ファイル名の作成
- ファイルにコンテンツが含まれるのを待つバックグラウンドタスクを残します。
- リダイレクト時にファイル名を環境変数としてサーバーに渡すSSHファイルの標準エラー
- バックグラウンドジョブは、別の方法を使用してstderr一時ファイルをサーバー側にコピーするために続行されます。SCP
- さらに、バックグラウンドジョブはフラグファイルをサーバーにコピーし、stderrファイルが準備されたことを示します。
スクリプトの断片:
REMOTE=$USER@datserver
PORTFILE=`mktemp /tmp/sshdataserverports-$(hostname)-XXXXX`
test -e $PORTFILE && rm -v $PORTFILE
# EMPTYFLAG servers both as empty flag file for remote side,
# and safeguard for background job termination on this side
EMPTYFLAG=$PORTFILE-empty
cp /dev/null $EMPTYFLAG
# this variable has the file name sent over ssh connection
export MY_PORT_FILE=$(basename $PORTFILE)
# background job loop to wait for the temp file to have data
( while [ -f $EMPTYFLAG -a \! -s $PORTFILE ] ; do
sleep 1 # check once per sec
done
sleep 1 # make sure temp file gets the port data
# first copy temp file, ...
scp $PORTFILE $REMOTE:portfiles/$MY_PORT_FILE
# ...then copy flag file telling temp file contents are up to date
scp $EMPTYFLAG $REMOTE:portfiles/$MY_PORT_FILE.flag
) &
# actual ssh terminal connection
ssh -X -o "SendEnv MY_PORT_FILE" -R0:localhost:631 -R0:localhost:4713 $REMOTE 2> $PORTFILE
# remove files after connection is over
rm -v $PORTFILE $EMPTYFLAG
その後、正しいリモート側の断片.bashrc:
# only do this if subdir has been created and env variable set
if [ -d ~/portfiles -a "$MY_PORT_FILE" ] ; then
PORTFILE=~/portfiles/$(basename "$MY_PORT_FILE")
FLAGFILE=$PORTFILE.flag
# wait for FLAGFILE to get copied,
# after which PORTFILE should be complete
while [ \! -f "$FLAGFILE" ] ; do
echo "Waiting for $FLAGFILE..."
sleep 1
done
# use quite exact regexps and head to make this robust
export CUPS_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:631[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
export PULSE_SERVER=localhost:$(grep '^Allocated port [0-9]\+ .* localhost:4713[[:space:]]*$' "$PORTFILE" | head -1 | cut -d" " -f3)
echo "Set CUPS_SERVER and PULSE_SERVER"
# copied files served their purpose, and can be removed right away
rm -v -- "$PORTFILE" "$FLAGFILE"
fi
ノート:もちろん、上記のコードは徹底的にテストされておらず、さまざまなバグ、コピー&ペーストエラーなどが含まれる可能性があります。使ってみた人なら誰でももっとよく理解できるだろうが、自分の責任で使用してください!私はlocalhost接続を使ってテストし、私のテスト環境ではうまくいきました。 YMMV。
答え4
これは難しい問題です。SSH_CONNECTION
または、行に沿って追加のサーバー側処理がある場合はDISPLAY
良いですが、追加するのは簡単ではありません。問題の一部は、クライアントだけがローカル宛先をssh
知っていて(サーバーへの)要求パケットにはローカル宛先のみを知っていることです。リモートアドレスとポート。
ここにある他の答えには、このクライアントをキャプチャしてサーバーに送信する、あまりよくないさまざまなソリューションがあります。ここに別のアプローチがあります。正直言ってあまりきれいではありませんが、少なくとも醜い当事者はクライアント側に残ります;-)
- クライアント、
SendEnv
SSHを介してデフォルトで一部の環境変数を送信できるように追加/変更します(おそらくデフォルトではない可能性があります) AcceptEnv
サーバー側、同じ内容を許可する追加/変更(デフォルトでは有効になっていない可能性があります)- 動的にロードされたライブラリを使用してクライアントのstderr出力を監視
ssh
し、SSHクライアント環境を更新します。接続設定中 - 構成ファイル/ログインスクリプトで、サーバー側の環境変数を選択します。
ssh -vv ...
環境が交換される前にリモート転送が設定され、記録(確認とともに)されるため、これは機能します(幸いなことに現在では)。動的にロードされたライブラリはlibc関数write()
(ssh_confirm_remote_forward()
→→→)をキャプチャする必要があります。 ELFバイナリの関数を再コンパイルせずにリダイレクトまたはラップすることは、動的ライブラリの関数で同じことを行うよりもはるかに複雑です。logit()
do_log()
write()
クライアント.ssh/config
(またはコマンドライン-o SendEnv ...
)から
Host somehost
user whatever
SendEnv SSH_RFWD_*
サーバーでsshd_config
(root / admin変更が必要)
AcceptEnv LC_* SSH_RFWD_*
この方法はLinuxクライアントで動作し、サーバーで特別な作業を行う必要はなく、少し調整するだけで他の* nixでも動作します。少なくともOpenSSH 5.8p1から7.5p1まで動作します。
呼び出しのコンパイルgcc -Wall -shared -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c
:
LD_PRELOAD=./rfwd.so ssh -R0:127.0.0.1:4713 -R0:localhost:631 somehost
パスワード:
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
// gcc -Wall -shared -ldl -Wl,-soname,rfwd -o rfwd.so rfwd.c
#define DEBUG 0
#define dfprintf(fmt, ...) \
do { if (DEBUG) fprintf(stderr, "[%14s#%04d:%8s()] " fmt, \
__FILE__, __LINE__, __func__,##__VA_ARGS__); } while (0)
typedef ssize_t write_fp(int fd, const void *buf, size_t count);
static write_fp *real_write;
void myinit(void) __attribute__((constructor));
void myinit(void)
{
void *dl;
dfprintf("It's alive!\n");
if ((dl=dlopen(NULL,RTLD_NOW))) {
real_write=dlsym(RTLD_NEXT,"write");
if (!real_write) dfprintf("error: %s\n",dlerror());
dfprintf("found %p write()\n", (void *)real_write);
} else {
dfprintf(stderr,"dlopen() failed\n");
}
}
ssize_t write(int fd, const void *buf, size_t count)
{
static int nenv=0;
// debug1: Remote connections from 192.168.0.1:0 forwarded to local address 127.0.0.1:1000
// Allocated port 44284 for remote forward to 127.0.0.1:1000
// debug1: All remote forwarding requests processed
if ( (fd==2) && (!strncmp(buf,"Allocated port ",15)) ) {
char envbuf1[256],envbuf2[256];
unsigned int rport;
char lspec[256];
int rc;
rc=sscanf(buf,"Allocated port %u for remote forward to %256s",
&rport,lspec);
if ( (rc==2) && (nenv<32) ) {
snprintf(envbuf1,sizeof(envbuf1),"SSH_RFWD_%i",nenv++);
snprintf(envbuf2,sizeof(envbuf2),"%u %s",rport,lspec);
setenv(envbuf1,envbuf2,1);
dfprintf("setenv(%s,%s,1)\n",envbuf1,envbuf2);
}
}
return real_write(fd,buf,count);
}
(この方法を使用するシンボリックバージョン管理に関連するいくつかのglibcベアトラップがありますが、write()
この問題は存在しません。)
勇気がある場合は、setenv()
関連コードを取得してssh.c
ssh_confirm_remote_forward()
コールバック関数にパッチを適用できます。
これにより、という環境変数が設定されますSSH_RFWD_nnn
。構成ファイルでこれらの変数を確認してください。bash
for fwd in ${!SSH_RFWD_*}; do
IFS=" :" read lport rip rport <<< ${!fwd}
[[ $rport -eq "631" ]] && export CUPS_SERVER=localhost:$lport
# ...
done
指示:
- コードにエラーチェックがない
- 環境を変える可能スレッドに関連する問題が発生します。 PAMはスレッドを使用します。問題があるとは思わないが、まだテストしていない。
ssh
* local:port:remote:port* 形式の完全な転送は現在明示的に文書化されていませんが(必要に応じてdebug1
メッセージの追加解析が必要ですssh -v
)、ユースケースではこれを必要としません。
奇妙なことは、OpenSSHがポート転送に関する情報を取得する方法がないようです。
escapeを使用して(部分的に)対話的にこれを行うことができます。~#
奇妙なことに、実装はリスニングチャネルをスキップして開いている(TCP ESTABLISHEDなど)チャネルのみを一覧表示し、いずれにせよ有用なフィールドを印刷しません。バラよりchannels.c
channel_open_message()
スロットの詳細を印刷する関数をパッチすることはできますが、SSH_CHANNEL_PORT_LISTENER
これはローカル転送のみ可能ですチャンネル実際の状況と異なる今後)。あるいは、それらをパッチして、グローバル構造から両方の転送テーブルをダンプすることもできますoptions
。
#include "readconf.h"
Options options; /* extern */
[...]
snprintf(buf, sizeof buf, "Local forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_local_forwards; i++) {
snprintf(buf, sizeof buf, " #%d listen %s:%d connect %s:%d\r\n",i,
options.local_forwards[i].listen_host,
options.local_forwards[i].listen_port,
options.local_forwards[i].connect_host,
options.local_forwards[i].connect_port);
buffer_append(&buffer, buf, strlen(buf));
}
snprintf(buf, sizeof buf, "Remote forwards:\r\n");
buffer_append(&buffer, buf, strlen(buf));
for (i = 0; i < options.num_remote_forwards; i++) {
snprintf(buf, sizeof buf, " #%d listen %s:%d connect %s:%d\r\n",i,
options.remote_forwards[i].listen_host,
options.remote_forwards[i].listen_port,
options.remote_forwards[i].connect_host,
options.remote_forwards[i].connect_port);
buffer_append(&buffer, buf, strlen(buf));
}
これは「プログラミング方式」ソリューションではありませんが、うまく機能します。ただし、転送を動的に追加/削除すると、クライアントコードはリスト(~C
)を更新しません(ただし、ソースコードではXXXとして表示されます)。
サーバーがLinuxの場合、私が一般的に使用する別のオプションがありますが、リモート転送ではなくローカル転送用です。lo
127.0.0.1/8です。 Linuxでは、次のことができます。127/8のすべてのアドレスに透明にバインドしたがって、一意の127.xyzアドレスを使用している場合は、固定ポートを使用できます。例:
mr@local:~$ ssh -R127.53.50.55:44284:127.0.0.1:44284 remote
[...]
mr@remote:~$ ss -atnp src 127.53.50.55
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.53.50.55:44284 *:*
これは特権ポート<1024バインディングに依存し、OpenSSHはLinux機能をサポートせず、ほとんどのプラットフォームでハードコードされたUID検証機能を提供します。
オクテットを賢く選択すると(私の場合はASCII序数ニーモニック)、一日の終わりに混乱を解決するのに役立ちます。