yum で古いパッケージをインストールする方法

何らかの理由で、古いパッケージをインストールしたい時のためのメモ。

yum で利用可能な古いパッケージを探すには、--showduplicates オプションを付加して検索する。

利用可能なパッケージは、RHELCentOSでは、動作が異なるらしい。
 RHEL :過去のバージョン全てを利用可能(たぶん、全てと思われる)
 CentOS:過去のバージョンの一部


RHEL 6.10の例

$ yum search --showduplicates nmap
・・・略
2:nmap-5.21-3.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.21-4.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-2.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-3.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-4.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-6.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-6.el6.x86_64 : Network exploration tool and security scanner


CentOS 6.10の例

$ yum search --showduplicates nmap
・・・略
2:nmap-frontend-5.51-6.el6.noarch : The GTK+ front end for nmap
2:nmap-5.51-6.el6.x86_64 : Network exploration tool and security scanner
2:nmap-5.51-6.el6.x86_64 : Network exploration tool and security scanner


CentOSの場合、パッケージによって利用可能なバージョンの数が異なる模様。

$ yum search --showduplicates firefox
・・・略
firefox-52.8.0-1.el6.centos.i686 : Mozilla Firefox Web browser
firefox-52.8.0-1.el6.centos.x86_64 : Mozilla Firefox Web browser
firefox-60.1.0-5.el6.centos.i686 : Mozilla Firefox Web browser
firefox-60.1.0-5.el6.centos.x86_64 : Mozilla Firefox Web browser
firefox-60.1.0-6.el6.centos.i686 : Mozilla Firefox Web browser
firefox-60.1.0-6.el6.centos.x86_64 : Mozilla Firefox Web browser
firefox-60.1.0-6.el6.centos.x86_64 : Mozilla Firefox Web browser


インストールの際は、パッケージ名のみでなく、バージョンまで含めて指定するとインストールできる。

# yum install firefox-52.8.0-1.el6.centos.x86_64

tcpdump でNSDのクエリログを取る

【環境】
CentOS 7.5
nsd-4.1.20-1.el7.x86_64


NSDDNSサーバ)だと、標準の機能ではクエリログを取得できない。
nsd-4.1.20 の時点では)

権威サーバでクエリログが必要なニーズが無いのかもしれないが、どれだけのクエリがあるのか調べたかったので、ログを取る方法を考えた。

で、思い付いたのが tcpdump でログを取ること。

#!/bin/bash

NIC="ens160"
DST_IP="192.168.1.20"
DST_PORT="53"
LOG_FILE="/var/log/nsd-query/query.log"
ROTATE_SIZE=10485760
REMOVE_RANGE=129600

# check log rotate
if [ ${ROTATE_SIZE} -lt $(ls -l ${LOG_FILE} | awk '{print $5}') ] ; then
  pkill -9 tcpdump
  mv ${LOG_FILE} ${LOG_FILE}"-"$(date "+%Y%m%d-%H%M%S")
fi

# remove old files
find $(dirname ${LOG_FILE}) -type f -name $(basename ${LOG_FILE})"*" -mmin +${REMOVE_RANGE} -delete

# start logger
if [ $(ps aux | grep tcpdump | grep -v 'grep' -c) -lt 1 ] ; then
  /usr/sbin/tcpdump -p -l -nn -tttt -i ${NIC} dst host ${DST_IP} and dst port ${DST_PORT} >> ${LOG_FILE} &
fi

このスクリプトは、以下のような動作を行う。

  • キャプチャするNIC、そのNICのIP、ポート番号を指定
  • クエリログの出力先を指定
  • クエリログをローテーションするファイルサイズ(バイト)の閾値を指定
  • 古いクエリログファイルを削除するための閾値(秒)を指定
  • クエリログのファイルのサイズが設定値を超えた場合、tcpdump プロセスをkill してログファイルをリネームしてmv
  • 指定秒より古いクエリログファイルがあれば削除
  • ps コマンドでtcpdump プロセスが見つからない場合だけ(重複起動をチェック)、ログ取得のためのtcpdump を実行

これを cron などで定期時刻すれば、重複実行を避けつつクエリログを取得し、ログファイルのローテーションを行う。
テキストファイルなので、cat(圧縮したものはzcat)で開き、適当な条件で grep する。


ログファイルのローテーションと言えば、logrotate が手軽だが、tcpdump をローテーションしようとすると、anacron がゾンビのように残ってしまい、うまくローテーションされなかった。

tcpdump にも、出力ファイルをローテーションするオプション(-G)があるが、tcpdump -w で生データを書き出す場合、-r オプションでしか読めず、gzip圧縮して出力場合は直接読み込めない。

圧縮して出力すると、いったん非圧縮ファイルへ書きだす必要があり、圧縮するのを止めようか迷ったが、容量圧迫のプレッシャーに勝てず断念。

また、tcpdump のローテーションでは、古いファイルを削除する仕組みが無い。

これらをうまく解決できず、シェルスクリプト側で無理やりローテーションするようにした。

NSD で複数のスレーブにゾーン転送する場合の記述例

【環境】
CentOS 7.5
nsd-4.1.20-1.el7.x86_64


マスタとして動作しているNSDにて、複数のスレーブ(NSDでもBINDでも)へゾーン転送したい場合の記述例。

ドキュメントに説明が書いてあるが、具体的な記述例がない。

ゾーン オプション

ゾーン毎に一つのzone:節で指定されるオプションが必要です。複数のサーバー
を加えるためにはアクセス制御リストの要素を複数回与えます。これらの要素は
明示的に追加される必要があります。

スレーブが複数ある場合には、設定をその分だけ列挙する。

例)

zone:
        name: "aaa.bbb.domain"
        zonefile: "aaa.bbb.domain.zone"
        provide-xfr: 192.168.1.6 NOKEY
        provide-xfr: 192.168.1.7 NOKEY
        notify: 192.168.1.6 NOKEY
        notify: 192.168.1.7 NOKEY
        notify-retry: 5
provide-xfr: 192.168.1.6 192.168.1.7 NOKEY
 あるいは
provide-xfr: 192.168.1.6, 192.168.1.7 NOKEY

のような書式ではエラーになる。
1つのIPについて1行記載し、スレーブが複数台の場合は繰り返す。

なお、ゾーン転送のログは、verbosity:1 にしないと確認できない。
(デフォルトは、verbosity:0 になっていて、ログに出ない)

参考;
nsd.conf(5) – 日本Unboundユーザー会

Postfix でメールの宛先をもとにフィルタする方法

テスト環境にて、誤ってメールを送信してしまう場合に備え、予め設定した宛先以外にはPostfixがメールを送信しないようにする方法。
但し、テスト環境におけるメールの送信は、他ホストのSMTPを利用せず、自身で動作しているPostfixから送信する前提。

【環境】
CentOS 6/postfix-2.6.6-8.el6.x86_64
CentOS 7/postfix-2.10.1-6.el7.x86_64


/etc/postfix/main.cf にて、ヘッダーのチェックを有効化する。

#header_checks = regexp:/etc/postfix/header_checks
 ↓
header_checks = regexp:/etc/postfix/header_checks


/etc/postfix/header_checks を開いて、正規表現でルールを記載する。

例)全て拒否

/^To: .*/ REJECT


$ mail root のようなローカル配送も失敗する。
 →エラーログ:reject: header To: root from local;
但し、その後、失敗した旨を通知するメールはroot宛等に送信される。


例)OK にマッチしたアドレスなら送信、マッチしない場合は全て拒否

/^To: hoge@myhostname.domain/ OK
/^To: .*/ REJECT


例)特定アドレスと特定ドメインへは送信を許可、マッチしなければ全て拒否

/^To: hoge@myhostname.domain/ OK
/^To: .*@test.domain/ OK
/^To: .*/ REJECT


サービス再起動

CentOS 6
# /etc/init.d/postfix restart

CentOS 7
# systemctl restart postfix


メールを送信して、許可されていない宛先だった場合には、メールログに送信を拒否した旨が記録される。

reject: header To: 

追記(2018/2/20)

/^To: hoge/ OK

のように指定した OK は、DUNNO の別名。
これは後方互換性のため残されている設定値。
他の設定値は、man や以下の日本語ドキュメントを参照。

参考;
Postfix manual - header_checks(5)


注意しなければいけないのが、DUNNO/OK の動作。
DUNNO/OK は、「このテーブルに検索キーが見つからなかったように見せ、次の入力行を検査する」との事。

つまり、このアクションが行われた後、そこで以降のルールをチェックしない訳ではない。

ハマりやすいのは、以下のような定義をした場合。

/@test.domain/ OK
/./ REJECT

To か From かヘッダを記載していないので、たとえ To が OK にマッチしても、From など他のヘッダに対しても検査が行われるので、それが最後のREJECTに引っかかりREJECTされてしまう。

SQLite で正規表現を使う

【環境】
CentOS 7


CentOS 7 の SQLite(標準パッケージ)単体では、正規表現を使えない。

以下からモジュールのソースを入手して、.so ライブラリをロードすれば使えるようになる。
https://github.com/ralight/sqlite3-pcre

ビルド

ビルドには、sqlite-devel パッケージが必要。

$ make
cc -shared -o pcre.so   -fPIC -W -Werror pcre.c -lpcre   -Wl,-z,defs

使い方

ライブラリのロード

sqlite> .load /path-to/pcre.so

※毎回設定するのが面倒な場合は、~/.sqliterc にロードの記述をする。

正規表現を使ったSQLの書式

sqlite> ... WHERE x REGEXP <regex>

試す

テストデータを用意。

sqlite> select * FROM sample;
os
--------------------
Mac OS X 10.9
Mac OS X 10.10
Mac OS X 10.11
Mac OS X 10.12
Mac OS X 10.13
Windows NT 6.3
Windows NT 10.0

ライブラリをロードする。

sqlite> .load ./pcre.so

正規表現でSELECTする。

sqlite> select * FROM sample WHERE os REGEXP '[0-9]\.[0-9]$';
os
--------------------
Mac OS X 10.9
Windows NT 6.3
Windows NT 10.0

PostgreSQL で文字列と数値があるデータを(ちょっと良く)ソートする

【環境】
CentOS 6/PostgreSQL 8.4
CentOS 7/PostgreSQL 9.2


例えば、文字列型のカラムにて、文字列と数値が混じったデータの場合にソートすると、次のようになる。

db=> SELECT * FROM sample_data ORDER BY os;
       os
-----------------
 Mac OS X 10.12
 Mac OS X 10.13
 Mac OS X 10.9
 Windows NT 10.0
 Windows NT 6.3


いい感じにソートするには、少し工夫する。

db=> SELECT * FROM sample_data 
ORDER BY
  SUBSTRING(os FROM '^[A-Za-z ]+'), 
  TO_NUMBER(SUBSTRING(os FROM '[0-9.]+$'), '9999999999');
       os
-----------------
 Mac OS X 10.9
 Mac OS X 10.12
 Mac OS X 10.13
 Windows NT 6.3
 Windows NT 10.0


考え方としては、以下の通り。

・SUBSTRING を使い、ソートするカラムの先頭から英字を抜き出して、ソートの第一条件とする。
・SUBSTRING を使い、ソートするカラムの後ろから数値とドット(小数点)を抜き出して、to_numberで適当な桁数(上記では10桁)のnumeric型にキャストして、ソートの第二条件とする。


ソートの条件をSELECTで抽出してみると、どうなっているか分かりやすい。

db=> SELECT 
  os, 
  SUBSTRING(os FROM '^[A-Za-z ]+'), 
  TO_NUMBER(SUBSTRING(os FROM '[0-9.]+$'), '9999999999') 
FROM 
  sample_data;
        os        |  substring  | to_number
------------------+-------------+-----------
 Windows NT 10.0  | Windows NT  |       100
 Windows NT 6.3   | Windows NT  |        63
 Mac OS X 10.12   | Mac OS X    |      1012
 Mac OS X 10.9    | Mac OS X    |       109
 Mac OS X 10.13   | Mac OS X    |      1013


ここに、'Mac OS X 10.12.1' というデータが入ってくると、うまくいかない(´・ω・`)

db=> SELECT * FROM sample_data
ORDER BY
  SUBSTRING(os FROM '^[A-Za-z ]+'),
  TO_NUMBER(SUBSTRING(os FROM '[0-9.]+$'), '9999999999');
        os
------------------
 Mac OS X 10.9
 Mac OS X 10.12
 Mac OS X 10.13
 Mac OS X 10.12.1
 Windows NT 6.3
 Windows NT 10.0


バージョンの区切りになっているドットの出現回数が違うのが原因。
この場合、出現回ごとに桁数を揃えて(ドットで区切って0詰めする)、ソート条件に追加すると意図したようにソートされる。

db=> SELECT * FROM sample_data
ORDER BY
  SUBSTRING(os FROM '^[A-Za-z ]+'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 1), 3, '0'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 2), 3, '0'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 3), 3, '0');
        os
------------------
 Mac OS X 10.9
 Mac OS X 10.12
 Mac OS X 10.12.1
 Mac OS X 10.13
 Windows NT 6.3
 Windows NT 10.0


試しに、'Mac OS X 11.0' や 'Mac OS X 9.99' という架空のデータを入れて試してみる。

db=> SELECT * FROM sample_data
ORDER BY
  substring(os from '^[A-Za-z ]+'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 1), 3, '0'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 2), 3, '0'),
  LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 3), 3, '0');
        os
------------------
 Mac OS X 9.99
 Mac OS X 10.9
 Mac OS X 10.12
 Mac OS X 10.12.1
 Mac OS X 10.13
 Mac OS X 11.0
 Windows NT 6.3
 Windows NT 10.0


いい感じでソートされる。

ソート条件がどうなっているか、SELECTで抽出してみると、桁毎に0詰めになっている事が確認できる。

db=> SELECT 
    os,
    LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 1), 3, '0'),
    LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 2), 3, '0'),
    LPAD(SPLIT_PART(SUBSTRING(os FROM '[0-9.]+$'), '.', 3), 3, '0')
 FROM sample_data;
        os        | lpad | lpad | lpad
------------------+------+------+------
 Windows NT 10.0  | 010  | 000  | 000
 Windows NT 6.3   | 006  | 003  | 000
 Mac OS X 10.12   | 010  | 012  | 000
 Mac OS X 10.9    | 010  | 009  | 000
 Mac OS X 10.13   | 010  | 013  | 000
 Mac OS X 10.12.1 | 010  | 012  | 001
 Mac OS X 11.0    | 011  | 000  | 000
 Mac OS X 9.99    | 009  | 099  | 000


但し、前半に文字列があり、後半に数字(ドットも可)がある、という前提で、バージョン部分が「x.y.z」というフォーマットしか判別できない。

使える場面が限られるけど、とりあえずメモ。
UserAgentから取り出したOSのソートには使えそう。


参考;
https://www.postgresql.jp/document/9.2/html/functions-string.html
https://www.postgresql.jp/document/9.2/html/functions-formatting.html

rsyslog に *** Slice of root のログが出力される

【環境】

# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

# rpm -qa | grep rsyslog
rsyslog-8.24.0-12.el7.x86_64

# rpm -qa | grep systemd
systemd-libs-219-42.el7_4.4.x86_64
systemd-sysv-219-42.el7_4.4.x86_64
systemd-219-42.el7_4.4.x86_64


以下のようなログが定期的に出力される。

# cat /var/log/messages
・・・省略
Jan 10 22:30:01 hoge systemd: Created slice User Slice of root.
Jan 10 22:30:01 hoge systemd: Starting User Slice of root.
Jan 10 22:30:01 hoge systemd: Started Session 236 of user root.
Jan 10 22:30:01 hoge systemd: Starting Session 236 of user root.
Jan 10 22:30:01 hoge systemd: Removed slice User Slice of root.
Jan 10 22:30:01 hoge systemd: Stopping User Slice of root.


journald にも出力されているが、rsyslog 側で無視して、ファイルへ書き込まないようにする。
手順は、以前と同じ。
shobon.hatenablog.com


以下のようなファイルを作成する。

# cat /etc/rsyslog.d/ignore-systemd-session-slice.conf
if $programname == "systemd" and ($msg contains "Starting Session" or $msg contains "Started Session" or $msg contains "Created slice" or $msg contains "Starting user-" or $msg contains "Starting User Slice of" or $msg contains "Removed session" or $msg contains "Removed slice User Slice of" or $msg contains "Stopping User Slice of") then stop

rsyslogを再起動して反映し、/var/log/messages に出力されなくなった事を確認する。

# systemctl restart rsyslog


参考;
https://access.redhat.com/solutions/1564823