事前共有鍵(PSK)を用いた単純なOpenVPNの設定

さくらVPSOpenVPNサーバにしました。サーバ環境はDebian(sid)(d:id:rigarash:20101010#1286695769)です。クライアントは最大で1台のみの接続(私のノートPCからのみ)であり、OpenSSLのCA運用に自信がないので、事前共有鍵(Pre-Shared Key, PSK)を利用しました。これは、出張の時などに安全な通信を行うためのもので、クライアント(DebianWindows)からの通信がすべてさくらVPS経由になるようにします。

サーバ側の設定

まず、openvpnをインストールします。

$ sudo -H aptitude install openvpn

次に、事前共有鍵(/etc/openvpn/winclient.key)を生成します。

$ sudo -H openvpn --genkey --secrett /etc/openvpn/winclient.key

作成したサーバ設定ファイル(/etc/openvpn/winclient.conf)は以下の通りです。一応権限をnobody/nogroupに落としています。オプションの説明は、openvpn(8)に書いてあります。

$ cat /etc/openvpn/winclient.conf
port 1194
proto udp
dev tun
ifconfig 192.168.200.1 192.168.200.2
user nobody
group nogroup
persist-key
persist-tun
secret /etc/openvpn/winclient.key
status /etc/openvpn/winclient.log

OpenVPNをifup/ifdownできるようにします。ip_forwardの設定と、NATの設定が必要になります。

$ cat /etc/network/interfaces
...
## OpenVPN(winclient)
auto tun_winclient
iface tun_winclient inet manual
        pre-up iptables -t nat -A POSTROUTING -s 192.168.200.2/32 -j MASQUERADE
        openvpn winclient
        post-down iptables -t nat -D POSTROUTING -s 192.168.200.2/32 -j MASQUERADE
$ cat /etc/default/openvpn
...
AUTOSTART="none"
...
$ cat /etc/sysctl.conf
...
net.ipv4.ip_forward=1
...

クライアント(Windows Vista (x64))の設定

私がWindows Vista (x64)ユーザのため、他の環境でテストしてませんが、Windows XP以降ならあまり変わらないはずです。UACがあるので少し面倒でした。
まず、OpenVPNのサイト(Community Downloads | OpenVPN)から、"OpenVPN Community Software Windows Client Download"をダウンロードして、インストールします。
次に、メモ帳を管理者権限で起動して、以下の内容をC:\Program Files (x86)\OpenVPN\config\winclient.ovpnとして保存します。

remote XXX.XXX.XXX.XXX
port 1194
proto udp
dev tun
ifconfig 192.168.200.2 192.168.200.1
redirect-gateway bypass-dhcp bypass-dns def1
persist-key
persist-tun
secret winclient.key
status winclient.log

同様にC:\Program Files (x86)\OpenVPN\config\winclient.keyをサーバから持ってきます。鍵ファイルの改行コードはCR+LFに変換しておきました。(しないと動かないかどうかは未検証)
最後に、OpenVPN GUIを管理者権限で起動して、右クリック->"Connect"が成功すればOK。

クライアント(Debian)の設定

まず、openvpnをインストールします。

$ sudo -H aptitude install openvpn

クライアント側の設定ファイル(/etc/openvpn/winclient.conf)を作成します。redirect-gatewayが肝で、サーバ側に通信を振ってくれます。なお、私はローカルにunbound(DNSキャッシュサーバ)を立てているので必要ないのですが、一般的には、DNSの設定(/etc/resolv.confの処理等)が必要になります(未検証)。

$ cat /etc/openvpn/winclient.conf
remote XXX.XXX.XXX.XXX
port 1194
proto udp
dev tun
ifconfig 192.168.200.2 192.168.200.1
redirect-gateway def1
secret /etc/openvpn/winclient.key
status /etc/openvpn/winclient.log

次に、サーバ側で作成した/etc/openvpn/winclient.keyをローカルに準備(コピー)します。パーミッションは0600に合わせましょう。

$ ls -lAFi /etc/openvpn
...
269219 -rw-r--r-- 1 root root  432 2010-10-12 11:12 winclient.conf
269145 -rw------- 1 root root  636 2010-10-12 06:12 winclient.key
...

クライアント側でもifup/ifdownを利用することにします。クライアント側ではiptablesの設定は必要ないため、単純です。

$ cat /etc/network/interfaces
...
## OpenVPN(winclient)
auto tun_winclient
iface tun_winclient inet manual
        openvpn winclient
$ cat /etc/default/openvpn
...
AUTOSTART="none"
...

さくらVPSの設定

Debianのインストール

メモのみ。すぐにsidにしてしまいます。

  • 5.05(amd64)を選択
  • エキスパートモード
  • ディスク設定
    • primary
    • ext3
    • reserved 1%
  • bootパーティションは100MBでそのまま
    • bootable on
  • /は8GB
  • /homeは残り(13.4GB)
    • 200MBほど隠れて利用されている空間があるみたい
  • スワップに関して突っ込まれるけど続行(swapfileにする)
  • no root login
  • パッケージはインストールしない
  • GRUB2
  • 再起動
  • /etc/apt/sources.listをsidに変更
  • hardenの設定のみしてアップグレード
  • カーネルのアップグレード
  • 再起動
  • ntp
    • ntp1.sakura.ad.jp
    • ntp.nict.jp
    • ntp.jst.mfeed.ad.jp
  • swapfile(2GB)
$ sudo -H dd if=/dev/zero of=/home/swapfile bs=1024 count=2097152
$ sudo -H swapon /home/swapfile
$ sudo -H sh -c "echo '/home/swapfile swap swap defaults 0 0' >> /etc/fstab"

TODO

  • root mailの設定

VirtualBox設定備忘録

メインマシン(ThinkPad X61 Tablet)のSSDIntel X25-M Mainstream SATA SSD (80GB)から IO-DATA SSDN-ST256Bに交換しました*1

I-O DATA Serial ATA対応内蔵2.5インチSSD 256GB SSDN-ST256B

I-O DATA Serial ATA対応内蔵2.5インチSSD 256GB SSDN-ST256B

OSは(リカバリーではなく)Windows Vista Professional (64bit)のクリーンインストールです*2。研究上のほとんどの作業をDebian GNU/Linux上で行う私にとって*3、ホストOSにWindowsを選ぶ理由は、モバイル運用の際に、ネットワーク接続とマシンの頻繁なスリープで悩まないためです。

そこで必要となるのは仮想マシン環境でして、以前から、VMware Workstation, coLinux, VMware Player, VMware Server, そして今回のVirtualBoxと一通り利用してきました。これまでは、64bitホストでも動き、さらにゲストをホストと同期して起動/シャットダウンするために、仮想マシンWindowsのサービスとして設定できるVMware Serverをずっと使用してきました。しかし、VMware Serverには、いくつか解決されそうにない問題があります。

  1. 2008年以来アップデートがない*4
  2. NATがよく切れる*5
  3. ゲストの時間の同期がいまいちである*6

VMware ServerをノートPCで運用する、というのは想定外の利用法であるとはわかっているので、理解できますが,結構ストレスが溜まっていました。
VMware Serverの売りである、Web AccessVMware Server Consoleを利用することで、リモートホストからもゲストの管理ができるという点は、ノートPCで運用するにあたっては不要でした。

VirtualBoxの情報も増えてきたので調べてみると、VirtualBoxコマンドラインからほとんどすべての設定・操作をすることができるため*7、簡単に自動起動/自動シャットダウンスクリプトを書くことができます。そのため、SSDの入れ替えを機に乗り換えてみました。また、VirtualBoxだとWindows 7ホストにも対応していますし、定期的にアップデートもされています*8

インストールしたのは、リモートデスクトップ接続が使えるPUELなVirtualBox 3.2.6です。ネットワークをどうするかは迷いましたが,ホストのネットワーク接続の頻繁な変更への対応と、ホストからゲストへのアクセスを共存することを目的として、結局以下のように2つ接続を考えることにしました。

  1. ネットワークアダプタ1(eth0)-NAT
  2. ネットワークアダプタ2(eth1)-ホストオンリーネットワーク

なお、VirtualBoxのNATではDNS変換もしてくれるのですが、とても遅いので、ゲストではGoogleDNS(8.8.8.8)を利用することにしました*9。平均的にはこちらが早いです。ゲストにDNSキャッシュサーバとしてunboundを立てるのも選択肢にのぼるかと思います。

自動起動スクリプトと自動シャットダウンスクリプト

バッチファイルやVBScriptのサンプルはいろいろありますが、コマンドプロンプトを出さないようにしたい、という希望と、JavaScriptの時代がきていると勝手に思っているため、JScriptで書きました。これらをWeb上の他の多くのスクリプトと異なり、エスケープをきちんと行ってLong File Nameを使っています。
自動起動スクリプトは次のとおりです。Runの最後の引数にfalseを与えることで、waitせずにホストに制御を戻しています。このスクリプト仮想マシン名はDebianにしています。

var WshShell = new ActiveXObject("WScript.Shell");
WshShell.Run("\"C:\\Program Files\\Oracle\\VirtualBox\\VBoxHeadless.exe\" --startvm \"Debian\"", 0, false);
WshShell = null;

自動シャットダウンスクリプトは次のとおりです。ゲストがACPIによる自動シャットダウン可能にしておく必要があります。Runの最後の引数をtrueにすることで、シャットダウン終了までスクリプト終了をwaitさせることができます。

var WshShell = new ActiveXObject("WScript.Shell");
WshShell.Run("\"C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe\" controlvm \"Debian\" acpipowerbutton", 0, true);
WshShell = null;

ファイル共有

Windows側にはPUELなVirtualBoxをインストールしたのですが、ゲスト側のモジュール群は、アップデートが面倒なため、Debianオフィシャルに存在するvirtualbox-ose-guest-dkmsを入れました。だいたいの操作に問題はなかったのですが、ファイル共有を利用しようとしたところ、ゲスト側でmountした瞬間にカーネルパニックでゲストが落ちました。詳しく追うのは面倒なので、ファイルはいつもどおりsambaで共有しています。

細かな点

  1. VirtualBoxGUIを開いたときにHeadlessなゲストが電源OFF状態と誤認されることがある
    1. PuTTYリモートデスクトップで作業する上では無問題
    2. 電源Onボタンは機能しない(のでやはり無問題)

*1:メインマシンの主記憶容量には80GBでは足りませんでした

*2:Lenovo System Updateを利用するとLenovoオリジナルのソフトウェアも簡単に導入できます

*3:ブラウザはFlashで悩まないためにWindows

*4:このままだと2011年にはEOL

*5:ノートPCなのでいろいろなネットワーク環境で利用する

*6:ノートPCではCPUのクロックが可変

*7:VBoxManage.exe

*8:SunがOracleに買収されて、VirtualBoxも先行き不透明ですが、少なくともGPLOSEがあります

*9:ホストのネットワークが変わるごとにゲストのresolv.confを書き換えるのは非現実的

JabRefからResearchmapのCSV形式を出力するExportFilter

d:id:next49:20100316:p3にあるように、JabRefの文献リストをResearchmapに取り込むには、CSV形式をいじらないといけません。そこで、ExportFilterを書いてみました。
次の内容を1行にして、拡張子をlayoutにしたファイルを作ります。JabRefのメニューからOptions->Manage Custom Exportsを選んで登録すると、Researchmap向けのExportが使えるようになります。ファイル本体は、launchpadにもおいてあります。

"\format[FormatChars]{\title}","\format[FormatChars]{\author}",
"\journal","\volume","\number","\format[FirstPage]{\pages}",
"\format[LastPage]{\pages}","\format[]{\year}00",
"null","null","null","null","null",
"\doi","null","null","\url","\format[FormatChars]{\abstract}"

いくつか未実装点もあります。

  • 出版月(英語<->数字の変換が現状簡単にはできない)
  • PubMed(物理の人間は利用しないため、データがない)

また、論文のデータによってはうまくいかないこともあります。
なお、一般的なJabRefのExportFilterの書き方は、ドキュメントがhttp://jabref.sourceforge.net/help/CustomExports.phpにあります。

Debian GNU/Linux (sid)での日本語TeX環境(20100211版)

私が利用しているDebian GNU/Linux (sid)環境では、TeXの環境が2009年末にTeX Live 2009にアップデートされました。アップデート当時はptex(platex)が使えなくなったり(#561427)しましたが、現在では安定して利用できています。ただ、現在のところ、一部手動設定が必要なところがあるため、まとめてみます。
なお、私の現在のワークフローでは、dvipdfmxを利用してjsarticleを利用したPDFを作成できれば十分です。

CMapをTeX Liveから認識させる

jsarticleだけでなく、jarticleだけであってもCMapのインストールは必要です。CMapが以前non-freeだったという歴史上の事情により、現状CMapのファイルはいろいろなパッケージに散らばっています。明朝とゴシックの2書体だけの最低限の設定には、cmap-adobe-japan1をインストールすればよいです*1。残念ながらインストールしただけではTeX Liveからはまだ利用できないので、手動でリンクを貼る必要があります。

$ sudo ln -s /usr/share/fonts/cmap/adobe-japan1 /usr/share/texmf-texlive/fonts/cmap

JISフォントメトリックをdvipdfmxで利用する方法(フォントを埋めこまない)

ptex-jisfontsの自動設定は現状うまくいかないようです(最近手動設定しかしてなくて未調査)。

$ sudo echo "f jis-cjk.map" >> /etc/texmf/dvipdfmx/dvipdfmx.cfg

として、dvipdfmxの設定ファイルに1行加えるか、

$ dvipdfmx -f jis-cjk.map XXX.dvi

として、mapファイルをコマンドラインから指定すればよいです。

JISフォントメトリックをdvipdfmxで利用する(IPAフォントの埋め込み)

mainにotf-ipafontパッケージが入ったので、mainだけでIPAフォントを埋め込んだPDFファイルを作成できます。mainに入っているIPAフォントはTrueTypeなOpenTypeです。TexLive 2009に含まれているdvipdfmxは、OpenTypeなフォントとしては、PostScriptなOpenTypeフォントしか認識しません(バグ報告します)。そのため、TeXシステムにTrueTypeフォントとして認識させる必要があります。

$ sudo ln -s /usr/share/fonts/opentype /usr/share/texmf-texlive/fonts/truetype

とすると、認識されます(バグ報告します)。
また、/etc/texmf/dvipdfmx/jisembed.map*2などのファイルを作成して、

rml-jis H :0:ipam.otf
gbm-jis H :0:ipag.otf

として、mktexlsrとupdate-updmap*3すると、

$ dvipdfmx -f jisembed.map XXX.dvi

としてmapファイルをコマンドラインから指定すれば、IPAゴシックとIPA明朝が埋め込まれたPDFを作成できます。もし、埋め込むのをデフォルトにしたいなら、

$ sudo echo "f jisembed.map" >> /etc/texmf/dvipdfmx/dvipdfmx.cfg

とすればいいです。

*1:poppler-dataでも可

*2:/etc/texmf/dvipdfmx以下に配置すると、コマンドラインからの指定で

*3:本来はどっちかでいいような

商用SSHにOpenSSHクライアントから公開鍵認証する方法

これは、7年ほど前に研究室でAlphaの計算機を購入したときに書いた資料ですが、あまりにマイナーな場所にファイルを放置していたので、blogに載せておきます。なお、HP Tru64 UNIXとしか書いてないのは、商用SSH(現SSH Tectia Server/Client)がインストールされているマシンが、手元にはTru64しかなかったからです。商用SSHがインストールされている他のUNIX上でも、手順は同じと思われます。
sshを用いれば、毎回passwordを打ちこんだとしても、passwordを盗まれる危険性は低いです。しかし、たとえ暗号化されているとしても、passwordを打ち込まない公開鍵認証(public key authentication)は、便利で、かつより安全です。
ところで、世の中にはOpenSSHサーバ<->OpenSSHクライアント間での認証の説明はたくさんあるのですが、商用SSH<->OpenSSH間の相互運用についての日本語の説明はあまりありません。そこで、今回は、研究室で新たに購入したHP Tru UNIX 5.1B (Alpha)に付属する商用 SSHサーバ(Version 3.2.0)に、 OpenSSHクライアント (Version 3.6.1p2 (Debian sid 2004/01/04))から公開鍵認証で接続する方法を調べました。
なお、ここでは、OpenSSH相互、また商用SSH相互の接続では公開鍵認証ができていることを前提とします。

OpenSSHで作成した公開鍵を商用SSHサーバのフォーマットに変換

商用SSHが用いる公開鍵のフォーマットと、OpenSSHが用いる公開鍵のフォーマットは異なります。そこで、OpenSSH側で、公開鍵のフォーマットを商用SSHのものに変換します。

$ ssh-keygen -e -f .ssh/hogehoge.pub > .ssh/hogehoge_ssh2.pub

商用SSHサーバが稼働しているマシンでのファイルの配置

商用SSHが用いる個人用設定ファイル群の配置は、OpenSSHのものとだいぶ異なります。最初は戸惑いましたが、次のようにすればよいです。

  1. ~/.ssh2/ ディレクトリの作成
  2. 先程作った商用SSHフォーマットの公開鍵を ~/.ssh2/hogehoge_ssh2.pubというファイル名で保存(名前は何でもかまいません)
  3. echo "Key hogehoge_ssh2.pub" >> ~/.ssh2/authorization として、~/.ssh2/authorization に公開鍵を登録

MPIを用いたプログラムでパラメータを外部ファイルから入力するためのサンプルプログラム

Fortranプログラムにおいて、d:id:rigarash:20100201:1264984235で書いたように、namelistからの入力は強力なのですが、MPI並列化のプログラムでは、コマンドラインなどにアクセスできるのは1ノードだけだったりするので、ポータブルに読み込むにはもう少し注意が必要です。少なくともIntel Fortran 11.0 + Intel MPI 3.1.0 と gfortran 4.4.3 + OpenMPI 1.3.3 (Debian GNU/Linux (sid))でうまく動き、できるだけ標準(Fortran2003含む)に準拠したサンプルを書いてみました。

program main
  implicit none
  include "mpif.h"

  integer :: a,b,c
  integer :: res
  integer, dimension(:), allocatable :: resv

  integer :: clcount
  character(len=256) :: arg
  integer :: arglen
  integer :: ioerr,mpierr
  integer :: i,j

  integer :: rank,np

  namelist /param/ a,b,c
  a=1
  b=2
  c=3

  call MPI_Init(mpierr)
  call MPI_Comm_rank(MPI_COMM_WORLD,rank,mpierr)
  call MPI_Comm_size(MPI_COMM_WORLD,np,mpierr)

  if (rank == 0) then
     clcount=command_argument_count()
  endif
  call MPI_Bcast(clcount,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
  if (clcount == 0) then
     call stop_program(rank,np,"*** no input file specified. ***")
  endif
  if (rank == 0) then
    allocate(resv(np),stat=ioerr)
  endif
  call MPI_Bcast(ioerr,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
  if (ioerr > 0) then
     call stop_program(rank,np,"*** result vector allocation fails ***")
  endif
  do i=1,clcount
     if (rank == 0) then
        call get_command_argument(i,arg,arglen,ioerr)
     endif
     call MPI_Bcast(ioerr,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     if (ioerr > 0) then
        call stop_program(rank,np,"*** input file name retrieval fails ***")
     elseif (ioerr == -1) then
        call stop_program(rank,np,"*** input file name too long ***")
     endif
     if (rank == 0) then
        open(unit=100,file=arg,iostat=ioerr)
     endif
     call MPI_Bcast(ioerr,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     if (ioerr > 0) then
        call stop_program(rank,np,"*** Cannot open input file ***")
     endif
     if (rank == 0) then
        read(unit=100,nml=param,iostat=ioerr)
        if (ioerr < 0) then
           print*,"*** parameter reading FAILED. Use default value instead ***"
        endif
        close(unit=100)
        write(unit=6,nml=param)
     endif
     call MPI_Bcast(a,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     call MPI_Bcast(b,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     call MPI_Bcast(c,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     res = a + b + c
     call MPI_gather(res,1,MPI_INTEGER,resv,1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)
     if (rank == 0) then
        do j=1,np
           write(6,*), j,resv(j)
        enddo
     endif
     deallocate(resv,stat=ioerr)
  enddo
  call stop_program(rank,np,"")
end program main

subroutine stop_program(rank,np,text)
  implicit none
  include "mpif.h"

  integer :: rank,np
  integer :: mpierr
  character(*) :: text

  if (rank == 0) then
     write(6,*), trim(text)
  endif
  call MPI_finalize(mpierr)
  stop
end subroutine stop_program