hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

ipsetコマンドの使い方

1 ipsetコマンドとは?

ipsetコマンドは、IPアドレスやポート番号などをまとめて管理するためのツールです。ipsetを使用することで、これらの要素をセットとしてまとめることができます。作成したセットは、iptablesのsetモジュールで使用することが可能です。これにより、iptablesコマンドで個々のIPアドレスを1つずつ登録するのではなく、セットを使用して一括登録することができるようになります。

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

ipsetコマンドの版数は以下のとおりです。

[root@server ~]# ipset -v
ipset v7.11, protocol version: 7

3 オプション一覧

[root@server ~]# ipset help
ipset v7.11

Usage: ipset [options] COMMAND

Commands:
create SETNAME TYPENAME [type-specific-options]
        Create a new set
add SETNAME ENTRY
        Add entry to the named set
del SETNAME ENTRY
        Delete entry from the named set
test SETNAME ENTRY
        Test entry in the named set
destroy [SETNAME]
        Destroy a named set or all sets
list [SETNAME]
        List the entries of a named set or all sets
save [SETNAME]
        Save the named set or all sets to stdout
restore
        Restore a saved state
flush [SETNAME]
        Flush a named set or all sets
rename FROM-SETNAME TO-SETNAME
        Rename two sets
swap FROM-SETNAME TO-SETNAME
        Swap the contect of two existing sets
help [TYPENAME]
        Print help, and settype specific help
version
        Print version information
quit
        Quit interactive mode

Options:
-o plain|save|xml
       Specify output mode for listing sets.
       Default value for "list" command is mode "plain"
       and for "save" command is mode "save".
-s
        Print elements sorted (if supported by the set type).
-q
        Suppress any notice or warning message.
-r
        Try to resolve IP addresses in the output (slow!)
-!
        Ignore errors when creating or adding sets or
        elements that do exist or when deleting elements
        that don't exist.
-n
        When listing, just list setnames from the kernel.

-t
        When listing, list setnames and set headers
        from kernel only.
-f
        Read from the given file instead of standard
        input (restore) or write to given file instead
        of standard output (list/save).

Supported set types:
    list:set            3       skbinfo support
    list:set            2       comment support
    list:set            1       counters support
    list:set            0       Initial revision
-snip-

4 セットの作成、削除方法

セットはメソッドとデータタイプを指定して作成します。書式は以下のとおりです。

TYPENAME := method:datatype[,datatype[,datatype]]

・method:list,hash,bitmapを指定できます。
・datatype:ip,net,mac,port,ifaceを指定できます。

メソッドの各意味を以下のとおりです。

メソッド 意味
list セットをリスト形式で格納します
hash ハッシュテーブルを使用してセットを格納します。ハッシュメソッドは、IPアドレスやネットワークを格納するときに使用します
bitmap ビットマップを使用してセットを格納します。ポート番号やポート範囲を格納するときに使用します

4.1 セットを作成する方法(nまたはcreate)

名前がtest1、タイプがhash:ipのセットを作成してみます。

[root@server ~]# ipset n test1 hash:ip

作成したセットを確認します。test1という名前のセットが作成できたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xcbb84ee8
Size in memory: 216
References: 0
Number of entries: 0
Members:

4.2 セットを削除する方法(xまたはdel)

セットの一覧を確認します。test1という名前のセットが存在することがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xcbb84ee8
Size in memory: 216
References: 0
Number of entries: 0
Members:

test1という名前のセットを削除します。

[root@server ~]# ipset x test1

セットの一覧を確認します。test1という名前のセットが削除されたことがわかります。

[root@server ~]# ipset l
[root@server ~]#

4.3 セットを一括削除する方法(xまたはdel)

事前準備として、test1,test2という名前のセットを2つ作成しておきます。

[root@server ~]# ipset n test1 hash:ip
[root@server ~]# ipset n test2 hash:ip

セットの一覧を確認します。test1,test2という名前のセットが作成されたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xa5a2e8c8
Size in memory: 216
References: 0
Number of entries: 0
Members:

Name: test2
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x0dad6e43
Size in memory: 216
References: 0
Number of entries: 0
Members:

2つのセットを一括で削除します。

[root@server ~]# ipset x

セットの一覧を確認します。test1,test2という名前のセットが削除されたことがわかります。

[root@server ~]# ipset l
[root@server ~]#

5 セットの名前を変更する方法(eまたはrename)

事前準備として、test1という名前のセットを作成しておきます。

[root@server ~]# ipset n test1 hash:ip

作成したセットを確認します。test1という名前のセットが作成できたことがわかります。

[root@server ~]# ipset l -n
test1

test1という名前のセットをtest2に変更します。

[root@server ~]# ipset e test1 test2

セットの一覧を確認します。test1という名前のセットがtest2に変更されたことがわかります。

[root@server ~]# ipset l -n
test2

あと始末をします。

[root@server ~]# ipset x

6 セットにエントリを追加/削除する方法

6.1 エントリを追加する方法(aまたはadd)

事前準備として、名前がtest1、タイプがhash:ipのセットを作成してみます。

[root@server ~]# ipset n test1 hash:ip

作成したセットを確認します。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 120
References: 0
Number of entries: 0
Members:
[root@server ~]#

セットにIPアドレスのエントリを2つ追加します。

[root@server ~]# ipset add test1 192.168.10.10
[root@server ~]# ipset add test1 192.168.10.20

セットを確認します。追加したエントリが2つ作成されたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 216
References: 0
Number of entries: 2
Members:
192.168.10.20
192.168.10.10

6.2 エントリを削除する方法(dまたはdel)

セットからエントリを1つ削除します。

[root@server ~]# ipset d test1 192.168.10.10

セットを確認します。エントリが1つ削除されたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 168
References: 0
Number of entries: 1
Members:
192.168.10.20

セットからもう1つエントリを削除します。

[root@server ~]# ipset d test1 192.168.10.20

セットの中身を確認します。エントリが全て削除されたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 120
References: 0
Number of entries: 0
Members:

6.3 エントリを一括削除する方法(fまたはflush)

セットを確認します。エントリが2つ存在することがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 216
References: 0
Number of entries: 2
Members:
192.168.10.20
192.168.10.10

エントリを一括で削除します。

[root@server ~]# ipset f test1

セットの中身を確認します。エントリが全て削除されたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 120
References: 0
Number of entries: 0
Members:

7 セーブ、リストア方法

セットの内容をファイルに保存したり、ファイルに保存したセットをリストアすることができます。

7.1 セットの内容をファイルに保存する方法(save)

テスト用のセットを作成します。

[root@server ~]# ipset n test1 hash:ip
[root@server ~]# ipset a test1 192.168.10.1

作成したセットをファイルに保存します。

[root@server ~]# ipset save > ip_set.txt

ファイルに保存したセットの内容を確認します。

[root@server ~]# cat ip_set.txt
create test1 hash:ip family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x1266b74c
add test1 192.168.10.1

7.2 リストアする方法(restore)

セットの一覧を確認します。セットが登録されていないことを確認します。

[root@server ~]# ipset l
[root@server ~]#

ファイルに保存されているセットを確認します。

[root@server ~]# cat ip_set.txt
create test1 hash:ip family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x1266b74c
add test1 192.168.10.1

ファイルに保存されているセットをリストアします。

[root@server ~]# ipset restore < ip_set.txt

セットを確認します。ファイルに保存されていたセットがリストアされたことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0x1266b74c
Size in memory: 256
References: 0
Number of entries: 1
Members:
192.168.10.1

8 タイムアウトの設定方法(timeout)

エントリにタイムアウトを設定することができます。指定した時間を経過すると、エントリが削除されます。ここでは、エントリに10秒のタイムアウトを設定してみます。10秒経過すると、エントリが削除されることを確認してみます。

[root@server ~]# ipset n test1 hash:ip timeout 10

セット(test1)にエントリ(192.168.10.10)を追加します。

[root@server ~]# ipset a test1 192.168.10.10

セットに追加されたエントリを確認します。エントリの削除まで4秒であることがわかります。

[root@server ~]# ipset l test1
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 timeout 10 bucketsize 12 initval 0x728c1f29
Size in memory: 280
References: 0
Number of entries: 1
Members:
192.168.10.10 timeout 4

セットに追加されたエントリを確認します。エントリが削除されたことがわかります。

[root@server ~]# ipset l test1
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 timeout 10 bucketsize 12 initval 0x728c1f29
Size in memory: 280
References: 0
Number of entries: 0
Members:

9 カウンタの設定方法(counters)

カウンタ付のセットを作成します。

[root@server ~]# ipset n test1 hash:ip counters

セットにエントリを追加します。

[root@server ~]# ipset a test1 192.168.122.213

セットの内容を表示します。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 counters bucketsize 12 initval 0x1707fb58
Size in memory: 296
References: 0
Number of entries: 1
Members:
192.168.122.213 packets 0 bytes 0

セットをINPUTチェインに追加します。

[root@server ~]# iptables -A INPUT -m set --match-set test1 src -p icmp -j LOG

INPUTチェインのルールを確認します。test1セットがINPUTチェインに追加されたことがわかります。

[root@server ~]# iptables -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 LOG        icmp --  *      *       0.0.0.0/0            0.0.0.0/0            match-set test1 src LOG flags 0 level 4

クライアントからサーバに対してpingコマンドを1回実行します。なお、pingコマンドの使い方は、pingコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@client~]# ping -c 1 192.168.122.16

セットの内容を確認します。192.168.122.213から84バイトのパケットを1つ受信したことがわかります。

[root@server ~]# ipset l
Name: test1
Type: hash:ip
Revision: 5
Header: family inet hashsize 1024 maxelem 65536 counters bucketsize 12 initval 0x1707fb58
Size in memory: 296
References: 1
Number of entries: 1
Members:
192.168.122.213 packets 1 bytes 84

INPUTチェインを確認します。ICMPパケットを受信したことがわかります。

[root@server ~]# iptables -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1    84 LOG        icmp --  *      *       0.0.0.0/0            0.0.0.0/0            match-set test1 src LOG flags 0 level 4

ipsetコマンドを実行したときのカーネルの動作をsystemtapで確認する。

[root@server ~]# ipset n test1 hash:ip
pp=module("ip_set_hash_ip").function("hash_ip_create@net/netfilter/ipset/ip_set_hash_gen.h:1207")
pp=module("ip_set_hash_ip").function("htable_size@net/netfilter/ipset/ip_set_hash_gen.h:103")

シグナルの受信処理について

1 はじめに

シグナルの受信処理について、以下のことを確認してみます。
・同じシグナルを複数回受信した場合の挙動
・通常シグナル、リアルタイムシグナルの受信処理の順序

シグナルについて以下の記事も書きました。
シグナルについて - hana_shinのLinux技術ブログ

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 テストプログラム

テストプログラムの内容は次のとおりです。
SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)の各シグナルについて、シグナルハンドラを登録し、それらシグナルを受信した際にはシグナル番号を表示します。シグナルハンドラでは、fprintf関数やprintf関数ではなく、シグナルセーフなwriteシステムコールを使ってメッセージを出力します。また、main関数ではfprintfの出力先にstderrを指定しています。これは、メッセージ出力をバッファリングせず、即座に端末に出力できるようにするためです。

[root@server tp]# cat signal.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sig_int(int sig) {
    char msg[100];
    snprintf(msg, sizeof(msg), "Signal number:%d\n", sig);
    write(STDERR_FILENO, msg, strlen(msg));
}

int main() {
    struct sigaction sa[4];
    int signals[] = {1, 11, 63, 64};

    for (int i = 0; i < 4; ++i) {
        sa[i].sa_handler = sig_int;
        sigemptyset(&sa[i].sa_mask);
        sa[i].sa_flags = 0;
        sigaction(signals[i], &sa[i], NULL);
    }

    fprintf(stderr, "PID=%d\n", getpid());
    while(1) {
        sleep(600);
    }
}

テストプログラムをコンパイルします。

[root@server tp]# gcc -Wall -o signal signal.c

4 同じシグナルを複数回受信した場合について

4.1 通常シグナルを複数回受信した場合

テストプログラムを実行します。

[root@server tp]# ./signal
PID=1189

Ctrl+zを押下して、signalプロセスを停止状態にします。なお、SIGSTOPシグナルをsignalプロセスに送信しても同じ状態になります。

[root@server tp]# ./signal
PID=1189
^Z
[1]+  停止                  ./signal

psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1189 0000000000000000 0000000000000000 0000000000000000 c000000000000401 T    pts/1      0:00 ./signal

signalプロセスにSIGHUPシグナルを3つ送信します。

[root@server ~]# kill -SIGHUP 1189
[root@server ~]# kill -SIGHUP 1189
[root@server ~]# kill -SIGHUP 1189

psコマンドを実行して、signalプロセスの状態を確認します。PENDINGが0000000000000001であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1189 0000000000000001 0000000000000000 0000000000000000 c000000000000401 T    pts/1      0:00 ./signal

シグナルについて - hana_shinのLinux技術ブログに記載したプログラム(signal.py)を実行すると、SIGHUPシグナルが保留されていることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:0000000000000001
Active signals:
SIGHUP(1)

fgコマンドを実行して、signalプロセスを再開します。signalプロセスにSIGHUPシグナルを3つ送信したのですが、シグナルハンドラが1回しか実行されていないので、処理されシグナルは1回だけであることがわかります。

[root@server tp]# fg
./signal
Signal number:1

psコマンドを使用してsignalプロセスの状態を確認すると、PENDINGが0000000000000000であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1189 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+   pts/0      0:00 ./signal

テストCtrl+cを押下して、テストプログラムを終了します。

[root@server tp]# fg
./signal
Signal number:1
^C

4.2 リアルタイムシグナルを複数回受信した場合

テストプログラムを実行します。

[root@server tp]# ./signal
PID=1230

psコマンドを実行して、プロセスの状態を確認します。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+   pts/1      0:00 ./signal

Ctrl+zキーを押下して、signalプロセスを停止状態にします。

[root@server tp]# ./signal
PID=1230
^Z
[1]+  停止                  ./signal

psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 T    pts/1      0:00 ./signal

signalプロセスにSIGRTMAXシグナルを3つ送信します。

[root@server ~]# kill -SIGRTMAX 1230
[root@server ~]# kill -SIGRTMAX 1230
[root@server ~]# kill -SIGRTMAX 1230

psコマンドを実行して、signalプロセスの状態を確認します。PENDINGが8000000000000000であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1230 8000000000000000 0000000000000000 0000000000000000 c000000000000401 T    pts/1      0:00 ./signal

シグナルについて - hana_shinのLinux技術ブログに記載したプログラムを実行すると、SIGRTMAXシグナルが保留されていることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:8000000000000000
Active signals:
SIGRTMAX(64)

fgコマンドを実行して、signal プロセスを再開します。シグナルハンドラが3回実行されたため、処理されたシグナルは3回であることがわかります。通常のシグナルとは異なり、リアルタイムシグナルは受信したシグナルの回数を実行することができます。

[root@server tp]# fg
./signal
Signal number:64
Signal number:64
Signal number:64

signalプロセスが再開して、保留中のシグナルを処理したので、PENDINGが0になったことがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1230 0000000000000000 0000000000000000 0000000000000000 c000000000000401 S+   pts/1      0:00 ./signal

5 通常シグナルとリアルタイムシグナルの優先度について

テストプログラムを実行します。

[root@server tp]# ./signal
PID=1321

Ctrl+zを押下して、signalプロセスを停止状態にします。

[root@server tp]# ./signal
PID=1321
^Z
[1]+  停止                  ./signal

signalプロセスにSIGHUP, SIGSEGV, SIGRTMAX-1, SIGRTMAX を送信します。SIGHUP, SIGSEGVは通常シグナルです。SIGRTMAX-1, SIGRTMAXはリアルタイムシグナルです。

[root@server ~]# kill -SIGHUP 1321
[root@server ~]# kill -SIGSEGV 1321
[root@server ~]# kill -SIGRTMAX-1 1321
[root@server ~]# kill -SIGRTMAX 1321

psコマンドを実行して、signalプロセスの状態を確認します。PENDINGがc000000000000401であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1321 c000000000000401 0000000000000000 0000000000000000 c000000000000401 T    pts/1      0:00 ./signal

signal.pyを実行すると、SIGHUP, SIGSEGV, SIGRTMAX-1, SIGRTMAXが保留されていることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:c000000000000401
Active signals:
SIGHUP(1), SIGSEGV(11), SIGRTMAX-1(63), SIGRTMAX(64)

fgコマンドを実行して、signal プロセスを再開します。リアルタイムシグナル、通常シグナルの順でシグナルが処理されていることがわかります。また、リアルタイムシグナルは番号の大きいものから、通常シグナルは番号の小さいものから処理されていることがわかります。

[root@server tp]# fg
./signal
Signal number:64
Signal number:63
Signal number:1
Signal number:11

6 まとめ

項目 説明
通常シグナルとリアルタイムシグナルの優先度 リアルタイムシグナルが通常シグナルより優先して処理されます
リアルタイムシグナル同士の優先度 番号の大きいリアルタイムシグナルが優先して処理されます
通常シグナル同士の優先度 番号の小さい通常シグナルが優先して処理されます
同じシグナルの実行回数 通常シグナルの場合、同じシグナルをN回受信しても処理するのは1回です。リアルタイムシグナルの場合、同じシグナルをN回受信したら、N回受信処理をします

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

シグナルについて

1 はじめに

シグナルに関して様々な実験を実施してみます。

他にも、以下の記事を投稿しました。
シグナルの受信処理について - hana_shinのLinux技術ブログ

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 シグナル一覧を表示する方法

killコマンドを実行すると、シグナルの一覧を表示することができます。通常シグナルは1~32までの範囲で、リアルタイムシグナルは33~64までの範囲にあります。

[root@server ~]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

4 シグナルを送信する方法

killコマンドを実行すると、プロセスにシグナルを送信することができます。ここでは、sleepプロセスにSIGKILLシグナルを送信してみます。まず、sleepコマンドを実行します。sleepコマンドを実行すると、sleepプロセスが起動され、その後600秒スリープします。

[root@server ~]# sleep 600

psコマンドを実行して、sleepプロセスのPIDを確認します。sleepプロセスのPIDは19876であることがわかります。なお、psコマンドの使い方は、psコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# ps -C sleep
    PID TTY          TIME CMD
  19867 pts/2    00:00:00 sleep

4.1 シグナル名を指定する方法

シグナル名を指定してkillコマンドを実行します。

[root@server ~]# kill -SIGKILL 19867

sleepプロセスがSIGKILLシグナルを受信すると、強制終了することがわかります。

[root@server ~]# sleep 600
強制終了

4.2 シグナル番号を指定する方法

シグナル番号を指定してkillコマンドを実行します。

[root@server ~]# kill -9 1188

sleepプロセスがSIGKILLシグナルを受信すると、強制終了することがわかります。

[root@server ~]# sleep 600
強制終了

5 シグナルの状態を表示する方法

psコマンドにsオプションを指定すると、シグナルの各種状態(PENDING、BLOCKED、IGNORED、CAUGHT)を表示することができます。ここでは、これらの各種状態をシグナル情報と呼ぶことにします。シグナル情報は64ビットのデータです。通常シグナルには32ビットが割り当てられており、リアルタイムシグナルにも32ビットが割り当てられています。

[root@server ~]# ps s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0     672 0000000000000000 0000000000000000 0000000000000006 0000000000000000 Ss+  tty1       0:00 /sbin/agetty -o -p
    0    1124 0000000000000000 0000000000010000 0000000000384004 000000004b813efb Ss   pts/0      0:00 -bash
    0    1195 0000000000000000 0000000000000000 0000000000384004 000000004b813efb Ss+  pts/1      0:00 -bash
    0   19660 0000000000000000 0000000000010000 0000000000384004 000000004b813efb Ss   pts/2      0:00 -bash
    0   19908 0000000000000000 0000000000000000 0000000000000000 0000000000000000 S+   pts/2      0:00 sleep 600
    0   19915 0000000000000000 0000000000000000 0000000000000000 0000000073d1fef9 R+   pts/0      0:00 ps s

シグナル情報の意味は以下のとおりです。

シグナル情報 意味
PENDING プロセスが受信したがまだ処理していないシグナルを示します
BLOCKED プロセスが特定のシグナルを受信しないように一時的にシグナルの処理をブロックするシグナルを示します。ブロックを解除するとシグナルを処理します
IGNORED プロセスが特定のシグナルを受信しても無視するシグナルを示します
CAUGHT シグナルハンドラを登録しているシグナルを示します

PIDを指定すると、特定プロセスのシグナル情報を表示することができます。ここでは、systemd(PID=1)のシグナル情報を表示してみます。

[root@server ~]# ps s -p 1
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0       1 0000000000000000 7fe3c0fe28014a03 0000000000001000 00000001000004ec Ss   ?          0:05 /usr/lib/systemd/s

次のようにフォーマットを明に指定しても、プロセスのシグナル情報を表示することができます。

[root@server ~]# ps -p 1 -o comm,pid,sig,sigmask,sigignore,sigcatch
COMMAND             PID          PENDING          BLOCKED          IGNORED           CAUGHT
systemd               1 0000000000000000 7fe3c0fe28014a03 0000000000001000 00000001000004ec

-Cオプションでプロセス名を指定すると、指定したプロセスのシグナル情報を表示することができます。chronydプロセスのシグナル情報を表示してみます。

[root@server ~]#  ps -C chronyd -o comm,pid,sig,sigmask,sigignore,sigcatch
COMMAND             PID          PENDING          BLOCKED          IGNORED           CAUGHT
chronyd             656 0000000000000000 0000000000000000 0000000000001000 0000000100004007

記事末尾のサンプルプログラム(signal.py)を使用してIGNOREDのシグナル名を確認すると、SIGPIPEが無視されていることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:0000000000001000
Active signals:
SIGPIPE(13)

次に、chronydプロセスがSIGPIPEシグナルを無視するかどうかを確認するため、chronydプロセスにSIGPIPEシグナルを送信してみます。通常、SIGPIPEを受信するとプロセスは終了しますが、chronydプロセスはSIGPIPEシグナルを無視する設定になっているため、SIGPIPEシグナルを受信してもchronydプロセスは終了しません。

[root@server ~]# kill -SIGPIPE 656

chronydプロセスの状態を確認します。chronydプロセスのPIDは656のままで、chronydプロセスが終了していないことがわかります。

[root@server ~]# ps -C chronyd -o comm,pid,sig,sigmask,sigignore,sigcatch
COMMAND             PID          PENDING          BLOCKED          IGNORED           CAUGHT
chronyd             656 0000000000000000 0000000000000000 0000000000001000 0000000100004007

6 CAUGHTの確認方法

6.1テストプログラムの作成

CAUGHTを確認するためのテストプログラムを作成します。SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)の各シグナルについて、シグナルハンドラを登録し、それらシグナルを受信した際にはシグナル番号を表示します。シグナルハンドラでは、fprintf関数やprintf関数ではなく、シグナルセーフなwriteシステムコールを使ってメッセージを出力します。また、main関数ではfprintfの出力先にstderrを指定しています。これは、メッセージ出力をバッファリングせず、即座に端末に出力できるようにするためです。

[root@server ~]# cat signal.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sig_int(int sig) {
    char msg[100];
    snprintf(msg, sizeof(msg), "Signal number:%d\n", sig);
    write(STDERR_FILENO, msg, strlen(msg));
}

int main() {
    struct sigaction sa[4];
    int signals[] = {1, 2, 63, 64};

    for (int i = 0; i < 4; ++i) {
        sa[i].sa_handler = sig_int;
        sigemptyset(&sa[i].sa_mask);
        sa[i].sa_flags = 0;
        sigaction(signals[i], &sa[i], NULL);
    }

    fprintf(stderr, "PID=%d\n", getpid());
    while(1) {
        sleep(600);
    }
}

テストプログラムをコンパイルします。

[root@server ~]# gcc -Wall -o signal signal.c

6.2 確認結果

テストプログラムを実行します。

[root@server ~]# ./signal
PID=1421

psコマンドを実行してシグナル情報を確認すると、CAUGHTがc000000000000003であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1421 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+   pts/1      0:00 ./signal

signal.pyを実行すると、CAUGHTのc000000000000003は、テストプログラムで定義した4つのシグナルを補足することを示していることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:c000000000000003
Active signals:
SIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)

7 PENDINGの確認方法

6章と同じテストプログラムを実行します。signalプロセスのPIDが1207であることがわかります。

[root@server ~]# ./signal
PID=1207

Ctrl+zキーを押下して、signalプロセスを停止状態にします。なお、SIGSTOPシグナルをsignalプロセスに送信しても同じ状態になります。

[root@server ~]# ./signal
PID=1207
^Z
[1]+  停止                  ./signal

psコマンドを使用してsignalプロセスの状態を確認すると、停止状態(STATがT)であることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1207 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+   pts/1      0:00 ./signal

signalプロセスにSIGHUP(1)シグナルを送信します。

[root@server ~]# kill -1 1207

psコマンドを実行してシグナル情報を確認すると、PENDINGが0000000000000001になったことがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1207 0000000000000001 0000000000000000 0000000000000000 c000000000000003 T    pts/1      0:00 ./signal

signal.pyを実行すると、SIGHUPシグナルが保留されていることがわかります。これは、シグナルを受信するプロセスが停止状態になっているため、SIGHUPシグナルを受信しても処理できずに保留しているからです。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:0000000000000001
Active signals:
SIGHUP(1)

次に、signalプロセスにSIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)を送信します。

[root@server ~]# kill -2 1207
[root@server ~]# kill -63 1207
[root@server ~]# kill -64 1207

psコマンドを実行してシグナル情報を確認すると、PENDINGがc000000000000003になっていることがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1207 c000000000000003 0000000000000000 0000000000000000 c000000000000003 T    pts/1      0:00 ./signal

signal.pyを使ってPENDINGのシグナルを確認すると、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)が保留中であることがわかります。

[root@server ~]# ./signal.py
Please enter a hexadecimal number:c000000000000003
Active signals:
SIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)

fgコマンドを実行して、signalプロセスを停止状態からスリープ状態に戻します。

[root@server ~]# fg
./signal
Signal number:64
Signal number:63
Signal number:2
Signal number:1

psコマンドを実行してシグナル情報を確認します。signalプロセスが起床して、保留中のシグナルを処理したので、PENDINGが0になったことがわかります。

[root@server ~]# ps -C signal s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1207 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+   pts/1      0:00 ./signal

8 IGNOREDの確認方法

8.1テストプログラムの作成

IGNOREDを確認するためのテストプログラムを作成します。実行開始から30秒間は、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)を受信しても無視します。30秒経過すると、無視していたシグナルを実行します。

[root@server ~]# cat signal1.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sig_int(int sig) {
    char msg[100];
    snprintf(msg, sizeof(msg), "Signal number:%d\n", sig);
    write(STDERR_FILENO, msg, strlen(msg));
}

int main() {
    struct sigaction sa[4];
    int signals[] = {1, 2, 63, 64};
    int block_time = 30;

    for (int i = 0; i < 4; ++i) {
        sa[i].sa_handler = SIG_IGN;
        sigemptyset(&sa[i].sa_mask);
        sa[i].sa_flags = 0;
        sigaction(signals[i], &sa[i], NULL);
    }

    fprintf(stderr, "PID=%d\n", getpid());
    sleep(block_time);
    for (int i = 0; i < 4; ++i) {
        sa[i].sa_handler = sig_int;
        sigaction(signals[i], &sa[i], NULL);
    }

    fprintf(stderr, "Signals unblocked.\n");
    while(1) {
        sleep(600);
    }
    return 0;
}

テストプログラムをコンパイルします。

[root@server ~]# gcc -Wall -o signal1 signal1.c

8.2 確認結果

テストプログラムを実行します。

[root@server ~]# ./signal1
PID=1318

プロセスの状態を確認すると、IGNOREDがc000000000000003になっていることがわかります。

[root@server ~]# ps -C signal1 s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1318 0000000000000000 0000000000000000 c000000000000003 0000000000000000 S+   pts/1      0:00 ./signal1

signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。

[root@server ~]# kill -1 1318
[root@server ~]# kill -2 1318
[root@server ~]# kill -63 1318
[root@server ~]# kill -64 1318

シグナルを受信してもシグナル番号が表示されないことから、シグナルが無視されていることがわかります。

[root@server ~]# ./signal1
PID=1318

30秒経過したあと、プロセスの状態を確認するとIGNOREDが0000000000000000になっていることがわかります。

[root@server ~]# ps -C signal1 s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1318 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+   pts/1      0:00 ./signal1

signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。

[root@server ~]# kill -1 1318
[root@server ~]# kill -2 1318
[root@server ~]# kill -63 1318
[root@server ~]# kill -64 1318

シグナルを受信してシグナルハンドラが実行されたため、シグナル番号が表示されていることがわかります。

[root@server ~]# ./signal1
PID=1318
Signals unblocked.
Signal number:1
Signal number:2
Signal number:63
Signal number:64

9 BLOCKEDの確認方法

9.1テストプログラムの作成

BLOCKEDを確認するためのテストプログラムを作成します。テストプログラムを実行すると30秒間シグナルの受信処理をブロックします。30秒経過するとブロックを解除してシグナルの受信処理を実行します。

[root@server ~]# cat signal2.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sig_int(int sig) {
    char msg[100];
    snprintf(msg, sizeof(msg), "Signal number:%d\n", sig);
    write(STDERR_FILENO, msg, strlen(msg));
}

int main() {
    struct sigaction sa[4];
    int signals[] = {1, 2, 63, 64};
    int block_time = 30;
    sigset_t set;

    for (int i = 0; i < 4; ++i) {
        sa[i].sa_handler = sig_int;
        sigemptyset(&sa[i].sa_mask);
        sa[i].sa_flags = 0;
        sigaction(signals[i], &sa[i], NULL);
    }

    fprintf(stderr, "PID=%d\n", getpid());

    sigemptyset(&set);
    for (int i = 0; i < 4; ++i) {
        sigaddset(&set, signals[i]);
    }
    sigprocmask(SIG_BLOCK, &set, NULL);

    fprintf(stderr, "Signals blocked for %d seconds.\n", block_time);
    sleep(block_time);

    sigprocmask(SIG_UNBLOCK, &set, NULL);
    fprintf(stderr, "Signals unblocked.\n");

    while (1) {
        sleep(600);
    }
    return 0;
}

テストプログラムをコンパイルします。

[root@server ~]# gcc -Wall -o signal2 signal2.c

9.2 確認結果

テストプログラムを実行します。

[root@server ~]# ./signal2
PID=1383

プロセスの状態を確認すると、BLOCKEDがc000000000000003になっており、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)がブロックされれいることを示しています

[root@server ~]# ps -C signal2 s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1383 0000000000000000 c000000000000003 0000000000000000 c000000000000003 S+   pts/0      0:00 ./signal2

signalプロセスにSIGHUP(1), SIGINT(2), SIGRTMAX-1(63), SIGRTMAX(64)を送信します。

[root@server ~]# kill -1 1383
[root@server ~]# kill -2 1383
[root@server ~]# kill -63 1383
[root@server ~]# kill -64 1383

プロセスの状態を確認すると、PENDINGがc000000000000003になっており、SIGHUP(1)、SIGINT(2)、SIGRTMAX-1(63)、SIGRTMAX(64)が保留中であることを示しています。これは、シグナルの受信処理がブロックされていてシグナルが保留されているからです。

[root@server ~]# ps -C signal2 s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1383 c000000000000003 c000000000000003 0000000000000000 c000000000000003 S+   pts/0      0:00 ./signal2

テストプログラムを実行して30秒経過するとブロックしているシグナルのシグナルハンドラが実行されます。シグナルの処理はリアルタイムシグナルが通常シグナルの処理より優先されます。また、シグナル番号の大きいシグナルから処理されていることがわかります。

[root@server ~]# ./signal2
PID=1383
Signals blocked for 30 seconds.
Signal number:64
Signal number:63
Signal number:2
Signal number:1
Signals unblocked.

プロセスの状態を確認すると、BLOCKEDが0000000000000000 になっていることがわかります。これは、30秒経過してブロックしていたシグナルを解除したからです。

[root@server ~]# ps -C signal2 s
  UID     PID          PENDING          BLOCKED          IGNORED           CAUGHT STAT TTY        TIME COMMAND
    0    1383 0000000000000000 0000000000000000 0000000000000000 c000000000000003 S+   pts/0      0:00 ./signal2

X シグナル名とシグナル番号を表示するプログラム

以下は、シグナル情報の16進数をシグナル名とシグナル番号で表示するプログラムです。

[root@server ~]# cat signal.py
#!/usr/bin/python3

def binary_to_signals(hex_input):
    signals = [
        "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
        "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE",
        "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2",
        "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT",
        "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP",
        "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU",
        "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH",
        "SIGIO", "SIGPWR", "SIGSYS", "SIGUNUSED", "SIGUNUSED",
        "SIGRTMIN", "SIGRTMIN+1", "SIGRTMIN+2", "SIGRTMIN+3",
        "SIGRTMIN+4", "SIGRTMIN+5", "SIGRTMIN+6", "SIGRTMIN+7",
        "SIGRTMIN+8", "SIGRTMIN+9", "SIGRTMIN+10", "SIGRTMIN+11",
        "SIGRTMIN+12", "SIGRTMIN+13", "SIGRTMIN+14", "SIGRTMIN+15",
        "SIGRTMAX-14", "SIGRTMAX-13", "SIGRTMAX-12", "SIGRTMAX-11",
        "SIGRTMAX-10", "SIGRTMAX-9", "SIGRTMAX-8", "SIGRTMAX-7",
        "SIGRTMAX-6", "SIGRTMAX-5", "SIGRTMAX-4", "SIGRTMAX-3",
        "SIGRTMAX-2", "SIGRTMAX-1", "SIGRTMAX",
    ]

    signals_activated = []
    binary_str = bin(int(hex_input, 16))[2:]
    binary_str = binary_str.zfill(64)

    for i, bit in enumerate(reversed(binary_str)):
        if bit == "1":
            if i < len(signals):
                signal_name = signals[i]
                signal_number = i + 1
                signals_activated.append(f"{signal_name}({signal_number})")

    return signals_activated

if __name__ == "__main__":
    hex_input = input("Please enter a hexadecimal number:")

    if not all(ch in "0123456789abcdefABCDEF" for ch in hex_input):
        print("Input error: Please enter a hexadecimal number.")
    else:
        activated_signals = binary_to_signals(hex_input)
        if not activated_signals:
            print("There are no active signals:")
        else:
            print("Active signals:")
            for i in range(0, len(activated_signals), 5):
                signals_line = ", ".join(activated_signals[i:i+5])
                print(signals_line)

実行権を付与します。

[root@server ~]# chmod 744 signal.py

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

lscpuコマンドの使い方

1 lscpuコマンドとは?

lscpuコマンドは、CPUの数、スレッド数、コア数、ソケット数、およびNUMAノードなどの情報を表示するコマンドです。

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 パッケージのインストール方法

util-linuxパッケージをインストールします。

[root@server ~]# dnf -y install util-linux

lscpuコマンドの版数は以下のとおりです。

[root@server ~]# lscpu -V
lscpu from util-linux 2.37.4

4 オプション一覧

lscpuコマンドのオプション一覧は以下のとおりです。

[root@server ~]# lscpu -h

使い方:
 lscpu [オプション]

CPUアーキテクチャについての情報を表示します。

オプション:
 -a, --all               オンラインの CPU とオフラインの CPU を両方表示します (-e を指定した場合の既定値)
 -b, --online            オンラインの CPU のみを表示します (-p を指定した場合の既定値)
 -B, --bytes             print sizes in bytes rather than in human readable format
 -C, --caches[=<list>]   info about caches in extended readable format
 -c, --offline           オフラインの CPU のみを表示します
 -J, --json              use JSON for default or extended format
 -e, --extended[=<リスト>] 読みやすい拡張形式で表示します
 -p, --parse[=<list>]    プログラムなどで処理しやすい形式で表示します
 -s, --sysroot <dir>     指定したディレクトリをシステムルートとみなすようにします
 -x, --hex               CPU をリストではなく 16 進数のマスク形式で表示します
 -y, --physical          print physical instead of logical IDs
     --output-all        print all available columns for -e, -p or -C

 -h, --help              このヘルプを表示します
 -V, --version           バージョンを表示します

Available output columns for -e or -p:
-snip-

5 CPUに関する情報を表示する方法

lscpuコマンドを引数なしで実行すると、CPUに関する情報を表示することができます。

[root@server ~]# lscpu
アーキテクチャ:                        x86_64
  CPU 操作モード:                      32-bit, 64-bit
  Address sizes:                       45 bits physical, 48 bits virtual
  バイト順序:                          Little Endian
CPU:                                   4
  オンラインになっている CPU のリスト: 0-3
ベンダー ID:                           GenuineIntel
  BIOS Vendor ID:                      Red Hat
  モデル名:                            Intel Core Processor (Skylake, IBRS)
    BIOS Model name:                   RHEL 7.6.0 PC (i440FX + PIIX, 1996)
    CPU ファミリー:                    6
    モデル:                            94
    コアあたりのスレッド数:            1
    ソケットあたりのコア数:            1
    ソケット数:                        4
    ステッピング:                      3
    BogoMIPS:                          5616.01
    フラグ:                            fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mm
                                       x fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopolo
                                       gy cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic mov
                                       be popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dno
                                       wprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust
                                       bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsa
                                       ves arat umip md_clear arch_capabilities
Virtualization features:
  ハイパーバイザのベンダー:            KVM
  仮想化タイプ:                        完全仮想化
Caches (sum of all):
  L1d:                                 128 KiB (4 instances)
  L1i:                                 128 KiB (4 instances)
  L2:                                  16 MiB (4 instances)
  L3:                                  64 MiB (4 instances)
NUMA:
  NUMA ノード数:                       1
  NUMA ノード 0 CPU:                   0-3
Vulnerabilities:
  Itlb multihit:                       Not affected
  L1tf:                                Mitigation; PTE Inversion
  Mds:                                 Mitigation; Clear CPU buffers; SMT Host state unknown
  Meltdown:                            Mitigation; PTI
  Mmio stale data:                     Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown
  Retbleed:                            Mitigation; IBRS
  Spec store bypass:                   Mitigation; Speculative Store Bypass disabled via prctl
  Spectre v1:                          Mitigation; usercopy/swapgs barriers and __user pointer sanitization
  Spectre v2:                          Mitigation; IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS Not affected
  Srbds:                               Unknown: Dependent on hypervisor status
  Tsx async abort:                     Not affected

6 CPUの状態を表示する方法

事前準備としてCPU0の状態をオフラインに変更しておきます。

CPU0の状態を確認します。CPU0はオンラインであることがわかります。

[root@server ~]# cat /sys/devices/system/cpu/cpu0/online
1

CPU0の状態をオフラインに変更します。

[root@server ~]# echo 0 > /sys/devices/system/cpu/cpu0/online

CPU0の状態を確認します。CPU0の状態がオフラインになったことがわかります。

[root@server ~]# cat /sys/devices/system/cpu/cpu0/online
0

6.1 オンライン/オフラインのCPUを表示する方法(-a)

-aはオンライン/オフラインのCPUを全て表示するオプションです。以下の例ではCPU0がオフライン、他のCPUはオンラインであことがわかります。

[root@server ~]# lscpu -ae
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
  0    -      -    - -                 no
  1    0      0    0 1:1:1:1          yes
  2    0      1    1 2:2:2:2          yes
  3    0      2    2 3:3:3:3          yes

6.2 オンラインのCPUを表示する方法(-b)

-bオプションは、オンラインのCPUのみを表示するオプションです。CPUの状態を確認すると、オンラインのCPU1、2、3が表示されていることが分かります。

[root@server ~]# lscpu -be
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
  1    0      0    0 1:1:1:1          yes
  2    0      1    1 2:2:2:2          yes
  3    0      2    2 3:3:3:3          yes

6.3 オフラインのCPUを表示する方法(-c)

-cオプションは、オフラインのCPUを表示するためのオプションです。CPUの状態を確認すると、オフラインのCPU0が表示されていることが分かります。

[root@server ~]# lscpu -ce
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
  0    -      -    - -                 no

CPU0の状態をオンラインに戻します。

[root@server ~]# echo 1 > /sys/devices/system/cpu/cpu0/online

CPUの状態を確認します。CPU0がオンラインになったことがわかります。

[root@server ~]# lscpu -ae
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
  0    0      0    0 0:0:0:0          yes
  1    0      1    1 1:1:1:1          yes
  2    0      2    2 2:2:2:2          yes
  3    0      3    3 3:3:3:3          yes

7 特定の情報を表示する方法(-p)

-pは指定したCPUの情報を表示するオプションです。指定できる情報として以下のものがあります。

Available output columns for -e or -p:
      BOGOMIPS  crude measurement of CPU speed
           CPU  論理 CPU 番号
          CORE  論理コア番号
        SOCKET  論理ソケット番号
       CLUSTER  logical cluster number
          NODE  論理 NUMA ノード番号
          BOOK  論理ブック番号
        DRAWER  logical drawer number
         CACHE  CPU 間でどのようにキャッシュが共有されるかの表示
  POLARIZATION  仮想ハードウェア上での CPU ディスパッチモード
       ADDRESS  CPU の物理アドレス
    CONFIGURED  ハイパーバイザが CPU を割り当てたかどうかの表示
        ONLINE  Linux が CPU を利用しているかどうかの表示
           MHZ  shows the currently MHz of the CPU
        MAXMHZ  CPU の最大 MHz を表示します
        MINMHZ  CPU の最小 MHz を表示します

論理CPUを表示してみます。

[root@server ~]# lscpu -p=CPU
# The following is the parsable format, which can be fed to other
# programs. Each different item in every column has an unique ID
# starting usually from zero.
# CPU
0
1
2
3

次に、CPUの論理番号とクロック数を表示してみます。

[root@server ~]# lscpu -p=CPU,MHZ
# The following is the parsable format, which can be fed to other
# programs. Each different item in every column has an unique ID
# starting usually from zero.
# CPU,Mhz
0,2808.006
1,2808.006
2,2808.006
3,2808.006

8 CPUのキャッシュの情報を表示する方法(-C)

-CはCPUのキャッシュ情報を表示するオプションです。

[root@server ~]# lscpu -C
NAME ONE-SIZE ALL-SIZE WAYS TYPE        LEVEL  SETS PHY-LINE COHERENCY-SIZE
L1d       32K     128K    8 Data            1    64        1             64
L1i       32K     128K    8 Instruction     1    64        1             64
L2         4M      16M   16 Unified         2  4096        1             64
L3        16M      64M   16 Unified         3 16384        1             64

-Cに指定できるオプションは以下のとおりです。

Available output columns for -C:
      ALL-SIZE  size of all system caches
         LEVEL  cache level
          NAME  cache name
      ONE-SIZE  size of one cache
          TYPE  キャッシュタイプ
          WAYS  ways of associativity
  ALLOC-POLICY  allocation policy
  WRITE-POLICY  write policy
      PHY-LINE  number of physical cache line per cache t
          SETS  number of sets in the cache; set lines has the same cache index
 COHERENCY-SIZE  minimum amount of data in bytes transferred from memory to cache

キャッシュの名前とタイプを表示してみます。

[root@server ~]# lscpu -C=NAME,TYPE
NAME TYPE
L1d  Data
L1i  Instruction
L2   Unified
L3   Unified

9 CPUの情報をJSON形式で表示する方法(-J)

-JはCPUの情報をJSON形式で表示するオプションです。

[root@server ~]# lscpu -J
{
   "lscpu": [
      {
         "field": "アーキテクチャ:",
         "data": "x86_64",
-snip-

10 物理 ID を表示する代わりに論理 ID を表示する方法(-y)

[root@server ~]# lscpu -y
アーキテクチャ:                        x86_64
  CPU 操作モード:                      32-bit, 64-bit
  Address sizes:                       45 bits physical, 48 bits virtual
  バイト順序:                          Little Endian
CPU:                                   4
  オンラインになっている CPU のリスト: 0-3
ベンダー ID:                           GenuineIntel
  BIOS Vendor ID:                      Red Hat
  モデル名:                            Intel Core Processor (Skylake, IBRS)
    BIOS Model name:                   RHEL 7.6.0 PC (i440FX + PIIX, 1996)
    CPU ファミリー:                    6
    モデル:                            94
    コアあたりのスレッド数:            1
    ソケットあたりのコア数:            1
    ソケット数:                        4
    ステッピング:                      3
    BogoMIPS:                          5616.00
    フラグ:                            fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2
                                        ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology cpuid tsc_known_freq pni pc
                                       lmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f1
                                       6c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb stib
                                       p fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xget
                                       bv1 xsaves arat umip md_clear arch_capabilities
Virtualization features:
  ハイパーバイザのベンダー:            KVM
  仮想化タイプ:                        完全仮想化
Caches (sum of all):
  L1d:                                 128 KiB (4 instances)
  L1i:                                 128 KiB (4 instances)
  L2:                                  16 MiB (4 instances)
  L3:                                  64 MiB (4 instances)
NUMA:
  NUMA ノード数:                       1
  NUMA ノード 0 CPU:                   0-3
Vulnerabilities:
  Itlb multihit:                       Not affected
  L1tf:                                Mitigation; PTE Inversion
  Mds:                                 Mitigation; Clear CPU buffers; SMT Host state unknown
  Meltdown:                            Mitigation; PTI
  Mmio stale data:                     Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown
  Retbleed:                            Mitigation; IBRS
  Spec store bypass:                   Mitigation; Speculative Store Bypass disabled via prctl
  Spectre v1:                          Mitigation; usercopy/swapgs barriers and __user pointer sanitization
  Spectre v2:                          Mitigation; IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS Not affected
  Srbds:                               Unknown: Dependent on hypervisor status
  Tsx async abort:                     Not affected

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

DNSSECコマンドの使い方

1 はじめに

1.1 DNSSEC(DNS Security Extensions)とは?

DNSSECは、キャッシュDNSサーバの問い合わせに対して、以下を検証する仕組みです。
・応答が正当な権威DNSサーバからのものであること(真正性)
・応答が権威DNSサーバからの送信後に改ざんされていないこと(完全性)
DNSSECは、キャッシュポイズニングなどの攻撃によってキャッシュDNSサーバのキャッシュが改ざんされ、クライアントが意図しないサーバに誘導されるリスクを防ぐために使用します。ここでは、DNSSECで使うコマンドの使い方を説明します。なお、キャッシュDNSサーバと権威DNSサーバの関係は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

1.2 DNSSECで使用するコマンド

DNSSECでは、以下のコマンドを使います。

コマンド 用途
dnssec-keygen ZSK(*1),KSK(*2)を作成するコマンドです。ZSK,KSKはそれぞれ秘密鍵、公開鍵のペアからなります。つまり、4つの鍵が存在します
dnssec-signzone ZSK,KSKを使ってゾーンファイルに署名するコマンドです
dnssec-dsfromkey DSレコードを作成するコマンドです。DSリソースレコードは、KSK公開鍵のハッシュ値を含む情報です。自ゾーンのKSK公開鍵を検証するために上位の権威DNSサーバに登録します

(*1) Zone Signing Key(ゾーン署名鍵)
(*2) Key Signing Key(鍵署名鍵)

ZSK,KSKの用途は以下のとおりです。

名称 用途
ZSK ゾーンファイルのリソースレコードに署名をするために使用します
KSK ZSKに署名するために使用します

2 検証環境

プライマリーサーバのAlmaLinux版数は以下のとおりです。

[root@primary ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@primary ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 ZSK,KSKの作成方法

ZSK,KSKはdnssec-keygenコマンドを使って作成します。コマンドの書式は以下のとりです。

dnssec-keygen [オプション] ドメイン名

オプションの意味は以下のとおりです。

オプション 意味
-f KSK:KSKを作成するときに指定します
REVOKE:作成した鍵を無効化するときに指定します
未指定:ZSKを作成する場合、オプションを指定する必要はありません
-a 暗号アルゴリズムを指定します。RSASHA1, NSEC3RSASHA1, RSASHA256, RSASHA512, ECDSAP256SHA256, ECDSAP384SHA384, ED25519, ED448のいずれかを指定します
-b 鍵のサイズ(bit)を指定するオプションです。オプションを指定しなければデフォルトの鍵サイズが使用されます。たとえば、ゾーンの署名に使うRSAの場合1024(bit)、鍵の署名に使うRSAの場合2048(bit)になります
RSASHA1:1024~4096
NSEC3RSASHA1:1024~4096
-K(大文字) ZSK,KSKを作成するディレクトリを指定するオプションです
-n 鍵のオーナタイプを指定するオプションです。 ZONE,HOST,ENTITY,USER ,OTHERのいずれかを指定します

3.2 KSKの作成方法

KSKを作成します。

[root@primary ~]# dnssec-keygen -f KSK -a RSASHA256 -b 1024 -K /var/named/keys -n zone abc.test
Generating key pair............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .............++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Kabc.test.+008+18256

作成したKSKを確認します。KSKの公開鍵(key)と秘密鍵(private)が作成されたことがわかります。

[root@primary ~]# ls -l /var/named/keys/
合計 8
-rw-r--r--. 1 root root  424  6月 11 22:05 Kabc.test.+008+18256.key
-rw-------. 1 root root 1012  6月 11 22:05 Kabc.test.+008+18256.private

公開鍵の中身を確認してみます。

[root@primary ~]# cat  /var/named/keys/Kabc.test.+008+18256.key
; This is a key-signing key, keyid 18256, for abc.test.
; Created: 20230611130539 (Sun Jun 11 22:05:39 2023)
; Publish: 20230611130539 (Sun Jun 11 22:05:39 2023)
; Activate: 20230611130539 (Sun Jun 11 22:05:39 2023)
abc.test. IN DNSKEY 257 3 8 AwEAAbsk2bsnSHR/+xywTwKAAWZiTFHLv67DwWDxpWiu6dRq3DTH1xRL 4McB9vpCjUac8XzO4QUZKayPQ7eON0cHSroGYEcFmX3ghJ1MJu1l/FPW RMaRABD6rHaSqnStrKhlza0aZ5DXdi/VOaY2xFd1PCkFwA67FosSHFTI SfbmWoOP

DNSKEYレコードのフォーマットは以下のとおりです。
フォーマットは、RFC 4034: Resource Records for the DNS Security Extensionsで規定されています。

<ドメイン名> IN DNSKEY <フラグ> <プロトコル> <アルゴリズム> <公開鍵>
レコード 意味
フラグ 256はZSK、257はKSKを意味します
プロトコル プロトコル番号は3になります。
アルゴリズム DNSSECアルゴリズム番号を意味します。8はRSA/SHA-256アルゴリズムを示しています。詳細はhttps://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtmlを参照ください
公開鍵 公開鍵をBase64エンコードした文字列です

3.3 ZSKの作成方法

[root@primary ~]# dnssec-keygen -a RSASHA256 -b 1024 -K /var/named/keys -n zone abc.test
Generating key pair......................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ....................................................++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Kabc.test.+008+43296

作成したZSKを確認します。ZSKの公開鍵(key)と秘密鍵(private)が作成されたことがわかります。

[root@primary ~]# ls -l /var/named/keys/
合計 16
-rw-r--r--. 1 root root  424  6月 11 22:05 Kabc.test.+008+18256.key
-rw-------. 1 root root 1012  6月 11 22:05 Kabc.test.+008+18256.private
-rw-r--r--. 1 root root  425  6月 11 22:45 Kabc.test.+008+43296.key
-rw-------. 1 root root 1012  6月 11 22:45 Kabc.test.+008+43296.private
[root@primary ~]# cat /var/named/keys/Kabc.test.+008+43296.key
; This is a zone-signing key, keyid 43296, for abc.test.
; Created: 20230611134551 (Sun Jun 11 22:45:51 2023)
; Publish: 20230611134551 (Sun Jun 11 22:45:51 2023)
; Activate: 20230611134551 (Sun Jun 11 22:45:51 2023)
abc.test. IN DNSKEY 256 3 8 AwEAAdM31XgEivQjEwdaMD5Q6+4yi//wZFq3fz0WzgL/bwvIXvppyGL8 bP0yL0ILgx+tN4bNvhUvUTo7yE/C01Ra2axPyAgQ/RO4AUMxxVzagCyw JiLUPIkQCCtTCskStTVlIlhOoTL6j1S+QiQpVgaClv/o6tzItvhrJR1T EbsLjgy7

4 リソースレコードの署名方法

ゾーンファイル内のリソースレコードに署名するためには、dnssec-signzoneコマンドを使用します。以下にコマンドの書式の例を示します。

dnssec-signzone [オプション] ゾーンファイル [keys]

オプションの意味は以下のとおりです。

オプション 意味
-a 生成されたすべての署名を検証するときに指定します
-S 鍵をゾーンファイル書き込むときに指定します
-x BIND 9がDNSKEY、CDNSKEY、およびCDSのRRセットに対してのみキーサインキーで署名し、ゾーンサインキーによる署名を省略することを示します
-3 salt ソルトを指定します。このソルトを使用してNSEC3チェーンを生成します
-K(大文字) DNSSECキーを検索するためのディレクトリを指定します。指定されていない場合、デフォルトで現在のディレクトリが使用されます
-o ゾーンのオリジンを指定します

dnssec-signzoneコマンドを使ってリソースレコードに署名をします。以下の例ではソルト(-3)に1234、オリジン(-o)にabc.testを指定しています。

[root@primary ~]# dnssec-signzone -a -S -x -3 1234 -K /var/named/keys -o abc.test /var/named/abc.test.db
Fetching abc.test/RSASHA256/18256 (KSK) from key repository.
Fetching abc.test/RSASHA256/43296 (ZSK) from key repository.
Verifying the zone using the following algorithms:
- RSASHA256
Zone fully signed:
Algorithm: RSASHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                      ZSKs: 1 active, 0 present, 0 revoked
/var/named/abc.test.db.signed

ゾーンファイルを確認します。abc.test.db.signedというファイルが作成されたことがわかります。

[root@primary ~]# ls -l /var/named/abc.test.db*
-rw-r--r--. 1 root root  485  6月  1 19:58 /var/named/abc.test.db
-rw-r--r--. 1 root root  451  6月  1 19:58 /var/named/abc.test.db.org
-rw-r--r--. 1 root root 3966  6月 12 21:49 /var/named/abc.test.db.signed

作成したゾーンファイルの中身を確認します。既存のレコードに加え、RRSIGレコード、NSEC3PARAMレコード、NSEC3レコードが追加されていることがわかります。

[root@primary ~]# cat /var/named/abc.test.db.signed
; File written on Mon Jun 12 21:49:47 2023
; dnssec_signzone version 9.16.23-RH
abc.test.               3600    IN SOA  primary.abc.test. root.abc.test. (
                                        2023052802 ; serial
                                        300        ; refresh (5 minutes)
                                        900        ; retry (15 minutes)
                                        3600       ; expire (1 hour)
                                        3600       ; minimum (1 hour)
                                        )
                        3600    RRSIG   SOA 8 2 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        zwap89WPc+C/NZD072SLvnTUD8308ZOzb8tx
                                        Hj0/o7EUyKKKO8RnsJxeAu14bWpD3bXU9YEF
                                        cL+9NwitF/pdgePSu9kLdLJOFHj+q1xdToZe
                                        ISBa+qH6DqNSds2CpH11wON3I8UmGl1cqgeB
                                        rQxoFX4OXq0n/Myegk7Ae7TMuzE= )
                        3600    NS      primary.abc.test.
                        3600    RRSIG   NS 8 2 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        ItAfBAP0ndlLr6Y9Zo3fiFaasOCk1lUT3q7S
                                        Rcga8f/9Uij9ASqKt+W+iBO33zCbHeUwPhtX
                                        t6C30GmPDXS4ox2OX6Xlv8NYM8ICjBHrC2pN
                                        wwM4tD+uG4DG2y6kDp/wMY5JUDwjIohVp8Ck
                                        O5zS/wIKei5s1zPtt1tx8vnyoGk= )
                        3600    DNSKEY  257 3 8 (
                                        AwEAAbsk2bsnSHR/+xywTwKAAWZiTFHLv67D
                                        wWDxpWiu6dRq3DTH1xRL4McB9vpCjUac8XzO
                                        4QUZKayPQ7eON0cHSroGYEcFmX3ghJ1MJu1l
                                        /FPWRMaRABD6rHaSqnStrKhlza0aZ5DXdi/V
                                        OaY2xFd1PCkFwA67FosSHFTISfbmWoOP
                                        ) ; KSK; alg = RSASHA256 ; key id = 18256
                        3600    DNSKEY  256 3 8 (
                                        AwEAAdM31XgEivQjEwdaMD5Q6+4yi//wZFq3
                                        fz0WzgL/bwvIXvppyGL8bP0yL0ILgx+tN4bN
                                        vhUvUTo7yE/C01Ra2axPyAgQ/RO4AUMxxVza
                                        gCywJiLUPIkQCCtTCskStTVlIlhOoTL6j1S+
                                        QiQpVgaClv/o6tzItvhrJR1TEbsLjgy7
                                        ) ; ZSK; alg = RSASHA256 ; key id = 43296
                        3600    RRSIG   DNSKEY 8 2 3600 (
                                        20230712114947 20230612114947 18256 abc.test.
                                        Sh+47dbiEg1QiUn5N4aystCzZoPioxdgtmHu
                                        hpIO9E9+VC3ZUjDKLSn9uFg64plXHgx5EG8v
                                        Wy15gSyLW5IWUEX0y3rxzi9MbwhUAe5YJm74
                                        EmwPea3dUzIpUkZZXH3vBcm9O1Ke3lv8V1Rt
                                        LiQwtksJGFzoGJpnsRI3Evc3Os4= )
                        0       NSEC3PARAM 1 0 10 1234
                        0       RRSIG   NSEC3PARAM 8 2 0 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        J549EEC6bARktJaTXPKsvhF3AxK+AoCV+jt5
                                        HaAA5A3Jm1Ts6k8XQE6bjV+Pb5a8PUNrkeLM
                                        6ZEF2w9MwlLpEdmoiCHN7JpDAhfCvxSBKZ6v
                                        ueGxgoMXUdT0etaFsRVpFiAz3LZXTAd8jkcE
                                        OqHmxaTAT3dT1K044t7BXaIDf4k= )
primary.abc.test.       3600    IN A    192.168.122.16
                        3600    RRSIG   A 8 3 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        IMHwi3Icml76UOlEbjgQ3XkmH+s+hEWhismT
                                        J9ZyPKiXSTpcT+EAzmrRP0f0jUTXVKIT/mfv
                                        GJutJqCibE1OZv6wNBAfff1M4P9sW1ykyuUc
                                        S3kl7hgM9+r6c3fmw8TIW21rfzH8KGY3qnzl
                                        nRkM5Abd80eoGyKB8kMum6+KIWw= )
FKUSJSS19E8994LO00GH510HCD7I4AMM.abc.test. 3600 IN NSEC3 1 0 10 1234 (
                                        UBJNF1IDKRB7SGG2P11RLSAI7GBSJ38J
                                        A RRSIG )
                        3600    RRSIG   NSEC3 8 3 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        UVyKxOeyRyn3l+erymeb3kgknL/0TpxAlPQS
                                        A7JOK9VSXrzzKsOFCO9Ohu9laWw3ZXwcpoky
                                        +q9Vh6P6tKSlNgvQPu8p6XWCAznDXRPov2pA
                                        38NoCQsTbZY0A/Pbcalr/euK5gZRrcS3Lub1
                                        BaJ3jV/r/YyGn33fM4ma4/vYVqw= )
BK5S6VI9M6F57QF0ODM1CR8ITTMJTJ3P.abc.test. 3600 IN NSEC3 1 0 10 1234 (
                                        FKUSJSS19E8994LO00GH510HCD7I4AMM
                                        NS SOA RRSIG DNSKEY NSEC3PARAM )
                        3600    RRSIG   NSEC3 8 3 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        Jdhz/pK/5JxDQDpbeDXvJdfz5Qlab76uYeR/
                                        ++FMFWhSj0UkbKuRRJzZBlJaUmfzKfEed/SK
                                        Gj0isMxsw40FWxxJS4rMW3FBbl8K3PKV4KR9
                                        DJ864iZPOC6oKKb1IV4p1+oSXQQD5AQiJLDy
                                        OeCPgC/fIRy0i/TfHC+qzZM774A= )
www.abc.test.           3600    IN A    192.168.122.20
                        3600    RRSIG   A 8 3 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        JKMVPFA6sEChBRp8DvZnJO+UE23z6fcRAfxm
                                        BVmeln1vAcjND85+IT0vLkp3G78CZaEn5Jeg
                                        w9Fk/RM5uC3+0j1RWEfI9Ri/4Fh0IesJCgAt
                                        1od1zww6C23itIf5C0nhrb+PNn22sfy8UQQD
                                        xaMBzwrjHBBWnmV+6FsDuQoyYEo= )
UBJNF1IDKRB7SGG2P11RLSAI7GBSJ38J.abc.test. 3600 IN NSEC3 1 0 10 1234 (
                                        BK5S6VI9M6F57QF0ODM1CR8ITTMJTJ3P
                                        A RRSIG )
                        3600    RRSIG   NSEC3 8 3 3600 (
                                        20230712114947 20230612114947 43296 abc.test.
                                        ZoYTcbesk0srNmHwT/AIHNB9KY4iwt8qp0rQ
                                        ma1iX73Ixn51UbUCVIKNLPHml+8Pfm3Z6J57
                                        chg/FtfUKrj9V6P+ZcP+FpnJy0YvepIYB6ro
                                        EmwYJSqJGmJp6zlqtKhHurDWfFqeSy57YVX1
                                        mOg2rzfr6trFIDUpfkTacoKEyAU= )

各種リソースレコードの意味を以下に示します。

レコード名 意味
RRSIG 各リソースレコードに対する署名が格納されます
NSEC3 リソースレコードの情報をハッシュしたNSEC
NSEC3PARAM NSEC3の利用に必要とされる情報

5 DSリソースレコードの作成方法

DSリソースレコードは、dnssec-dsfromkeyコマンドを使って作成します。dnssec-dsfromkeyコマンドの書式は以下のとおりです。キーファイルには、KSKの公開鍵を指定します。

dnssec-dsfromkey [オプション] キーファイル 

オプションの意味は以下のとおりです。

オプション 意味
-1 ハッシュ値を生成するアルゴリズムSHA-1を使用する
-2 ハッシュ値を生成するアルゴリズムにSHA-256を使用する
-a ハッシュ値を生成するアルゴリズムを指定するオプションです

KSKの公開鍵を指定して、dnssec-dsfromkeyコマンドを実行します。

[root@server ~]# dnssec-dsfromkey /var/named/keys/Kabc.test.+008+18256.key
abc.test. IN DS 18256 8 2 9C4C6BBD44E0F04BEFB50729773F75461A166BF4823D9F911F0EACEE8E88FD45

BINDの使い方(TSIG)

1 TSIG(Transaction Signature)とは?

TSIGは次のことを保証する仕組みです。
DNSメッセージの完全性
DNSメッセージ送信元の真正性
これにより、プライマリーサーバとセカンダリーサーバの間でゾーン情報を安全に転送することができます。TSIG はDNS メッセージにTSIGレコードを付加することで、DNS メッセージに電子署名を行います。なお、ゾーン転送は、BINDの使い方(ゾーン転送) - hana_shinのLinux技術ブログを参照してください。

2 検証環境

2.1 ネットワーク構成

DNSサーバは、プライマリーサーバとセカンダリーサーバの2台構成です。

                       192.168.122.0/24
primary(eth0) ----------------------------------(eth0) secondary
             .16                             .213

2.2 版数

プライマリーサーバとセカンダリーサーバのAlmaLinux版数は以下のとおりです。

[root@primary ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@primary ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 動作確認

bindパッケージのインストール方法やポート番号の開放は、BINDの使い方(ゾーン転送) - hana_shinのLinux技術ブログを参照ください。

3.1 共有鍵の作成

共有鍵はtsig-keygenコマンドを使って作成します。書式は以下のとおりです。tsig-keygenコマンドの引数にはハッシュ関数と共有鍵名を指定します。デフォルトのハッシュ関数はhmac-sha256です。

# tsig-keygen -a [アルゴリズム] 共有鍵名

tsig-keygenコマンドを使用して共有鍵を作成します。共有鍵の名前はprimary-secondaryとします。

[root@primary ~]# tsig-keygen primary-secondary
key "primary-secondary" {
        algorithm hmac-sha256;
        secret "QBTirziTOPJe3Fa0lA8hVXt9hNxuqAAKz8jIwYiZGck=";
};

3.2 プライマリーサーバ

作成した共有鍵をプライマリーサーバの設定ファイルに追加します。

[root@primary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-06-03 23:42:27.674145301 +0900
+++ /etc/named.conf     2023-06-03 23:40:37.412881984 +0900
@@ -63,3 +63,10 @@
        allow-transfer { 192.168.122.213; };
        notify yes;
 };
+
+key "primary-secondary" {
+        algorithm hmac-sha256;
+        secret "QBTirziTOPJe3Fa0lA8hVXt9hNxuqAAKz8jIwYiZGck=";
+};
+
+

3.3 セカンダリーサーバ

作成した共有鍵をセカンダリーサーバの設定ファイルに追加します。さらに、共有鍵を使用するため、serverステートメント内でkeysサブステートメントを使って定義します。keysサブステートメント内のパラメータは鍵の名前(primary-secondary)を指定します。

[root@secondary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-06-03 23:43:34.299629797 +0900
+++ /etc/named.conf     2023-06-03 23:50:39.562587606 +0900
@@ -62,3 +62,13 @@
        file "slaves/abc.test.db";
        masters { 192.168.122.16; };
 };
+
+key "primary-secondary" {
+        algorithm hmac-sha256;
+        secret "QBTirziTOPJe3Fa0lA8hVXt9hNxuqAAKz8jIwYiZGck=";
+};
+
+server 192.168.122.16 {
+        keys { primary-secondary; };
+};
+

3.4 TSIGレコードの確認

TSIG レコードを確認するため、tcpdumpコマンドを実行します。tcpdumpコマンドの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。

[root@secondary ~]# tcpdump -i eth0 host 192.168.122.16 and port 53 -w dns.pcap

セカンダリーサーバのnamedを起動したらすぐにゾーン転送が行われるようにするため、セカンダリーサーバの/var/named/slaves配下のゾーンファイルを削除します(もし存在していたら)。以下の実行例では、ゾーンファイルが存在しないことがわかります。

[root@secondary ~]# ls /var/named/slaves/
[root@secondary ~]#

プライマリーサーバでnamedサービスを起動します。

[root@primary ~]# systemctl start named

セカンダリーサーバでnamedサービスを起動すると、ゾーン転送が開始されます。

[root@secondary ~]# systemctl start named

以下は、セカンダリーサーバからプライマリーサーバにゾーン転送を要求したときのWiresharkのキャプチャ画面です。Additional RRsが1となっていて、TSIGレコードが1つ追加されていることがわかります。また、TSIGレコードのMACフィールドは、DNSメッセージの完全性/真正性を実現するために使用されます。

次は、プライマリーサーバからセカンダリーサーバにゾーン転送をしている時のWiresharkのキャプチャ画面です。

BINDの使い方(ゾーン転送)

1 はじめに

DNSの運用では、複数の権威DNSサーバを用意するのが一般的です。複数の権威DNSサーバを運用する場合、全ての権威DNSサーバでゾーンファイルを一致させる必要があります。管理者がこれを手作業で行うのは手間がかかり、ミスも発生します。このため、DNSでは複数の権威DNSサーバでゾーンファイルを同期するゾーン転送という仕組みがあります。ゾーンファイルを管理する権威DNSサーバをプライマリーサーバと呼び、ゾーン転送によってゾーンファイルのコピーを受け取り運用するサーバをセカンダリーサーバと呼びます。なお、検証に使うドメイン名は、RFC 2606 - Reserved Top Level DNS Namesで以下のように記述されているので、abc.testとします。

".test" is recommended for use in testing of current or new DNS related code.

DNSの名前解決の様子は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

2 検証環境

2.1 ネットワーク構成

DNSサーバは、プライマリーサーバとセカンダリーサーバの2台構成です。

                       192.168.122.0/24
primary(eth0) ----------------------------------(eth0) secondary
             .16                             .213

2.2 版数

プライマリーサーバとセカンダリーサーバのAlmaLinux版数は以下のとおりです。

[root@primary ~]# cat /etc/redhat-release
AlmaLinux release 9.1 (Lime Lynx)

カーネル版数は以下のとおりです。

[root@primary ~]# uname -r
5.14.0-162.6.1.el9_1.x86_64

3 インストール方法

プライマリーサーバとセカンダリーサーバで bindパッケージ、bind-utilsパッケージをインストールします。なお、dnfコマンドの使い方は、dnfコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@primary ~]# dnf -y install bind bind-utils

BINDの版数を確認します。

[root@primary ~]# named -v
BIND 9.16.23-RH (Extended Support Version) <id:fde3b1f>

4 ポート番号の開放

ゾーン転送に使うTCP/UDPのポート番号53を解放します。なお、firewall-cmdの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。

4.1 プライマリーサーバのポート番号開放

[root@primary ~]# firewall-cmd --add-port=53/tcp
success
[root@primary ~]# firewall-cmd --add-port=53/udp
success

開放したポート番号を確認します。

[root@primary ~]# firewall-cmd --list-ports
53/tcp 53/udp

4.2 セカンダリーサーバのポート番号開放

[root@secondary ~]# firewall-cmd --add-port=53/tcp
success
[root@secondary ~]# firewall-cmd --add-port=53/udp
success

開放したポート番号を確認します。

[root@secondary ~]# firewall-cmd --list-ports
53/tcp 53/udp

5 プライマリーサーバの設定

5.1 設定ファイルの編集

設定ファイル編集前後の差分を確認するため、バックアップファイルを作成します。

[root@primary ~]# cp /etc/named.conf /etc/named.conf.org

設定ファイルの差分を確認します。

[root@primary ~]# vi /etc/named.conf
[root@primary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-05-21 20:12:04.638427807 +0900
+++ /etc/named.conf     2023-05-27 19:59:22.375933433 +0900
@@ -8,7 +8,7 @@
 //

 options {
-       listen-on port 53 { 127.0.0.1; };
+       listen-on port 53 { 192.168.122.16; };
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
@@ -16,7 +16,7 @@
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
-       allow-query     { localhost; };
+       allow-query     { any; };

        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
@@ -28,7 +28,7 @@
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
-       recursion yes;
+       recursion no;

        dnssec-validation yes;

@@ -57,3 +57,9 @@
 include "/etc/named.rfc1912.zones";
 include "/etc/named.root.key";

+zone "abc.test" IN {
+       type master;
+       file "abc.test.db";
+       allow-transfer { 192.168.122.213; };
+       notify yes;
+};

設定変更したステートメントの意味を以下に示します。

ステートメント 意味
listen-on DNSサーバが問い合わせを受け付けるIPアドレスを設定します。
allow-query DNSクエリーを受け付けるDNSクライアントのIPアドレスを設定します。ここでは、全てのDNSクライアントからのDNSクエリを受け付けるanyを設定します。
recursion 再帰問い合わせを受け付けるかどうかを設定します。DNS権威サーバは再帰クエリは受け付けないのでnoを設定します
type DNSサーバがプライマリーサーバか、セカンダリーサーバなのかを設定します。プライマリーサーバはmaster、セカンダリーサーバはslave、DNSキャッシュサーバはhintを設定します。
file ゾーンファイル名を設定します。ゾーンファイルは、directoryステートメントで指定したディレクトリ以下に格納されます
allow-transfer ゾーンファイルの転送を許可するセカンダリーサーバのIPアドレスを設定します。
notify プライマリーサーバのゾーンファイルが更新された時、セカンダリーサーバに更新があったことを通知するかどうかを設定します。通知する場合はyes、通知しない場合はnoを設定します。

5.2 ゾーンファイルの作成

ゾーン転送の動作確認をするため、正引きのゾーンファイルのみを作成します。ゾーン転送はゾーンファイルのSOAレコードで制御されます。なお、SOAレコードのパラメータの意味は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@primary ~]# vi /var/named/abc.test.db
[root@primary ~]# cat /var/named/abc.test.db
$ORIGIN abc.test.
$TTL 3600
@    IN SOA     primary.abc.test. root.abc.test. (
                                        2023052801 ; serial
                                        300        ; refresh
                                        900        ; retry
                                        3600       ; expire
                                        3600 )     ; minimum
           NS      primary.abc.test.
primary    A       192.168.122.16

6 セカンダリーサーバの設定

6.1 設定ファイルの編集

設定ファイル編集前後の差分を確認するため、バックアップファイルを作成します。

[root@secondary ~]# cp /etc/named.conf /etc/named.conf.org

設定ファイルの差分を確認します。

[root@secondary ~]# vi /etc/named.conf
[root@secondary ~]# diff -Nur /etc/named.conf.org /etc/named.conf
--- /etc/named.conf.org 2023-05-21 20:16:02.611164689 +0900
+++ /etc/named.conf     2023-05-21 20:18:38.335385768 +0900
@@ -8,7 +8,7 @@
 //

 options {
-       listen-on port 53 { 127.0.0.1; };
+       listen-on port 53 { 192.168.122.213; };
        listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
@@ -16,7 +16,7 @@
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
-       allow-query     { localhost; };
+       allow-query     { any; };

        /*
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
@@ -28,7 +28,7 @@
           attacks. Implementing BCP38 within your network would greatly
           reduce such attack surface
        */
-       recursion yes;
+       recursion no;

        dnssec-validation yes;

@@ -57,3 +57,8 @@
 include "/etc/named.rfc1912.zones";
 include "/etc/named.root.key";

+zone "abc.test" IN {
+       type slave;
+       file "slaves/abc.test.db";
+       masters { 192.168.122.16; };
+};

7 設定ファイル、ゾーンファイルの構文チェック

設定ファイル、およびゾーンファイルの構文が正しいかどうかをチェックします。それぞれ、以下のコマンドでチェックすることができます。
・named-checkconf:設定ファイル(named.conf)の構文チェック
・named-checkzone:ゾーンファイルの構文チェック

7.1 プライマリーサーバ

named-checkconfコマンドを使って、プライマリーサーバの設定ファイルの構文をチェックします。named-checkconfコマンドが正常終了しているので、設定ファイルに誤りがないことがわかります。

[root@primary ~]# named-checkconf /etc/named.conf
[root@primary ~]#

named-checkzoneコマンドを使って、プライマリーサーバのゾーンファイルの構文をチェックします。named-checkzoneコマンドが正常終了しているので、ゾーンファイルに誤りがないことがわかります。

[root@primary ~]# named-checkzone abc.test /var/named/abc.test.db
zone abc.test/IN: loaded serial 2023052801
OK

7.2 セカンダリーサーバ

named-checkconfコマンドを使って、セカンダリーサーバの設定ファイルの構文をチェックします。named-checkconfコマンドが正常終了しているので、設定ファイルに誤りがないことがわかります。

[root@secondary ~]# named-checkconf /etc/named.conf
[root@secondary ~]#

8 セカンダリサーバ起動時のシーケンス

セカンダリサーバ起動時、プライマリサーバからセカンダリサーバにゾーンファイルが転送されます。その時の状況を確認してみます。

プライマリーサーバでnamedサービスを起動します。

[root@primary ~]# systemctl start named

セカンダリーサーバのゾーンファイルを確認すると、まだゾーンファイルが存在しないことがわかります。

[root@secondary ~]# ls -l /var/named/slaves
合計 0

セカンダリーサーバでnamedサービスを起動します。

[root@secondary ~]# systemctl start named

セカンダリーサーバでnamedサービスを起動すると、プライマリーサーバからセカンダリサーバにゾーンファイルが転送されたことがわかります。

[root@secondary ~]# ls -l /var/named/slaves/abc.test.db
-rw-r--r--. 1 named named 203  5月 31 20:03 /var/named/slaves/abc.test.db

ゾーンファイルはバイナリファイルなので、named-compilezoneコマンドを使ってテキストファイルに変換します。

[root@secondary ~]# named-compilezone -f raw -F text -o /tmp/abc.test.db abc.test. /var/named/slaves/abc.test.db
zone abc.test/IN: loaded serial 2023052801
dump zone to /tmp/abc.test.db...done
OK

ゾーンファイルを確認すると、プライマリサーバのゾーンファイルが転送されたことがわかります。

[root@secondary ~]# cat /tmp/abc.test.db
abc.test.                                     3600 IN SOA       primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600
abc.test.                                     3600 IN NS        primary.abc.test.
primary.abc.test.                             3600 IN A         192.168.122.16

tcpdumpコマンドで採取したゾーン転送時のキャプチャファイルを以下に示します。

キャプチャファイルのシーケンスを以下に示します。まず、セカンダリサーバはUDPを使用してゾーンファイルの転送を要求します。そして、ゾーンファイルが存在する場合は、TCPコネクションを確立し、ゾーンファイルの転送を行います。ゾーンファイルの転送が完了すると、セカンダリサーバはTCPコネクションをクローズします。

プライマリーサーバ                      セカンダリーサーバ

TCP/53    UDP/53                         UDP/53    TCP/53
  |          |                             |          |
  |          |<----- DNS query ------------|          | ---
  |          |                             |          |  | <= ゾーンファイルの確認
  |          |------ DNS query response -->|          | ---
  |          |                             |          |
  |<---------|------ TCP SYN --------------|----------| ---
  |----------|------ TCP SYN+ACK ----------|--------->|  | <= TCPコネクションの確立
  |<---------|------ TCP ACK --------------|----------| ---
  |          |                             |          |
  |<---------|------ DNS query ------------|----------| ---
  |          |                             |          |  | <= ゾーンファイルの転送
  |----------|------ DNS query response ---|--------->| ---
  |          |                             |          |
  |<---------|------ TCP FIN --------------|----------| ---
  |----------|------ TCP FIN+ACK ----------|--------->|  | <= TCPコネクションのクローズ
  |<---------|------ TCP ACK --------------|----------| ---
  |          |                             |          |

9 セカンダリサーバ起動後のシーケンス

セカンダリサーバが起動した後、プライマリサーバとのパケットのやりとりを確認してみます。セカンダリサーバは定期的にプライマリサーバに対してゾーンファイルの更新があるかどうかをチェックします。このチェックはおおよそ4分の間隔で行われています。私はSOAレコードのrefreshで指定した間隔で行われると思っていたため、5分間隔で行われると考えていました。しかし、実際は違っていました。なぜ5分間隔でチェックが行われないのかについて、ご存じの方がいらっしゃいましたら、教えていただけませんか。

[root@secondary ~]# tcpdump -i eth0 host 192.168.122.16 and port 53 -v -nn
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
21:46:00.719188 IP (tos 0x0, ttl 64, id 12655, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.42212 > 192.168.122.16.53: 34635 [1au] SOA? abc.test. (41)
21:46:00.724449 IP (tos 0x0, ttl 64, id 27651, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.42212: 34635*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
21:49:53.730645 IP (tos 0x0, ttl 64, id 63337, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.32943 > 192.168.122.16.53: 17190 [1au] SOA? abc.test. (41)
21:49:53.738170 IP (tos 0x0, ttl 64, id 14792, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.32943: 17190*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
21:54:36.741113 IP (tos 0x0, ttl 64, id 58342, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.48592 > 192.168.122.16.53: 27517 [1au] SOA? abc.test. (41)
21:54:36.747100 IP (tos 0x0, ttl 64, id 32930, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.48592: 27517*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052801 300 900 3600 3600 (124)
-snip-

10 ゾーンファイル編集後のシーケンス

ゾーンファイルを編集します。シリアル番号を1増やして、wwwサーバのリソースレコードを1つ追加します。

[root@primary ~]# vi /var/named/abc.test.db
[root@primary ~]# diff -Nur /var/named/abc.test.db.org /var/named/abc.test.db
--- /var/named/abc.test.db.org  2023-06-01 19:58:07.222806548 +0900
+++ /var/named/abc.test.db      2023-06-01 19:50:41.223070363 +0900
@@ -1,10 +1,11 @@
 $ORIGIN abc.test.
 $TTL 3600
 @    IN SOA     primary.abc.test. root.abc.test. (
-                                        2023052801 ; serial
+                                        2023052802 ; serial
                                         300        ; refresh
                                         900        ; retry
                                         3600       ; expire
                                         3600 )     ; minimum
            NS      primary.abc.test.
 primary    A       192.168.122.16
+www        A       192.168.122.20

ゾーンファイルを編集したら、namedを再起動します。

[root@primary ~]# rndc reload
server reload successful

tcpdumpコマンドを使って、ゾーン転送時のパケットをキャプチャします。

[root@secondary ~]# tcpdump -i eth0 host 192.168.122.16 and port 53 -v -nn
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
-snip-
19:54:33.608079 IP (tos 0x0, ttl 64, id 14416, offset 0, flags [none], proto UDP (17), length 69)
    192.168.122.213.36158 > 192.168.122.16.53: 52391 [1au] SOA? abc.test. (41)
19:54:33.612003 IP (tos 0x0, ttl 64, id 34989, offset 0, flags [none], proto UDP (17), length 152)
    192.168.122.16.53 > 192.168.122.213.36158: 52391*- 1/1/2 abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600 (124)
19:54:33.613313 IP (tos 0x0, ttl 64, id 59507, offset 0, flags [none], proto TCP (6), length 60)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [S], cksum 0x7665 (incorrect -> 0x89b9), seq 256144245, win 64240, options [mss 1460,sackOK,TS val 2617157140 ecr 0,nop,wscale 7], length 0
19:54:33.615881 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [S.], cksum 0x5884 (correct), seq 62942961, ack 256144246, win 65160, options [mss 1460,sackOK,TS val 75478619 ecr 2617157140,nop,wscale 7], length 0
19:54:33.616054 IP (tos 0x0, ttl 64, id 59508, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x83e0), ack 1, win 502, options [nop,nop,TS val 2617157143 ecr 75478619], length 0
19:54:33.616912 IP (tos 0x0, ttl 64, id 59509, offset 0, flags [none], proto TCP (6), length 129)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [P.], cksum 0x76aa (incorrect -> 0xd6cf), seq 1:78, ack 1, win 502, options [nop,nop,TS val 2617157144 ecr 75478619], length 77 9258 [1n] IXFR? abc.test. (75)
19:54:33.619731 IP (tos 0x0, ttl 64, id 65243, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [.], cksum 0x8388 (correct), ack 78, win 509, options [nop,nop,TS val 75478622 ecr 2617157144], length 0
19:54:33.621098 IP (tos 0x0, ttl 64, id 65244, offset 0, flags [DF], proto TCP (6), length 215)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [P.], cksum 0x486d (correct), seq 1:164, ack 78, win 509, options [nop,nop,TS val 75478624 ecr 2617157144], length 163 9258*- 5/0/0 abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600, abc.test. NS primary.abc.test., primary.abc.test. A 192.168.122.16, www.abc.test. A 192.168.122.20, abc.test. SOA primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600 (161)
19:54:33.621139 IP (tos 0x0, ttl 64, id 59510, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x82e7), ack 164, win 501, options [nop,nop,TS val 2617157148 ecr 75478624], length 0
19:54:33.623264 IP (tos 0x0, ttl 64, id 59511, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [F.], cksum 0x765d (incorrect -> 0x82e4), seq 78, ack 164, win 501, options [nop,nop,TS val 2617157150 ecr 75478624], length 0
19:54:33.625855 IP (tos 0x0, ttl 64, id 65245, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.122.16.53 > 192.168.122.213.34845: Flags [F.], cksum 0x82d6 (correct), seq 164, ack 79, win 509, options [nop,nop,TS val 75478629 ecr 2617157150], length 0
19:54:33.625906 IP (tos 0x0, ttl 64, id 59512, offset 0, flags [none], proto TCP (6), length 52)
    192.168.122.213.34845 > 192.168.122.16.53: Flags [.], cksum 0x765d (incorrect -> 0x82db), ack 165, win 501, options [nop,nop,TS val 2617157153 ecr 75478629], length 0

named-compilezoneコマンドを使って、ゾーンファイルをテキストファイルに変換します。

[root@secondary ~]# named-compilezone -f raw -F text -o /tmp/abc.test.db abc.test. /var/named/slaves/abc.test.db
zone abc.test/IN: loaded serial 2023052802
dump zone to /tmp/abc.test.db...done
OK

ゾーンファイルを確認すると、シリアル番号が1つ増加したことと、wwwサーバのリソースレコードが追加されたことがわかります。

[root@secondary ~]# cat /tmp/abc.test.db
abc.test.                                     3600 IN SOA       primary.abc.test. root.abc.test. 2023052802 300 900 3600 3600
abc.test.                                     3600 IN NS        primary.abc.test.
primary.abc.test.                             3600 IN A         192.168.122.16
www.abc.test.                                 3600 IN A         192.168.122.20

11 ゾーンファイルの転送確認

ゾーンファイルを転送したセカンダリーサーバに対して名前解決を要求してみます。まず、primary.abc.testのIPアドレスの解決を要求してみます。primary.abc.testのIPアドレスが192.168.122.16であることがわかります。

[root@primary ~]# dig @192.168.122.213 primary.abc.test +short
192.168.122.16

次に、www.abc.testのIPアドレスの解決を要求してみます。www.abc.testのIPアドレスが192.168.122.20であることがわかります。

[root@primary ~]# dig @192.168.122.213 www.abc.test +short
192.168.122.20

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

BIND 9 Administrator Reference Manual — BIND 9 9.19.22-dev documentation