1 ip_local_port_rangeとは?
プロセスがパケットの到着を待つポート番号は、bindシステムコールを使って指定します。パケットの到着を待つポート番号は、bindシステムコールに指定するポート番号によって、以下のようになります。
bindに指定するポート番号 | 意味 |
---|---|
0を指定した場合 | ip_local_port_rangが示す範囲の中から、OSが任意のポート番号を割り当てる |
0以外を指定した場合 | bindシステムコールで指定したポート番号が割り当てられる |
つまり、ip_local_port_rangeは、bindシステムコールに指定するポート番号に0を指定した場合、OSがプロセスに割り当てるポート番号の範囲を示します。
なお、私の環境では、ip_local_port_rangeはデフォルトで以下の設定になっていました。
[root@server ~]# sysctl -n net.ipv4.ip_local_port_range 32768 60999
2 検証環境
CentOS版数は以下のとおりです。
[root@server ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)
カーネル版数は以下のとおりです。
[root@server ~]# uname -r 3.10.0-1160.el7.x86_64
3 事前準備
3.1 テストプログラムの作成
任意のポートでListenするテストプログラムを作成します。テストプログラムの第1引数にポート番号を指定して実行します。
[root@server ~]# cat sv.c #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdlib.h> int main(int argc, char *argv[]) { int lfd, cfd, optval=1; socklen_t len; struct sockaddr_in sv, cl; char buf[32]; ssize_t n; u_short port; lfd = socket(AF_INET, SOCK_STREAM, 0); port = atoi(argv[1]); sv.sin_family = AF_INET; sv.sin_port = htons(port); sv.sin_addr.s_addr = INADDR_ANY; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); bind(lfd, (struct sockaddr *)&sv, sizeof(sv)); listen(lfd, 5); len = sizeof(cl); cfd = accept(lfd, (struct sockaddr *)&cl, &len); while (1) { memset(buf, 0, sizeof(buf)); n = read(cfd, buf, sizeof(buf)); if(n > 0) fprintf(stderr,"%zd bytes received:%s", n, buf); else if(n == 0){ fprintf(stderr,"EOF recieved. I'm going to sleep 300s.\n"); exit(0); } else { perror("read"); exit(1); } } close(lfd); exit(0); }
4 実験
4.1 ip_local_port_rangeをデフォルトで使用した場合
ip_local_port_rangeの初期値を確認します。
[root@server ~]# sysctl -n net.ipv4.ip_local_port_range 32768 60999
テストプログラムを実行します。このとき、テストプログラムの第1引数に、パケットの到着を待ち受けるポート番号を明に指定します。
[root@server ~]# ./sv 11111 & [1] 1651
lsofコマンドを実行します。テストプログラムの引数に指定したポート番号でListenしていることがわかります。なお、lsofコマンドの使い方は、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1651 root 3u IPv4 32048 0t0 TCP *:11111 (LISTEN)
次に、引数に0を指定してテストプログラムを実行します。
[root@server ~]# ./sv 0 & [1] 1636
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1636 root 3u IPv4 28848 0t0 TCP *:33246 (LISTEN)
引数に0を指定してテストプログラムを実行します。
[root@server ~]# ./sv 0 & [2] 1639
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1636 root 3u IPv4 28848 0t0 TCP *:33246 (LISTEN) sv 1639 root 3u IPv4 31522 0t0 TCP *:38166 (LISTEN)
引数に0を指定してテストプログラムを実行します。
[root@server ~]# ./sv 0 & [3] 1642
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1636 root 3u IPv4 28848 0t0 TCP *:33246 (LISTEN) sv 1639 root 3u IPv4 31522 0t0 TCP *:38166 (LISTEN) sv 1642 root 3u IPv4 31532 0t0 TCP *:34320 (LISTEN)
4.2 ip_local_port_rangeをカスタマイズした場合
ip_local_port_rangeが示す範囲を50001から50003に変更します。
[root@server ~]# sysctl -w net.ipv4.ip_local_port_range="50001 50003" net.ipv4.ip_local_port_range = 50001 50003
ip_local_port_rangeが示す範囲を確認します。
[root@server ~]# sysctl -n net.ipv4.ip_local_port_range 50001 50003
引数に0を指定して、テストプログラムを実行します。
[root@server ~]# ./sv 0 & [1] 1689
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1689 root 3u IPv4 33904 0t0 TCP *:50002 (LISTEN)
引数に0を指定して、テストプログラムを実行します。
[root@server ~]# ./sv 0 & [2] 1692
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1689 root 3u IPv4 33904 0t0 TCP *:50002 (LISTEN) sv 1692 root 3u IPv4 37000 0t0 TCP *:50003 (LISTEN)
引数に0を指定して、テストプログラムを実行します。
[root@server ~]# ./sv 0 & [3] 1695
lsofコマンドを実行します。ip_local_port_rangeが示す範囲の中からポート番号が選択されていることがわかります。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1689 root 3u IPv4 33904 0t0 TCP *:50002 (LISTEN) sv 1692 root 3u IPv4 37000 0t0 TCP *:50003 (LISTEN) sv 1695 root 3u IPv4 28963 0t0 TCP *:50001 (LISTEN)
引数に0を指定して、テストプログラムを実行します。しかし、ip_local_port_rangeが示す範囲のポート番号は全て使われているので、テストプログラムが実行できないことがわかります。
[root@server ~]# ./sv 0 & [4] 1698 [root@server ~]# read: Bad file descriptor
テストプログラムを終了します。
[root@server ~]# pkill sv [1] Terminated ./sv 0 [2]- Terminated ./sv 0 [3]+ Terminated ./sv 0
Z 参考情報
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ