ほぼ雑記的メモ
いろいろと案件がありまして、LinuxやらほげほげやらいろんなものでBLEを使って調べ物をしていたのですが、これがなかなか期待通り動いてくれないんですよねぇ・・・いつものようにソースやらBluetooth4.0の仕様書(2000頁以上ある)などをいろいろ読み始めたのですが linuxの bleno -> Bluezという流れが複雑で実験環境すらままならないので使い慣れたFreeBSDで動かんものかとtwitterでつぶやいてみました。すると・・・
@issei10193 ん呼んだ? CURRENTに一応突っ込んであるよ。— Takanori Watanabe (@takawata19) 2015, 9月 7
@issei10193 ん呼んだ? CURRENTに一応突っ込んであるよ。
以外と近いところに解はあるんだなー。まさかフォロワーさんがCURRENTにコミットしてたとわ。 ということで手持ちのPCに最新のCURRENTをいれてセコセコ調査を始めた次第。
ちなみにドングルはこれ アイ・オー・データ機器 I-O DATA USB-BT40LE [Bluetooth4.0+EDR/LE準拠 USBアダプター]
ぱっと調べたところBroadcomの BCM20702を使ってるドングルはアイオーのこれしかないようなので無難に。あきばお~とかで安売りしているやつは地雷の可能性が大そうなのでやめました。
これをBSDに差してみるとこういうメッセージが出ます
Sep 10 10:45:01 kernel: WARNING: attempt to domain_add(netgraph) after domainfinalize() Sep 10 10:45:06 kernel: ugen0.3: <Broadcom Corp> at usbus0 Sep 10 10:45:06 kernel: ubt0: <Broadcom Corp BCM20702A0, rev 2.00/1.12, addr 3> on usbus0 Sep 10 10:45:06 kernel: WARNING: attempt to domain_add(bluetooth) after domainfinalize()
何やらwarningは出ますがとりあえず使えそう…… ngctl listで見ると
# ngctl list There are 8 total nodes: Name: ubt0 Type: ubt ID: 00000002 Num hooks: 1 Name: btsock_hci_raw Type: btsock_hci_raw ID: 00000003 Num hooks: 1 Name: btsock_l2c_raw Type: btsock_l2c_raw ID: 00000004 Num hooks: 1 Name: btsock_l2c Type: btsock_l2c ID: 00000005 Num hooks: 1 Name: btsock_sco Type: btsock_sco ID: 00000006 Num hooks: 0 Name: ubt0hci Type: hci ID: 00000008 Num hooks: 3 Name: ubt0l2cap Type: l2cap ID: 0000000c Num hooks: 3 Name: ngctl714 Type: socket ID: 00000012 Num hooks: 0
hccontrolでスキャンをしてみます。BLE対応の接続先が必要ですが、iOSでlightBlueをつかって立てました
# hccontrol le_enable enable # hccontrol le_set_scan_param passive 10 10 public all # hccontrol le_set_scan_enable enable
結果は近傍キャッシュから読めました
# hccontrol read_neighbor_cache BD_ADDR Features Clock offset Page scan Rep. scan XX:XX:XX:XX:XX:XX 00 00 00 00 00 00 00 00 0 0 0
今回はここまで
標準のオプションでコンパイルしていないportsを利用しているときとか自分専用のpkgサイトがあると便利ですよね。例えば弊社ではDOVECOT2のオプションをONにしてpostfixをビルドしています。その作り方をかなり前に社内の掲示板に書いたのですが、それをブログに転載します。
普通にportsからpostfixをコンパイル、インストールする。
pkgコマンドでpackageにする。
pkg -vv で ABIを確認しておくとVersion毎にディレクトリをわけなくてよいので楽。
とりあえず
/usr/ports/packages/FreeBSD:10:amd64
をパッケージの保存先とする。dovecot2,cyrus-sasl,pcreも依存しているのでいれておく
# pkg create -o /usr/ports/packages/FreeBSD:10:amd64 postfix
レポジトリを作る
# pkg repo /usr/ports/packages/FreeBSD:10:amd64/
ローカルファイルから持ってくるだけならこれで完成である
/usr/local/etc/pkg/repos/test.conf
というファイルに
test: { url: file:/usr/ports/packages/${ABI} enable: yes priority: 1 }
と書いておけばよい。pkg -vvで確認できる。その後
# pkg install -r test postfix
でインストールできることを確認できる。
# pkg install -rtest postfix Updating test repository catalogue... test repository is up-to-date. All repositories are up-to-date. The following 2 packages will be affected (of 0 checked): New packages to be INSTALLED: postfix: 2.11.3_3,1 [test] dovecot2: 2.2.15_2 [test] The process will require 27 MB more space. 5 MB to be downloaded. Proceed with this action? [y/N]:
man pkg.confによると URLは
http://, https://, ftp://, file://, ssh://
が使えるようである。SSHは
ssh: { url: ssh://user@ssh.example.com/usr/ports/packages/${ABI} enable: yes priority: 1 }
と書いておけばよい。httpもftpも同様。
ftp: { url: ftp://ftp.example.com/pub/packages/${ABI} enable: yes priority: 1 }
当然 sshや ftpのサーバをセットアップしておかないといけない
デフォルトの設定 /etc/pkg/FreeBSD.conf を覗くと、
/etc/pkg/FreeBSD.conf
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
と書いてある。これはDNSのSRVレコードを使って効率よく ミラー等を利用するための記法である。drillや digコマンドを使って
# drill _http._tcp.pkg.freebsd.org. srv
と調べてみるとよいであろう。
ここまでの手順で作成したものには署名がない。個人的に使う分にはこれでよいだろうが、 一般公開をするためには署名があったほうがよいであろう。 (もちろん署名があるだけでは不十分で通信そのものがSSLなどで保護されているべきである) 署名の方法は公開鍵とフィンガープリントの二種類用意されている。
opensslで公開鍵のペアを作り公開鍵を提示する手法。
% man pkg-repo
に詳しく書いてある。まず鍵を作成する
% openssl genrsa -out repo.key 2048 % chmod 0400 repo.key % openssl rsa -in repo.key -out repo.pub -pubout
repo.keyが秘密鍵で、repo.pubが公開鍵である。公開鍵はなんらか方法でクライアント(pkgを利用するサイト)に送っておく
次にその秘密鍵で署名をしてレポジトリを作成する
# pkg repo /usr/ports/packages/FreeBSD:10:amd64/ repo.key
クライアント側では設定ファイルに公開鍵のパスを指定する
test: { url: http://www.example.com/pub/packages/${ABI} enable: yes priority: 1 signature_type: pubkey pubkey: /usr/local/etc/pkg/repos/repo.pub }
man pkg-repoを参考に署名をするためのscriptを作成する。 sign.shとでもして作成をしておく
man pkg-repo
#!/bin/sh read -t 2 sum [ -z "$sum" ] && exit 1 echo SIGNATURE echo -n $sum | /usr/bin/openssl dgst -sign repo.key -sha256 -binary echo echo CERT cat repo.pub echo END
その後
# pkg repo /usr/ports/packages/FreeBSD:10:amd64/ signing_command: ./sign.sh
を実行する。
インストールする側に署名ファイルを置いておく必要がある。ここでは
/usr/local/etc/pkg/repos
とし、その下に revokedと trustedというディレクトリを用意する。 fingerprintを
# sha256 -q repo.pub
で求めておき、truestedの下に適当なファイル名で
function: sha256 fingerprint: ae9f016190512cc2107f2555c070c5ab2bad1ef73a370edc96f1b1b18022cdc1
のように置いておく。
クライアント側の設定は以下のようにする。
test: { url: http://www.example.com/pub/packages/${ABI} enable: yes priority: 1 signature_type: fingerprints pubkey: /usr/local/etc/pkg/repos }
いつからか分からないけれど(いや最初からかもしれませんが)、さくらのVPSはCMOSがJSTに合わせられているようで再起動すると9時間ずれてしまうことに気がつきました。 というわけで、
# touch /etc/wall_cmos_clock
で解決。
request domain-name-servers;
をinteterfaceの設定に書くとDNSのサーバが降ってくるので、それをスクリプトをつかって/etc/resolv.confを書き換える
といった流れにするのがよいようです。もっとよいやり方があるのかもしれませんが・・・ちなみにname serversは $new_domain_name_serversでスクリプトから参照することができます。
/usr/local/etc/dhcp6c.conf:
interface tun2{ send ia-pd 0; request domain-name-servers; script "/usr/local/sbin/iijmio6.script"; }; id-assoc pd 0 { prefix-interface fxp0 { sla-id 1; sla-len 8; }; };
私は以下のようなスクリプトを書きました。
/usr/local/sbin/iijmio6.script:
#!/bin/sh echo -n "" > /etc/newresolv.conf if [ -n "$new_domain_name_servers" ] ; then for i in $new_domain_name_servers ; do echo nameserver $i >> /etc/newresolv.conf done mv /etc/newresolv.conf /etc/resolv.conf fi
rtadvdだけで配るのなら簡単なんですが、やはりちゃんと逆引きもさせたいよねー、とかなるとDHCPv6で配りたくなるというのが人情。その場合
の二つが必要なようですが、それは分かっても具体的な記述方法がよくわかりませんでした。これは、普通に10進数で /etc/rtadvd.confで raflagsに 192, pinfoflagsに 128を指定すればよいようです。
例)
fxp0:\ :addr="2400:XXXX:YYYY:ZZZZ::":prefixlen#64:raflags#192:pinfoflags#128
これで、RAからのアドレスではなくDHCPv6サーバから取得したアドレスをクライアントが振るようになりました。
我が家のマンションもBフレッツからフレッツネクストになり、やっとIPv6接続が安価に可能になりました。IIJmioに限らずフレッツ網使ってる限り、pppoeで接続後にDHCPv6でプレフィックスが振り出されるというやり方は基本同じなので、他のプロバイダでも通用するでしょう。
DHCPv6が必要になるので、あらかじめ pkg から dhcp6を インストールしておきます。
# pkg install dhcp6
pppの設定
/etc/ppp/ppp.conf:
iijmiov6: set authname AUTHNAME@bnf6.iij.ad.jp set authkey AUTHKEY set device PPPoE:re0:pppoe-in enable lqr disable ipcp enable ipv6cp set cd 5 set dial set login set redial 0 0 set timeout 0 set reconnect 10 20
AUTHNAME, AUTHKEY, deviceは適宜環境に合わせてください。 ipcpをdisableしてipv6cpをenableにするのがコツです。うまく設定できているかどうかは以下のコマンドで確認できます。
# ppp -unit2 iijmiov6 Working in interactive mode Using interface: tun2 ppp ON peach> dial ppp ON peach> Warning: deflink: Reducing configured MRU from 1500 to 1492 Ppp ON peach> PPp ON peach> Warning: ::/0: Change route failed: errno: No such process PPP ON peach>
pppがPPPになれば、リンクが確立したことになります。ここで、ワーニングが出ますが、これを消す方法があるのかどうかは不明です。別に出てもちゃんと動くようなので気にしないようにしました。
この状態では、リンクがつながってもIPアドレスも振られてなければdefault rotueも設定されていないので、まだIPv6で通信はできません。これらを自動で取得するためにpppを一旦終了し、次のような設定ファイルを書きます。
/etc/ppp/ppp.linkup:
iijmiov6: ! sh -c "/usr/local/sbin/dhcp6c tun2" ! sh -c "route -6 add default -iface tun2"
/etc/ppp/ppp.linkdown:
iijmiov6: ! sh -c "route -6 delete default" ! sh -c "kill `cat /var/run/dhcp6c.pid`"
interface tun2{ send ia-pd 0; }; id-assoc pd 0 { prefix-interface fxp0 { sla-id 1; sla-len 8; }; };
dhcp6c.confの fxp0等は適宜読み替えてください。
やってることはなんということはなく、リンクが確立したら
/usr/local/sbin/dhcp6c tun2 route -6 add default -iface tun2
が順番に実行されるだけです。設定段階では上記コマンドを手動でタイプしてちゃんと動いているかどうか、設定に間違いがないかどうか確認するとよいでしょう。特にdhcp6cは間違いやすいので -D -f オプションをつけて実行すると捗るのではないかと思います。
ちなみに dhcp6c.confの意味ですが、プロバイダから振り出されたプレフィックスに 8ビット足してその部分を1にしたものがfxp0にIPv6アドレスとして振るという設定です。IIJmioからは /56でIPv6アドレスが振り出されるので結果/64のアドレスがfxp0に振られます。
うまく動いているようでしたら、起動時に自動で実行されるよう /etc/rc.confに以下の行を追加します
ppp_enable="YES" ppp_profile="iijmiov6" ppp_mode="ddial" ppp_iijmiov6_unit="2" ppp_iijmiov6_nat="NO"
これで
# /etc/rc.d/ppp start
でIPv6アドレスが振り出されていれば成功です。
IntelのNUC(DN2820FY)のファームをFY0041.BIOからFY0048.BIOにしたところ起動しなくなりました(UEFI経由)。
写真のように
とか表示されて起動がとまってしまいます。少しづつファームを戻していったところFY0045.BIOでは起動することまでは確認しました。UEFI経由で起動しなければいいだけどいう話もありますが、その場合はパーティションがMBRでないと起動しないので、それもどうかと思いますし・・
調べて見るとこの問題はFreeBSDのUEFI wikiに Knwon Issues としてかかれていて
とります。ファームのバージョンアップで some hardwareに属してしまったぽいです。
このr258754の修正を見てみると printfの位置をずらしているだけで(printfがあるせいでメモリマップが変わってしまうというもののようで、しかも今現在CURRENTには取り込まれていないようなので、この修正を手動であててみれば起動するやもしれません。
search しても何も帰ってこない。というかinstallもできない。
そこで ls -l /var/db/pkg/repo-FreeBSD.sqlite
を見てみると
-rw-r--r-- 1 root wheel 54272 2月 5 09:49 /var/db/pkg/repo-FreeBSD.sqlite
とあからさまにファイルのサイズが小さいようです。どうもぶっ壊れたもよう。
sqlite3を起動して select name from packages;とかやっても何も帰ってきません。
強引に更新するほうほうが分からなかったのでrepo-FreeBSD.sqliteを削除。その後
pkg searchなど実行したら
-rw-r--r-- 1 root wheel 43327488 2月 5 03:41 /var/db/pkg/repo-FreeBSD.sqlite
となり正常になりました
ググると結構面倒な方法でupgradeしている人が多いのでメモがてら。
例えば母艦が10.1で、jailが10.0の場合、母艦側で
# freebsd-update -b /jails/hogehoge -r 10.1-RELEASE upgrade
とかやっても
freebsd-update: Cannot upgrade from 10.1-RELEASE to itself
というエラーが出てupdateできません。これは環境変数をいじくってunameの出力をごまかしてやることで解決できます。
# setenv UNAME_r 10.0-RELEASE
とすれば自分自身が10.0-RELEASEに見えるので、(uname -rで出力を確認できる)その状態で
を実行すれば jailがupgradeされます。その後
# freebsd-update -b /jails/hogehoge install
を実行すると
Installing updates... Kernel updates have been installed. Please reboot and run "/usr/sbin/freebsd-update install" again to finish installing updates.
のようにrebootしろと出ますが、これは
# unsetenv UNAME_r 10.0-RELEASE
とするだけでok。これで10.1-RELEASEにバージョンがあがったように見えます。その後何食わぬ顔で
を再び実行してやればokです
今迄業務でDebianを入れていたIntelのNUC(DN2820FYKH)にFreeBSD-10.1を入れてみました。
このマシンは発売当初から結構クセがあってBIOSのバージョンをアップデートしたり、設定しなおしたりで、なんとかDebianを動かした記憶があるので(具体的に何をしたかは忘れました)今回も苦労するだろうなぁと思ったらやっぱりその通りでした。以下そのメモです
まず、BIOSは現時点での最新のものをもってきました。
FY0041.BIO
というやつです。ググって見ると古いほうが安定してるとかいろんな情報がありますが一々確認してられないのでとりあえず最新のにしました。設定もとりあえずBIOSのデフォルトに。
次に 起動imageをもってきます。USBメモリからの起動が楽だと思います。10.1からはUEFIからの起動イメージがあるんでそれを持ってきました。
ftp://ftp6.jp.freebsd.org/pub/FreeBSD/ISO-IMAGES-amd64/10.1/ ftp://ftp6.jp.freebsd.org/pub/FreeBSD/ISO-IMAGES-amd64/10.1/FreeBSD-10.1-RELEASE-amd64-uefi-mini-memstick.img.xz
xzを解凍してからusbメモリに焼きます。このUSBから起動してインストールをすすめていくとUEFIから起動するようにパーティションが切られてセットアップが完了するはず……なんですが、あっさりとはいきませんでした
ブートする途中でコケてしまうんですよね。ちなみに非UEFIバージョンのイメージではちゃんと起動します。これで起動してLiveCDに移行して gpart等でパーティションを作ってインストールするという手段をとるとインストールはできましたが、OSの再起動で同じことがおきます。詰み。 さてどうしたものかと、試行錯誤的を繰替えしていたところ
Booting [/boot/kernel/kernel] in 10 seconds...
とカウントダウンが始まったら適当なキー(スペースとか)を押して止めて
mode 2 boot
とタイプして画面のモードを切りかえてbootすればうまく行くことにきがつきました。あとはインストーラが起動するのでそれに従っていきます。diskパーティションは Auto(UFS)を選択すればUEFIから起動するようにパーティションが自動で設定されます。
インストールが終わってHDDから起動するときもbootの途中で止めて、
をタイプします。毎回こんなことをしてられないので
/boot/loader.rc.local
というファイルを作成し
mode 2
と書いておけば次から自動でmodeが切り替わります。まぁまだ
Root mount waiting for: usbus0 ugen0.3: <Logitech> at usbus0 Root mount waiting for: usbus0 usb_alloc_device: set address 4 failed (USB_ERR_TIMEOUT, ignored) Root mount waiting for: usbus0 usbd_setup_device_desc: getting device descriptor at addr 4 failed, USB_ERR_TIMEOUT
とか妙な警告がでますが・・・これについてはこれから調査。