2017/10/16(月)CGI に Python を利用し、PostgreSQL を使用する

どちらかというと、自分メモ。

CGIというのは、環境変数からパラメータを受け取り、
標準出力へ HTTPヘッダ群とコンテンツを出力する、というのが基本的セオリーで特別なことは必要ないです。

しかし、昨今の Python3系では、WSGIインタフェースというものを意図してCGIを制作するのが普通になっており、これはパフォーマンスの点で有利とされています。
Apache に mod_wsgi 拡張モジュールをインストールする必要があります。
現在のところ、標準モジュールにはなっていないため、別途インストールが必要です。

FreeBSD11 における mod_wsgi インストールは、ソースコードから下記のように行うのが確実。
pip (後述しています) でのインストールは、環境判定を誤認識したり変にエラーを吐いたりすることが環境によっては発生するため、筆者は全くお勧めしません。
# cp mod_wsgi-4.5.20.tar.gz /usr/local/src 
# cd /usr/local/src
# tar xvzf mod_wsgi-4.5.20.tar.gz
# cd mod_wsgi-4.5.20
# ./configure --with-python=/usr/local/bin/python3.5 --with-apxs=/usr/local/apache2/bin/apxs
# make
# make install

--with-apxs を指定することで、お使いのサーバにおける環境に合わせた構築が出来ます。
通常、mod_wsgi は、上記の場合、/usr/local/apache2/modules/ 配下に動的リンクでインストールされます。

Apache への mod_wsgi に対する設定は、以下を参考にどうぞ:
LoadModule wsgi_module modules/mod_wsgi.so

WSGIDaemonProcess cgi-bin user=webadmin group=webuser processes=1 threads=5 WSGIScriptAlias / /home/webroot/hoge/cgi/app.wsgi <Directory "/home/webroot/hoge/cgi"> WSGIProcessGroup cgi-bin WSGIApplicationGroup %{GLOBAL} </Directory>

ちなみに WSGIインタフェース自体は、Python に特化する目的を持つものではありません。
この辺りは勘違いされている諸氏が結構多いようです。

Perl だと mod_perl という Apache に組み込む形での有名な高速化拡張モジュールがありますが、それと同じようなものでしょうか。
Python 以外では導入メリットが見えにくいです。

最近のPerl はそれ自身が高速化してきているので、mod_perl 導入のメリットが見えにくくなってきているのと、mod_perl を組み込んだ状態にてCGIをスレッド動作させると原因不明の不安定な動作になったり、Perl 5.26 にすると、静的モジュールでは何故かインストールできないなど、色々問題があり、筆者のサーバでは mod_perl の利用は見合わせている状況です。

次に、Python から、PostgreSQL インタフェースを扱うモジュールをインストールするのですが、このインストールに先立ち、pip というサポートツール(?)を導入する必要があります。
Perl で言うところの CPAN に該当するものですね。

# python3.5 -m ensurepip

あれ? と思った諸氏も居られるかもしれません。
多くのサイトには「Python 3.4 以降では、pip は同時にインストールされる」と説明されているからですが、FreeBSD11 にて Ports から Python を導入した場合、pip は導入されません。FreeBSD11 にて Ports から Python を導入した場合、pip は手動操作で導入しないと駄目らしいです。
でも、pip は今後のメンテナンスで必須になるものの、今回は使いません。

最後に Python の PostgreSQLインタフェースモジュールをインストールするのですが、これもpip では環境誤認識をするため、ソースコードを持ってきて、下記の手順が確実です。
事前に、PostgreSQL 本体をインストールしておくことは言うまでもありませんね。
# cp psycopg2-2.7.3.1.tar.gz /usr/local/src
# tar xvzf psycopg2-2.7.3.1.tar.gz
# cd psycopg2-2.7.3.1
# setenv PATH '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/pgsql/bin/usr/local/pgsql/bin'
# python3.5 setup.py build
# python3.5 setup.py install
ここで重要なのは、pg_config コマンドのパスを、環境変数 PATH に含めることにあります。
Python の psycopg2 は、Perl における DBI と DBD::Pg の組み合わせに相当します。

2017/10/13(金)はんかくさい日報を新システムへ移行しました。

移行といっても、(adiary を)バージョンアップしただけです。
しかし、見栄えは以前よりシンプルになってしまいました。

移行が何故か上手く行かず、更にデータの一部を壊してしまったため、
移行そのものを全て手動操作でやる羽目になり、足掛け3日掛かってしまいました。

また、手動操作移行の故、記事番号・記事URLが変わってしまい、Google 等への反映は1カ月程度かかるものと思われます。

2017/10/07(土)メールサーバへの攻撃事情

この1週間で「電子メールが送れない・受け取れない」という障害報告が4件ありました。
こういう障害は20年運用していて初めてのことでして・・・

どうも直接の原因は、これです。IPアドレスも晒します。 ↓
20171007_1.png

52.166. 系のIPアドレスの登録上の使用者は、皆が誰でも知っている企業です。
調べればすぐ判るので、ここでは敢えて言及しません。

なんと、概ね 10秒毎にSMTP認証を失敗しては繰り返しています。
文字列 'UGFzc3dvcmQ6' は、'Password:' を Base64エンコードして得られる文字列です。
SMTP認証も現在は数種類あって、これはセキュリティレベルが低いとされている LOGIN 認証と言われる種別。

サーバ負荷をこのようにして意図的に高くし、サーバ障害やサーバダウンを引き起こそうとする愉快犯か、何等かの意図を持っている連中の仕業です。

10/5 の 21:00 頃に、現在一緒に仕事をしている同業者がこのログを見て、 Twitter で呟いたそうです。
『○○社のネットワークから、メールサーバへの攻撃を受けている』と。
そうしたら、52.166. 系からの攻撃は「ピタッ」と止まりました。
これには余りの素早さに笑ってしまいましたね。勿論、対応された方々には感謝申し上げます。確信犯的にやっていたのであれば、逆に許せないですが。

で、今の攻撃主体はどうやら ↓ の模様。これもIPアドレスを晒しておきます。
20171007_2.png

間隔は4分毎ですが、攻撃と言えるレベルです。
時折「セキュリティ対策業者がセキュリティホール探しのためにやっている」なんていう話をする奴がいますが、ならサーバ負荷を意図的に上げるような行為を何故やる? という 疑問が必然的に湧きますね。

SMTP サーバ自体の接続拒否機能は、SMTP認証処理成功後に機能するようで、認証前にIPアドレスや接続元ドメインなどで強制切断するようにはなっていないようです。
これをするには、ファイアウォールを使わないと駄目ですね。
この手の設定は、微々たるものだとしても傘下ネットワーク全体のパフォーマンス低下を招くので、出来れば余計なことはしたくない。

SMTP サーバ単体で、接続そのもの自体を拒否できる機能が欲しいと考えるのは自分だけでしょうか。
ま、発信元で犯人の処分をしてくれるのが最も有益なわけですが・・・

2017/08/28(月)powerDNS 4.0.4 は FreeBSD10 以降でソースコード構築途上でコンパイルエラー

PowerDNS 4.0.4 をソースコードから構築しようとすると・・・
コンパイルを始めたばかりのところで、
ext/json11/json11.cpp:153:24: error: invalid operands to binary expression
      ('nullptr_t' and 'nullptr_t')
        return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
               ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ext/json11/json11.cpp:209:5: note: in instantiation of member function
      'json11::Value<json11::Json::Type::NUL, nullptr_t>::less' requested here
    JsonNull() : Value(nullptr) {}
    ^
のようなエラーを吐いて構築不能になります。
どうやら clang/LLVM 4.0.0 環境が少なくとも全滅です。
FreeBSD 11 はまさにこの環境。
% /usr/bin/clang -v
FreeBSD clang version 4.0.0 (tags/RELEASE_400/final 297347) (based on LLVM 4.0.0)
Target: x86_64-unknown-freebsd11.1
Thread model: posix
InstalledDir: /usr/bin
日本語の情報が殆ど無いですね。
これは ext/json11/json11.cpp と ext/json11/json11.hpp の2つのファイルを修正することで解決します。

具体的な修正内容は下記リンクです:
json11 fixes from upstream via pdns #135
https://github.com/PowerDNS/weakforced/pull/135/commits/9e4d9bd48663e849be13e2cb5fcf64f917aec608
それにしても日本人の感覚だと、この修正量と内容だとバージョンアップしてソースコード一式を再リリースするものですが、開発元であるオランダ人の感覚は違うようです。

2017/05/23(火)権威DNS ― SOA レコードの記述方法

どちらかというと自分メモです。。。
SOA とは Start Of Authority を略したもので、
よく「権威の開始」を意味すると説明されます。

このあたりが、日本語での感覚と英語圏での感覚が合わなくてピンとこないのですが、要するにここでいう「権威の開始」というのは、「ゾーン情報を管理する権限を持っているこ とを明示する」ということになります。

SOAレコードは、BIND の設定ファイルに従うと、下記のような書式になります:
@               IN SOA  ns.example.jp. postmaster.example.jp. (
                        17052301        ; Serial-No.
                        3600            ; Refresh
                        900             ; Retry
                        604800          ; Expire
                        1800            ; Minimum
                        )
以下、「マスターDNS」「スレーブDNS」「権威サーバ」等の用語は理解しているものとして記述していきます。これらの意味は1つ前の記事に全て記してあります。

ひとつひとつのパラメータを理解しているようでよく解かっていないのではないかなと。
SOA レコードは実に7つのパラメータで成り立っています。
個々に示してみます:

MNAME [ns.example.jp.]
 ・マスターDNSのホスト名。
 ・「完全修飾」という書式で通常、最後にもドットを付ける。
 ・CNAME レコードのホスト名は指定不可。IPアドレス自体も指定不可。

RNAME [postmaster.example.jp.]
 ・連絡先の電子メールアドレス。
 ・「完全修飾」という書式で通常、最後にもドットを付ける。
 ・DNSの動作上使われることはないが、管理者同士の連絡先として使われることがある。
 ・記述の際、@ マークは . に置き換える。

SERIAL [17052301]
 ・ゾーンシリアル番号。符号なし 32bit長整数で保持される。
 ・ゾーン内容を更新したら、必ずこの番号を+1以上更新する。
 ・0以上ならどのような値でも構わないのだが、更新日(作成日)を示す YYYYMMDDnn 或いは YYMMDDnn の形式が多い。
 ・4294967295 の状態で+1すると 0 になるが、こういう場合の正常な動作は基本的に考慮されていないことに留意。
 → この場合は、スレーブDNSを一旦停止し、該当ゾーンを含む保持データそのものを削除してから、スレーブDNSを再起動するしかありません。 SERIAL を前回より小さい番号にした場合も同様の対処です。

○ 以下3つはスレーブDNSの挙動を指定:
REFRESH [3600] 〔単位:秒〕
 ・当該ゾーン情報をリフレッシュする間隔。
 ・スレーブDNSは、マスターDNSからのゾーン転送処理を受け入れたあと、ここで指定した時間経過すると、マスターDNSへゾーン情報更新問合わせを行い、シリアル番号 が更新されていたら適宜更新処理を行う挙動になる。

RETRY [900] 〔単位:秒〕
 ・リフレッシュがマスターDNSや回線障害など原因で上手く行かなかった場合、リトライを試みる間隔。
 ・従って、REFRESH で指定する値よりも小さな値でないと意味がなく、通常は、REFRESH の整数分の1の値とする。(この例では4分の1)

EXPIRE [604800] 〔単位:秒〕
 ・ゾーン情報のリフレッシュができない状態が続いた場合、スレーブDNSにて、ゾーン情報を最後にリフレッシュが成功してから保持を可能とする時間を示す。
 ・従って、REFRESH の整数倍で無いと意味がなく、2週間から4週間が適切とされている。(この例では7日=1週間)

○最後の1つはキャッシュDNSの挙動を指定:
MINIMAM [1800] 〔単位:秒〕
 ・このパラメータは Negative cache TTL とも呼ばれる。
 ・各レコードのデフォルトキャッシュ保持時間を指定する。
 ・値が小さいほど臨機応変に権威サーバにおける保持情報に追従できるが、DNSの負荷が上がるため、60 ~ 3600 の間で適宜指定されるのが実態である。
 ・また、レコードに存在しない情報の問い合わせを受けた場合、'NXDOMAIN' (情報なし)という回答をするが、キャッシュDNSは「情報なし」もここで指定した時間だけ保持する挙動になる。

 以上、参考にどうぞ。

 ダイナミックDNSを運用している場合、MINIMAM は 60 を指定するのが通例の設定のようです。ホストの増減が多い環境では MINIMAM は 600、比較的変化が少ない環境では 1800 や 3600 という設定が多いようです。

2017/05/15(月)権威DNSとキャッシュDNSの分離をしました

5月連休中は、専らこの作業をしていました。
DNSをいじるので、工程途上で作業ミスがあると傘下のネットワーク運用への影響が大きいため、1年近くやりたくてもできない状態だったので、出来る時にやってしまおうとい うことで。。

権威DNSとかキャッシュDNSとか判らない方々も多いので、基礎的な解説を交えていきます。
変更前は以下のような単純な構成でした:
20170515_1.png

これは、弊社管轄ドメインのネームサーバとして、レジストラに登録しているサーバになります。
レジストラに登録するサーバは、「権威サーバ」となる種別のDNSでなければなりません。
では、「権威サーバ」と「キャッシュサーバ」の違いは何? というところですが・・

「権威サーバ」とは、ドメイン各種情報の原本を持つサーバ、
「キャッシュサーバ」とは、探索したドメイン情報の写しを持つサーバ
を言います。
 従来のDNSは、「権威サーバ」と「キャッシュサーバ」が一緒で、DNSのサーバソフトウェアで有名な BIND が以前は「権威サーバ」「キャッシュサーバ」と区別する概念が 無く、最初から両方使えるようになっているので、このあたりが混乱を来す要因になっています。

さて、「権威サーバ」には更に2種類あって、
かつては本当の原本情報を持たせるサーバを「プライマリDNS」
原本情報の複製を保持するサーバを「セカンダリDNS」と言っていました。

最近では、
「プライマリDNS」は「マスターDNS」とか「マスター権威DNS」、
「セカンダリDNS」は「スレーブDNS」とか「スレーブ権威DNS」とかいう言い方が主流になってきているようです。
ちなみに、「キャッシュDNS」には「プライマリ」「セカンダリ」あるいは「マスター」「スレーブ」の区別も概念もありません。

さて、「マスターDNS」も「スレーブDNS」も「権威サーバ」の位置づけなので、レジストラに「ネームサーバ」として登録できます。
「マスターDNS」か「スレーブDNS」かの種別は問いません。「権威サーバ」であることが重要です。
「マスターDNS」か「スレーブDNS」かの種別は問いません。「権威サーバ」であることが重要です。

弊社では、DNS関係は下記のような構成にしました(2017/05/08より):
20170515_2.png

最近はこのような構成がやや強めにお勧めされています。
使用するDNSソフトウェアは何でも良いのですが、弊社での環境的事情や BIND の相次ぐセキュリティアラートに加え、常用の FreeBSD にて BIND が標準提供から外された(BIND 10 から Python ベースになったのが主たる理由)のに辟易して、PowerDNS,nsd,unbound という構成を採用した次第です。

「hidden マスターDNS」とは、その名の通り、マスターDNSを公開ネットワーク上から隠しています。
こうすることで、ドメイン原本情報に「毒」が外部から入ることを防ぐセキュリティ対策が出来ます。
レジストラへのドメイン登録はネームサーバが最低2つ要るため、2つのスレーブDNSを稼働させます。このスレーブDNSは自前ですが、費用面さえ許す環境ならば、他社サー ビスの利用でも良いでしょう。

同じくキャッシュDNSも2つ用意します。これは最低でも1つあればいいです。
逆に3つ以上キャッシュDNSを指定できるアプリケーションはあまり見かけませんね。

キャッシュDNSは「ドメイン情報探索専用」のサーバです。
「権威DNS」とは物理的に別のサーバとし、利用を許可するネットワークを限定することがコツです。

「権威DNS」はCPU負荷はあまり重くならないので、Raspberry Pi 等の活用も可能です。

キャッシュDNSで特殊なのは google の 8.8.8.8 とか 8.8.4.4 とかで、これはオープンDNSとかオープンリゾルバとか呼ばれ、誰でも使用できる代物ですが、負荷分散の意味 で、キャッシュサーバを用意しない場合や、用意できない場合、出来る限り加入しているプロバイダで指定されているネームサーバを使うことをお勧めします。

2016/12/31(土)FreeBSD11 で OpenLDAP・Courier-Authlib・postfix3.1.x インストール時の注意

今年最後の更新です。

年明けから、FreeBSD11 を使用したARM系ボードの試作の仕事が入りそうなこともあり、弊社管轄の幾つかのサーバを FreeBSD 11.0 にしてみました。
FreeBSD 9系 のサポートは本日で終了です。
FreeBSD10.3 は、少なくとも 2018年4月末までのサポート、
FreeBSD11系 は、少なくとも 2021年9月末までのサポートになっています。
FreeBSD10系 は微妙ですが、FreeBSD11系は、サポート期間が延びる可能性ありです。

FreeBSD 11 にすると、コンソール(画面表示)ドライバが変更されており、こんな表示になります。↓
20161231.JPG

フォントさえ設定できれば、日本語表示できるのですが、11.0 の時点ではまだデフォルトでは出来ないようです。
また、スクリーンセーバーは機能しません。今後の課題でしょうか。。

本題ですが、FreeBSD11にするにあたり、注意すべき気づいた点をメモ書きしておきます。
1)OpenLDAP 2.4.44 のインストール
 FreeBSD10 まで普通に使い回しが出来たのですが、
 どうやら、BDB 形式でデータベースクラスタを構築している場合、
 FreeBSD11 上で OpenLDAP自体を構築し、FreeBSD10 で使っていた BDB を使用しようとすると、slapd 自体が起動しなくなるようなのです。
 これをしなければ大丈夫ぽいですが、問題の先送りをするだけです。

 このため、
 ○ FreeBSD 11 移行前に slapcat コマンドで LDIF をエクスポート
 ○ FreeBSD 11 移行後に openLDAPを再構築したら、slapadd コマンドで LDIF インポート

 という手順で解決しました。

2)Courier-Authlib のインストール
 ソースコードからインストール作業する場合、以下のメッセージが出て configure に失敗することがあります。
 Shared object "libssl.so.7" not found, required by "courierauthconfig"
これは、 /usr/local/bin/courierauthconfig 、/usr/local/courier/bin/courierauthconfig をバッサリと削除し、 configure をやり直せば大丈夫です。
過去に Courier IMAP 等を使用したことがあって、FreeBSD を更新インストール継続しているとこうなると思います。

3)postfix 3.1.x のインストール
 現時点での最新バージョンは 3.1.3 ですが、これは FreeBSD11 には対応しておらず、ソースコードからの構築はそのままではできません。
 ですが、機能的には問題ないと思われますので、以下の修正を行ってから構築を行います。
・ makedef 260行目付近 ~ (行頭が + の行を挿入)
   FreeBSD.10*)  SYSTYPE=FREEBSD10
                 : ${CC=cc}
                 : ${SHLIB_SUFFIX=.so}
                 : ${SHLIB_CFLAGS=-fPIC}
                 : ${SHLIB_LD="${CC} -shared"' -Wl,-soname,${LIB}'}
                 : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'}
                 : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"}
                 : ${PLUGIN_LD="${CC} -shared"}
                 ;;
+  FreeBSD.11*)  SYSTYPE=FREEBSD11
+                : ${CC=cc}
+                : ${SHLIB_SUFFIX=.so}
+                : ${SHLIB_CFLAGS=-fPIC}
+                : ${SHLIB_LD="${CC} -shared"' -Wl,-soname,${LIB}'}
+                : ${SHLIB_RPATH='-Wl,-rpath,${SHLIB_DIR}'}
+                : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"}
+                : ${PLUGIN_LD="${CC} -shared"}
+                ;;
  DragonFly.*)   SYSTYPE=DRAGONFLY
                 ;;
   OpenBSD.2*)   SYSTYPE=OPENBSD2
・ src/util/sys_defs.h 25行目付近~ (行頭が + の行を挿入)
 #if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
     || defined(FREEBSD5) || defined(FREEBSD6) || defined(FREEBSD7) \
     || defined(FREEBSD8) || defined(FREEBSD9) || defined(FREEBSD10) \
+    || defined(FREEBSD11) \
     || defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
     || defined(OPENBSD2) || defined(OPENBSD3) || defined(OPENBSD4) \

2016/12/10(土)perl 5.24 にしたら ports の XPDFJ は動作しない

提起の通りです。
サーバのエラーログに
Can't use 'defined(%hash)' (Maybe you should just omit the defined()?) at /usr/local/lib/perl5/site_perl/XPDFJ.pm line 757.
と文句を垂れますので、XPDFJ.pm の 757行目を以下の要領で直接修正します。

《変更前》
    if( defined %{$tab->{$name}} && $name !~ /::$/ ) {
《変更後》
    if ((%{$tab->{$name}})  && ($name !~ /::$/ )) {
こうすると、perl 5.24 でも動作するようです。
筆者がメンテナンスを請け負っている企業のサーバでは動作確認できました。

原因は、perl 5.24 にて defined(%hash) の構文を致命的エラーとするように変更されたためです。何故こうするのかはよく判りませんが。。。

2016/08/06(土)プライベートCAの構築[FreeBSD] (3)

このシリーズのその1 → プライベートCAの構築[FreeBSD] (1)
このシリーズのその2 → プライベートCAの構築[FreeBSD] (2)

自分メモですが、証明書の失効方法や、証明書には種類があるというお話です。

● 証明書の失効手続き
利用対象者が居なくなった場合とか、何らかの問題が起きた場合に発行した証明書を取り消したい(無効にしたい)場合があります。

そんな場合には、「証明書失効操作」を行います。
openssl ca -gencrl -revoke user.pem -out cert.crl
cert.crl が失効リストで、実際には証明書のシリアルナンバーと対応する証明書の失効日が暗号化(?)されて記述されたものが書き込まれるようです。
この cert.crl を各サーバ(Apache、OpenVPN等)の設定で参照するようにします。

これとは別に、証明書発行リストが以下のようにCA管理ディレクトリの index.txt に生成されます。
20160806_1.png
Vで始まる行は、現在有効な証明書、
Rで始まる行は、失効する証明書を示しています。

●証明書には種類がある。
多くの場合、ディジタル証明書といえば、サーバ証明書をさす場合が多いです。
Webサーバで https を行う場合や、電子メールサーバにて TLS 通信を行う場合は、必ず必要になるのでお馴染みの方も多いでしょう。

OpenVPN のクライアント側には、接続先のサーバ証明書(公開鍵のみ)のほかに、クライアント証明書というのが必要になります。
これを OpenSSL コマンドラインで発行するには、 FreeBSD では /etc/ssl/openssl.cnf の設定を一部変更する必要があります。
20160806_2.png

具体的には、[ usr_cert ] ブロックの nsCertType パラメータを
nsCertType = client, email, objsign
とする必要があります。
こうしないと、少なくとも OpenVPN は KU ERROR が発生したり、接続途上でダンマリを決め込んでしまい、クライアント側から上手く接続できません。

ですが、サーバ証明書の場合は、これでは逆に駄目で、
nsCertType  = server
とする必要があります。

2016/07/27(水)FreeBSD 10.3R 環境で dovecot 2.2.25 はそのままでは動作しない

dovecot は、電子メール送受信サービスを実現する際に欠かせないサーバソフトウェアで、皆様が利用する多くのISPで採用されています。
弊社でも採用していますが、どうやら FreeBSD固有のバグがあるようです。
具体的には、
Last died with error (see error log for more information):
 kevent(EV_ADD, READ, 56) failed: Bad file descriptor
(実際は改行しません)

といったメッセージが起動時に発生し、サービスを全く提供出来なくなるという重篤な問題。
これは、日本語の情報がほぼ皆無ですが、以下のパッチで凌げます。(弊社でも確認済。)
#Ports でインストールする場合は、既にパッチが当たった状態でインストールされるので問題ありません。
画像をクリックすると見やすい大きさで表示されると思います。

20160728_1.png

20160728_2.png
〔参考URL〕 https://github.com/dovecot/core/commit/ffd8dc932516bc55bf01d91355540daab365e5e9

余りお勧めしませんが、次のバージョン 2.2.26 が出るのを待つ手もあります。
OK キャンセル 確認 その他