OpenBlocks のおと

はじめに

FreeBSD 4.4Rそのままだと、ifconfig の仕様が以前と変わったのに(gifインターフェースの clone 化の影響と思われる)一部整合性が取れず ifconfig tun0 down delete が出来なくなっています。4.5Rでは直る模様。
vtun-2.4の暗号化は定常的に使うには弱すぎます(使ってる関数は BF_ecb_encrypt)最初に交換した共通鍵をいつまでも同一のまま使って、転送の各パケットを暗号化しています。例えばpingの場合、連続してほとんど同じ内容を暗号化した結果、似たようなパケットが連続して流れるため共通鍵を推定することはかなり容易と思われます。
せめてcbc(共通鍵+前回のパケットを次回の共通鍵の元にする)にしてくれればましなんですが…
どうせOpenSSLを呼んでいるだけなのでソースの改変することを検討しましたが、とりあえず stone/SSL で暗号化経路を確保した上でvtunを通すことにしました。
# 実は本当に改変したんだけど、参照したWeb上のAPIマニュアルが新しすぎて安定版として公開されている 0.9.6b/c に実装されていなかったのにがっくりして中断…

OpenBlockSS でOpenVPNクライアント

OpenVPNベースのページを作成しました。できましたらそちらをまず参照して下さい。

OpenBlockSS でvtunクライアント

OpenBlockSS CF起動またはハードディスク環境においてvtunクライアントにするための設定です。

コンパイル済みダウンロード

zImage.initrd.treeboot.vtun tunデバイスを有効にしたカーネル2.4.10イメージ = ファームウェア。MD5 (zImage.initrd.treeboot.vtun) = da8ae520653615d5897d6a2a1ec713cc
stone stone
vtund vtund
以下はソース+コンパイルオブジェクトのかたまり
stone-2.1d-openblocks.tar.gz
vtun-2.5b1-openblocks.tar.gz
OpenSSLについては、OpenVPNのページから取得してください。(OpenSSL-0.9.6e アップグレードに伴う追記)

設定ファイル集。
/etc/ld.so.conf

/usr/lib
/lib
/local/lib
/usr/local/lib
/etc/rc.d/rc.local (/etc/rc.d/rc.sysinit を編集してこのスクリプトを起動するようにする)
#!/bin/sh
/local/sbin/ldconfig
/local/sbin/sshd
/local/bin/stone -l vtunserver.example.com:963/ssl localhost:962 &
/local/sbin/vtund sayama localhost

tun デバイスの作成

クロスコンパイル環境にて。クロスコンパイル環境で実行するには source /usr/local/obS/example/.setup でクロスコンパイル向け環境を設定する。
基本的にはOBSS のカーネル再構築を参照。コンフィグファイルの CONFIG_TUN の行をCONFIG_TUN=yとしてから make oldconfig を実行する。
この方法ではトンネルデバイスファイルは作ってくれないため、mkdir /dev/net, mknod /dev/net/tun c 10 200を実行する必要がある。

OpenSSLの作成

クロスコンパイル環境にて。クロスコンパイル環境で実行するには source /usr/local/obS/example/.setup でクロスコンパイル向け環境を設定する。 ./configure; makeでさくっと完成。
インストールはコンパイル済みイメージをFTPで転送して、make install。ただしなぜか実行に必要なランダムデバイス /dev/urandom, /dev/randomがないため、mknod /dev/random c 1 8, mknod /dev/urandom c 1 9を一度実行する必要がある。

stoneの作成

SSL付きで普通にコンパイル
stone SSLの設定の仕方は http://www.gcd.org/sengoku/docs/NikkeiLinux00-09/Welcome.ja.html を参照

vtundの作成

いちおーSSL付きでコンパイル。


ここから下は初代OpenBlockS 上の設定

コンパイル済みダウンロード

vtund-openblocks.tar.gz 以下で利用しているOpenBlocks用のバイナリ。めんどくさいのでソースは省略。

tunドライバのインストール

ドライバのコンパイルはimacにインストールされたHOLON Linux上で行った。ぷらっとホームにあるOpenBlockSの開発環境に従って開発環境を設定。ただspecs fileはインストールされているファイルをspecファイルを上書きするのではなく、gcc(スクリプト)の中を書き換えて別の場所に保管する方法で実現した。
Universal TUN/TAP driverよりドライバをダウンロードして、make 。上記のOpenBlocks開発環境上だと Kernel 2.2.13 用のオブジェクトが作成できる。(そのためimacに make install でインストールしても使えない)
OpenBlocksに作成された linux/tun.o を転送
通常のmake installだとcreate_devスクリプトが呼ばれるのだが、OpenBlocksではcreate_devを実行するための環境が不足しているので、結果として行われる以下のコマンドをOpenBlocksの起動時のスクリプトに埋め込んだ。
もちろん起動デバイスをCFやHDDにした場合は1回やればよい。スクリプトにしたのは当初ramdisk起動だったため。

/sbin/insmod /ext1/lib/tun.o
rm -f /dev/tun0 /dev/tun1 /dev/tun2 /dev/tun3
rm -f /dev/tap0 /dev/tap1 /dev/tap2 /dev/tap3
mknod /dev/tun0 c 90 0
mknod /dev/tun1 c 90 1
mknod /dev/tun2 c 90 2
mknod /dev/tun3 c 90 3
mknod /dev/tap0 c 90 128
mknod /dev/tap1 c 90 129
mknod /dev/tap2 c 90 130
mknod /dev/tap3 c 90 131

vtunのインストール

とりあえずvtunホームページよりソースを持ってきてimac上でコンパイル。出来上がった vtund を OpenBlocksの /ext1/bin に転送。
OpenBlocks上でダイナミックリンクライブラリが不足しているのでldd でライブラリを調査するとlibz.so.1とlibcrypto.so.0を追加で利用している。これをimacからOpenBlocksの /ext1/lib に転送、ldconfig も OpenBlocksの /ext1/bin に転送。
そこで /etc/ld.so.conf に /ext1/lib を追加して以下のようなファイルにする。

/lib
/usr/lib
/ext1/lib
/etc/ld.so.conf は /etc/flashcfg に追加してフラッシュメモリに書き込まれるようにし、またOpenBlocksの起動時に /ext1/bin/ldconfig を呼ぶようにする。
あとは普通のvtundの設定だけ。以下の内容を /ext1/etc/vtund.conf に書き込み、OpenBlocksの起動時に /ext1/bin/vtund -f /etc/vtund.conf sayama vtun.somewhere で起動。
#
options {
  port 5000;             # Connect to this port.
  timeout 60;           # General timeout

  # Path to various programs
  ifconfig      /sbin/ifconfig;
  route         /sbin/route;
}

# TUN example. Session 'sayama'.
sayama {
  pass  ********;       # Password
  device tun1;          # Device tun1
  persist yes;          # Persist mode
  up {
        ifconfig "%% 192.168.255.2 pointopoint 192.168.255.1 mtu 1450";
        route "add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.255.1";
  };
  down {
        ifconfig "%% down";
  };
}

vtunのサーバ側インストール

FreeBSDの /usr/ports/net/vtun にて make install
/usr/local/etc/vtund.conf はこんな感じ

#
options {
  port 5000;             # Listen on this port.

  # Path to various programs
  ifconfig      /sbin/ifconfig;
  route         /sbin/route;
}

# Default session options
default {
  compress no;          # Compression is off by default
  speed 0;              # By default maximum speed, NO shaping
  type  tun;
  proto tcp;
  comp  lzo:1;
  encr  yes;            # Encryption
  keepalive yes;        # Keep connection alive
  multi deny;
}

# TUN Session 'sayama'.
sayama {
  pass  ********;       # Password
  up {
        ifconfig "%% 192.168.255.1 192.168.255.2 netmask 0xffffffff mtu 1450";
        route "add -net 192.168.200.0 -netmask 255.255.255.0 192.168.255.2";
  };
  down {
        ifconfig "%% delete down";
        route "delete -net 192.168.200.0 -netmask 255.255.255.0";
  };
}

/usr/local/etc/rc.d/vtund.sh はこんな感じ。(本当は引数にstopが来たら止めないと…)
#!/bin/sh
/usr/local/sbin/vtund -s
echo -n ' vtund'

この例ではTCPを使っているが、これはうちの自宅ではNATの内側にOpenBlocksが設置されているため。global addressをもらっている環境ならUDPの方がよさそう。

OSPF

FreeBSD同士 vtun で接続したセグメントは管理がめんどくさくなってきたので OSPF を導入してみた。将来的には OpenBlocks にも導入予定
FreeBSD の /usr/ports/net/zebra で make install
起動は /usr/local/sbin/zebra -k -d ; /usr/local/sbin/ospfd -d
特定のインターフェースを有効にするには、interface ---network x.x.x.x/x area xを記述するのがミソであった。
/usr/local/etc/zebra/ospfd.conf

! -*- ospf -*-
! $Id: vtun.html,v 1.4 2006/05/10 17:49:07 h Exp $
! OSPFd configuration file
!
hostname ospfd
password ********
enable password ********
!
interface fxp0
interface fxp1
interface fxp2
! for vtun
interface tun0
  ip ospf cost 100
  ip ospf network point-to-point
interface tun1
  ip ospf cost 100
  ip ospf network point-to-point
interface tun2
  ip ospf cost 100
  ip ospf network point-to-point
!
router ospf
  ospf abr-type standard
  router-id 192.168.0.3
  network 192.168.0.0/24 area 0
  network 192.168.1.0/24 area 0
  network 192.168.255.1/32 area 0
  network 192.168.255.2/32 area 0
  network 192.168.255.3/32 area 0
  network 192.168.255.4/32 area 0
  network 192.168.255.5/32 area 0
  network 192.168.255.6/32 area 0
  passive-interface fxp2
!

log file /var/log/ospfd.log

OSPFの動作状況の確認は telnet localhost ospfd でデーモンに接続する。telnetで入った後の操作方法はCISCOっぽく作ってある。
newsyslogでログのローテーションをするときは SIGUSR1 を送る必要がある。FreeBSDでは30番なので/etc/newsyslog.confは以下のような感じ。
/var/log/ospfd.log                      640  5     700  *     Z /var/run/ospfd.pid 30

OpenBlocks上でvtun+OSPF

imac上でGNU zebra をコンパイルし出来上がったバイナリ zebra と ospfd を OpenBlocks の /ext1/bin に転送する。今回は不足しているダイナミックリンクライブラリはないのでそのまま動作する。
zebra.conf はとりあえずパスワードの設定以外どうでもよいのでサンプルを参考に /ext1/etc/zebra.conf として適当に作成する。起動はzebra -k -d -f /ext1/etc/zebra.conf
以下のような /ext1/etc/ospfd.conf を作成し、ospfd の起動は ospfd -d -f /ext1/etc/ospfd.conf

! -*- ospf -*-
! $Id: vtun.html,v 1.4 2006/05/10 17:49:07 h Exp $
! OSPFd configuration file
!
hostname ospfd
password *******
enable password ********
!
interface eth0
interface eth1
! for vtun
interface tun1
  ip ospf cost 100
  ip ospf network point-to-point
!
router ospf
  ospf abr-type standard
  router-id 192.168.200.2
  network 192.168.200.0/24 area 200
  network 192.168.255.3/32 area 0
  network 192.168.255.4/32 area 0
  passive-interface eth1
!

さて、手動での起動は問題なかったが、このzebra,ospfdの起動をブート時のスクリプトに直接書くとうまくいかなかった。vtunのセッションが確立する前だとtunインターフェースが認識できないらしい。
そこで、vtunの設定でセッションの確立後 route コマンドを呼んでいるところを zebra, ospfd に変更することとした。最終的な /ext1/etc/vtund.conf はこんな感じ。
#
options {
  port 963;             # Connect to this port.
  timeout 60;           # General timeout

  # Path to various programs
  ifconfig      /sbin/ifconfig;
  route         /ext1/etc/zebraall.sh;
  firewall      /ext1/etc/zebrakill.sh;
}

# TUN example. Session 'sayama'.
sayama {
  pass  ********;       # Password
  device tun0;          # Device tun0
  persist yes;          # Persist mode
  up {
        ifconfig "%% 192.168.255.2 pointopoint 192.168.255.1 mtu 1450";
        route "";
  };
  down {
        ifconfig "%% down";
        firewall "";
  };
}
/ext1/etc/zebraall.sh
#!/bin/sh
/ext1/bin/zebra -k -d -f /ext1/etc/zebra.conf
/ext1/bin/ospfd -d -f /ext1/etc/ospfd.conf
# /ext1/bin/ripd -d -f /ext1/etc/ripd.conf
/ext1/etc/zebrakill.sh
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/ext1/bin
export PATH
/bin/kill -TERM `head -1 /var/run/ospfd.pid` `head -1 /var/run/zebra.pid`
# `head -1 /var/run/ripd.pid`
sleep 3

vtun開通時に設定されるルーティングも全部OSPFまかせにできるようになったので、サーバ側の vtund.conf は以下のように変更した。
OSPFは状況の変化をほとんど勝手に見つけてくれるはずなのだが、tunデバイスそのものが増減するのにはいまいち対応しきれてないようだったのでSIGHUPを送ってみた。
上にあるようにOpenBlocks側ではSIGHUPでもうまくいかなくて SIGHUPじゃなくてプロセスを完全に再起動 というようにしてある。

#
options {
  port 963;             # Listen on this port.

  # Path to various programs
  ifconfig      /sbin/ifconfig;
  route         /local/bin/zebrahup.sh;
}

# Default session options
default {
  compress no;          # Compression is off by default
  speed 0;              # By default maximum speed, NO shaping
  type  tun;
  proto tcp;
  comp  lzo:1;
  encr  yes;            # Encryption
  keepalive yes;        # Keep connection alive
  multi deny;
}

# TUN Session 'sayama'.
sayama {
  pass  ********;       # Password
  up {
        ifconfig "%% 192.168.255.1 192.168.255.2 netmask 0xffffffff mtu 1450";
        route "";
  };
  down {
        ifconfig "%% delete down";
        route "";
  };
}
/local/bin/zebrahup.sh
#!/bin/sh
/bin/kill -HUP `head -1 /var/run/ospfd.pid` `head -1 /var/run/zebra.pid`

RIPでルーティング情報伝達

更にADSLルータにルーティング情報を伝達させるために、OSPFで設定されたルーティング情報をRIPで流すようにしてみた。例によって ripd -d -f /ext1/etc/ripd.conf で起動。
ADSLルータはRIPv2を解釈しないらしく、RIPv1にしないとうまくいかなかった。当初v2だったのがいけなかったのか、192.168.1.0/24向けゲートウェイとして192.168.1.0が登録されるという謎の事態が発生。

!
hostname ripd
password ********
enable password ********
!
interface lo
!
interface eth0
 ip rip send version 1
!
interface eth1
!
interface tun1
!
router rip
 redistribute ospf metric 3
 network 192.168.200.0/24
 network eth0
 neighbor 192.168.200.1
!
line vty
!
end

このままだと zebra や ospf に向かってどこからでもtelnet接続できるのでIPフィルタリングの設定も書いた方がよい。それはまた後日。

番外編: CFをブートデバイスとして使用する

当初あまりにもすぐにswapしはじめるので「本当にメモリー少ないなあ」と思ってたんですが、16M中ramdiskに6M使ってたのが最大の原因なのが判明。CFでブートするようにするとずいぶんと楽になりました。
Plathomeに記載されている手順が基本ですが、 /etc/mkcfrt を編集しようとしたら中身が「tgzファイルを作ってから展開する」というちょっとCFにやさしくないスクリプトになっていたので このスクリプトを使う代わりに rsync で一気に転送する方法です。
エスケープするのがめんどかったので<>は2バイト文字になっています。rsyncはOpenBlockS Users の部屋にあります。

mke2fs /dev/hda1
mount /dev/hda1 /ext1
(どっかからrsyncをもってくる)
rsync -avz --exclude=/proc --exclude=/ext1 / /ext1/
mkdir /ext1/proc
cat > /ext1/etc/fstab << __EOF__
/dev/hda1     /     ext2   defaults   1 1
/dev/hda2     swap  swap   defaults   0 0
/proc         /proc proc   defaults   0 0
__EOF__

CFデバイスのフォーマット

同じメーカーのCFデバイスを、毎回fdiskでパーティション設定するのも面倒になってきた。 カードスロットのあるLinuxノートパソコンにて、以下の内容を CF128-linux.out としてファイルを作成しておくと、sfdisk /dev/hdg < CF128-linux.outを実行するだけでパーティションが作成できる。 このファイルを作成するためのコマンドは、作成元となるCFデバイスが /dev/hde だったとして、sfdisk -d /dev/hde > CF128-linux.out

# /dev/hde のパーティションテーブル
unit: sectors

/dev/hde1 : start=       32, size=  250848, Id=83
/dev/hde2 : start=        0, size=       0, Id= 0
/dev/hde3 : start=        0, size=       0, Id= 0
/dev/hde4 : start=        0, size=       0, Id= 0

パーティション作成だけ自動化できれば、後はmke2fsmountしてファイルを展開するだけである。まずダンプのとり方。

dump -0u -f /var/tmp/CFall.dmp /dev/hde1