空きポートを検索する
通信に割り当てるポートの範囲が事前に定義されている
インターネットプロトコル(IP)を用いた通信を行うため、TCP/IPプロトコルスタックが事前に定義されている範囲内から自動的に割り当てるポートをエフェメラルポートという。
RFC 6056ではポート番号1024から65535までの範囲を使うよう提言されている。
自動割り当て可能なポートの範囲を取得する
Linuxでは/proc/sys/net/ipv4/ip_local_port_rangeでエフェメラルポートの範囲を取得できる。
$ docker run -it debian:bookworm cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
macOSではsysctlコマンドでエフェメラルポートの範囲を取得できる。
$ sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535
ランダムなポートを取得する
Linuxではshufコマンドでランダムなポートを取得できる。
$ docker run -it debian:bookworm sh -c "shuf -i \$(cat /proc/sys/net/ipv4/ip_local_port_range | awk '{print \$1 \"-\" \$2}') -n 1"
51234
macOSではjotコマンドでランダムなポートを取得できる。
$ jot -r 1 $(sysctl net.inet.ip.portrange.first | awk '{print $2}') $(sysctl net.inet.ip.portrange.last | awk '{print $2}')
51234
自動割り当て可能なポートの範囲内で空きポートを検索する
ssコマンドはソケットの統計情報を表示するコマンドでnetstatコマンドと同様の情報を表示でき、使用中のソケットが返されるため空きポートの検索に使用できる。
$ docker run -it debian:bookworm sh -c "\
apt-get update && apt-get install -y --no-install-recommends iproute2 ; \
for port in \$(shuf -i \$(cat /proc/sys/net/ipv4/ip_local_port_range | awk '{print \$1 \"-\" \$2}') -n 100) ; \
do ss -H -ltn \"sport = :\$port\" | grep -q . > /dev/null || break ; done ; \
echo \$port"
51234
ncコマンドはネットワーク診断ツールでポートが使用中かどうかを確認できる。
$ docker run -it debian:bookworm sh -c "\
apt-get update && apt-get install -y --no-install-recommends netcat-openbsd ; \
for port in \$(shuf -i \$(cat /proc/sys/net/ipv4/ip_local_port_range | awk '{print \$1 \"-\" \$2}') -n 100) ; \
do nc -z localhost \$port > /dev/null || break ; done ; \
echo \$port"
51234
macOSではnetstatコマンドとncコマンドが標準搭載されているため空きポートの検索に使用できる。
for port in $(jot -r 100 $(sysctl net.inet.ip.portrange.first | awk '{print $2}') $(sysctl net.inet.ip.portrange.last | awk '{print $2}'))
do
netstat -a -n | grep "\*\.$port.*LISTEN" > /dev/null || break
done
echo $port
for port in $(jot -r 100 $(sysctl net.inet.ip.portrange.first | awk '{print $2}') $(sysctl net.inet.ip.portrange.last | awk '{print $2}'))
do
nc -z localhost $port > /dev/null || break
done
echo $port