Bitcasaのためにかもめインターネットを契約してみた

ちょっと前の記事で、Bitcasaを使い始めてからIIJmioに、上り回線を規制値の15GB/day以上に使いすぎだからこのままだと回線止めるぞ警告をいただいたという話の続き。トラフィックを監視するために、Vyattaのトラフィック状況をmuninでグラフ化するとかやってましたが、結局、トラフィック量の規制がそれほどでもないらしい、かもめインターネットを契約してみました。3ヶ月先払いで6900円。基本的には、3ヶ月で契約一度やめようかなと思っていて、この間に、手元にある6TB分くらいの各種データをBitcasaにアップロードしようと目論んでいます。また怒られるかなぁ。

Bitcasa宛のトラフィックだけをかもめインターネット経由にしたい

基本的に、かもめインターネットはFreebit系かVectant系が上位回線らしく、大きくないプロバイダでありがちなパターンのようです。いままでもOpenCircuitだったりを使ってて、大抵この手の上位回線つかってる安いプロバイダは、夜に混雑しててあまり速度が出ないとか、なぜか特定の宛先だけすごい遅いとか、そういう微妙なことが起こりやすい印象があります。ってことで、そういう面倒くさいトラブルに遭いたくないので、基本的にIIJmioを常用の回線としておいて、Bitcasa向けの通信だけをかもめインターネット経由にするということにしたいなぁということで設定していきます。

Bitcasaクライアント動かしているマシンで静的ルーティング設定するという手もなくはなさそうですが、今回はインターネットの出口なっているVyattaがうごいているノートPCさんでトラフィックを振り分けるように設定してみました。あとは、Bitcasaはクライアントで暗号化してからアップロードするようで、がんばって動いている間は結構CPUがぶん回るのでアップロード専用のPCを用意してソースルーティングで、そいつだけかもめインターネット経由にするという方法もありますね。ちょっとこの方法は次点の方法として想定しています。こっちのが楽かもなー。IP調べたりせんでいいし。

宛先といっても、要は通信先のIPアドレスなので、まずは、Bitcasaクライアントが実際にはどこのIPと通信するかを突き止めてみます。といっても、それほど難しいことはなくて、Bitcasaクライアントが動いているマシン(私の場合は手元のMac mini)にWiresharkを入れて、Bitcasaが通信しているパケットをがーっとキャプチャします。極力見やすくなるように、Bitcasaクライアント以外が動いていないような状況にして、

  1. パケットキャプチャ開始
  2. Bitcasaクライアントを立ち上げる
  3. FinderでBitcasa Infinite Driveがマウントされているディレクトリを開く
  4. 適当なファイルをコピーして、削除する
  5. Bitcasaクライアントを終了
  6. パケットキャプチャ終了

という流れで、パケットを採取します。一応、一覧取得→コピー(アップーロード)→削除という感じで、Bitcasaのクライアントが通信しそうな操作を行います。

で、ここからは、正直それほど正確でもなくていいというか、とりあえず設定してみようという感じなので、やっつけ感あふれますが、パケットキャプチャ結果をProtocolでソートして、送信しているDNSクエリ(特に、Aレコード引いてるやつ)をまとめて見てみます。(実際、ほぼSSL/TLSで通信してて素直には中身が見れないって話もあります。)その上で、Bitcasaのクライアントが発したようなクエリを探します。基本的には、bitcasa.comのドメインの名前引いてるのがすべてっぽくて、結果として、クライアントがDNSで名前を引いているのは以下のホスト名のようです。

  • ap1.api.bitcasa.com
  • us1.sync.bitcasa.com
  • dist.bitcasa.com
  • desktop.api.bitcasa.com

なんとなく法則が見えてきます。一つ一つ見ていきましょう。

ap1.api.bitcasa.comですが、api.bitcasa.comというホスト名も存在していて、こちらもずらーっとIPが返ってきます。そして、返ってきたIPを逆引きするとわかるのですが(というか、パケットキャプチャしてるとホスト名が逆引きされているのですぐ気づきますが)、Bitcasaは全面的にAWSを使っているようで、ap1.api.bitcasa.comで返ってくるIPはap-northeast-1のEC2のインスタンス達のようで、api.bitcasa.comで返ってくるIPアドレス達はus-west-1のEC2インスタンス達のようです。

us1.sync.bitcasa.comで返ってくるIPアドレスとsync.bitcasa.comで返ってくるIPアドレスは同一で、試しにap1.sync.bitcasa.comを引いてみると、こちらはap-northeast-1のアドレスではなく、sync.bitcasa.comのaliasで同一のIPアドレスが返ってきました。どうも、sync.bitcasa.comが担う役割の部分はus-westに集中しているようですね。(なんとなく、DBは集約されていてus-westに一括で保存されていそうですね、us-westのRDSかな。)

詰まるところ、ap1はap-northeast-1の略、us1(もしくは、省略した場合)はus-west-1の略、ということなのでしょうか。どうもそう考えて問題なさそうです。蛇足的ですが、www.bitcasa.comの名前をひいたときは、www.bitcasa.comはwww.geo.bitcasa.comのCNAMEになっており、その結果として、ap1-www.bitcasa.comのアドレスのIPが返ってくるような仕組みになっていました。おそらく、www.geo.bitcasa.comの返答はソースIPの地域を見て結果を変化させるDNSサーバなのでしょうね。たぶん、上のap1.api.bitcasa.comを使うかどうかあたりも同じような地域を判別するような仕組みが導入されているのでしょう。

次に、desktop.api.bitcasa.comですが、これはprod.api.bitcasa.comのaliasで、IPとしては、ap-northeast-1のec2のアドレスが1つだけ返ってきました。おそらく、これも地域によって返答が変わる系のDNSなのではないかと思います(Route53かな?)が、ap1.api.bitcasa.comとの役割の差が分かりませんね。基本的に、手元の3台くらいのマシンで試したところ、どれも同じIPアドレスが返ってくるようです。その後の通信を見ていると、アップロードとかはおそらくこのアドレス宛にSSL/TLSなTCP接続が張られて行われているようです。

最後に、dist.bitcasa.comですが、これはCloudFrontのアドレスが返ってくるようです。アプリのアップデートとか確認してるんですかね。きっとアプリにアップデートがあると、このホストからダウンロードしそうな気がします。これはおそらく今回の通信の振り分けには参加させなくてよさそう、という風にCloudFrontであることからとりあえず判断してしまいましょう。

ここまでをざっくりまとめると、

  • ap1.api.bitcasa.com, us1.api.bitcasa.com(=api.bitcasa.com), sync.api.bitcasa.com(=us1.sync.bitcasa.com, ap1.sync.bitcasa.com)で返ってくるIPアドレス
  • desktop.api.bitcasa.com(=pd.bitcasa.com)で返ってくるIPアドレス
  • my.bitcasa.com 上には出てきませんが、ブラウザでログインしたときにファイル一覧とか見れるページのホスト(ほぼテスト用です。)

という3種のIPアドレス達をVyattaでかもめインターネット側の経路に流すようにルーティングを設定してやると、Bitcasaの通信だけをかもめインターネット経由の経路に変えることができるような気がしてきました。

Vyattaのルーティング設定する

というわで、この情報をもとにVyattaでPPPoEの設定とNATルールを追加して対処を行います。

PPPoEのほうは、0がIIJmio,1がかもめインターネットとして、一応、注意点はdefault-routeの設定の有無です、IIJmio側をauto,かもめインターネット側をnoneとしておいて、デフォルトゲートウェイはIIJmio側に自動で向けさせます。

pppoe 0 {
    default-route auto
    mtu 1454
    name-server none
    password xxxxxxx
    user-id xxxxxxxx@iij.ad.jp
}
pppoe 1 {
    default-route none
    mtu 1454
    name-server none
    password xxxxxxxx
    user-id xxxxxxxx@kamome.or.jp
}

これで、commit&saveして、とりあえず、pppoeを2本張ります。disconnect&connectなり、clear interdace connection pppoe0,clear interdace connection pppoe1みたいなことをして、pppoeが正しく接続できて、グローバルIPがとれてることを確認します。ついでに、show ip routeして、pppoe1の先のnetxt-hopのIPアドレスをメモっておきます。

この後、SNATの設定とルーティングの設定を足していくんですが、上記のap1.api.bitcasa.comなど複数のIPアドレスを足すと、軽く30を超えます。そして、AWSを使っているせいもあって、Rangeで指定できるようにIPが並んでるわけでもありません。つまり、ルーティングやSNATで設定する場合には、/32で個別に1つ1つ設定するしかなさそうです(たぶん)。 はじめ、SNATでdestinationを指定しつつ、ルーティングの設定を足さないといけないことに気づかず、スタティックルーティングだけ足して、あれーと一人で悩んでいました。んで、ふとSNATみたところ、outbound-interfaceってのがあることを思い出して、こっちもかー、と一人で結構いろいろ悩みました。 ってことで、まあそういう右往左往はさておいて、この設定で動くっぽいということがわかったので、IPごとにVyattaの設定を適当に生成するスクリプトをでっち上げます。

from logbook import Logger

log = Logger('main')

SNAT_RULE_START_ID = 1
BITCASA_ROUTES_IFNAME = 'pppoe1'
BITCASA_ROUTES_NEXTHOP = 'xxx.xxx.xxx.xxx'

BITCASA_HOSTS = ['www.bitcasa.com', 'my.bitcasa.com',
                 'ap1.api.bitcasa.com', 'us1.api.bitcasa.com',
                 'ap1.sync.bitcasa.com', 'us1.sync.bitcasa.com',
                 'desktop.api.bitcasa.com',]

import dns.resolver

bitcasa_ips = []
for h in BITCASA_HOSTS:
#    log.info('resolving {0}'.format(h))

    try:
        answers = dns.resolver.query(h, 'A')
        for a in answers:
            bitcasa_ips += [a.to_text(),]
    except dns.resolver.NXDOMAIN as e:
        log.warn('Cannot find hostname: {0}'.format(h))

snat_rule_num = SNAT_RULE_START_ID
from cStringIO import StringIO
vc_buf = StringIO()
for ip in list(set(bitcasa_ips)):

    # nat config
    vc_buf.write("delete nat source rule {snat_rid}\n".format(snat_rid=snat_rule_num))
    vc_buf.write("set nat source rule {snat_rid} destination address {dest_addr}\n".format(
                  snat_rid=snat_rule_num, dest_addr=ip))
    vc_buf.write("set nat source rule {snat_rid} outbound-interface {outbound_ifname}\n".format(
                  snat_rid=snat_rule_num, outbound_ifname=BITCASA_ROUTES_IFNAME))
    vc_buf.write("set nat source rule {snat_rid} translation address masquerade\n".format(
                  snat_rid=snat_rule_num))

    # route config
    vc_buf.write("set protocols static route {ip}/32 next-hop {next_hop}\n".format(
                  ip=ip, next_hop=BITCASA_ROUTES_NEXTHOP))

    snat_rule_num += 1

print vc_buf.getvalue()

DNSクエリを発行するために、dnspythonをつかっているので、pip install dnspythonは実行してパッケージ入れておく必要があります。

BITCASA_ROUTES_IFNAMEは、Bitcasaに接続する際に出ていきたいインターフェース名、BITCASA_ROUTES_NEXTHOPはそのインターフェースの先のIP指定します。さっきメモった通り、show ip routeで分かります。

どかーっと標準出力にVyattaのコマンドが吐かれます。

delete nat source rule 1
set nat source rule 1 destination address 176.34.32.173
set nat source rule 1 outbound-interface pppoe1
set nat source rule 1 translation address masquerade
set protocols static route 176.34.32.173/32 next-hop xxx.xxx.xxx.xxx
(以下、IPアドレスの数だけ続く...)

(なんだかいろいろ不格好ですが、ほんとにこれでいいんでしょうか...)という不安はまあものは試し的なノリで置いておきますが、、、、

んで、VyattaのコンソールにSSHかなんかで入って

$ configure
# cat > /tmp/bitcasa_config
(さっき生成された設定をペースト)
# . /tmp/bitcasa_config

とやると、設定が投入されます。ちなみにデフォルトだと、SNATのruleを1番からゴリゴリ消して書き換えるので、既存設定がある場合は、SNAT_RULE_START_IDを書き換える必要があります。IIJmio向けの常用向けのruleは100に設定してあります。

outbound-interface pppoe0
translation {
    address masquerade
}

というシンプルな感じで、アドレスもなにも指定しない形です。VyattaのNATの設定はシーケンシャルにID順に評価されるようなので、この設定はすべての設定の最後に書いておくのがたぶん無難です。

ここまでくれば一応設定は完了です。

適当にNAT化のホストで
$ curl https://my.bitcasa.com
として通信した後で、Vyatta上で、
$ show nat source statistics
で、該当ルールのpkts,bytesが増えていることを確認します。
もしくは、単純に、tracerouteで、
$ traceroute my.bitcasa.com
を実行して、IIJmioっぽくないことを確認します。

こういう感じで通信がちゃんと別経路で流れていることが確認できれば終了です。これで、BitcasaでアップロードしまくってIIJmioに怒られることはなくなりました。かもめインターネットに怒られる可能性は十二分にありますが。

とりあえず、この状態でアップロードをがしがしやろうとおもいます、怒られるまで。

今回の設定の問題はいくつかあって、

  • Bitcasaの各ホストが返してくるIPが変わったら設定も当然変える必要があるんだけど、定期的に監視するくらいしか方法がない
  • かもめインターネットとのPPPoEが切れて再接続すると、next-hopが変わってまったく通信できなくなる予感→これはBitcasaに繋がらなくなるのでたぶん分かるかな

くらいでしょうか。まあとりあえずこれで一旦使ってみる。

(おまけ)Bitcasaはアジア向けにAWSのtokyoリージョン使ってるのでいつのまにか速くなってるよ

ベータのときはそんなことなかったんだとおもうけど、今回いろいろ見てきたところ、アジア向けとして、BitcasaはTokyoリージョンを使うようになったらしく、最近、アップロード/ダウンロードはそれなりに速いです。アップロードは気がついたら、平均で5-10Mbit/secくらいは出ます。ダウンロードもシークとかはちょっと厳しいけど、普通に再生してて裏でダウンロードしてるのは気づかない程度に再生できたりします。

なんというか、すごく長くなった割に、いろいろ穴がある設定のままになってしまった。もうすこしまともに設定する方法はおいおい考えたいところ。