仙石浩明の日記

La Fonera

2008年11月25日

10階以上のホテルの部屋から公衆無線LAN に接続する方法 hatena_b

休暇をとってハワイ (オアフ島) へ行ってきた。

泊まったのはワイキキの安ホテル。 部屋はもちろんマウンテンビュー (つまり海が見えない側)。 一般に階数が高いほどいい部屋とされるが、 公衆無線LAN を使いたい場合は低層階のほうがいい。 もう少し上のランクのホテルだと、 各階に無線LAN のアクセスポイントが設置されていたり、 あるいは各部屋に LAN が敷設してあったりするが、 私が泊まったホテルだと無線LAN が使えるのは一階ロビーだけ。 部屋でインターネットにアクセスしたければ、 屋外で利用可能な公衆無線LAN を利用するしかない (もちろん電話でダイアルアップ接続する手も無くはないが、 あくまでそれは最後の手段)。

こういう場合、部屋が高層階だとやっかいである。 公衆無線LAN のアクセスポイントは、たいてい地上近辺に設置されているので、 階数が高いほど接続しにくくなるからだ。 今回は運悪く (フツーの意味では運良く) 最上階に近い 15階。 厳しいんじゃないかなぁと思いつつ、 ノートPC 内蔵の無線LAN 端末で接続を試みたら案の定、全く接続できず。 ラナイ (Lanai, ハワイ語で「ベランダ」) から身を乗り出して、 ノートPC を外に突き出して (落下注意!) みたのだがダメだった。

高層階だと当然遠くの街路まで見渡せるわけで、 やたらと沢山のアクセスポイントが見通し距離範囲に入ってくる。 が、こちらから出す電波が、 同じチャンネルで電波を出す機器に届かなければ衝突回避してもらえない (CSMA/CA, Carrier Sense Multiple Access/Collision Avoidance) わけで、 ノートPC 内蔵のアンテナではどうにも力不足である。

こんなこともあろうかと、 私は長期旅行には La Fonera+ を持っていくことにしている。 ノートPC 内蔵の無線LAN 端末と違って、 La Fonera+ には外部アンテナがあり、 また内蔵アンテナもあるので、 組合わせてダイバーシチ送信/受信が可能である。

La Fonera / La Fonera+ (FON ソーシャル ルータ) は、 本来は無線LAN アクセス ポイントなのであるが、 中身は普通の Linux マシンなので何でもアリである。 もちろん 無線LAN 端末として 使うこともできる。 まずは La Fonera+ をラナイの端ギリギリ (落下注意!) のところに置き、 ノートPC と Ether ケーブルでつなぐ。 ノートPC で試したときに比べてはるかに多くのアクセスポイントが見つかった (実に 49個!)。

無線LAN 端末としての La Fonera+ が見つけたアクセスポイントの一覧 (信号強度 dBm 順):

More...
Filed under: Hawaii,La Fonera — hiroaki_sengoku @ 08:17
2008年1月4日

La Fonera をディスクレス (flash less) ブートする hatena_b

あけましておめでとうございます。 今年もよろしくお願いします。

La Fonera (La Fonera+) のブート・ローダ RedBoot は、 TFTP サーバに置いたカーネルを load して起動することができる。 したがって、 TFTP サーバから load したカーネルで root ファイル・システムを NFS マウントすれば、 フラッシュ・メモリを使わずにブートすること (ディスクレス・ブート、というか flashless boot) ができる。

La Fonera のようなルータをディスクレスにして 何が嬉しいのかと思う人もいるかもしれないが、 ルータのように常時ネットワークにつなぐものだからこそ、 ネットワークにつないでいないと使えないという ディスクレス最大の欠点が欠点にならないわけで、 むしろルータこそ積極的にディスクレスにすべきではなかろうか。

ディスクレス化することによるメリットは数多い。 なんといっても最大のメリットは、 フラッシュ・メモリを書き換えること無く、 手軽にファームウェアを入れ替えられる (OpenWrt や DD-WRT など) こと。 フラッシュ・メモリを書き換える時間が節約できるし、 書き換え回数を気にする必要もなくなるわけで、 心置き無くファームウェアのデバッグを行なえる。 また、 NFS を使えばフラッシュ・メモリの容量をはるかに超えるディスク領域を使えるので、 セルフ・コンパイル環境の構築なども容易に行なうことができる。

試しに、 La Fonera のフラッシュ・メモリを書き換えること無く DD-WRT をブートさせてみる。

まず、 DD-WRT の root ファイル・システムを NFS サーバ上に展開する。 ここでは例として /nfs/dd-wrt に展開した。 /usr/sbin/udhcpc の実行を抑制するため (理由は後述) に、 /nfs/dd-wrt/usr/sbin/udhcpc を削除しておく。

senri:/tmp # wget "http://www.dd-wrt.com/dd-wrtv2/downloads/release candidates/DD-WRT v24 RC6.2/Atheros WiSoc/Fonera/root.fs"
--09:22:37--  http://www.dd-wrt.com/dd-wrtv2/downloads/release%20candidates/DD-WRT%20v24%20RC6.2/Atheros%20WiSoc/Fonera/root.fs
           => `root.fs'
        ...
09:22:46 (335.56 KB/s) - `root.fs' saved [2834432/2834432]

senri:/tmp # unsquashfs.dd-wrt -dest /nfs/dd-wrt root.fs
Reading a different endian SQUASHFS filesystem on root.fs

created 347 files
created 61 directories
created 159 symlinks
created 0 devices
created 0 fifos
senri:/tmp # rm /nfs/dd-wrt/usr/sbin/udhcpc

次に DD-WRT のカーネルを改変して、 root ファイル・システムを NFS マウントできるようにする。 DD-WRT のソースを取得:

senri:/usr/local/src % svn co svn://svn.dd-wrt.com/DD-WRT
A    DD-WRT/tools
A    DD-WRT/tools/addpattern_gs
A    DD-WRT/tools/uemf.h
        ...

La Fonera 用のカーネルは、 DD-WRT/src/linux/ar531x/linux-2.6.23 にある。
SVN revision 8745 の場合は Linux 2.6.23.12 ベース。
ビルド用ディレクトリ /usr/local/src/linux-2.6.23.12-dd-wrt を作って、 DD-WRT のデフォルトのカーネル設定ファイル .config_generic をコピーし、 make menuconfig を実行:

senri:/usr/local/src % mkdir /usr/local/src/linux-2.6.23.12-dd-wrt
senri:/usr/local/src % cd DD-WRT/src/linux/ar531x/linux-2.6.23
senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % make O=/usr/local/src/linux-2.6.23.12-dd-wrt menuconfig
        ...
senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % cp .config_generic /usr/local/src/linux-2.6.23.12-dd-wrt/
senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % cd /usr/local/src/linux-2.6.23.12-dd-wrt
senri:/usr/local/src/linux-2.6.23.12-dd-wrt % make menuconfig

root ファイル・システムを NFS マウントするために必要な変更は以下の通り:

まず、 カーネルによる IP アドレス自動取得機能を有効にする:

-> Networking
  -> Networking support (NET [=y])
    -> Networking options
      -> TCP/IP networking (INET [=y])
        -> IP: kernel level autoconfiguration (IP_PNP [=y])
          -> IP: DHCP support (IP_PNP_DHCP [=y])

DD-WRT のデフォルト設定では、 ネットワーク・ドライバ AR2313 がモジュールになっているので、 カーネル組み込み (built-in) に変更する:

-> Device Drivers
  -> Network device support (NETDEVICES [=y])
    -> Ethernet (10 or 100Mbit) (NET_ETHERNET [=y])
      -> AR2313 Ethernet support (AR2313 [=y])

そして NFS サポートを有効にする:

-> File systems
  -> Network File Systems
    -> NFS file system support (NFS_FS [=y])
      -> Provide NFSv3 client support (NFS_V3 [=y])
    -> Root file system on NFS (ROOT_NFS [=y])

root ファイル・システムはカーネルがマウントするので mount コマンドは使用しないが、 La Fonera 用の DD-WRT の mount コマンド (busybox に含まれる) は、 NFS をサポートしていないので注意が必要である。 NFS サーバ上の root ディレクトリ /nfs/dd-wrt には、 NFS マウントをサポートした mount コマンドをインストールしておいたほうが便利。

RedBoot の exec コマンドでカーネル・コマンドラインを指定しても、 なぜか無視される (バグ?) ので、 カーネルのデフォルト・コマンドラインを変更しておく:

-> Kernel hacking
  -> Default kernel command string (CMDLINE)

カーネル・コマンドラインとして以下を設定:

console=ttyS0,115200 ip=on root=/dev/nfs nfsroot=/nfs/dd-wrt,nolock

以上まとめると、 カーネル設定ファイル .config の変更箇所は以下の通り:

CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y

CONFIG_AR2313=y

CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y

CONFIG_CMDLINE="console=ttyS0,115200 ip=on root=/dev/nfs nfsroot=/nfs/dd-wrt,nolock"

make して TFTP サーバに置く:

senri:/usr/local/src/linux-2.6.23.12-dd-wrt % make
make -C /usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 O=/usr/local/src/linux-2.6.23.12-dd-wrt
  GEN     /usr/local/src/linux-2.6.23.12-dd-wrt/Makefile
        ...
  LD      vmlinux
  SYSMAP  System.map
        ...
senri:/usr/local/src/linux-2.6.23.12-dd-wrt % mips-linux-uclibc-objcopy -O binary vmlinux /var/tftp/vmlinux.bin

La Fonera で読み込んでブートさせる... といいたいところだが、 DD-WRT のカーネルは、 flash RAM に「nvram」という名前の区画がないと Kernel panic を起こす:

RedBoot> load -r -b 0x80041000 vmlinux.bin
Using default protocol (TFTP)
Raw file loaded 0x80041000-0x8031cbb3, assumed entry at 0x80041000
RedBoot> exec
Now booting linux kernel:
 Base address 0x80030000 Entry 0x80041000
 Cmdline : 
Linux version 2.6.23.12 (sengoku@senri.gcd.org) (gcc version 4.1.2) #14 Wed Jan 2 13:20:19 JST 2008
        ...
Unhandled kernel unaligned access[#1]:
Cpu 0
$ 0   : 00000000 0000006e ffffffed 00000000
        ...
Kernel panic - not syncing: Attempted to kill init!

flash-less boot の主旨には反するが (^^;)、 nvram 区画を作って再度ブートを試みる。

もちろん、 flash を一切参照しないファームウェアを作ることも可能ではあるが、 わずか 64k byte の flash 領域を確保するだけで、 既存のファームウェアをほとんどそのまま流用できるのであれば、 費用対効果の高い flash の使い方と言えるのではないだろうか。

nvram 区画の内容は「空っぽ」でも構わないのであるが、 ついでなので他の DD-WRT マシンで設定した nvram (nvram.bin) をコピーすれば、 設定の手間が省ける。

DD-WRT のデフォルト設定では、 ath0 (無線LAN) と eth0 (WAN) がブリッジとして動作する設定になっていて、 ブート途中で一時的に eth0 を停止する (ifconfig eth0 down あるいは ifconfig eth0 0.0.0.0)。 当然、eth0 を止めた瞬間に NFS サーバと通信できなくなり、 「nfs: server not responding, still trying」という ログを出し続けてハングしてしまう。 したがって、 eth0 を止めない設定にしておく必要がある。 例えば、 NFS サーバ上の root ディレクトリから /usr/sbin/udhcpc を削除した上で、 「WAN Connection Type」を DHCP に設定する。

ついで^2 に、 La Fonera+ には、 「image2」という名前の普段は使われていない区画がある (「image」区画が壊れた場合の非常用) ので削除しておく (fis delete image2)。

RedBoot> fis delete image2
Delete image 'image2' - continue (y/n)? y
... Erase from 0xa8660000-0xa87a0000: ....................
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .
RedBoot> load -r -b 0x80041000 nvram.bin
Using default protocol (TFTP)
Raw file loaded 0x80041000-0x80050fff, assumed entry at 0x80041000
RedBoot> fis create -b 0x80041000 -f 0xA87D0000 -l 0x00010000 nvram
... Erase from 0xa87d0000-0xa87e0000: .
... Program from 0x80041000-0x80051000 at 0xa87d0000: .
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .
RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0xA8000000  0xA8000000  0x00030000  0x00000000
loader            0xA8030000  0x80100000  0x00010000  0x80100000
image             0xA8040000  0x80040400  0x00240230  0x80040400
nvram             0xA87D0000  0xA87D0000  0x00010000  0x80041000
FIS directory     0xA87E0000  0xA87E0000  0x0000F000  0x00000000
RedBoot config    0xA87EF000  0xA87EF000  0x00001000  0x00000000

flash がこの状態でも、 La Fonera+ のオリジナル・ファームウェアは正常に起動する。 また、 ここでは La Fonera+ を使用しているが、 La Fonera でも同様に nvram 区画を作ればよい。

より正確に言うと、 区画の個数が同じ (/dev/mtd9 が board_config) でないと、 オリジナル・ファームウェアでは fonsmcd が異常終了してしまって、 FON ルータが接続されていないと FON にみなされてしまう。 image2 を削除して nvram を追加すれば区画の個数は変わらないので、 fonsmcd を正常に動かすことができる。
ついでに言うと、 区画の個数が変化してしまっても、 /usr/sbin/fonsmcd ファイル中の「/dev/mtd9ro」という部分を変更すれば、 この問題は回避できる。 MTD パーティションの番号をハードコーディングしてしまっているのは、 この部分だけだと思われる。

再度ブート:

RedBoot> load -r -b 0x80041000 vmlinux.bin
Using default protocol (TFTP)
Raw file loaded 0x80041000-0x8031cbb3, assumed entry at 0x80041000
RedBoot> exec
Now booting linux kernel:
 Base address 0x80030000 Entry 0x80041000
 Cmdline : 
Linux version 2.6.23.12 (sengoku@senri.gcd.org) (gcc version 4.1.2) #14 Wed Jan 2 13:20:19 JST 2008
        ...
IP-Config: Got DHCP answer from 172.16.255.254, my address is 172.16.191.230
IP-Config: Complete:
      device=eth0, addr=172.16.191.230, mask=255.255.0.0, gw=172.16.255.254,
     host=172.16.191.230, domain=, nis-domain=(none),
     bootserver=172.16.255.254, rootserver=172.16.255.254, rootpath=
Looking up port of RPC 100003/2 on 172.16.255.254
Looking up port of RPC 100005/1 on 172.16.255.254
VFS: Mounted root (nfs filesystem) readonly.
Mounted devfs on /dev
Freeing unused kernel memory: 140k freed
        ...
DD-WRT v24 std (c) 2008 NewMedia-NET GmbH
Release: 01/02/08 (SVN revision: 8743)

DD-WRT login: root
Password: XXXXXXXX
==========================================================

 ____  ___    __        ______ _____         ____  _  _
 | _ \| _ \   \ \      / /  _ \_   _| __   _|___ \| || |
 || | || ||____\ \ /\ / /| |_) || |   \ \ / / __) | || |
 ||_| ||_||_____\ V  V / |  _ < | |    \ V / / __/|__   _|
 |___/|___/      \_/\_/  |_| \_\|_|     \_/ |_____|  |_|

                       DD-WRT v24
                   http://www.dd-wrt.com

==========================================================


BusyBox v1.4.2 (2008-01-02 03:34:20 CET) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

root@DD-WRT:~# cat /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / nfs ro,vers=2,rsize=4096,wsize=4096,hard,nolock,proto=udp,timeo=10,retrans=2,sec=sys,addr=172.16.255.254 0 0
none /dev devfs rw 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0
ramfs /tmp ramfs rw 0 0
devpts /dev/pts devpts rw 0 0
root@DD-WRT:~# 

NFS サーバに置いた DD-WRT の root ディレクトリ /nfs/dd-wrt が、 無事 / にマウントできている。

Filed under: La Fonera — hiroaki_sengoku @ 08:38
2007年12月21日

La Fonera+ へ ssh でログインする (3) root イメージの改変

前回抽出した ROOT ディレクトリ を改変する。 真っ先に変更すべきなのは /etc/inittab で、 以下のように 1行挿入して /bin/ash が立ち上がるようにしておく。 これだけで、 シリアル・コンソールでシェルが使えるようになる。

--- ROOT.org/etc/inittab        2007-06-19 03:47:32.000000000 +0900
+++ ROOT/etc/inittab        2007-12-15 10:28:06.317233846 +0900
@@ -1,2 +1,3 @@
 ::sysinit:/etc/init.d/rcS
+ttyS0::askfirst:/bin/ash --login
 #::respawn:/sbin/monit -Ic /etc/monitrc

この変更だけでも、 La Fonera+ がいじり放題になるので、 改変ファームウェアを作ってみる。

当然 kernel が必要になる。 FON のソースからビルドするのは難しくはないが、 クロスコンパイル環境の構築など、 それなりの時間がかかるので、 とりあえず純正ファームウェアのものをそのまま使って、 改変ファームウェアを作ってみる。 まず純正ファームウェアから取り出した image_full のヘッダを参照して、...

senri:/tmp % od -t x1 image_full | head -1
0000000 00 21 bf de a2 14 d3 9b 00 0a 50 34 6d 00 00 80

前回説明したように image_full は以下のフォーマットなので、 「lzma 圧縮したカーネル」は、 12 バイト目から 000A5034 (上記ヘッダ 8 バイト目~ に注目) バイトであることが分かる。

┌───────┬───────┬───────┬───<<───┬───<<───┐
│rootイメージの│チェック・サム│rootイメージの│lzma 圧縮した │root イメージ │
│サイズ   4byte│(CRC32)  4byte│位置     4byte│カーネル      │squashfs      │
└───────┴───────┴───────┴───>>───┴───>>───┘

000A5034 は 10進数に直すと 675892 なので、 以下のように dd コマンドに「count=675892」を指定して、 image_full から lzma 圧縮したカーネル「vmlinux.lzma」を取り出す:

senri:/tmp % dd if=image_full bs=1 skip=12 count=675892 of=vmlinux.lzma
675892+0 records in
675892+0 records out
675892 bytes (676 kB) copied, 1.25156 seconds, 540 kB/s

前述したパッチを前回抽出した ROOT ディレクトリへ適用し、 mksquashfs-lzma コマンドを使って root イメージ root.squashfs を作成する:

senri:/tmp # patch -p0 < patch
patching file ROOT/etc/inittab
senri:/tmp # mksquashfs-lzma ROOT root.squashfs -nopad -noappend -root-owned -be
Creating big endian 3.0 filesystem on root.squashfs, block size 65536.

Big endian filesystem, data block size 65536, compressed data, compressed metadata, compressed fragments
Filesystem size 1499.77 Kbytes (1.46 Mbytes)
        31.47% of uncompressed filesystem size (4766.19 Kbytes)
Inode table size 4802 bytes (4.69 Kbytes)
        23.45% of uncompressed inode table size (20479 bytes)
Directory table size 5571 bytes (5.44 Kbytes)
        56.99% of uncompressed directory table size (9776 bytes)
Number of duplicate files found 4
Number of inodes 639
Number of files 407
Number of fragments 28
Number of symbolic links  165
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 67
Number of uids 1
        root (0)
Number of gids 0

以上で、 カーネルと root イメージの準備ができた。 vmlinux.lzma と root.squashfs をつなげて image ファイルを作成する:

senri:/tmp % fonimage.pl image vmlinux.lzma root.squashfs

fonimage.pl は、 FON のソース を展開すると、 fon/target/linux/fonera-2.6/image/fonimage.pl にある perl スクリプト。 CRC32 の算出 (前述した image_full のフォーマット参照) のため、 Digest::CRC モジュールが必要。

できた image を TFTP サーバに置いて、 La Fonera+ の flash へ書込む

試しに起動してみる:

RedBoot> fis load loader
RedBoot> go
Failsafe loader v0.2

Looking for board config data... found at offset 0xa87f0000
Reset button GPIO: 6
Reading flash from 0xa8040000 to 0xa825bf48... done.
Verifying CRC... OK - 0x766770d6
Uncompressing Linux... Ok, booting the kernel.
[sighandler]: No more events to be processed, quitting.
[cleanup]: Waiting for children.
[cleanup]: All children terminated.
Unlocking rootfs ...
Could not open mtd device: rootfs
switching to jffs2
init started:  BusyBox v1.4.1 (2007-09-03 10:39:50 UTC) multi-call binary

Please press Enter to activate this console. 


BusyBox v1.4.1 (2007-09-03 10:39:50 UTC) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

  ______                                           __      
 /\  ___\                                         /\ \     
 \ \ \__/  __     ___      __   _ __    __        \_\ \___ 
  \ \  _\/ __`\ /' _ `\  /'__`\/\`'__\/'__`\     /\___  __\
   \ \ \/\ \L\ \/\ \/\ \/\  __/\ \ \//\ \L\.\_   \/__/\ \_/
    \ \_\ \____/\ \_\ \_\ \____\\ \_\\ \__/.\_\      \ \_\ 
     \/_/\/___/  \/_/\/_/\/____/ \/_/ \/__/\/_/       \/_/ 

--------------  Fonera 1.5 Firmware (v1.1.1.1) -----------------

               * Based on OpenWrt - http://openwrt.org
             * Powered by FON - http://www.fon.com
      -----------------------------------------------------
root@OpenWrt:/# 

カーネルは改変していないので、 起動ログを見ることはできないが、 シェルが使えるのでいじり放題。

では早速...

root@OpenWrt:/# cat > /etc/ipkg.conf <<EOF
> src gcd http://www.gcd.org/fonera
> dest root /
> dest ram /tmp
> EOF
root@OpenWrt:/# ipkg update
Downloading http://www.gcd.org/fonera/Packages
Updated list of available packages in /usr/lib/ipkg/lists/gcd
Done.
root@OpenWrt:/# ipkg install dropbear
Installing dropbear (0.48.1-1) to root...
Downloading http://www.gcd.org/fonera/dropbear_0.48.1-1_mips.ipk
xsystem: ERROR: fork failed before execution: `wget --passive-ftp    -q -P /tmp/ipkg-0dCiiX http://www.gcd.org/fonera/dropbear_0.48.1-1_mips.ipk'
Nothing to be done
An error ocurred, return value: 22.
Collected errors:
Failed to download dropbear. Perhaps you need to run 'ipkg update'?
root@OpenWrt:/#

つまり GCD の ipkg feed から dropbear をインストールしようとしたのだが、 La Fonera+ の wget は busybox 内蔵のもので ipkg が期待する wget とは引数の形式が異なるようだ。 ipkg のためだけに GNU Wget をインストールするのも牛刀なので、 手作業で dropbear をインストールしてみる。

root@OpenWrt:~# wget http://www.gcd.org/fonera/Plus/dropbear_0.49-1_mips.ipk
Connecting to www.gcd.org [60.32.85.216:80]
dropbear_0.49-1_mips 100% |*****************************|    98 KB --:--:-- ETA
root@OpenWrt:~# tar xvzf dropbear_0.49-1_mips.ipk
./debian-binary
./data.tar.gz
./control.tar.gz
root@OpenWrt:~# cd /
root@OpenWrt:/# tar xvzf ~/data.tar.gz
./
./usr/
./usr/sbin/
./usr/sbin/dropbear
./usr/bin/
./usr/bin/scp
./usr/bin/ssh
./usr/bin/dbclient
./usr/bin/dropbearkey
./etc/
./etc/config/
./etc/config/dropbear
./etc/init.d/
./etc/init.d/dropbear
root@OpenWrt:/# /etc/init.d/dropbear start
root@OpenWrt:/#

これで外部から ssh でログインできるようになる。

La Fonera+ 起動時に自動的に dropbear (ssh サーバ) を立ち上げるには、

root@OpenWrt:/# /etc/init.d/dropbear enable

を実行すればよい。 以上は、 dropbear を La Fonera+ に直接インストール方法であるが、 もちろん前述した ROOT ディレクトリに対して dropbear をインストールして、 dropbear 入り image ファイルを作って flash メモリに書込んだ方がよい。

Filed under: La Fonera — hiroaki_sengoku @ 14:06
2007年12月18日

La Fonera+ へ ssh でログインする (2) root イメージの抽出

La Fonera+ の場合、 全てのソースが公開されているわけでは無い (例えば fonsmcd などが非公開)。 したがって La Fonera+ の機能を出来るかぎり損なわずに ファームウェアの改変を行なうには、 ソースから全てをビルドすることを目指すよりは、 純正ファームウェアの root イメージを入手して、 それをベースに改変を行なう方がよい。

純正ファームウェアの root イメージを入手する方法としては、 La Fonera+ をディスクレス (フラッシュメモリレス?) 起動させて フラッシュ・メモリの内容を丸ごとコピーする方法がまず考えられる。 実際、私はこの方法で La Fonera+ のフラッシュ・メモリの内容を抽出したのだが、 La Fonera+ は 純正ファームウェアがダウンロードできる。 わざわざ実機からファームウェアを抽出しなくてもいいのでお手軽である。 そこで今回はダウンロードした純正ファームウェアから root イメージを取り出して 改変を行なう方法を紹介する。

まず FON のダウンロードページ から foneraplus_1.1.1.1.fon をダウンロードする。 「.fon」という見慣れない拡張子だが、 このファイルの 519 バイト目以降が tar + gz アーカイブになっている。 519 という数字はバージョンによって変わるかも知れないので、 算出方法を説明しておく。 先頭 4 バイトは マジック・ナンバー「FON5」なのでスキップ。

余談だが、 La Fonera のファームウェア (例えば fonera_0.7.1.1.fon) の場合だと、 このマジック・ナンバーは「FON3」であり、 La Fonera のファームウェアの更新差分 (例えば upgrade.fon) の場合だと、 「FON4」になっている。

マジック・ナンバーの次、すなわち 4 バイト目 (先頭を 0 バイト目と数える) から 3 バイトに注目する。

% od -t a foneraplus_1.1.1.1.fon | head -1
0000000   F   O   N   5   5   1   2   !   V sub   ,  cr   ^   -   k   e

ASCII コードで「512」と入っていることが分かる。 この数値は、 tar + gz アーカイブの位置を表わしている。 すなわち、 この「512」の文字列の直後の位置 (つまり 7 バイト目) から数えて 512 バイト目、 先頭から数えれば 519 バイト目が、 tar + gz アーカイブの先頭位置である。 アーカイブを取り出して展開してみる:

% dd if=foneraplus_1.1.1.1.fon bs=1 skip=519 of=foneraplus_1.1.1.1.tgz
2213430+0 records in
2213430+0 records out
2213430 bytes (2.2 MB) copied, 4.95395 seconds, 447 kB/s
% tar xvzf foneraplus_1.1.1.1.tgz
-rwxr-xr-x iurgi/iurgi     666 2007-09-07 23:39 upgrade
-rw-r--r-- iurgi/iurgi 2293764 2007-09-05 23:28 image_full
-rw-r--r-- iurgi/iurgi     102 2007-04-23 21:12 hotfix

展開すると「image_full」というファイルが得られる。 これは、 kernel と root イメージをつなげて、 先頭にヘッダをつけた、 次のようなフォーマットのファイル。

┌───────┬───────┬───────┬───<<───┬───<<───┐
│rootイメージの│チェック・サム│rootイメージの│lzma 圧縮した │root イメージ │
│サイズ   4byte│(CRC32)  4byte│位置     4byte│カーネル      │squashfs      │
└───────┴───────┴───────┴───>>───┴───>>───┘

つまり 前回 flash へ書込んだ image ファイルと同じフォーマットである。

image_full から root イメージを取り出すには、 このファイルのヘッダから 「root イメージサイズ」と「root イメージの位置」を取り出せばよい。

% od -t x1 image_full | head -1
0000000 00 21 bf de a2 14 d3 9b 00 0a 50 34 6d 00 00 80

先頭 4 バイトは「0021BFDE」であり、 これを 10進数に変換すると 2211806 であるから、 root イメージサイズが 2211806 バイトであることがわかる。 また、 8 バイト目から 4 バイトは「000A5034」であり、 これを 10進数に変換すると 675892 であることから、 root イメージの位置がこの「000A5034」の直後の位置 (つまり 12 バイト目) から数えて 675892 バイト目、 すなわち先頭から数えれば 675904 バイト目であることがわかる。 root イメージを取り出して展開してみる:

% dd if=image_full bs=1 skip=675904 count=2211806 of=root.squashfs
1617860+0 records in
1617860+0 records out
1617860 bytes (1.6 MB) copied, 3.61499 seconds, 448 kB/s
# unsquashfs-lzma -dest ROOT root.squashfs
Reading a different endian SQUASHFS filesystem on root.squashfs
created 407 files
created 67 directories
created 165 symlinks
created 0 devices
created 0 fifos

これで、La Fonera+ の root ディレクトリ以下の全ファイルが、 ROOT ディレクトリ以下に展開される。 unsquashfs-lzma というコマンドが見慣れないかも知れないが、 これは squashfs に含まれる unsquashfs を lzma ライブラリとリンク して作ったコマンドである。

(つづく)

Filed under: La Fonera — hiroaki_sengoku @ 08:53
2007年12月17日

La Fonera+ へ ssh でログインする (1) flash への書込み hatena_b

FON ソーシャル・ルータ La Fonera+ へログインするのは、 La Fonera のときほど容易ではない。 La Fonera はシリアル・コンソールでシェル (/bin/ash) を使えたので、 dropbear (ssh サーバ) を立ち上げるだけで、 ssh でログインできるようになる。 しかし La Fonera+ はシリアル・コンソールをつなげても シェルが動いていないので、 Linux 起動後はコンソール出力を眺めることくらいしかできない。

ログインできないようにしてあると、 余計にログインしたくなるのは人の常であるようで、 すでに多くの方が挑戦し 成功しているようだ。 基本的には、 ファームウェアを書き換えてシリアル・コンソールを 有効にしてしまえばいいだけのことであるが、 いかに La Fonera+ の機能そのままに、 シリアル・コンソールだけ有効にするかが肝であろう。

というわけで、 先人が作ったファームウェアをそのまま使うのでは面白くないので、 FON が公開しているソース を元に、 改変ファームウェアを作ってみた。 作り方を書いていると長くなるので、 次回以降で説明するとして、 まずは作った改変ファームウェアを La Fonera+ に書込むところから。

RedBoot> load -r -b 0x80040400 image
Using default protocol (TFTP)
Raw file loaded 0x80040400-0x8028062f, assumed entry at 0x80040400
RedBoot> fis create image
... Erase from 0xa8040000-0xa8280230: .....................................
... Program from 0x80040400-0x80280630 at 0xa8040000: .....................................
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

ここで TFTP サーバから読み込んでフラッシュへ書込んだ image というファイルが、 今回作成した改変ファームウェア。 これは、 kernel と root イメージをつなげて、 先頭にヘッダをつけた、 次のようなフォーマットのファイル。

┌───────┬───────┬───────┬───<<───┬───<<───┐
│rootイメージの│チェック・サム│rootイメージの│lzma 圧縮した │root イメージ │
│サイズ   4byte│(CRC32)  4byte│位置     4byte│カーネル      │squashfs      │
└───────┴───────┴───────┴───>>───┴───>>───┘

FON のソース に含まれる (fon/target/linux/fonera-2.6/image/fonimage.pl)、 fonimage.pl コマンドを 以下のように実行すると、 この image ファイルを作成できる。

fonimage.pl  image 《lzma圧縮したカーネルイメージ》 《squashfsなrootイメージ》

前回書いたように、 La Fonera+ は起動すると「loader」を起動する。 この loader プログラムが、 上記 image ファイルを読み込んで、 カーネルと root イメージに分解し、 カーネルを lzma 展開した上で起動する。

試しに起動してみる。 printk サポートを有効にしてある (CONFIG_PRINTK=y) ので、 Linux 起動ログを見ることができる。

RedBoot> fis load loader
RedBoot> go
Failsafe loader v0.2

Looking for board config data... found at offset 0xa87f0000
Reset button GPIO: 6
Reading flash from 0xa8040000 to 0xa8280224... done.
Verifying CRC... OK - 0x9ffc079a
Uncompressing Linux... Ok, booting the kernel.
Linux version 2.6.19.2 (sengoku@senri.gcd.org) (gcc version 4.1.2) #8 Sun Dec 16 16:52:31 JST 2007
CPU revision is: 00019064
Determined physical RAM map:
 memory: 01000000 @ 00000000 (usable)
Initrd not found or empty - disabling initrd
Built 1 zonelists.  Total pages: 4064
Kernel command line: console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/etc/preinit
        ... 中略 ...
switching to jffs2
mini_fo: using base directory: /
mini_fo: using storage directory: /jffs
init started:  BusyBox v1.4.1 (2007-12-13 15:41:27 JST) multi-call binary

Please press Enter to activate this console. 
eth0.0: dev_set_promiscuity(master, 1)
device eth0 entered promiscuous mode
device eth0.0 entered promiscuous mode
: udhcpc (v1.4.1) started

        ... 中略 ...

: 21 2 * * * /bin/thinclient cron

: 13 5 * * * ntpclient -s -h ntp-1.cso.uiuc.edu

: fonsmcd successfully started

La Fonera と同様に mini_fo を使って、 squashfs の上に jffs2 を 重ねることによって、 / (root ファイル・システム) を書込み可能にしている。

La Fonera と同様、 cron から /bin/thinclient を実行しているが、 実はこれは機能していない。 つまり、 /bin/thinclient cron を実行してみると、 以下のように Usage が表示されてしまう。

root@OpenWrt:/# /bin/thinclient cron
Usage /bin/thinclient (dummy|start|config|upgrade) [voucher_file]

La Fonera の thinclient が果たしていた役割は、 La Fonera+ では /usr/sbin/fonsmcd が担っているようだ。 しかしながら fonsmcd のソースは公開されていない (少なくとも前述したソースには含まれていない) ので、 詳細は不明。

シリアル・コンソールで「Enter」を入力すれば、 シェルを使うことができるようにしてある。 さらに、ネットワーク経由で ssh ログインすることもできる:

% rsh -l root 172.16.191.252


BusyBox v1.4.1 (2007-12-13 15:41:27 JST) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

  ______                                           __      
 /\  ___\                                         /\ \     
 \ \ \__/  __     ___      __   _ __    __        \_\ \___ 
  \ \  _\/ __`\ /' _ `\  /'__`\/\`'__\/'__`\     /\___  __\
   \ \ \/\ \L\ \/\ \/\ \/\  __/\ \ \//\ \L\.\_   \/__/\ \_/
    \ \_\ \____/\ \_\ \_\ \____\\ \_\\ \__/.\_\      \ \_\ 
     \/_/\/___/  \/_/\/_/\/____/ \/_/ \/__/\/_/       \/_/ 

--------------  Fonera 1.5 Firmware (v1.1.0.2) -----------------

               * Based on OpenWrt - http://openwrt.org
             * Powered by FON - http://www.fon.com
      -----------------------------------------------------
root@OpenWrt:/# df
Filesystem           1k-blocks      Used Available Use% Mounted on
tmpfs                      512         0       512   0% /dev
/dev/mtdblock4            3840       284      3556   7% /jffs
/jffs                     1664      1664         0 100% /
root@OpenWrt:/# free
              total         used         free       shared      buffers
  Mem:        13612        12680          932            0         1064
 Swap:            0            0            0
Total:        13612        12680          932
root@OpenWrt:/# ifconfig eth0.1
eth0.1    Link encap:Ethernet  HWaddr 00:18:84:XX:XX:XX
          inet addr:172.16.191.252  Bcast:172.16.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1480  Metric:1
          RX packets:1367 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1212 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:129328 (126.2 KiB)  TX bytes:184394 (180.0 KiB)

root@OpenWrt:/# 

La Fonera+ には ether ケーブルのソケットが二つついているが、 カーネルから見ると WAN 側ソケットは eth0.1 つまり VLAN デバイスとして見える。 LAN 側ソケットは eth0.0 である。

(つづく)

Filed under: La Fonera — hiroaki_sengoku @ 07:59
2007年12月10日

La Fonera+ を買ってシリアル・ケーブルをつないでみた hatena_b

FON から無料キャンペーンのお知らせが来たので、 土曜日に秋葉原の九十九電機へ行ってラ・フォネラ+を ?台買ってきた。

La Fonera+

一台 1000円。 以前から La Fonera+ に興味はあったのだが、 3800円はチト高いなぁと思って手を出さずにいたので、 この機会に是非入手すべく、朝早く (といっても 10:00 ごろだが) から店頭へ。

ツクモ パソコン本店には開店前から行列ができている。 本店の整然とした並びとは対照的に、 DOS/V パソコン館では La Fonera+ の棚の前に無秩序に人が群がっている。 私は大阪人なので、並ぶのはニガテである。 なので DOS/V パソコン館の前で開店を待つことにする。 ちなみに、 ツクモケース王国や 12号店は開店時間が 11:00 なので誰も並んでいない。

10:30 開店の合図と同時に La Fonera+ 目指して飛びかかる客数人 (^^;)。 みるみる間に棚の上の La Fonera+ が減っていく。 無事入手して足早に秋葉原を後にする。

帰宅してすぐ、La Fonera+ 裏面のゴム足をはがす。 う、トルクス (TORX は登録商標なので、ヘックスローブ Hexlobe とも呼ばれる) ねじだ。 La Fonera は普通の「+」ネジだったのに... 慌てて近所のホームセンターに走る。 ねじのサイズは T-9H のようだ。 1サイズ小さい T-8H でも使えた。

La Fonera+ 内部

La Fonera にはヒートシンクがあったのに、La Fonera+ には無い。 ↑ 基板下辺に、JP1 と書かれたジャンパ・ピンが 4本立っている。 基板裏を見ると、一番右は明らかに GND である。 真ん中二本は信号線のようなので、 UP-12C (USB携帯電話メモリー転送ケーブル) の線を、 JP1 左から NC(つながない)、白(Rx)、緑(Tx)、黒(GND) の順につないでみると、 無事 RedBoot の出力を PC 側で見ることができた。

google で検索してみると、 UP-12C の緑が Rx で、白が Tx と書いてある説明が多いが、 これは緑を (デバイスの) Rx につなぐという意味で書いた (オリジナルの) 記述が、 「緑=Rx」と誤解されて広まったためではないだろうか? デバイス (La Fonera+) の Rx (受信入力) につなぐのは、 UP-12C の Tx 信号 (送信) 線だから、 「緑=Tx」「白=Rx」と書くべきだと思う。 逆に、ジャンパ・ピンの説明をするなら、 緑をつなぐピンが Rx ということになる。

つまり、JP1 左から (La Fonera+ 側から見て) Vcc, Tx, Rx, GND だと思われる。 ちなみに UP-12C の赤は電源なので接続してはいけない。 赤をショートさせると、 USB の電源供給能力一杯の電流が流れ、 UP-12C 本体が過熱する (でも壊れなかった。経験者談 ^^;)。

La Fonera+ にシリアル・ケーブルをつなぐ

RedBoot は boot script を自動的に実行しようとするので、 2秒以内に ^C を入力すると、 RedBoot のコマンドプロンプトが表示される:

senri %        cu -l ttyUSB1
Connected.
+Ethernet eth0: MAC address 00:18:84:xx:xx:xx
IP: 192.168.1.1/255.255.255.0, Gateway: 0.0.0.0
Default server: 192.168.1.254

RedBoot(tm) bootstrap and debug environment [ROMRAM]
OpenWrt certified release, version 1.1 - built 22:32:28, May  7 2007

Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

Board: FON 2201 
RAM: 0x80000000-0x81000000, [0x80040290-0x80fe1000] available
FLASH: 0xa8000000 - 0xa87f0000, 128 blocks of 0x00010000 bytes each.
== Executing boot script in 2.000 seconds - enter ^C to abort
^C
RedBoot> 

コマンド一覧を表示させてみる:

RedBoot> help
Manage aliases kept in FLASH memory
   alias name [value]
Set/Query the system console baud rate
   baudrate [-b <rate>]
Move Atheros Board Data information
   bdmove 
Restore Atheros Board Data information
   bdrestore 
Manage machine caches
   cache [ON | OFF]
Display/switch console channel
   channel [-1|<channel number>]
Compute a 32bit checksum [POSIX algorithm] for a range of memory
   cksum -b <location> -l <length>
Display (hex dump) a range of memory
   dump -b <location> [-l <length>] [-s] [-1|2|4]
Execute an image
   exec [-b <argv addr>] [-c "kernel command line"] [-w <timeout>]
        [<entry point>]
Manage FLASH images
   fis {cmds}
Manage configuration kept in FLASH memory
   fconfig [-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]
Get Key number
   get_key 
Get Mac addresses
   get_mac 
Get Serial number
   get_serial 
Execute code at a location
   go [-w <timeout>] [-c] [-n] [entry]
Help about help?
   help [<topic>]
Display command history
   history 
Set/change IP addresses
   ip_address [-l <local_ip_address>[/<mask_len>]] [-h <server_address>]
Load a file
   load [-r] [-v] [-d] [-h <host>] [-p <TCP port>][-m <varies>] [-c <channel_number>] 
        [-b <base_address>] <file_name>
Compare two blocks of memory
   mcmp -s <location> -d <location> -l <length> [-1|-2|-4]
Copy memory from one address to another
   mcopy -s <location> -d <location> -l <length> [-1|-2|-4]
Fill a block of memory with a pattern
   mfill -b <location> -l <length> -p <pattern> [-1|-2|-4]
Network connectivity test
   ping [-v] [-n <count>] [-l <length>] [-t <timeout>] [-r <rate>]
        [-i <IP_addr>] -h <IP_addr>
Reset the system
   reset 
Set values
   set 
Display RedBoot version information
   version 
Display (hex dump) a range of memory
   x -b <location> [-l <length>] [-s] [-1|2|4]

La Fonera の RedBoot と比べると、 bdshow コマンド (Display Atheros Board Data information) が削除され、 get_key, get_mac, get_serial, set コマンドが追加されているが、 機能的には大差ないようだ。

フラッシュ・メモリの内容は、こんな感じ:

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0xA8000000  0x80040400  0x00030000  0xA8000000
loader            0xA8030000  0x80100000  0x00010000  0x80100000
image             0xA8040000  0x80040400  0x00230004  0x80040400
image2            0xA8660000  0xA8660000  0x00140000  0x80040400
FIS directory     0xA87E0000  0xA87E0000  0x0000F000  0x00000000
RedBoot config    0xA87EF000  0xA87EF000  0x00001000  0x00000000

「vmlinux.bin.l7」や「rootfs」の区画があった La Fonera とは様変わりしている。 サイズからいって、「loader」は単なるイニシャル・ローダであろう。 「image」「image2」はカーネル・イメージ? 0xA8270004 ~ 0xA8660000 の 4M Byte 弱 (0x3EFFFC = 4128764) が空いているが、 おそらくここにルート・イメージがあるのではないかと思われる。 ルート・イメージにしては少し小さすぎる気がするが、 おいおい解析していく予定。

設定 (fconfig) は次のようになっていた:

Run script at boot: true
Boot script:
.. fis load -b 0x80100000 loader
..  go 0x80100000
Boot script timeout (1000ms resolution): 2
Use BOOTP for network configuration: false
Gateway IP address:
Local IP address: 192.168.1.1
Local IP address mask: 255.255.255.0
Default server IP address: 192.168.1.254
Console baud rate: 9600
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false

なぜ RedBoot から直接 Linux を起動せず、 「loader」を起動しているのか謎であるが、 変則的な fis list と関係があるのかも知れない。 また、La Fonera と異なり、 La Fonera+ ではシリアル・コンソールが有効になっていない。 すなわちカーネルの起動メッセージが出力されず、 ブート後にログインすることもできない。

- o -

さて、一段落ついたところで、 「La Fonera+ の登録」をしておこうかと思い、 同梱されていたマニュアルにしたがって http://registerlafonera.fon.com にアクセスしたところ、

EN
You are not connected through your “MyPlace” signal. Please choose the “MyPlace” signal in your “Wireless Network Connection” window and click connect. See image.

日本語
あなたはMy Placeでの接続をなさっておりません。 'ワイアレスネットワークコ ネクションより 'My Place'を選択して接続し直してください。画像をご覧になってください。

と表示されてしまった。 今まで何台かの La Fonera を登録してきたが、 スムーズに登録できたためしがない。 FON の主旨は面白いのに、 こういう細かいところのツメが甘いのは、とてもモッタイナイ。 ついでに言うと、 あいかわらず日本語が微妙なのはなんとかならないものか。

「あなたはMy Placeでの接続をなさっておりません」などと 決めつけられてしまったが、 もちろん決してそんなことはない。 WPA パスフレーズとして S/N を入力して接続に成功したのだから、 確かに目の前の La Fonera+ の My Place 経由で インターネットに接続しているはずである。

さて、どうしたものか、と思いつつ、試しに FON_AP のほうを試してみたら、 あっさり登録できてしまった。 なんだかなぁ... これでは以前の La Fonera と同じ登録方法ではないか。 FON_AP 経由でルータ登録を行なうこの方法では、 第三者が勝手に他人の La Fonera+ を登録できてしまう。

Filed under: La Fonera — hiroaki_sengoku @ 07:28
2007年11月21日

La Fonera ファームウェア vmlinux.bin.l7 の拡張子「L7」とは? hatena_b

FON ソーシャルルータ La Fonera のファームウェアは Linux であり、 RedBoot ブートローダ から起動される。 デフォルト状態の La Fonera では、 以下のように RedBoot がフラッシュメモリから Linux カーネルをロードして 自動起動する設定になっている。

== Executing boot script in 1.000 seconds - enter ^C to abort
RedBoot> fis load -l vmlinux.bin.l7
Image loaded from 0x80041000-0x801ba000
RedBoot> exec
Now booting linux kernel:
 Base address 0x80030000 Entry 0x80041000
 Cmdline : 
(以下略)

fis (Flash Image System) は、 フラッシュメモリの読み書きを行なうためのコマンドである。

fis load -l vmlinux.bin.l7」を実行することにより、 フラッシュメモリ内の「vmlinux.bin.l7」と名前をつけられた区画の内容を RAM へコピー (つまり load) する。

ところが、 fis load コマンドのマニュアルには、 「-l」オプションの記述がない。

Synopsis
fis load [-b load address] [-c ] [-d ] [name]

にもかかわらず、 La Fonera の RedBoot で fis コマンドのヘルプを表示させると、 「-l」オプションが指定できることが分かる。

RedBoot> fis help
*** invalid 'fis' command: unrecognized command
Usage:
  fis create -b <mem_base> -l <image_length> [-s <data_length>]
      [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>
  fis delete name
  fis erase -f <flash_addr> -l <length>
  fis free
  fis init [-f]
  fis list [-c] [-d]
  fis load [-d] [-l] [-b <memory_load_address>] [-c] name    ← コレ
  fis write -f <flash_addr> -b <mem_base> -l <image_length>

一体この「-l」オプションとは何なのか?

というか、 そもそも「vmlinux.bin.l7」という名前の見慣れない拡張子「L7」とは何なのか?
(L7 というと Layer 7 くらいしか思いつかない... ^^;)

というわけで調べてみた。

「vmlinux.bin.l7」の内容と、 「fis load -l」コマンドによって 0x80041000 番地にロードされた内容を見比べると、 「vmlinux.bin.l7」はデータ圧縮を行なった形式であるように見える。 おそらく「-l」オプションは、 フラッシュメモリ上の圧縮データを展開して RAM へロードするための オプションなのだろう。 圧縮データを展開するオプションとして「fis load」コマンドには、 すでに「-d」(gzip 圧縮データを展開) があるにもかかわらず、 何故わざわざ gzip 以外の圧縮形式を使っているのか謎であるが、 おそらくはより圧縮率の高い圧縮形式を使いたかったのだろう。

gzip より圧縮率が高い圧縮形式で「7」といえば 「7-Zip」、 という (安直な ^^;) 連想をもとに、 とりあえず手元にあった lzma コマンドで展開を試みてみる。

% lzma d vmlinux.bin.l7 vmlinux.bin

LZMA 4.43 Copyright (c) 1999-2006 Igor Pavlov  2006-06-04

ありゃ、あっさり展開できてしまった。 ちょっと拍子抜け。

展開した vmlinux.bin を TFTP サーバに置いて、 La Fonera に読み込ませて起動してみる:

RedBoot> load -r -b 0x80041000 vmlinux.bin
Using default protocol (TFTP)
Raw file loaded 0x80041000-0x8029aa37, assumed entry at 0x80041000
RedBoot> exec
Now booting linux kernel:
 Base address 0x80030000 Entry 0x80041000
 Cmdline :
(以下略)

これで、TFTP サーバに置いた任意のカーネルを La Fonera で起動することが できるようになった。 フラッシュメモリに書込む必要がないので手軽にカーネルの入れ替えができる。

ちなみに、 「vmlinux.bin」は RAM 上にコピーして即実行 (RedBoot の exec コマンド) 可能であることから、 raw binary 形式 (つまりオブジェクトファイルから、 シンボル情報やリロケーション情報を取り除いたもの) であることが分かる。 つまり、「vmlinux.bin」の拡張子「bin」は「raw binary」の意味なのだろう。 vmlinux から raw binary 形式のファイル vmlinux.bin を得るには、 次のように objcopy コマンドを実行すればよい。

% mips-linux-uclibc-objcopy -O binary vmlinux vmlinux.bin
Filed under: La Fonera — hiroaki_sengoku @ 06:49
2007年1月15日

La Fonera (FON ソーシャルルータ) で VPN-Warp を使う hatena_b

La Fonera (FON ソーシャルルータ) って知っていますか?

FONは世界最大のWiFiコミュニティです。 誰もが「世界中どこからでもインターネットに無料で接続したい!」という 望みを持っているはずです。 そのようなメンバーが助け合ってWiFiを広めて行こう!ということを コンセプトに私たちは活動しています。 元々簡単なアイディアで始まったFONコミュニティ。 メンバーが作るWiFiインフラを用いて、 WiFiを世界中のどこからでも楽しめるようにしましょう!。
参加は簡単!FON取り扱い店でLa Foneraを購入して接続してスタートするだけ!

La Fonera は、FON のアクセスポイントであると同時に、 普通の (プライベートな) 無線LAN アクセスポイントとしても利用できます。 自宅などで無線LAN アクセスポイントを設置している人は多いと思いますが、 おそらくそのまま La Fonera で置き換えることが可能でしょう。

実際、私はそれまで使ってた 無線LAN ルータ WN-G54/R2 を La Fonera で置き換えてしまいました。 La Fonera が提供する二つのアクセスポイントのうち、 プライベート側を使えば、 自宅LAN に普通にアクセスできて、 いままで使っていた無線LAN ルータに比べて全く遜色ありません。 もちろん WPA2 (Wi-Fi Protected Access 2) 暗号化方式が使えます。

より正確に言うと、 La Fonera のプライベート側アクセスポイント (MyPlace) は、 自宅LAN とは異なるセグメントになります。 有線LAN と無線LAN 相互で自由に通信するためには、 多少の設定変更 (/etc/firewall.user に 2行ほど追加) が必要になります。

私の場合 WPA に対応していない古い無線LAN 端末 (Windows98マシン^^;) も 持っていて、 自宅の無線LAN を WEP から WPA2 に変更した (自宅LAN といえど、WEP を使うのはちょっと抵抗がありますよね?) 時点で、 お蔵入りにしていました。 La Fonera が提供するもう一つのアクセスポイント (パブリック側) を使えば、 直接自宅LAN へはアクセスできないもののインターネットへは接続できるし、 インターネット経由で自宅LAN に戻ってくる (もちろんインターネットからアクセス可能な部分に限定されますが) ことも可能なので、 La Fonera の導入によって古い無線LAN 端末も再び利用できるようになった、 というオマケがつきました。

さて、 この La Fonera で VPN-Warp が利用可能になったらどうなるでしょうか? 無線LAN ルータが VPN ゲートウェイの機能も持つわけです。 つまりインターネットに接続できる環境ならどこからでも、 自宅LAN へ手軽にアクセスできるようになります。

ここで La Fonera は固定 IP アドレスを持つ必要がないばかりか、 そもそもグローバルアドレスを持つ必要性すらない、 という点がミソです。 必要なことは、La Fonera からインターネットへ接続可能、ということだけです。 La Fonera をどこに設置しようと、 その設置した LAN に外部からアクセスすることができます。

以下は、La Fonera で VPN-Warp を使うようにするための手順です。 現状は多少の Linux の知識が必要となってしまうのですが、 要は relayagent プログラムを La Fonera にインストールするだけのことなので、 適切なインストーラさえ作ればいくらでも簡単な手順になることでしょう。 なので、難しそうだとあきらめるのではなく、 関心がある方はご連絡頂ければと思います。

まず La Fonera に ssh あるいはシリアルコンソールで ログインすることが必要となります。 おそらくこれが最大の難関でしょう (^^;)。

senri:/home/sengoku % ssh fonera
root@fonera's password:


BusyBox v1.1.3 (2006.11.21-19:49+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

 _______  _______  _______
|   ____||       ||   _   |
|   ____||   -   ||  | |  |
|   |    |_______||__| |__|
|___|

 Fonera Firmware (Version 0.7.1 rev 2) -------------
  *
  * Based on OpenWrt - http://openwrt.org
  * Powered by FON - http://www.fon.com
 ---------------------------------------------------
root@OpenWrt:~#

ログインさえ可能なら、あとはさほど難しくはありません。 まずネットワーク経由で La Fonera に relayagent を インストールするための準備をします。 具体的には、 以下のように /etc/ipkg.conf に「src gcd http://www.gcd.org/fonera」 を追加し、 「ipkg update」 を実行します。

root@OpenWrt:~# echo "src gcd http://www.gcd.org/fonera" >> /etc/ipkg.conf
root@OpenWrt:~# ipkg update
Downloading http://download.fon.com/release/fonera/0.7/packages/Packages
Updated list of available packages in /usr/lib/ipkg/lists/fon
Downloading http://www.gcd.org/fonera/Packages
Updated list of available packages in /usr/lib/ipkg/lists/gcd
Done.
root@OpenWrt:~#

http://www.gcd.org/fonera というのは、 私が最近始めた La Fonera 用の ipkg feed です。 つまり、上記のような設定をしておくと、 La Fonera にいろいろなソフトウェアを ネットワーク経由でインストールすることができるようになります。 もちろん ;-) VPN-Warp の relayagent も、 ここからインストールできます。 インストールに必要なコマンドは、 「ipkg install relayagent」だけです。 このコマンドを打ち込むだけで、 relayagent の実行に必要な OpenSSL ライブラリ等が 自動的にインストールされます。

root@OpenWrt:~# ipkg install relayagent
Installing relayagent (1.0.7) to root...
Downloading http://www.gcd.org/fonera/relayagent_1.0.7_mips.ipk
Installing libopenssl (0.9.8d-1) to root...
Downloading http://www.gcd.org/fonera/libopenssl_0.9.8d-1_mips.ipk
Installing zlib (1.2.3-3) to root...
Downloading http://www.gcd.org/fonera/zlib_1.2.3-3_mips.ipk
Configuring libopenssl
Configuring relayagent
Configuring zlib
Done.
root@OpenWrt:~#

次に、VPN-Warp の証明書をインストールします。 BIGLOBE の VPN ワープのページ などから入手した証明書とそのパスワードを記したファイルを、 La Fonera の /etc/warp ディレクトリへコピーしてください。 以下の実行例では relay,5000005.pfx が証明書のファイル、 relay,5000005-pass.txt がパスワードを記したファイルです。 5000005 というのは私が使用している証明書の番号なので、 実際に取得した証明書の番号で読み替えてください。

senri:/home/sengoku % echo "パスワード" > relay,5000005-pass.txt
senri:/home/sengoku % scp -p relay,5000005.pfx relay,5000005-pass.txt fonera:/etc/warp/
root@fonera's password:
relay,5000005.pfx                             100% 4856     4.7KB/s   00:00
relay,5000005-pass.txt                        100%    9     0.0KB/s   00:00

次が最後の難関で、 VPN-Warp の設定ファイルを作成します。 /etc/warp/relayagent.cfg.sample に設定ファイルのサンプルがあるので、 これを /etc/warp/relayagent.cfg へコピーして、 vi エディタで編集します。

root@OpenWrt:~# cd /etc/warp/
root@OpenWrt:/etc/warp# ls -l
-rw-------    1 root     root            9 Jan  9 04:09 relay,5000005-pass.txt
-rw-------    1 root     root         4856 Jan  9 04:09 relay,5000005.pfx
-rw-r--r--    1 root     root         3290 Jan  9 07:47 relayagent.cfg.sample
root@OpenWrt:/etc/warp# cp relayagent.cfg.sample relayagent.cfg
root@OpenWrt:/etc/warp# vi relayagent.cfg

設定ファイル relayagent.cfg の中に、以下のような部分があるので、
「relay,0000000」の数字の部分を実際に取得した証明書
(私の場合は「relay,5000005」) の番号で置き換えます。

#--------------------------------------------------------------------
#
# -x  PFX 形式 クライアント証明書を指定
# -X  同パスワードファイルを指定
#
#--------------------------------------------------------------------

-x "/etc/warp/relay,0000000.pfx"
-X "/etc/warp/relay,0000000-pass.txt"

以上で設定ファイルの作成が完了しました。 あとは La Fonera を再起動する (裏面のリセットスイッチを押す) だけです。 再起動する代わりに、起動スクリプトを実行することによって relayagent を起動することもできます。

root@OpenWrt:~# /etc/init.d/N50relayagent start
root@OpenWrt:~#

では、ブラウザで https://warp.klab.org へアクセスしてみましょう。 La Fonera にインストールした証明書と同じ証明書、あるいは その子証明書を使ってアクセスしてください。 La Fonera の Web 設定ページが表示されたら成功です。

Web 設定ページが表示されるのは、 先ほど作成した設定ファイル /etc/warp/relayagent.cfg に、

#--------------------------------------------------------------------
#
# <relay サーバ名:ポート番号>  <転送先ホスト名:ポート番号>
#
# ※-p オプション指定時は下記の意味となる
#
# <プロキシサーバ名:ポート番号> <転送先ホスト名:ポート番号>
#
#--------------------------------------------------------------------

warp.klab.org:443 localhost:80

と書いてあるからです。 「localhost:80」だから La Fonera 内蔵の WWW サーバ (つまり設定ページ) ですね。 「localhost:80」の部分を、 自宅LAN 内の適当なサーバの「アドレス:ポート」で置き換えれば、 そのサーバにアクセスできますし、 通常の VPN-Warp と全く同様に、 任意のサーバに接続するように設定することもできます。

Filed under: La Fonera,システム構築・運用 — hiroaki_sengoku @ 07:02
2007年1月9日

La Fonera 用の ipkg feed を始めました hatena_b

ネットワーク経由で La Fonera にパッケージをインストール

La Fonera (FON ソーシャル ルータ) のベースとなっている OpenWrt は、 パッケージ管理システムとして ipkg を利用している。 La Fonera 用の ipkg feed を 作ってみた。 この feed を使うには、 以下のように /etc/ipkg.conf に 「src gcd http://www.gcd.org/fonera」 を追加し、 「ipkg update」 を実行する。

root@OpenWrt:/# echo "src gcd http://www.gcd.org/fonera" >> /etc/ipkg.conf
root@OpenWrt:/# ipkg update
Downloading http://www.gcd.org/fonera/Packages
Updated list of available packages in /usr/lib/ipkg/lists/gcd
Done.

すると、feed のリスト (パッケージ名の一覧) が /usr/lib/ipkg/lists/gcd に保存される。 あとは、「ipkg install パッケージ名」などと実行するだけで、 パッケージをネットワーク経由で La Fonera にインストールできる。

例えば stone をインストールするには、 次のように「ipkg install stone」と実行するだけでよい。

root@OpenWrt:~# ipkg install stone
Installing stone (2.3c-2.2.4.12) to root...
Downloading http://www.gcd.org/fonera/stone_2.3c-2.2.4.12_mips.ipk
Installing libopenssl (0.9.8d-1) to root...
Downloading http://www.gcd.org/fonera/libopenssl_0.9.8d-1_mips.ipk
Installing zlib (1.2.3-3) to root...
Downloading http://www.gcd.org/fonera/zlib_1.2.3-3_mips.ipk
Installing libpthread (0.9.28-8) to root...
Downloading http://www.gcd.org/fonera/libpthread_0.9.28-8_mips.ipk
Configuring libopenssl
Configuring libpthread
Configuring stone
Configuring zlib
Done.

stone の実行に必要な、libopenssl, zlib, libpthread パッケージの インストールも自動的に行なわれている。 このようにパッケージの依存関係も管理してくれるので便利なのであるが、 残念ながら現行の La Fonera 上の ipkg にはバグがある。 インストールしたパッケージをアンインストールしようとして、

ipkg remove stone

などと実行してはいけない。 /usr/bin/stone だけでなく、 /usr/bin ディレクトリまでもが削除されてしまう。 なぜこんなバグがあるかというと、 mini_fo の rmdir の実装にバグがあるからだ。 すなわち、空でないディレクトリに対して rmdir を行なっても、 ディレクトリが削除されてしまうことがある。 試しに、あまり重要そうでないディレクトリに対して rmdir してみる:

root@OpenWrt:/www/images# ls -a table
.                 bottom-right.gif  logo.gif          top-left.gif
..                bottom.gif        right.gif         top-right.gif
bottom-left.gif   left.gif          sidebar.gif       top.gif
root@OpenWrt:/www/images# rmdir table
root@OpenWrt:/www/images# ls table
ls: table: No such file or directory

La Fonera のファイルシステムは mini_fo (mini fan-out) を使っている。 つまり squashfs を read only でマウントした「上」に、 jffs を重ねてマウントしている。 前述の例で言えば、 /www/images/table ディレクトリは squashfs 上にあり、 jffs 上には /www/images/table ディレクトリは存在しない。 「rmdir table」などファイルシステムに対する変更は、 「上」に重ねられた jffs に対して行なわれるが、 ディレクトリが空か否かの判断まで、 「上」のファイルシステムに対してのみ行なっているのだろう、 jffs 上では /www/images/table ディレクトリの中にはファイルが存在しない (ディレクトリが存在しないので当然だが) ため、 rmdir がエラーにならずにディレクトリの削除が行なわれてしまう。

La Fonera の ipkg (busybox に含まれている) のソース ipkg_remove.c を 確認してみると、

    for (iter = installed_dirs.head; iter; iter = iter->next) {
            file_name = iter->data;
 
            if (rmdir(file_name) == 0) {
                 ipkg_message(conf, IPKG_INFO, "  deleting %s\n", file_name);
                 removed_a_dir = 1;
                 str_list_remove(&installed_dirs, &iter);
            }
    }

などとなっている。 つまりディレクトリが空かどうかは判断せず、 いきなり rmdir してみて成功すればヨシとしている。 このため、「ipkg remove パッケージ名」を実行すると、 空でないディレクトリまで削除してしまうのだろう。

空でないディレクトリに対して rmdir を実行したら ENOTEMPTY を返すのがスジであるので、 mini_fo 側を修正すべきだとは思うのだが、 とりあえず sh スクリプト版の ipkg を拾ってきて、 rmdir するまえに中身の確認をするように変更し、 /usr/bin/ipkg を この修正済み sh スクリプトで置き換えてみた。

root@OpenWrt:~# wget http://www.gcd.org/fonera/ipkg-0.9-1.32.sh
Connecting to www.gcd.org[60.32.85.216]:80
ipkg-0.9-1.32.sh     100% |*****************************| 27925       00:00 ETA
root@OpenWrt:~# chmod 755 ipkg-0.9-1.32.sh
root@OpenWrt:~# mv ipkg-0.9-1.32.sh /usr/bin/ipkg

などと置き換えるとよいだろう。 これで安全にパッケージをアンインストールできるようになる。

root@OpenWrt:~# ipkg remove stone
ipkg_remove: Removing stone...
ipkg_remove: Warning: Not removing the following directories since they are not
empty:
 /usr /usr/bin
Done.

/usr および /usr/bin ディレクトリが空でなかったので削除できなかった旨が、 表示されている。

La Fonera の自動アップデートのまとめ

La Fonera の自動アップデートは、 cron から呼び出される /bin/thinclient プログラムによって行なわれている。 このアップデートは ipkg とは独立した形で行なわれているので、 ipkg でパッケージのインストールを行なう場合は、 この自動アップデートで何が行なわれているか把握しておく必要がある。 確認できたアップデートについてまとめてみた。

0.7.0 rev 2 -> 0.7.0 rev 3 (upgrade.fon)
修正: /usr/lib/webif/validate.awk
0.7.0 rev 3 -> 0.7.0 rev 4 (upgrade.fon)
[WiFi] 暗号方式のデフォルトを WPA+TKIP に変更
修正: /etc/init.d/rcS /sbin/ifup /www/cgi-bin/webif/*.sh
変更: /lib/modules/2.4.32/wlan.o /lib/modules/2.4.32/ath_ahb.o
追加: /etc/hotplug.d/iface/10-ppp_hack
0.7.0 rev 4 -> 0.7.1 rev 1 (upgrade.fon) 2006-11-21 0.7.1 rev 1
[Web interface] 多言語サポート
[Web interface] ポートフォワード機能
[NTP] ntpclient による時刻同期
修正: /bin/thinclient /etc/functions.sh /usr/lib/webif/*
変更: /usr/bin/webif-page
追加: /etc/config/ntpservers /etc/config/openports /etc/config/webif /etc/init.d/N45ntpclient /usr/lib/webif/lang /usr/sbin/adjtimex /usr/sbin/ntpclient /www/cgi-bin/webif/adv_pf.sh /www/cgi-bin/webif/language.sh
0.7.1 rev 1 -> 0.7.1 rev 2 (upgrade.fon) 2007-01-04 01:00 JST
[Web interface] 任意のコマンドを実行させられてしまう脆弱性を修正
[NTP] crontab に複数の ntpclient 呼び出しが登録されてしまうバグを修正
修正: /etc/init.d/N45ntpclient /usr/lib/webif/validate.awk /www/cgi-bin/webif/*.sh
変更: /usr/bin/haserl

特に重要なのが、0.7.1 rev 2 で行なわれた、 Web インタフェースにおける脆弱性の修正だろう。 POST した入力データのチェックが厳密になった。 La Fonera に ssh でログインする最も手軽な方法が、 この脆弱性を利用する方法だっただけに、 0.7.1 rev 2 にアップデートする際は注意が必要である。

Filed under: La Fonera — hiroaki_sengoku @ 06:51
2007年1月4日

La Fonera 上で stone を走らせてみる hatena_b

La Fonera (FON ソーシャル ルータ) のファーム ウェアのソース コードは、 Fon blog に書かれているように、 http://download.fon.com/firmware/fonera/latest/fonera.tar.bz2 から取得できる。 これを展開して make を実行すると、 「OpenWrt Configuration」ダイアログが表示される。 現行の La Fonera のファーム ウェアと同じものをビルドするだけなら Configuration の変更は不要。そのまま save して exit すればビルドが行なわれる。

stone を make するには、 libpthread と libopenssl が必要なので、 以下のように設定する。
まず、

     Base system  --->

を選択して、以下のように libpthread を make するように指定する:

<*> libpthread.......................................... POSIX threa

続いて、

    Libraries  --->

を選択して、以下のように libopenssl も make するように指定しておく:

<M> libopenssl..................................... Open source SSL
< >   openssl-util.............................. OpenSSL command lin
<M> zlib................. Library implementing the deflate compressi

「Do you wish to save your new OpenWrt configuration?」 と聞かれるので「Yes」と答える。 するとクロスコンパイル環境とファームウェアのビルドがどんどん進む。

*** End of OpenWrt configuration.
*** Execute 'make' to build the OpenWrt or try 'make help'.

make[2] toolchain/install
make[3] -C toolchain install
make[4] -C toolchain/sed prepare
make[4] -C toolchain/sed compile
make[4] -C toolchain/sed install
make[4] -C toolchain/kernel-headers prepare
make[4] -C toolchain/kernel-headers compile
make[4] -C toolchain/kernel-headers install
make[4] -C toolchain/sstrip prepare
make[4] -C toolchain/sstrip compile
make[4] -C toolchain/sstrip install
make[4] -C toolchain/uClibc prepare
make[4] -C toolchain/binutils prepare
make[4] -C toolchain/binutils compile
make[4] -C toolchain/binutils install
make[4] -C toolchain/gcc prepare
make[4] -C toolchain/gcc compile
make[4] -C toolchain/uClibc compile
make[4] -C toolchain/uClibc install
make[4] -C toolchain/gcc install
make[4] -C toolchain/ipkg-utils prepare
make[4] -C toolchain/ipkg-utils compile
make[4] -C toolchain/ipkg-utils install
make[4] -C toolchain/libnotimpl prepare
make[4] -C toolchain/libnotimpl compile
make[4] -C toolchain/libnotimpl install
make[4] -C toolchain/lzma prepare
make[4] -C toolchain/lzma compile
make[4] -C toolchain/lzma install
make[4] -C toolchain/squashfs prepare
make[4] -C toolchain/squashfs compile
make[4] -C toolchain/squashfs install
make[4] -C toolchain/jffs2 prepare
make[4] -C toolchain/jffs2 compile
make[4] -C toolchain/jffs2 install

「install」と表示されているが、 これは「./staging_dir_mips」ディレクトリへのインストール。 「./staging_dir_mips」にクロスコンパイル環境がインストールされた後に、 これを使ってカーネルやライブラリ等のコンパイルが進む。

make[2] target/compile
make[3] -C target compile
make[4] -C target/utils prepare
make[4] -C target/utils compile
make[4] -C target/utils install
make[4] -C target/linux prepare
make[5] -C target/linux/ar531x-2.4 prepare
make[4] -C target/linux compile
make[5] -C target/linux/ar531x-2.4 compile
make[6] -C target/linux/ar531x-2.4 modules
make[6] -C target/linux/ar531x-2.4 packages
make[4] -C target/image/ar531x compile
make[2] package/compile
make[3] -C package compile
make[4] -C package compile-targets
make[5] -C package/base-files compile
make[5] -C package/bridge compile
make[5] -C package/busybox compile
make[5] -C package/chillispot compile
make[5] -C package/dnsmasq compile
make[5] -C package/dropbear compile
make[5] -C package/foncheckrsa compile
make[5] -C package/haserl compile
make[5] -C package/madwifi compile
make[5] -C package/hostapd compile
make[5] -C package/iptables compile
make[5] -C package/mini_fo compile
make[5] -C package/mtd compile
make[5] -C package/libpcap compile
make[5] -C package/linux-atm compile
make[5] -C package/ppp compile
make[5] -C package/pptp compile
make[5] -C package/iproute2 compile
make[5] -C package/qos compile
make[5] -C package/webif compile
make[5] -C package/wireless-tools compile
make[5] -C package/zlib compile
make[5] -C package/openssl compile

「OpenWrt Configuration」ダイアログで指定しなかった パッケージまで表示されるが、 これは単に make がそのパッケージのディレクトリの Makefile を実行しただけで、 コンパイルなどは何も行なわずに抜けている。

make[2] package/install
make[3] -C package install
make[4] -C package install-targets
make[5] -C package/base-files install
make[5] -C package/bridge install
make[5] -C package/busybox install
make[5] -C package/chillispot install
make[5] -C package/dnsmasq install
make[5] -C package/dropbear install
make[5] -C package/foncheckrsa install
make[5] -C package/haserl install
make[5] -C package/hostapd install
make[5] -C package/iptables install
make[5] -C package/madwifi install
make[5] -C package/mini_fo install
make[5] -C package/mtd install
make[5] -C package/ppp install
make[5] -C package/pptp install
make[5] -C package/qos install
make[5] -C package/iproute2 install
make[5] -C package/webif install
make[5] -C package/wireless-tools install
make[2] target/install
make[3] -C target install
make[4] -C target/image/ar531x clean
make[5] -C target/image/generic/lzma-loader clean
make[4] -C target/utils prepare
make[4] -C target/utils compile
make[4] -C target/utils install
make[4] -C target/linux prepare
make[5] -C target/linux/ar531x-2.4 prepare
make[4] -C target/linux compile
make[5] -C target/linux/ar531x-2.4 compile
make[4] -C target/linux install
make[5] -C target/linux/ar531x-2.4 install
make[4] -C target/image/ar531x compile
make[4] -C target/image/ar531x install
make[5] -C target/image/generic/lzma-loader clean compile

以上で、クロスコンパイル環境とファームウェアのビルドが全て完了。 所要時間は 30分ほど (私の Celeron D 345 マシンの場合)。

ビルドしたクロスコンパイル環境は、 「staging_dir_mips/bin」に PATH を通すだけで使用できる。

stone を make してみる。 まずは CVS レポジトリから最新版を checkout する:

senri % cvs -d:pserver:anonymous@cvs.sourceforge.jp:/cvsroot/stone login
Logging in to :pserver:anonymous@cvs.sourceforge.jp:2401/cvsroot/stone
CVS password:
senri % cvs -z3 -d:pserver:anonymous@cvs.sourceforge.jp:/cvsroot/stone co stone
cvs checkout: Updating stone
U stone/GPL.txt
U stone/Makefile
U stone/README.en.txt
U stone/README.txt
U stone/cryptoapi.c
U stone/dist
U stone/global.h
U stone/logmsg.mc
U stone/md5.h
U stone/md5c.c
U stone/stone.1
U stone/stone.1.ja
U stone/stone.c
U stone/stone.cnf
U stone/stone.sh
U stone/stone.spec

次に make する:

senri % cd stone
senri % make fon-ssl
make CC="mips-linux-uclibc-gcc" SSL_LIBS="-lssl -lcrypto" TARGET=fon ssl_stone
make[1]: Entering directory `stone'
make FLAGS="-DUSE_POP -DUSE_SSL " LIBS=" -lssl -lcrypto" fon
make[2]: Entering directory `stone'
make CC="mips-linux-uclibc-gcc" FLAGS="-Wall -DPTHREAD -DUNIX_DAEMON -DPRCTL -DUSE_POP -DUSE_SSL " LIBS="-lpthread -lssl -lcrypto" stone
make[3]: Entering directory `stone'
mips-linux-uclibc-gcc  -Wall -DPTHREAD -DUNIX_DAEMON -DPRCTL -DUSE_POP -DUSE_SSL  -o stone stone.c -lpthread -lssl -lcrypto
make[3]: Leaving directory `stone'
mips-linux-uclibc-strip stone
make[2]: Leaving directory `stone'
make[1]: Leaving directory `stone'

なお、CVS から checkout した最新版でなくても、 例えば stone 2.3c において

senri:/usr/src/stone-2.3c % mips-linux-uclibc-gcc  -Wall -DPTHREAD -DUNIX_DAEMON -DPRCTL -DUSE_POP -DUSE_SSL -o stone stone.c -lpthread -lssl -lcrypto

などとコンパイルすることにより La Fonera 版 stone を make することができる。 つまり特に変更することなく make できるわけで、 いかに La Fonera がフツーの Linux マシンであるかが分かる。

make した stone および、 libpthread, libopenssl を La Fonera へコピーすれば (libopenssl は SSL 版 stone の場合のみ必要)、 La Fonera 上で stone を実行することができる。

root@OpenWrt:~# stone
Jan  4 00:18:08.478674 1024 start (2.3c) [14946]
Jan  4 00:18:08.488958 1024 stone 2.3c  https://www.gcd.org/sengoku/stone/
Jan  4 00:18:08.570372 1024 Copyright(C)2007 by Hiroaki Sengoku <sengoku@gcd.org>
Jan  4 00:18:08.579479 1024 using OpenSSL 0.9.8d 28 Sep 2006  http://www.openssl.org/
Usage: stone <opt>... <stone> [-- <stone>]...
opt:  -h opt            ; help for <opt> more
      -h stone          ; help for <stone>
      -h ssl            ; help for <SSL>, see -q/-z opt
Filed under: La Fonera,stone 開発日記 — hiroaki_sengoku @ 09:32
2006年12月22日

La Fonera を無線LAN 端末として使ってみる hatena_b

La Fonera (FON ソーシャル ルータ) は、 無線LAN アクセス ポイントであるが、 中身は普通の Linux マシンなので、 いろんな用途に使うことができる。 一例として無線LAN 端末として使ってみる。
まずは ssh で La Fonera にログイン:

senri:/home/sengoku % ssh -l root 172.16.254.254
root@172.16.254.254's password: 


BusyBox v1.1.3 (2006.09.11-19:54+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

 _______  _______  _______ 
|   ____||       ||   _   |
|   ____||   -   ||  | |  |
|   |    |_______||__| |__|
|___|

 Fonera Firmware (Version 0.7.1 rev 1) -------------
  * 
  * Based on OpenWrt - http://openwrt.org
  * Powered by FON - http://www.fon.com
 ---------------------------------------------------
root@OpenWrt:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth0
172.16.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

実験に先だってアクセスポイントとしての機能は殺してあるので、 ルーティング テーブルは至ってシンプル。 default route がないので、この時点では当然インターネットへはアクセスできない。

まず wlanconfig コマンドを使って無線LAN デバイスを端末モードで作成し、 続いて接続先アクセスポイント (もう一台の La Fonera ;-) の ESSID および WEP キー (もちろん伏せ字) を設定:

root@OpenWrt:~# wlanconfig ath0 create wlandev wifi0 wlanmode sta
ath0
root@OpenWrt:~# iwconfig ath0 essid "MyPlace"
root@OpenWrt:~# iwconfig ath0 key "6162636465666768696a6b6c6d"
root@OpenWrt:~# ifconfig ath0 up

これだけでアクセスポイントへの接続が完了する。 iwconfig コマンドで確認してみる。

root@OpenWrt:~# iwconfig ath0
ath0      IEEE 802.11g  ESSID:"MyPlace"
          Mode:Managed  Frequency:2.417 GHz  Access Point: 00:18:84:10:XX:XX
          Bit Rate:36 Mb/s   Tx-Power:18 dBm   Sensitivity=0/3
          Retry:off   RTS thr:off   Fragment thr:off
          Encryption key:6162-6364-6566-6768-696a-6b6c-6d   Security mode:restricted
          Power Management:off
          Link Quality=53/98  Signal level=-42 dBm  Noise level=-95 dBm
          Rx invalid nwid:664  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

あとは 「ifconfig ath0 192.168.10.2」 などと手で IP アドレスを設定するか、 あるいは DHCP クライアントを実行すればよい。

root@OpenWrt:~# udhcpc -i ath0
info, udhcpc (v0.9.9-pre) started
debug, Sending discover...
debug, Sending select for 192.168.10.146...
info, Lease of 192.168.10.146 obtained, lease time 43200
deleting routers
adding router 192.168.10.1
adding dns 192.168.10.1
root@OpenWrt:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 ath0
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth0
172.16.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
0.0.0.0         192.168.10.1    0.0.0.0         UG    0      0        0 ath0

設定された default route 192.168.10.1 は NAT ルータなので、 これでインターネットへの接続が完了している。試しにアクセスしてみる:

root@OpenWrt:~# telnet mx.gcd.org 25
220 senri.gcd.org ESMTP
help
214 qmail home page: http://pobox.com/~djb/qmail.html
quit
221 senri.gcd.org
Connection closed by foreign host.
root@OpenWrt:~# wget http://www.klab.org/
Connecting to www.klab.org[211.13.209.203]:80
index.html           100% |*****************************| 11992       00:00 ETA
root@OpenWrt:~# ls -la index.html
-rw-r--r--    1 root     root        11992 Dec 22 05:27 index.html
Filed under: La Fonera — hiroaki_sengoku @ 14:44
2006年12月19日

La Fonera (FON ソーシャル ルータ) hatena_b

La Fonera (FON ソーシャル ルータ) を2台購入した (正確に言うと1台は店頭で購入、もう1台は無料キャンペーンで入手)。

入手方法 店頭で購入 無料キャンペーン
Model FON2100E FON2100E
S/N 8638001XXX 8646022XXX
MACアドレス 00:18:84:10:XX:XX 00:18:84:16:XX:XX
ROMバージョン 0.7.0 r3 0.7.0 r4

店頭で購入した物のほうが古いのは、まあ当たり前か。 新しい方のシリアル番号の下のほうの桁が 2万を超えているので、 現在は万単位で製造しているのだろう。 シリアル番号の上の方の桁、 および ROMバージョンが異なるのは、 製造ロットが違うから? もちろん両ルータともネットにつないでおくことにより、 現時点での最新バージョンである 0.7.1 r1 に自動アップデートした。

自動アップデートは、 cron から呼び出される /bin/thinclient プログラムによって行なわれる (/bin/thinclient は起動時にも呼び出される)。

root@OpenWrt:~# /bin/thinclient cron
upgrade.fon          100% |*****************************| 61473       00:00 ETA
This is a FON hotfix v2 archive
Verified OK
Upgrade name: upgrade_0711
Upgrading...

/bin/thinclient は、まず download.fon.com:1937 へ ssh 接続する。 ポート番号が変則的なのは、 間にファイアウォールがはさまっていないか確認するためか? なお、ssh は /etc/dropbear/key にある秘密鍵を用いて DSA 認証を行なう。 この秘密鍵は両ルータとも同じ内容だった。 /bin/thinclient は、次に この ssh セッションにおいて、 次の文字列を送信する。

mode='cron' wlmac='00:18:84:16:XX:XX' mac='00:18:84:16:XX:XX' fonrev='4' firmware='0.7.0'

ここで、「mode=」は /bin/thinclient の実行方法を示している。 cron から呼び出されたときは「mode='cron'」、 起動時に呼び出されたときは「mode='start'」。 「wlmac=」および「mac=」はそれぞれ、 無線(FON_AP)側の MAC アドレスと、 有線(WAN)側の MAC アドレス。 後者の MAC アドレスに 1 加えた値が前者のアドレスになっているようだ (ちなみにプライベート アクセス ポイント(MyPlace)側の MAC アドレスは、 さらに 1 を加えた値)。 「firmware=」および「fonrev=」はバージョンおよびリビジョン番号を示す。 つまり、個体識別ID を FON に送信しているものと考えられる。

すると、download.fon.com:1937 から、 以下のような sh スクリプトが返ってくる。

cd /tmp
wget http://download.fon.com/firmware/update/0.7.0/4/upgrade.fon
/bin/fonverify /etc/public_fon_rsa_key.der /tmp/upgrade.fon

rm -f /tmp/.thinclient.sh

exit

/bin/thinclient は、 この送られてきた sh スクリプトを /tmp/.thinclient.sh に保存した上で実行する。 つまり、 この例の場合だと、「upgrade.fon」をダウンロードして 「/bin/fonverify」に与える。 おそらく upgrade.fon がアップデートのための差分データで、 「/bin/fonverify」が、このデータを認証した上で展開しているのだろう。

アップデートの必要がないときは、 以下のような何もしない sh スクリプトが返ってくる。


rm -f /tmp/.thinclient.sh

exit

0.7.0 r4 と 0.7.1 r1 の差分をとってみた。
新規に追加されたファイル:

/etc/config/ntpservers
/etc/config/openports
/etc/config/webif
/etc/init.d/N45ntpclient

ntpclient を使って時刻あわせするようになったようだ。 アップデート前するは起動時に「2000年1月1日 9:00 JST」にセットされていた。 これでは起動時からの経過時間しかわからないので、 ntpclient を使うように変更したのだろう。

変更されたファイル:

--- /rom/etc/banner        2006-09-13 02:41:30.000000000 +0900
+++ /jffs/etc/banner        2006-11-22 04:07:20.000000000 +0900
@@ -4,7 +4,7 @@
 |   |    |_______||__| |__|
 |___|
 
- Fonera Firmware (Version 0.7.0 rev 4) -------------
+ Fonera Firmware (Version 0.7.1 rev 1) -------------
   * 
   * Based on OpenWrt - http://openwrt.org
   * Powered by FON - http://www.fon.com

--- /rom/etc/fon_revision        2006-09-12 06:43:42.000000000 +0900
+++ /jffs/etc/fon_revision        2006-11-16 05:08:40.000000000 +0900
@@ -1 +1 @@
-4
+1

--- /rom/etc/fon_version        2006-09-12 04:32:01.000000000 +0900
+++ /jffs/etc/fon_version        2006-11-16 05:08:40.000000000 +0900
@@ -1 +1 @@
-0.7.0
+0.7.1

--- /rom/etc/functions.sh        2006-09-12 04:32:01.000000000 +0900
+++ /jffs/etc/functions.sh        2006-11-15 02:44:26.000000000 +0900
@@ -112,3 +112,18 @@
         esac
 }
 
+#
+# This functions forwards a port. The next args are required:
+# $1 = WAN interface
+# $2 = Origin Port
+# $3 = Destination IP
+# $4 = Destination Port
+# $5 = protocol used
+#
+# Example: open_port $WAN 8080 192.168.1.2 80 tcp
+#
+open_port() {
+        iptables -t nat -A prerouting_rule -i $1 -p $5 --dport $2 -j DNAT --to-destination $3:$4
+        pdots=`echo $4 | sed 's/-/:/g'`
+        iptables        -A forwarding_rule -i $1 -p $5 --dport $pdots -d $3 -j ACCEPT
+}

--- /rom/etc/hotfix        2006-09-12 04:32:01.000000000 +0900
+++ /jffs/etc/hotfix        2000-01-01 09:35:00.000000000 +0900
@@ -0,0 +1 @@
+upgrade_0711

--- /rom/etc/init.d/S45firewall        2006-09-12 04:56:53.000000000 +0900
+++ /jffs/etc/init.d/S45firewall        2006-11-17 22:12:29.000000000 +0900
@@ -105,3 +105,7 @@
 }
 # check if the connection is already up and add WAN_HOOK rules automatically
 env -i ACTION=ifup INTERFACE=wan /bin/sh /etc/hotplug.d/iface/20-firewall
+#
+# Forwarded ports
+#
+/etc/config/openports $WAN

--- /rom/etc/sysctl.conf        2006-09-12 04:32:01.000000000 +0900
+++ /jffs/etc/sysctl.conf        2006-11-08 03:04:39.000000000 +0900
@@ -6,3 +6,4 @@
 net.ipv4.tcp_keepalive_time=120
 net.ipv4.tcp_timestamps=0
 net.ipv4.tcp_vegas_cong_avoid=1
+net.ipv4.ip_local_port_range=4096 8192

このあたりはわずかな修正だが...

--- /rom/etc/init.d/rcS        2006-09-12 22:16:13.000000000 +0900
+++ /jffs/etc/init.d/rcS        2006-11-15 02:44:26.000000000 +0900
@@ -21,13 +21,24 @@
         done
         
         while :; do
+                lock -w /var/run/restart-services
+                
+                # just in case
+                lock -u /var/run/network-connection 
+                killall lock
+                
+                # grab the locks again
                 lock /var/run/restart-services
+                lock /var/run/network-connection
+
                 killall N50chillispot
                 killall chilli
                 killall dnsmasq
                 ifup lan_noinet
                 ifup wan
                 /etc/init.d/S45firewall
+                
+                lock -w /var/run/network-connection
                 for i in /etc/init.d/N*; do
                   $i start 2>&1
                 done

これは、起動時に問題が起きることがあることへの対策か?

そして、0.7.1 へのアップデートで一番の目玉が、 /usr/lib/webif 以下の変更、 すなわち設定 Web インターフェースの多言語対応なのだろう。 /usr/lib/webif/lang ディレクトリが追加され、 /usr/lib/webif/lang/jp/fon.txt などのファイルに、 ローカライズのための文字列置換表が追加された。 /etc/config/webif に現在選択している言語が設定される。

日本語で設定できるようになったのはいいことだと思うが、 0.7.1 r1 にアップデートしてから、 FON Maps で濃いグリーンで表示されなくなったような気がする... アップデート前は FON_AP 登録位置に濃いグリーンの円が表示されていたのだが、 アップデート直後から薄いグリーン(直近で非アクティブ)の円で 表示されるようになってしまった。 前述したようにバージョン番号は thinclient で FON へ送信されるが、 0.7.1 r1 だと電波を出しているとは認識してもらえなくなってしまったのか? (thinclient の実行頻度を高めてみても、淡い緑のまま...)

もう一点、気づいた不具合として、 設定 Web インタフェースにて WAN 以外の設定を行なわずに何らかの設定を行なうと、 WAN が使えなくなってしまう、という問題がある。 すなわち、/etc/config/fon において

config network wan
        option mode        ''

などとなってしまう。 これだと WAN (つまり有線インタフェース) に IP アドレスが設定されない。 つまり有線もパブリック アクセス ポイント「FON_AP」も使えなくなってしまう。 エイリアス「eth0:1」には常に 169.254.255.1 が設定されるので、 大事には至らないのだが...

eth0:1    Link encap:Ethernet  HWaddr 00:18:84:16:XX:XX
          inet addr:169.254.255.1  Bcast:169.254.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1500  Metric:1
          Interrupt:4 Base address:0x1000

このような状態になってしまったときは、 この 169.254.255.1 へアクセスするか、 プライベート アクセス ポイント「MyPlace」へアクセスして、 設定 Web インタフェースにて WAN の設定を行なえばよい。 例えば「DHCP」を設定すると、 /etc/config/fon の該当箇所が

config network wan
        option mode        'dhcp'
        option ipaddr        ''

となるので、「/sbin/ifup wan」を実行するか、 あるいは再起動すれば DHCP で取得した IP アドレスが WAN に設定される。

Filed under: La Fonera — hiroaki_sengoku @ 14:15