LINEアプリのスタンプダウンロードについて解析してみる

私のウェブサイトにたどり着く検索ワードに、「LINE 解析」など、LINE関係の解析について知りたい方が多いようです。

ですので今回はLINEのスタンプについて書いていこうと思います。
iPhone版のアプリが、どうやってスタンプをダウンロードしているかです。
今回はアプリがサーバからスタンプをダウンロードし、フォルダに保存をするところまでをパソコン上でやります。
なお、アプリの逆コンパイルは禁止されている上に技術的にもそんなことできないので、
恐らくアプリはこうやってダウンロードしているんだろうなあ、という推定になります。

前提知識:スタンプフォルダの構成

自分の持っているスタンプのIDを特定

[LINEのフォルダ]/Library/Application Support/Sticker Packagesを開いてください。
f:id:shutingrz:20140813024246p:plain
"*1.*2.linestk"の、*1の部分がスタンプIDになります。

スタンプフォルダの構成

f:id:shutingrz:20140813032942p:plain
この画像を見てください。
ID:2431のフォルダの中に、
"*_key@2x.png"
"*@2x.png"
"productInfo.plist"
"tab_off@2x.png"
"tab_on@2x.png"
があります。

このファイル達は様々なタイプの画像になっています。

"*_key@2x.png"はトーク画面内のスタンプを選択した時の確認画面の画像
"*@2x.png"はスタンプの画像
"productInfo.plist"はスタンプの名前、値段などの情報
"tab_off@2x.png"は、トーク画面のスタンプ一覧で選択していない時の白黒画像
"tab_on@2x.png"は選択している時のカラー画像

また、LINE公式サイトからもスタンプのIDを特定できます。
LINE STOREに飛びます。
調べたいスタンプのURLにIDがあります。


アナと雪の女王のスタンプをダウンロードする

実はスタンプ達は購入しなくても誰でもダウンロードができるのです。
今回はスタンプID:2046の「アナと雪の女王」をダウンロードしていこうと思います。
burpsuiteでHTTPの盗聴をしながらスタンプショップの「アナと雪の女王」のスタンプ情報を見ると、
ttp://dl.stickershop.line.naver.jp/products/0/0/1/2046/iphone/productInfo.meta
にアクセスしていることが確認できます。
productInfo.metaの中身は以下のようになっています。

{"packageId":2046,"onSale":true,"validDays":0,"title":{"en":"Frozen","es":"Frozen","in":"Frozen","ja":"アナと雪の女王","ko":"겨울왕국","th":"Frozen","zh-Hans":"冰雪奇缘","zh-Hant":"冰雪奇緣"},"author":{"en":"The Walt Disney Company (Japan) Ltd.","ja":"ウォルト・ディズニー・ジャパン(株)","ko":"The Walt Disney Company (Japan) Ltd.","zh-Hans":"The Walt Disney Company (Japan) Ltd.","zh-Hant":"The Walt Disney Company (Japan) Ltd."},"price":[{"price":100.00,"symbol":"NLC","currency":"NLC","country":"@@"},{"price":15.00,"symbol":"HK$","currency":"HKD","country":"HK"},{"price":200.00,"symbol":"¥","currency":"JPY","country":"JP"},{"price":2000.00,"symbol":"₩","currency":"KRW","country":"KR"},{"price":2.58,"symbol":"S$","currency":"SGD","country":"SG"},{"price":60.00,"symbol":"NT$","currency":"TWD","country":"TW"},{"price":1.99,"symbol":"$","currency":"USD","country":"US"}],"stickers":[{"id":42836,"height":161,"width":170},{"id":42837,"height":151,"width":150},{"id":42838,"height":151,"width":159},{"id":42839,"height":151,"width":170},{"id":42840,"height":151,"width":160},{"id":42841,"height":150,"width":167},{"id":42842,"height":152,"width":165},{"id":42843,"height":161,"width":162},{"id":42844,"height":151,"width":174},{"id":42845,"height":151,"width":166},{"id":42846,"height":151,"width":182},{"id":42847,"height":161,"width":142},{"id":42848,"height":155,"width":166},{"id":42849,"height":161,"width":170},{"id":42850,"height":161,"width":170},{"id":42851,"height":151,"width":160},{"id":42852,"height":161,"width":130},{"id":42853,"height":151,"width":159},{"id":42854,"height":140,"width":185},{"id":42855,"height":142,"width":183},{"id":42856,"height":161,"width":167},{"id":42857,"height":152,"width":160},{"id":42858,"height":125,"width":179},{"id":42859,"height":151,"width":159},{"id":42860,"height":161,"width":183},{"id":42861,"height":156,"width":171},{"id":42862,"height":161,"width":130},{"id":42863,"height":151,"width":160},{"id":42864,"height":161,"width":160},{"id":42865,"height":161,"width":134},{"id":42866,"height":160,"width":159},{"id":42867,"height":151,"width":150},{"id":42868,"height":150,"width":149},{"id":42869,"height":152,"width":114},{"id":42870,"height":151,"width":160},{"id":42871,"height":161,"width":169},{"id":42872,"height":161,"width":162},{"id":42873,"height":133,"width":186},{"id":42874,"height":161,"width":157},{"id":42875,"height":159,"width":184}]}

順に見ていきましょう。

packageId:このスタンプのID
onSale:購入可能状態か
valieDays:有効期限
title:各言語(英語、日本語、韓国語、繁体字簡体字
price:各国の料金
stickers:スタンプ画像IDがスタンプの数だけあります。

このstickersのスタンプ画像IDは、例えば一番初めの画像ID、42836だと、
ttp://dl.stickershop.line.naver.jp/products/0/0/1/2046/PC/stickers/42836.png
ttp://dl.stickershop.line.naver.jp/products/0/0/1/2046/PC/stickers/42836_key.png
以上のように表示できます。

tab_off@2x.png、tab_on@2x.pngもダウンロードできます。
ttp://dl.stickershop.line.naver.jp/products/0/0/1/2046/android/tab_on.png

iPhoneのLINEアプリのスタンプフォルダの形式そのままにする

今までのURLを駆使して、2046.1.linestkフォルダを作成し、その中に
全ての*_key@2x.png、*@2x.png、tab_off@2x.png、tab_on@2x.pngをダウンロードし
そして最後に、productInfo.metaをproductInfo.plistに変換すれば、iPhoneのLINEアプリのスタンプフォルダそのままになります。
肝心のproductInfo.plistはどうすればいいでしょうか。これはMaxOSX版の独自の形式で、productInfo.metaそのままではありません。
というわけで作りました。
productInfo.metaからproductInfo.plistに変換するrubyスクリプトです。
gemでcfpropertylistを入れてください。

#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-

require 'json'
require 'net/http'
require 'uri'
require 'cfpropertylist'

id = ARGV[0]
stdir = "#{id}.1.linestk"
plist = CFPropertyList::List.new

plistName = "productInfo.plist"
url = URI.parse("http://dl.stickershop.line.naver.jp/")
res = Net::HTTP.start(url.host, url.port) {|http|
  http.get("/products/0/0/1/#{id}/iphone/productInfo.meta")
}
js = JSON.parse(res.body)

data = Array.new
sp = Hash.new
js.each do |param|
	data << param
end

data.each do |line|
	if (line[1].class == Array || line[1].class == Hash) then
		hashs = Hash.new
		line[1].each do |value|
			hashs.store(value[0],value[1])
		end
	end
	sp.store(line[0],line[1])
end


plist.value = CFPropertyList.guess(sp)
plist.save("#{plistName}", CFPropertyList::List::FORMAT_BINARY)

引数にスタンプIDを入れれば、カレントディレクトリにproductInfo.plistが作成されます。



そしてそれを2046.1.linestkの中に入れれば、このスタンプを買った時と同じ構成のフォルダができあがります。
f:id:shutingrz:20140813040946p:plain

以上でLINEアプリがスタンプをダウンロードしている仕組みとなっています。
インターネット上の不特定多数が見られる場所にこうやって著作物を置いていて、ちょっと怖いですよね〜

                • -

追記
これを全て自動でダウンロードするスクリプトを作成しました。
ruby1.9で動きます。また、gemでcfpropertylistを入れてください。
使用する際は引数にスタンプIDを入れてください。


getStickers.rb

夏のmixi Scrap Challenge 2014が開催されるので今年1月に開催したScrap Challenge2013でやったこと書く

夏のmixi Scrap Challenge2014が開催されるようです。
Scrap Challenge 2014 | 株式会社ミクシィ 学生向けエンジニアイベント

これに合わせて、放置していた 今まで温めておいたメモを書き起こし、記事を公開します。
結論から言うと、めちゃくちゃ楽しかったので行かなきゃ損です。

皆さんにはmixi Scrap Challengeに興味を持っていただき、大学3年生以下の方々にはぜひ参加していただきたいです。

応募のきっかけ

このイベントが開かれた年度にはセキュリティキャンプ2013中央大会に参加しており、私はネットワークセキュリティクラスだったんですが、
Webセキュリティクラスに凄くキャラが濃くてXSSヤバイ八木なんとかさんがいたのがキッカケで私もWebセキュリティに興味を持ち、
9月からちょいちょい勉強していた時にこのイベントのことを知ったからです。
また、mixiのサービスの脆弱性を報告して10万円貰ったこともあり、mixiについて良く知りたかったのもあります。
地方の貧乏学生の私には交通費が半額でたのも最高でしたね。

やったこと

概要

午前中の講習は、新卒の新人教育の2(3)日間のセキュリティ講習を、ぎゅっと30分に詰め込んだもの。
午後にScrap Challengeを行い、優勝者にはトロフィーを進呈。最後に懇親会を行う。

午前(前半)

講習を受けながらメモをしたので間違っているかもしれませんが勘弁してつかあさい。

午前(後半)

XSS

エスケープ処理について


キャンプ初日のランチのテーブルでやぎはしゅがニヤニヤしながらテレビ局の人に説明してたの思い出す。

CSRF

mixiモールにログイン中、メールで送られてきたURLをクリックしただけで徳丸本の注文が完了するなど

入力、確認、官僚的なフローのページ群ならば、完了のページのみ対策が必要
対抗策→セッション、hiddenパラメータ、POST専用にする、直前ページにパスワード入力を促す

SQLインジェクション

sql="select from users where name = {$name} amd pass={$pass};
対抗策→プレースホルダ(バインド機構、プリペアドステートメント)(厳密には異なる)

kvsやnosqlに対するインジェクション

memcachedや他のkvs、nosqlについてもsqlインジェクションのような攻撃がありうる
memcachedは正しいエスケープを行わないといけないため対策が難しい

オープンリダイレクタ

・http locationヘッダ
htmlのmeta要素
参考文献→徳丸本p184
脅威→フィッシング
対抗策→リダイレクト先を固定、外部からURLを指定できる仕様を改める、リダイレクト先のドメインを固定にする
httpヘッダインジェクションは防げない場合がある(0x0D0x0A)

脆弱性に対する基本的な対処

だいたいの脆弱性は正しい出力を行うことで防げる。
→何が正しいかは状況に応じて変わる。


Scrap Challenge簡単なチュートリアル

午後の本題のScrap Challengeについての説明。




・・・以上のことを30分で全てやりました。駆け足です。

昼ごはん

さすが、金かかってるわー

午後(Scrap Challenge)

Scrap Challengeのためにわざわざ用意された脆弱性付きのmixiに好き放題ハッキングできます。
f:id:shutingrz:20140810045337p:plain

      • -

3人一組でチームを組んでやりました。
Scrap Challengeの問題は午前中に講師の方から教えてもらった脆弱性を突くものしかありませんでした。
といっても午前中の講習はたった30分のみなので、習ったからといって解ける問題ではなく、ノー勉で行くと人権が無くなるので気をつけてください。
まあキャンプ終了後適当に4ヶ月しか勉強していない俺でも行けたので気張らなくてもいいです。


ネタバレしちゃうと今回応募する人がつまらなくなってしまうのでチュートリアル問題だけ。

問題例 -チュートリアル-

000 ( 0pt )

プロフィール(show_profile.pl)のXSS脆弱性を利用して、開くと任意の文字列がアラートされるようなURLを鴨ネギ-男に送ってください

結果

なんとか優勝できました。チームにSQLインジェクション神の子がいたため、2位以降と大きな差をつけて勝てました。感謝。
優勝したチーム全員にトロフィーが貰えます。

f:id:shutingrz:20140810045830j:plain
こんなやつです。スゲーかっこいい。

懇親会

最後に懇親会をしました。


お酒の量、寿司の量、お菓子の量、mixiからもらったアメニティの量、全てが半端無かったです。
余ったやつは好きに持ち帰って良かったので貧乏学生の俺はいっぱいいただきました。

感想

優勝出来て良かったです。

また、私の場合なんですが、大学3年生の1月にこのイベントがありまして、その後2月にこの御縁で人事の方から採用面接のお誘いをいただき、
書類選考、集団面接、人事面接を全て受けずに(スキップし)、技術者面接から選考を受けてほしいと言われました。
インターンはその企業の選考に有利になるという噂は聞いていましたが、まさかここまで飛び級で面接が受けられるとは・・・。
結果から言えば役員面接も通って内々定をいただくことができました。
(ですがすみません私が就職予定の会社はmixiではありません。本来私が志望していたネットワークセキュリティ業界の企業になります。)

人事の方もとてもいい方ばかりでした。就活している中で一番親身になってくれたかも?
このように就活を控えている大学生3年生以下の皆さんも受けてみるといいかも知れません。


開催日時は、
2014年8月23日(土) 11:00-19:00 で、


応募締め切りは、
2014年8月14日(木) 23:59です。
関東圏外の地方の方は交通費が半額出ます。



また、最後になりましたが、mixiの方々、本当にありがとうございました。

FreeBSDのカスタムカーネルをインストールメディアにする。

記事の最後に、Jail + VIMAGEを手っ取り早く触るための私が作成した
vimageカーネルFreeBSD-9.3-VIMAGE-amd64-disc1.isoへのリンクをつけます。


Jailの真の実力はやはり、VIMAGEを使ってこそでしょ!ということで
VIMAGEを色々なマシンに入れたいのですが、デフォルトのカーネルでは有効になっていません。
ですので複数台のPCを手っ取り早くVIMAGE仕様にするためにカスタムカーネルをインストールメディアにします。
色々カスタマイズはできるのですが、今回は早く簡潔にリリースできることを目標にします。

カスタムカーネルを作成する

カスタムカーネルを作成しましょう。
FreeBSDインストール時に、srcもインストールしたならば、/usr/src/に色々srcがあるはずです。
ここで、自分がインストールしたアーキテクチャによってディレクトリパスが変わります。
今回はamd64だと仮定しましょう。
/usr/src/sys/amd64/conf/GENERICを編集します。
(本来ならばカスタムカーネルは別ファイルに作成するのが主流なのでしょうが、make releaseの簡潔さを重視してGENERICに追加していきます。)

今回はJail+VIMAGEを実現するために最低限必要なVIMAGE、
そしてファイアウォールとしてipfwを用いるためIPFIREWALLとその他のオプション、
Jailのリソース管理をするためにRCTLとその他のオプションを入れます。
末尾に、

options VIMAGE
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=1000
options IPFIREWALL_DEFAULT_TO_ACCEPT
options RACCT
options RCTL

を追加します。
IPFIREWALLの4行については15.7. ファイアウォールを、
RCTL,RACCTについては自由な設定が可能な最新リソース制御機能(1/2) − @ITを参照してください。

記述したあとはついにコンパイルです。
/usr/srcに移動し、

make buildkernel

を入力し、コンパイルをします。時間がかかります。

これが終わりましたら、次はリリースの為にworldをコンパイルします。

make buildworld

を入力し、コンパイルをします。とても時間がかかります。

これが終わりましたら次はついにリリースをします。

インストールメディアを作成(リリース)する

/usr/src/releaseに移動します。
ここで、make releaseをするのですが、オプションが色々あります。
詳しいことはrelease(7) manページを参照していただくとして、
この記事ではスピード重視なので、簡単にすませていきます。
/use/src/releaseで、

make release BUILDNAME=[バージョンの名前。unameを参考に] MAKE_ISOS=1 NOPORTS=1

を入力し、リリースをします。今回私が作成したバージョンはFreeBSD-9.3なので、

make release BUILDNAME=9.3-VIMAGE MAKE_ISOS=1 NOPORTS=1

としました。
MAKE_ISOSを入れるとisoファイルが作成されます。
PortsCollectionはインストール後に各自更新すると思うのでNOPORTSを入れ、リリースに含まれないようにします。

リリースが終わったら、/usr/obj/usr/src/releaseに移動します。
そこに、disc1.isoがあると思います。これが今回作成したインストールメディアになります。
お疲れ様でした。


最後に、私が作成したFreeBSD-9.3-VIMAGE-amd64-disc1.isoをアップロードしておきました。
これをダウンロードしインストールすればすぐにJail + VIMAGEが楽しめます。

http://www.shutingrz.com/iso/FreeBSD-9.3-VIMAGE-amd64-disc1.iso

FreeBSd 9.xのjailで"Host name lookup failure","DNS lookup failure"

FreeBSD9.xでバグを踏んだみたいです。
同じ現象が起きた人の為にメモ。

今まで名前解決ができていたのに、hostをrebootをしたらjail内で名前解決ができなくなってしまいました。

エラー内容はpingの場合だと、
ping: cannot resolve Host name lookup failure。

しかしdrill(unbound)はできる。
それ以外のapachepingなどが全て名前解決ができなくなりました。

解決方法は、10.0-RELEASEにupgradeをすることです。これで直りました。

bridge+epairで仮想HUBをvitochaで作ってみる

先日書いた記事
bridge+epairで仮想HUBを作ってみる=>できた -

を@tss_ontapさんが作成したvitochaを用いて作成します。

              • -

vitochaについての情報はこちら。
公式サイト
VITOCHA

説明スライド
VIMAGE仮想ネットワーク構築クラスライブラリ VITOCHA (通称バーチャル◯もちゃ)

              • -

ネットワーク図は前回とほぼ同じです。
今回はswitchにIPaddrを割り当てていません。
f:id:shutingrz:20140714171640p:plain

スクリプト
#!/usr/local/bin/ruby

require './vitocha/vitocha.rb'

tomocha=Operator.new

#create switch
switchNAME = "switch"
switch=Bridge.new(switchNAME)
switch.on

#hostjail connect switch
epaira, epairb = tomocha.createpair
epairaIP = "192.168.20.1"
epairaMASK = "255.255.255.0"

ifconfig(epaira + " inet " + epairaIP + " netmask " + epairaMASK)
ifconfig(epaira + " up")
switch.connect(epairb)
switch.up(epairb)


#create server01
serverNAME = "server01"
epairaIP = "192.168.20.11"
epairaMASK = "255.255.255.0"

server = Server.new(serverNAME)
epaira, epairb = tomocha.createpair
server.connect(epaira)
server.assignip(epaira,epairaIP,epairaMASK)
tomocha.register(epaira,serverNAME,epairaIP,epairaMASK)
server.up(epaira)
switch.connect(epairb)
switch.up(epairb)

#create server02
serverNAME = "server02"
epairaIP = "192.168.20.12"
epairaMASK = "255.255.255.0"

server = Server.new(serverNAME)
epaira, epairb = tomocha.createpair
server.connect(epaira)
server.assignip(epaira,epairaIP,epairaMASK)
tomocha.register(epaira,serverNAME,epairaIP,epairaMASK)
server.up(epaira)
switch.connect(epairb)
switch.up(epairb)
スクリプトを動かす
 # ./test.rb 
Hi, I'll do your job.
shell(#<Th:0x00000801d901a8>): /usr/sbin/jls host.hostname
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig bridge create
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig bridge0 vnet switch
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig bridge0 name vbridge0
shell(#<Th:0x00000801d76f28>): /usr/sbin/jexec switch ifconfig vbridge0 up
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig vbridge0 up
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair create
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair0a link 02:c0:e4:00:0:0a
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair0b link 02:c0:e4:00:0:0b
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair0a inet 192.168.20.1 netmask 255.255.255.0
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair0a up
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair0b vnet switch
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig vbridge0 addm epair0b
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig epair0b up
shell(#<Th:0x00000801d901a8>): /usr/sbin/jls host.hostname
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair create
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair1a link 02:c0:e4:00:1:0a
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair1b link 02:c0:e4:00:1:0b
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair1a vnet server01
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec server01 ifconfig epair1a inet 192.168.20.11 netmask 255.255.255.0
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec server01 ifconfig epair1a up
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair1b vnet switch
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig vbridge0 addm epair1b
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig epair1b up
shell(#<Th:0x00000801d901a8>): /usr/sbin/jls host.hostname
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair create
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair2a link 02:c0:e4:00:2:0a
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair2b link 02:c0:e4:00:2:0b
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair2a vnet server02
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec server02 ifconfig epair2a inet 192.168.20.12 netmask 255.255.255.0
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec server02 ifconfig epair2a up
shell(#<Th:0x00000801d901a8>): /sbin/ifconfig epair2b vnet switch
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig vbridge0 addm epair2b
shell(#<Th:0x00000801d901a8>): /usr/sbin/jexec switch ifconfig epair2b up
jail hostから192.168.20.11(server01)にpingを打ってみる。
# ping 192.168.20.11
PING 192.168.20.11 (192.168.20.11): 56 data bytes
64 bytes from 192.168.20.11: icmp_seq=0 ttl=64 time=0.293 ms
64 bytes from 192.168.20.11: icmp_seq=1 ttl=64 time=0.253 ms
jail hostから192.168.20.12(server02)にpingを打ってみる
# ping 192.168.20.12
PING 192.168.20.12 (192.168.20.12): 56 data bytes
64 bytes from 192.168.20.12: icmp_seq=0 ttl=64 time=0.328 ms
64 bytes from 192.168.20.12: icmp_seq=1 ttl=64 time=0.080 ms
server01から192.168.20.12(server02)にpingを打ってみる
# jexec server01 ping 192.168.20.12
PING 192.168.20.12 (192.168.20.12): 56 data bytes
64 bytes from 192.168.20.12: icmp_seq=0 ttl=64 time=0.124 ms
64 bytes from 192.168.20.12: icmp_seq=1 ttl=64 time=0.080 ms

全て疎通できてますね。
vitochaを使えばepairのMACaddrの重複を防ぐことができ、また別プログラムとの連携も可能になります。



以上。

bridge+epairで仮想HUBを作ってみる=>できた


もっといい方法が必ずあるはずなので、とりあえずメモとして。

以下の様なネットワークを作ってみます。
f:id:shutingrz:20140714171640p:plain


まずはスイッチ部分を作成し、Jail hostまでつなげるところから。

 # ifconfig bridge create
bridge0
 # ifconfig bridge0 vnet switch
 # ifconfig epair create
epair0a
 # ifconfig epair0a 192.168.20.1/24 up
 # ifconfig epair0b vnet switch
 # jexec switch ifconfig bridge0 192.168.20.254/24 up
 # jexec switch ifconfig epair0b up
 # jexec switch ifconfig bridge0 addm epair0b
 # ping 192.168.20.254
PING 192.168.20.254 (192.168.20.254): 56 data bytes
64 bytes from 192.168.20.254: icmp_seq=0 ttl=64 time=0.269 ms
64 bytes from 192.168.20.254: icmp_seq=1 ttl=64 time=0.120 ms


これでJail hostとSwitch部分のネットワークが作成できました。
次はserver01とswitchをつなげるところ。

 # ifconfig epair create
epair1a
 # ifconfig epair1a vnet server01
 # ifconfig epair1b vnet switch
 # jexec server01 ifconfig epair1a 192.168.20.11/24 up
 # jexec switch ifconfig epair1b up
 # jexec switch ifconfig bridge0 addm epair1b
 # 
 # jexec server01 ping 192.168.20.1
PING 192.168.20.1 (192.168.20.1): 56 data bytes
64 bytes from 192.168.20.1: icmp_seq=0 ttl=64 time=0.181 ms
64 bytes from 192.168.20.1: icmp_seq=1 ttl=64 time=0.135 ms

最後にserver01とswitchをつなげるところ。server01とやっていることはほぼ同じ。

 # ifconfig epair create
epair2a
 # ifconfig epair2a vnet server02
 # ifconfig epair2b vnet switch
 # jexec server02 ifconfig epair2a 192.168.20.12/24 up
 # jexec switch ifconfig epair2b up
 # jexec switch ifconfig bridge0 addm epair2b
 # 
 # jexec server02 ping 192.168.20.1
PING 192.168.20.1 (192.168.20.1): 56 data bytes
64 bytes from 192.168.20.1: icmp_seq=0 ttl=64 time=0.181 ms
64 bytes from 192.168.20.1: icmp_seq=1 ttl=64 time=0.126 ms

これで全てつなぎ終えました。
server01とserver02の疎通も確認してみます。

 # jexec server01 ping 192.168.20.12
PING 192.168.20.12 (192.168.20.12): 56 data bytes
ping: sendto: Host is down
ping: sendto: Host is down

・・・疎通できない・・・・・・。


何か間違っている点、やっていない点があれば@Shutingrz宛に助言お願いします。


追記
server01から192.168.20.12(server02)にpingを飛ばした時のserver02のepair2aのtcpdumpです

server01のping

# jexec server01 ping 192.168.20.12
PING 192.168.20.12 (192.168.20.12): 56 data bytes
ping: sendto: Host is down

server02のtcpdump

# jexec server02 tcpdump -i epair2a
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on epair2a, link-type EN10MB (Ethernet), capture size 65535 bytes
22:28:18.952300 ARP, Request who-has 192.168.20.12 tell 192.168.20.11, length 28
22:28:20.003368 ARP, Request who-has 192.168.20.12 tell 192.168.20.11, length 28
22:28:21.053505 ARP, Request who-has 192.168.20.12 tell 192.168.20.11, length 28


追記
できなかった理由が判明しました。

jailer設定 [DEMON-LORD]

ifconfig epair[n] create
epair[n]aとepair[n]bが作成される。epairを一つ作成してjailerからprisonerに割り当ててから次のepairを作成するとMACアドレスが重複する場合がある。この場合、それぞれのepairを同じbridgeに接続するとMACアドレスが重複して通信が行えなくなる。問題を回避する為、epairの作成は同時期に行う。

まさかと思いjexec switch ifconfig。

epair1b: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:ff:50:00:06:0b
	inet6 fe80::ff:50ff:fe00:60b%epair1b prefixlen 64 scopeid 0x4 
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
epair2b: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:ff:50:00:06:0b
	inet6 fe80::ff:50ff:fe00:60b%epair2b prefixlen 64 scopeid 0x5 
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active

案の定macaddrが被ってました・・・。
@tss_ontap さんも昔この事言ってたのを今になって思い出しました。

修正として、まずifconfig epair createを3連続で行うようにしました。

結果。

# jexec server01 ping 192.168.20.12
PING 192.168.20.12 (192.168.20.12): 56 data bytes
64 bytes from 192.168.20.12: icmp_seq=0 ttl=64 time=0.219 ms
64 bytes from 192.168.20.12: icmp_seq=1 ttl=64 time=0.076 ms

バッチリです。

原因はわかったものの、今やってる卒論はリアルタイムにepairを作成、jailに割り当てる方式を採用しているので、この問題はどうやって解決すべきか・・・。



以上。

vnetが動かないqjailを無理やり動かしてみる

追記.2014/08/05
記事を修正しました。
qjail configでvnetが動きました。

qjail config -vを使う方法

# qjail config -v test01
 
At this time only ipfw firewall is vimage aware and can
run on the host and in the vnet jail at the same time.
 
Chose by entering ipfw or none and pressing the enter key.
none
 
There are two network configuration methods available for
connecting this vnet/vimage jail to the public internet.
The bridge/epair method and the netgraph method.
Chose which network method you want this vimage jail to use
by entering [ be ] for bridge/epair or [ ng ] for netgraph
and pressing the enter key.
be
Successfully enabled vnet for test01

noneを入力すると、ipfwを使いません。
epairを使うならば、beを入力します。

しかし、この方法だとqjail startした時にepairが1つ自動生成され、プライベートIPアドレスが自動で割り当てられるので、
自分で全てepairを作りたいときには正直邪魔です。
そのようなときには以下の2つの方法を使ったほうがいいです。

ソースコードを書き換える方法

ソースコードを書き換えるのに抵抗がなければ圧倒的にこちらのほうが楽です。
qjail Version 3.6のソースコードです。
/usr/local/bin/qjailを書き換えます。

echo "ip4,addr~ をコメントアウト

  echo "ip4.addr            =  ${ip4};"

    ↓

  #  echo "ip4.addr            =  ${ip4};"

echo vnet;を行う行のifをコメントアウトし、常に行われるようにする

    if [ ${vnet} ]; then 

    ↓

  #  if [ ${vnet} ]; then 
    fi 

    ↓

 #   fi 


この状態でqjail createし、startすれば、vnetが有効化されている状態になります。

qjailはBSDライセンスなので、ソースコードを改変して頒布しても著作権明記をすれば問題無いはずです。
しかしソースコードを書き換えてしまうと常にvnetが有効になってしまうので注意。

/usr/local/etc/qjail.vnet/を使う方法

まず、いつものように、qjail createをします。すると/usr/local/etc/qjail.local/test01が生成されます。

# cat /usr/local/etc/qjail.local/test01
name="test01"
ip4="0.0.0.0"
ip6=""
path="/usr/jails/test01"
interface="em1"
fstab="/usr/local/etc/qjail.fstab/test01"
securelevel=""
cpuset=""
fib=""
vnet=""
vinterface=""
rsockets=""
ruleset=""
sysvipc=""
quotas=""
nullfs=""
zfs=""
poststartssh=""
deffile="/usr/local/etc/qjail.local/test01"
image=""
imagetype=""
imageblockcount=""
imagedevice=""

ここからvnetを書き換えます。

vnet=""

    ↓

vnet="yes"

次に、/etc/jail.confを見ます。

test01 {
host.hostname       =  "test01";
path                =  "/usr/jails/test01";
mount.fstab         =  "/usr/local/etc/qjail.fstab/test01";
exec.start          =  "/bin/sh /etc/rc";
exec.stop           =  "/bin/sh /etc/rc.shutdown";
exec.consolelog     =  "/var/log/qjail.masterRouter.console.log";
mount.devfs;
ip4.addr            =  "0.0.0.0";
interface           =  "em1";
devfs_ruleset       =  "4";
}

もし作成されていなければqjail start test01;qjail stop test01をすれば作成されると思います。
/usr/local/etc/qjail.vnet/test01を作成し、この内容をコピーします。そして、
ip4,addrの行を削除し、vnet;を追加します。↓

test01 {
host.hostname       =  "test01";
path                =  "/usr/jails/test01";
mount.fstab         =  "/usr/local/etc/qjail.fstab/test01";
exec.start          =  "/bin/sh /etc/rc";
exec.stop           =  "/bin/sh /etc/rc.shutdown";
exec.consolelog     =  "/var/log/qjail.masterRouter.console.log";
mount.devfs;
interface           =  "em1";
devfs_ruleset       =  "4";
vnet;
}

そしてqjail startをすると、vnetが有効化されたjailが出来上がります。