2019/04/17(水)新元号の対応

弊社の現在公開しているページ( https://www.basekernel.co.jp/ )にて確認作業していたので、ひょっとしたら見た人がいたかもしれませんが・・・
#限りなくゼロに近いと思っているが。。

20190417_1.png

20190417_2.png

20190417_3.png

20190417_4.png

20190417_5.png


ま、こんな感じにしました。西暦2019年は、4/30,5/2 も祝日法に基づくと、
西暦2019年限定で休日になります。

ちなみに今年と来年は、オリンピックもあり、特例の祝日が結構あるんです。

2019/03/01(金)ディジタル証明書の形式 pem と der

https:// 接続などでサーバ証明書を扱ったことがある方は、下記フォーマットを見たことがあると思います。
※現在、実運用で使っていませんが念のため一部端折っています。
-----BEGIN CERTIFICATE-----
MIIC4TCCAkqgAwIBAgIBADANBgkqhkiG9w0BAQUFADB4MQswCQYDVQQGEwJKUDER
MA8GA1UECBMISG9ra2FpZG8xGzAZBgNVBAoTEkJhc2UgS2VybmVsIENvIEx0ZDEg
MB4GA1UECxMXTmV0d29yayBPcHJhdGlvbiBDZW50ZXIxFzAVBgNVBAMTDkJhc2Ug
S2VybmVsIENBMB4XDTA4MDcxMzEzMTU0NVoXDTI4MDcxMzEzMTU0NVoweDELMAkG

・・・・一部省略・・・・

A1UEBhMCSlAxETAPBgNVBAgTCEhva2thaWRvMRswGQYDVQQKExJCYXNlIEtlcm5l
+6EEruiOlNKYnViRTdjEoAPRYfgM+eqjnfbVOxB0wEV7w5GjcqbGe9ePrEUs1wYS
ktnZC7H0p5H01z92udKE3BaCEACQ
-----END CERTIFICATE-----
これは、pem 形式と呼ばれるディジタル証明書で、通常はこの形式で管理します。
ところが、時々、 der 形式しか受け付けないディジタル証明書アプリケーションがあるのです。

今回、コントロールパネルのサーバ設定部分の一部が時代に合わなくなっていて、この部分の改良を施しているところで、その一環でサーバ証明書をある程度自力管理できるようにしているのですが、その過程でディジタル証明書の内容を解析する Perl モジュールに Crypt::X509 という便利なものがあってそれを使おうとしたら、このモジュールが der 形式しか対応していないのです。

もっと便利そうなものに Crypt::OpenSSL::X509 というのがあるが、今のところ、OpenSSL 1.x 系への対応があまり芳しくなく、避けざるを得ない状況。

der 形式はバイナリファイルなので扱いにくいのです。ただ、具体的中身まではよく知りません。
調べると、 pem 形式ファイルの -----BEGIN CERTIFICATE----- 行と、-----END CERTIFICATE----- 行を取っ払った残りの部分を、Base64 デコードしてあげればいいだけであることが判りました。

つまり、pem 形式は、der 形式で生成したディジタル証明書のデータ構造を Base64 エンコードして、-----BEGIN CERTIFICATE----- 行と、-----END CERTIFICATE----- 行を付け足しただけなのです。

ここまで判れば、ディジタル証明書の内容確認は、Perl でやる場合は以下の要領で出来ます:
#!/usr/local/bin/perl

use MIME::Base64 ;                                     # Base64ライブラリ使用宣言
use Crypt::X509 ;                                      # 証明書内容参照ライブラリ使用宣言

$csr_pem = "" ;
$status  = open (CSRPEM,"hoge.pem") ;
if ($status) {
  local $/ = undef ; $csr_pem = <CSRPEM> ; close(CSRPEM) ;
}

$csr_pem =~ /\-\-\-\-\-BEGIN\s+CERTIFICATE\-\-\-\-\-(.+)\-\-\-\-\-END\s+CERTIFICATE\-\-\-\-\-/s ;
$x509_tmp = $1 ;
%outstr   = {} ;

$x509_decode = Crypt::X509->new(cert => decode_base64($x509_tmp)) ;
@nb = localtime($x509_decode->not_before) ;
@na = localtime($x509_decode->not_after) ;
@jw = ('日','月','火','水','木','金','土') ;
$outstr{'not_before'}     = sprintf("%d/%02d/%02d(%s) %02d:%02d:%02d",$nb[5] + 1900,$nb[4] + 1,$nb[3],$jw[$nb[6]],$nb[2],$nb[1],$nb[0]) ;
$outstr{'not_after'}      = sprintf("%d/%02d/%02d(%s) %02d:%02d:%02d",$na[5] + 1900,$na[4] + 1,$na[3],$jw[$na[6]],$na[2],$na[1],$na[0]) ;

$outstr{'subj_country'}   = $x509_decode->subject_country ;
$outstr{'subj_state'}     = $x509_decode->subject_state ;
$outstr{'subj_local'}     = $x509_decode->subject_locality ;
$outstr{'subj_org'}       = $x509_decode->subject_org ;
$outstr{'subj_ou'}        = $x509_decode->subject_ou ;
$outstr{'subj_cn'}        = $x509_decode->subject_cn ;

$outstr{'issuer_cn'}      = $x509_decode->issuer_cn ;
$serial16 = sprintf("%X",$x509_decode->serial) ;
$serial16 =  '0' . $serial16 if (length($serial16) % 2) ;
1 while $serial16 =~ s/^([\da-fA-F]+)([\da-fA-F][\da-fA-F])/$1\:$2/ ;
$outstr{'issuer_serial'}  = $serial16 ;
$outstr{'issuer_country'} = $x509_decode->issuer_country ;
$outstr{'issuer_state'}   = $x509_decode->issuer_state ;
$outstr{'issuer_local'}   = $x509_decode->issuer_locality ;
$outstr{'issuer_org'}     = $x509_decode->issuer_org ;
$outstr{'sigalgo'}        = $x509_decode->sig_algorithm ;
上記サンプルにて、連想配列 %outstr に表示可能な文字列にて解析内容が入ります。
参考:https://metacpan.org/pod/Crypt::X509

2019/02/13(水)perl にて IPv4 と IPv6 のデュアルスタックサーバを作る

Perl において、この用途には IO::Socket::INET というコアモジュールが広く使われていて、
ちまたにはこれを、IO::Socket::IP に変えるだけで IPv4/IPv6 デュアルスタックが実現するかのような話が広く知られているようだが、実際はどうも違う模様。。

今まで IPv4 で動作していたこのコード:
#!/usr/local/bin/perl
#
use utf8 ; binmode(STDOUT, ":utf8") ;
use IO::Socket::INET ;                     # ソケットインタフェース使用宣言

$comm_queue  = 5 ;                         # コネクション待ち受けキューの数
$port        = 9999 ;                      # port no.

### 通信ソケット生成
# ソケットオープン
$reqsock = IO::Socket::INET->new (LocalPort => $port,
                                  Listen    => $comm_queue,
                                  Proto     => 'tcp',
                                  Reuse     => 1,
                                 ) ;
if (not $reqsock) {
  err_trap("通信ソケットが作成できません。",$!) ;
  exit ;
}

### サーバメインルーチン
for (;;) {
  $sock = $reqsock->accept() ;
  if (not $sock) {
    err_trap("クライアントの要求受け付けに失敗しました。(accept error)",$!) ;
    exit ;
  }

  if ($child = fork()) {
  # 親プロセスの実行コード
    $sock->close() ;
    waitpid($child,0) ;
    next ;                                 # 次のコネクション要求を待つ

  } elsif (defined($child)) {
  # 子プロセスの実行コード(メインルーチン)
    $reqsock->close() ;
    select($sock) ; $| = 1;                # 常に flash するようにする
    select(STDOUT) ;
    binmode $sock ,':encoding(UTF-8)' ;

  以下、サーバの処理プログラム・・・・
  }
}
IO::Socket:INET の部分を、IO::Socket::IP に書き換えても、IPv6 しか受け付けない状態になります。
もしかしたら、IPv4射影アドレスを使えばいいのかもしれないですが、現状環境には全く合わない。

試行錯誤の結果、以下で動作する模様:
#!/usr/local/bin/perl
#
use utf8 ; binmode(STDOUT, ":utf8") ;
use IO::Socket::INET ;                     # IPv4 Socket インタフェースライブラリ使用宣言
use IO::Socket::INET6 ;                    # IPv6 Socket インタフェースライブラリ使用宣言
use IO::Select ;

$comm_queue  = 5 ;                         # コネクション待ち受けキューの数
$port        = 9999 ;                      # port no.

### 通信ソケット生成
$select = IO::Select->new ;

# ソケットオープン[IPv6]
$psock6 = IO::Socket::INET6->new (LocalPort => $port,
                                  Listen    => $comm_queue,
                                  Type      => SOCK_STREAM,
                                  Reuse     => 1,
                                  Proto     => "tcp"
                                 ) ;
if (not $psock6) {
  err_trap("通信ソケットが作成できません。[IPv6]",$!) ;
  exit ;
} else {
  $select->add($psock6) ;
}

# ソケットオープン[IPv4]
$psock4 = IO::Socket::INET->new (LocalPort => $port,
                                 Listen    => $comm_queue,
                                 Type      => SOCK_STREAM,
                                 Reuse     => 1,
                                 Proto     => "tcp"
                                ) ;
if (not $psock4) {
  err_trap("通信ソケットが作成できません。[IPv4]",$!) ;
  exit ;
} else {
  $select->add($psock4) ;
}

### サーバメインルーチン
for (;;) {
  while (my @ready = $select->can_read) {
    foreach my $reqsock (@ready) {
      $sock = $reqsock->accept() ;
      if (not $sock) {
        err_trap("クライアントの要求受け付けに失敗しました。(accept error)",$!) ;
        exit ;
      }

      if ($child = fork()) {
      # 親プロセスの実行コード
        $sock->close() ;
        waitpid($child,0) ;
        next ;                                 # 次のコネクション要求を待つ

      } elsif (defined($child)) {
      # 子プロセスの実行コード(メインルーチン)
        select($sock) ; $| = 1;                # 常に flash するようにする
        select(STDOUT) ;
        binmode $sock ,':encoding(UTF-8)' ;

      以下、サーバの処理プログラム・・・・
      }
    }
  }
}
参考になったのは、これ → How best to support IPv4/v6 in Perl server

2019/01/25(金)FreeBSD 12.0 カーネルにバグか

弊社管理サーバ19台の内、5台のサーバを FreeBSD12 に更新したのですが、そのうちの1台だけ、不定期に時折 Panic を起こして再起動を繰り返すサーバが・・・

ログメッセージにこんな感じで現れます:
Jan 25 04:15:46 uranus kernel: Fatal trap 12: page fault while in kernel mode
Jan 25 04:15:46 uranus kernel: cpuid = 1; apic id = 01
Jan 25 04:15:46 uranus kernel: fault virtual address    = 0xd8
Jan 25 04:15:46 uranus kernel: fault code               = supervisor read data, page not present
Jan 25 04:15:46 uranus kernel: instruction pointer      = 0x20:0xffffffff8091527d
Jan 25 04:15:46 uranus kernel: stack pointer            = 0x28:0xfffffe00185b9560
Jan 25 04:15:46 uranus kernel: frame pointer            = 0x28:0xfffffe00185b96b0
Jan 25 04:15:46 uranus kernel: code segment             = base 0x0, limit 0xfffff, type 0x1b
Jan 25 04:15:46 uranus kernel:                  = DPL 0, pres 1, long 1, def32 0, gran 1
Jan 25 04:15:46 uranus kernel: processor eflags = interrupt enabled, resume, IOPL = 0
Jan 25 04:15:46 uranus kernel: current process          = 0 (if_io_tqg_1)
Jan 25 04:15:46 uranus kernel: trap number              = 12
Jan 25 04:15:46 uranus kernel: panic: page fault
Jan 25 04:15:46 uranus kernel: cpuid = 1
Jan 25 04:15:46 uranus kernel: time = 1548357259
Jan 25 04:15:46 uranus kernel: KDB: stack backtrace:
Jan 25 04:15:46 uranus kernel: #0 0xffffffff8077a8c7 at kdb_backtrace+0x67
Jan 25 04:15:46 uranus kernel: #1 0xffffffff8072e4b3 at vpanic+0x1a3
Jan 25 04:15:46 uranus kernel: #2 0xffffffff8072e303 at panic+0x43
Jan 25 04:15:46 uranus kernel: #3 0xffffffff80a6496f at trap_fatal+0x35f
Jan 25 04:15:46 uranus kernel: #4 0xffffffff80a649c9 at trap_pfault+0x49
Jan 25 04:15:46 uranus kernel: #5 0xffffffff80a63fee at trap+0x29e
Jan 25 04:15:46 uranus kernel: #6 0xffffffff80a3f825 at calltrap+0x8
Jan 25 04:15:46 uranus kernel: #7 0xffffffff808feb43 at tcp_input+0x1553
Jan 25 04:15:46 uranus kernel: #8 0xffffffff80876a55 at ip_input+0x145
Jan 25 04:15:46 uranus kernel: #9 0xffffffff8084f496 at netisr_dispatch_src+0xd6
Jan 25 04:15:46 uranus kernel: #10 0xffffffff80833d83 at ether_demux+0x163
Jan 25 04:15:46 uranus kernel: #11 0xffffffff80834ee6 at ether_nh_input+0x346
Jan 25 04:15:46 uranus kernel: #12 0xffffffff8084f496 at netisr_dispatch_src+0xd6
Jan 25 04:15:46 uranus kernel: #13 0xffffffff80834184 at ether_input+0x54
Jan 25 04:15:46 uranus kernel: #14 0xffffffff8084b646 at iflib_rxeof+0xa16
Jan 25 04:15:46 uranus kernel: #15 0xffffffff80846476 at _task_fn_rx+0x76
Jan 25 04:15:46 uranus kernel: #16 0xffffffff80779154 at gtaskqueue_run_locked+0x144
Jan 25 04:15:46 uranus kernel: #17 0xffffffff80778db8 at gtaskqueue_thread_loop+0x98
Jan 25 04:15:46 uranus kernel: Uptime: 4h16m16s
Jan 25 04:15:46 uranus kernel: ---<<BOOT>>---
どうも、これに似ている模様・・・:
Bug 234296 - FreeBSD 12.0-STABLE r342216 Fatal trap 12

IPv4,IPv6 を直接扱う部分のようです。どうやら解決をみたらしいのですが、まだリリースバージョンへの反映はなされていません。FreeBSD12 への更新は様子見したほうがよさそう。

〔2019/02/06(Wed)追記〕
 昨日、リリースバージョン向けの対策版(FreeBSD 12.0-p3) が公開されたので、早速、本日未明から午前中にかけてFreeBSD 12 を稼働させている5台のサーバに対し、この不具合対策を行いました。
 数日様子を見て、安定しているようであれば他のサーバも FreeBSD12 に更新予定。

〔2019/02/28(Thu)追記〕
 どうも根本解決には至らない模様。頻度は減ったものの、5~6日経つと、勝手にリブートを繰り返します。
 なので、FreeBSD12 を運用環境に持ってくるのはお勧めできません。当面 FreeBSD 11系でやり過ごすことにします。

〔2019/08/02(Fri)追記〕
 Patch 7(FreeBSD12.0R-p7) あたりで安定した模様。引き続き、しばらく様子を見ます。