海外に置いたAppleTVで日本のNetflixを見る - Raspberry Piで作るVPN切り替え機

やりたいこと

  • USの家に置いてあるAppleTVで、日本のIPからしか使えないサービスを使いたい。
  • 常時日本経由のインターネットだと速度面、レイテンシ面で不利なので任意に切り替えられるようにしたい。

実装の方針

  1. RaspberryPiで日本の実家においてあるサーバへVPNを張り、日本側の出口とする。
  2. RaspberryPiのwlan0を家庭内LAN、eth0を切り替え用LANにして、eth0の先にAppleTVをぶら下げる。
  3. RaspberryPiにて
    • eth0DHCPサーバ立てて、IP配るようにする
    • eth0wlan0の転送設定を入れる
    • デフォルトゲートウェイ(DGW)をJP側とUS側の間で切り替えることで、出口を制御する
    • DGWの切り替えはコマンド入力だと家族が使えないので、Homebridgeを使ってiPhoneから制御できるようにする

実際の構築

VPNを張る

SoftEther VPN Serverを使った拠点間VPN。これはまぁ色んな所に参考情報が記載されているので簡単に。

  • 実家側はNIC2枚刺しのCentOSSoftEther VPN ServerVPNサーバを用意
    • 仮想HUBを作成し、2枚めのethにブリッジするようにする
    • これでこの仮想HUBへアクセスすると、実家のLANにL2接続できるようになる
  • USのRaspberryPiにSoftEther VPN Bridgeをインストール

    • 仮想HUBを作成して実家の仮想ハブにカスケード接続を設定する。
    • tapバイスにローカルブリッジするように設定する。(ここではtap_jikkaとした)
  • この時点でうまくローカルブリッジが動いていれば、数百msec遅延のping、すなわち日本経由でのpingが返ってくるはず。

$ ping -I tap_jikka 8.8.8.8

ラズパイのネットワークの設定

IPアドレスを固定

/etc/dhcpcd.conf で、下記行を追加して、eth0wlan0IPアドレスを固定する。

interface eth0
static ip_address=10.0.0.1/8

interface wlan0
static ip_address=192.168.50.111/24

udhcpd設定

DHCPサーバをインストールしてセットアップ。

  1. udhcpdをインストール。
  2. /etc/udhcpd.conf をデフォルトの設定を参考にしながら編集。
start           10.0.0.2        #default: 192.168.0.20
end             10.0.0.254      #default: 192.168.0.254
option  subnet  255.0.0.0
interface       eth0            #default: eth0
opt     dns     8.8.8.8
opt     router  10.0.0.1
option  domain  local
option  lease   864000          # 10 days of seconds
  1. 自動起動とかを設定
# systemctl enable udhcpd
# systemctl restart udhcpd

ルーティングやNATの設定

/etc/rc.localexit 0より前に下記記載を追加する。 これにより起動時にこれらのコマンドが実行され、再起動後も有効になる。

# パケット転送を許可
echo 1 > /proc/sys/net/ipv4/ip_forward

# 実家サーバへのアクセスは、常にUS側のゲートウェイを通るようにスタティックルートを設定
jikka_ip=$(ping <実家サーバドメイン> | head -n1 | awk 'BEGIN{FS="\\(|\\)"}{print $2}')
route add -host ${jikka_ip} gw 192.168.50.1 wlan0

# iptablesで転送の許可と、10.0.0.0/8 ネットワークへのIPマスカレード設定
iptables -I FORWARD -j ACCEPT
iptables -t nat -I POSTROUTING -s 10.0.0.0/8 -j MASQUERADE

ここまでで、eth0に繋がっている装置からインターネットに出ていこうとすると、10.0.0.1を経由して、192.168.50.1のルータ経由での通信となる。 

ここでデフォルトゲートウェイを下記コマンドで変更すると、日本のルータ192.168.0.1からインターネットに出ていくようになる。

# route add default gw 192.168.0.1 tap_jikka
# route del default gw 192.168.50.1 wlan0

Homebridgeで切り替えできるようにする

HomebridgeはApple HomeKitの装置を模倣するオープンソースプロダクト。 これを使って電球と同じような感じでiPhoneから切り替えられるようにする。

Homebridgeは導入済みとする。

  1. cmdswitch2プラグインを導入する。
# npm -g install homebridge-cmdswitch2
  1. config.json を編集する。
  2. on_cmdには日本ルータをデフォルトゲートウェイにする設定を入れる。
  3. off_cmdにはUSルータをデフォルトゲートウェイにする設定を入れる。また、VPNサーバへのスタティックルートが落ちる事があるので、ここで改めて追加するようにする。
  4. state_cmdには、日本ルータを向いているときに終了コード0を返すようなコマンドを設定する。
    {
      "platform": "cmdSwitch2",
      "name": "JP-US switch",
      "switches": [
        {
          "name": "JP net",
          "on_cmd": "sudo sh -c 'route add default gw 192.168.0.1 tap_jikka; route del default gw 192.168.50.1 wlan0; true'",
          "off_cmd": "sudo sh -c 'route add default gw 192.168.50.1 wlan0; route del default gw 192.168.0.1 tap_jikka; true'",
          "state_cmd": "ip route | grep default | grep jikka",
          "polling": true,
          "interval": 5
        }
      ]
    }

これでHomebridgeをrestartするとこんな感じにiPhoneに表示されるようになり、切り替えられるようになる。

Apple TVリモートを使えるようにする

この構成だとApple TVは10.0.0.0/8のネットワークにあり、iPhone192.168.0.50/24のネットワークにあるので、Apple TVからのBonjourマルチキャストDNS配信がiPhoneから見えないことになる。iOSにはAppleTVのリモコンとして動く機能があるが、この機能はBonjourに依存しているため、このままでは使えないことになる。

Bonjourの実装のひとつであるAvahi-daemonがRaspbianにはプリインストールされており、これのreflector機能を使って、プロキシとして機能して他のネットワークに伝播させることができる。

設定は、/etc/avahi/avachi-daemon.confenable-refrectoryesにして有効にすればOK。

enable-reflector=yes

ただしこれだけでは10.0.0.0/8への経路がiOSからは分からないので、家のルータにLAN側のスタティックルートを設定してやる必要がある。うちのASUSのルータだとこんな感じ。

複数インタフェースのサーバでHomebridgeがうまく動かないときの対処

TL;DR

config.json の一番上の階層に、mdnsプロパティを作って、HomebridgeにつなげるiOSバイスが居るネットワークに繋がっているインターフェースに割りあたっているIPアドレスを指定してやる。

{
  "bridge": {
    "name": "Homebridge",
    "username": "CC:22:33:44:55:66",
    "port": 51826,
    "pin": "031-45-155"
  },
  "mdns": {
    "interface": "192.168.50.123"   ←ココ
  },
  ....
}

詳細

RaspberryPiで、VPNサーバとHomebridgeをセットアップしようとしたところ、eth0とwlan0を両方使うと、wlan0側のネットワークからHomebridgeが見えなくなる現象が発生した。

avahi-browse -a でデバイスのアドバタイズがどうなっているのかを検索すると、Homebridgeのデバイスはeth0にしか流れていない。

どうやらデフォルトだと、先頭(?)のネットワークにしかmDNSのアドバタイズをしてくれないようで、eth0側にしか情報が流れていないらしい。

解決法

ソースを掘ると、配信はmulticast-dnsモジュールでやっている事がわかる。

multicast-dnsのコードを見ると、UDPのリスンはココでやっているので、interfaceオプションにインターフェースを示すIPを与えればいいことがわかる。

ここにオプションを渡すための変更が、このコミットで行われていたので、それに従って、config.jsonに設定を入れることで、うまく接続できるようになった。

Amazon Echo Wall Clock買ってみた

今年9月のイベントで発表されたAmazon Echo Wall Clockが発売されたのでポチってみたやつが届いた。

f:id:tomo-ono:20181224081631j:plain

付属品はペラいマニュアルと単3電池4本。電池はAmazon Basicのものだった。

デザインはシンプルで、文字盤がカバーで覆われておらず、むき出しになっているタイプの時計。

電池をセットして、マニュアルにかかれている通り、Alexaに「Setup Echo Wall Clock」というと、裏面の青いボタンを押すように言われる。

言われるがままに青いボタンを押すと文字盤中央のLEDが光り、ペアリング状態になる。しばらくするとAlexaがペアリングが完了したことを知らせてくれる。

この時計の機能は、普通の掛け時計に加えて下記の2つの機能しかない。

  • 時刻を自動で合わせる
  • タイマーが動いている場合、残り時間をLEDで示す

つまり時計だけではAlexaの操作もできないし、スピーカーにもならないということになる。

Alexaを使って5分タイマーを設定すると、下記のように0時から1時までの間のLEDが光り、残り時間が5分間であることを示してくれる。

残り時間が1minを切ると下記のように一周分を使ってカウントダウンしてくれる。

機能としては非常に少ないが、現在Alexaの一番の利用用途がタイマー機能なので、十分ペイすると考えている。 また、サマータイムがあるアメリカでは、時刻を自動で合わせてくれる時計は非常にありがたい。電波時計も試してみたが、家のあたりは電波が良くないようでうまく動かなかったので、これは嬉しい。

単3電池を4本も使うのはちょっと気になるところではある。使用頻度にもよると思うが、あまりに電池の持ちが悪かったりするとちょっと悲しい。。。 #初代ゲームボーイを彷彿させる。。。

また、日本に持っていけばそのまま動きそうなので、日本での発売もそれほど遠くないのではないだろうか?

Whole Foods Marketで生牡蠣Get

Wholefoods Marketの生鮮食品売り場カウンターで、生牡蠣が殻付きで1個1ドルで売られているのを発見した。

生牡蠣は好物なので生で食べれるか聞いてみたところ大丈夫らしい。

4個ほど買ってみた。殻は剥くか聞かれたので剥いてほしいと頼んだところ、お店で出てくるような氷満載のバットに並べて渡された。

f:id:tomo-ono:20181124184639j:plain

Wholefoods Market内にはバーコーナーも設けられているので「そこのバーで食べていってもいいよ」と至れり尽くせり。

家まで持ち帰って、ポン酢をかけて白ワインと頂く。身はしっかりしているし、以前近所のシーフード屋で食べたときのような消毒液の匂いもしない。非常に良いものを見つけた。

夏はバーベキューで焼いても良さそうだ。

なお、今の所食中毒の症状は出ていない。。。

D&Dやコピペでファイルアップロードできるtextareaをサクッと作る

GithubやQiitaなんかで使えるような、使い勝手の良い画像やファイル添付のTextareaをサクッと作った

使ったライブラリは Inline Attachement。 今回はレガシーWebAppに使ったので、JQueryで実装。

設定はドキュメントに掲載されているが、実はここに書かれている以上に拡張性があるので、コード自体を読むことをおすすめする。これによりやりたかったことは全て実現できた。

やりたかったこと

どんなファイルでも添付できるようにしたい

デフォルトだと画像ファイルに制限されているが、どんなファイルでも受け付けるようにしたかった。 コードを読んで、allowedTypes: ['*'] とすれば良いことがわかったのでそのようにした。

アップロードされたファイルの名前が、サーバサイドでわかるようにしたい

デフォルトだと、サーバサイドから見えるファイル名は、image-タイムスタンプ.拡張子となり、もとのファイル名がわからない。 ドキュメントに記載は無いが、remoteFilenameというプロパティに関数を入れてやると、引数にファイルオブジェクトを渡してくれるので、ファイルオブジェクトの内容を使ってファイル名を作成して返してやることで、サーバサイド側ではそのファイル名で見える。 例えば下記のようにすると、もともとのD&Dされたファイル名がサーバサイドに送付される。

    remoteFilename: (file)=>{return file.name}

ファイルの種類によって、埋め込まれるコードを変えたい

Markdown形式で入力するテキストエリアだったので、ファイルの種類によって埋め込まれるコードを修正したかった。

![image.png](url to image)   ←画像ならこっち
[document.docx](url to file)  ←ドキュメントならこっち

埋め込まれるコードは、urlTextプロパティで静的に設定できるが、このプロパティに関数を与えることで好きなデータに編集できる。 ファイルの種類はサーバサイドで判定したMIMEJSONに入れて返し、これを読んで画像ファイルか普通のファイルかどうかの判別がつくようにしてある。 また、リンク文字列ももともとのファイル名にしたかったので、同じくサーバサイドからオリジナルのファイル名を返して埋め込むようにしている。

    urlText: (filename,result)=>{
      if(result.mime.match(/image/)) {
        return `![${result.orig_file_name}](${filename})`
      } else {
        return `[${result.orig_file_name}](${filename})`
      }
    }

マウスオーバしたときにドロップできる感じを出す

ファイルをドラッグしてきたときに、textareaに点線で枠線を表示することで、ドロップできますよー感を出した。

textarea.dragover {
    border: dashed 6px #ccc;
    padding: 12px 6px 0px;
}
  $('textarea').on('dragenter dragover', function() {
    $(this).addClass('dragover')
  })
  $('textarea').on('drop dragleave dragend', function() {
    $(this).removeClass('dragover')
  })

最終型

JSはこんな感じ。

$(function(){
  // ファイル貼り付け
  $('textarea').inlineattachment({
    uploadUrl: 'upload_attachment.php',
    allowedTypes: ['*'],
    remoteFilename: (file)=>{return file.name},
    urlText: (filename,result)=>{
      if(result.mime.match(/image/)) {
        return `![${result.orig_file_name}](${filename})`
      } else {
        return `[${result.orig_file_name}](${filename})`
      }
    }
  });
  $('textarea').on('dragenter dragover', function() {
    $(this).addClass('dragover')
  })
  $('textarea').on('drop dragleave dragend', function() {
    $(this).removeClass('dragover')
  })
});

CSSはこんなん。

textarea.dragover {
    border: dashed 6px #ccc;
    padding: 12px 6px 0px;
}

PHPはこんなもんで。

$response = array();
$upload_directory = "/data/";
if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
 
    // MIMEタイプの取得
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime_type = $finfo->file($file['tmp_name']);
 
    // ファイルのID(=MD5ハッシュ)を計算
    $file_md5 = md5_file($file['tmp_name']);
 
    // ファイルの移動
    move_uploaded_file($file['tmp_name'], $upload_directory . "/" . $file_md5);
 
    $response['filename'] = "file_get.php?id=".$file_md5;
    $response["mime"] = $mime_type;
    $response["orig_file_name"] = $file["name"];
} else {
    $response['error'] = 'Error while uploading file';
}
echo json_encode($response);

BIABをAnovaでやってみた

個人でのビール自家醸造のやり方にBIAB(Brewing in A Bag)というのがある。これはビール醸造の最初の手順である麦芽の糖化(マッシング)にて、袋に麦芽を入れてそれをティーバックの要領で煮出すというやり方になる。使う鍋の量が少ないので、利便性が高く人気がある。

マッシング中は1時間以上に渡って温度を一定に保つ必要があるので、通常は定期的に温度を確認して、必要に応じて火にかけたりする必要がある。

要するにある程度の時間、水温を一定に保てばよいということなので、みんな大好き低温調理器Anovaが使えるんじゃないか?と思い、実際にやってみた。

Anovaは水を吸いこんでヒータで温度を上昇させ、水を吐くという仕組みになっている。Anovaに麦芽が吸い込まれるのはあまりよろしくなさそうなので、麦芽の入った袋の外側にAnovaを取り付ける。

今回は5galを仕込むので、その1.5倍の7.5galの水で煮出すことにした。

まずは鍋に水を張り、バッグとAnovaを取り付けてスイッチ・オン。マッシング温度は65℃とした。水の容量が大きいためAnovaだけの熱量だとパワー不足のため、最初は電熱コンロも併用する。

f:id:tomo-ono:20180908162707j:plain

65℃になった時点で麦芽を投入。最高水位線を超えてしまうことが懸念だったが、特に問題なかった。

f:id:tomo-ono:20180908163305j:plain

初めは非常に順調だったが、30分ほど経ったときに水量不足の警告音を出してAnovaが停止するようになってしまった。もちろん水量不足になるほど、鍋内の水は減っていない。誤検知かと思い、何度かスイッチをオンにしてもすぐに止まってしまう。

試行錯誤の上、Anovaの水を吸い込む口の部分にバッグと麦芽がへばりついて、水がうまく吸えなくなったので、水量不足という表示をしているのではないかと思いあたった。そこで、Anovaの水を吸い込む口のあたりにトングを突っ込んでバッグをブロックしてやったところ、うまく動作するようになってくれた。

次回は水を吸い込む口のところに、何らかのつっかえ棒などを取り付けて、バッグがへばりつくようなことが無いように工夫してみるつもり。

とにかくマッシングの工程は、多少エラーがでてまごついた部分はあったが、ほぼ全自動で完了させることが出来た。 比重も1052でほぼ狙い通りまで行けた。

ディズニーランド訪問雑感

自分が次回行くとき用のメモ。他の人にも役に立つかも。。。

空港(ロサンゼルス国際空港)からの交通

  • Disneyland Resort Express を利用した。(http://visitanaheim.org/partners/16394/the-disneyland-resort-express)
  • 冷房は寒すぎる。
  • 何故か車内ではToyStory2が流れている。
  • ホテルをいくつも回ってからパークに降ろされるので、パークに最初に行きたい人はDisneyland Hotelあたりで停車しているときに降りてしまうのが正解。
  • 往復で$48。行きのバスでDisneyland Hotelにて精算があった。カードのみで現金不可。
  • 公式サイトもドメイン期限切れで閲覧不可なのでなんともきな臭い感じ。次は別な方法を利用してみる。

アトラクション

ディズニーランド

  • インディ・ジョーンズ・アドベンチャー
    • シングルライダーで乗った。シングルライダーの人は出口から逆走して入るパターン。途中にエレベーターとかあるのでちょっとわかりにくい。
    • 日本のものとほぼ同じ構成。差分は煙幕吹きつけられる下りが無い位。
    • 写真撮影は無し。
    • ちょっと古い印象は否めない。
  • スペース・マウンテン
    • 改修後の日本のものとほとんど同じデザイン、構成。
    • 座席にスピーカーが付いており、終始ノリノリの音楽が流れている。
    • 最後に写真撮影あり。
  • スターツアーズ
    • こちらも改修後の日本のものと全く同じ。
    • Qラインの構成、映像も全部同じだった。
    • 観客の反応はノリノリなので面白い。
  • ビッグサンダー・マウンテン
    • 日本の強化版という感じ。
    • Qラインが日向なのでひたすら暑かった。
  • スプラッシュ・マウンテン
    • シングルライダーで乗った。シングルライダーの人は出口から逆走して入るパターン。ノンストップで乗れたので最高。
    • シートベルト類なし。ただただ座るだけ。
    • 日本よりも全体的に薄暗い感じ。
    • 水しぶきは日本より控えめか?
    • リュックを置くスペースもない程に席が狭い。
  • マッターホルンボブスレー
    • 一列タイプのコースター
    • 速度はそれほどでも無いが、線路が細く、急カーブがあるため妙に迫力がある。
    • 花やしきのジェットコースターに近い。
  • ディズニーランド・モノレール
    • ランド→ダウンタウンディズニー間で乗車。
    • どこを走っているのかの音声解説が入るので、一通り回ってからだと復習できていい感じだった。
    • スピードが結構出るので快適。
  • カリブの海賊
    • こちらも日本よりも何シーンか追加があるが、改装後のものとほぼ同じ。
    • ジョニー・デップは残念ながら不在。
  • オートピア
    • 日本のグランドサーキットレールウェイは終わってしまったがこちらは健在。
    • 提供がHONDAで、道端にASIMOが立っていたりする。
    • 日本のグランドサーキットレールウェイには装備されていた衝突防止機能がないので、普通にぶつかる。

カリフォルニアアドベンチャー

  • ラジエーター・スプリングス・レーサー
    • はじめはカートゥーンスピンみたいな感じだが途中レースモードになってからの迫力が凄い。なるほど話題になるだけの事があるという満足感。
    • シングルライダーで乗ったが、カップルの隣で激しく気まずかった。
  • グリズリー・リバー・ラン
    • ボート的なやつに乗って川下りする奴。
    • 笑えるくらい水がかかる。冬はどうするんだこれ。
  • カリフォルニア・スクリーミン
    • 引っ張り上げて落ちるのではなく、センター・オブ・ジ・アース的に下から急加速してスタートするジェットコースター。
    • ループあり。
    • コースといい感じに合わさった音楽も流れていて楽しめる。
    • スピード感だと一番か?
    • 写真撮影有り。
  • ソアリン・アラウンド・ザ・ワールド
    • 圧倒的な画質で世界遺産を飛んで廻るアトラクション。
    • 噂に違わぬ素晴らしさだった。
    • 最後にディズニーランドに戻ってきたときに観客から拍手が起こったのが印象的だった。
    • 日本にできるのが楽しみ。冒険とイマジネーションの海にピッタリだな。
  • モンスターズ・インク - マイクとサリーのレスキュー
  • ガーディアンズ・オブ・ギャラクシー:ミッション・ブレイクアウト
    • ガーディアンズ・オブ・ギャラクシー未見で大丈夫かと思ったが大丈夫だった。誰でも楽しめるように作られている。
    • 近くにMarvelオタクがいたので、彼らの話からトリビアをいくつも聞けたのが良かった。本当ならMarvelオタクに自分がなるか、オタクを連れて行くのがさらに楽しむためのコツだろう。
    • アトラクションの動きは基本タワテラだが、動きの激しさは遥かに上だったと思う。
  • キャラグリ
    • Disneylandのアプリでキャラクターのグリーティング場所と時刻を確認できるようになっている。
    • 時間近くになって行くと列が作られているので、それに並んでいると時間の10分過ぎぐらいにキャラがやってくるので、順番に写真をとるなりする感じ。
    • アメリカ人はめっちゃ話してたけどなんの話をしていたかは謎。。。

その他

缶バッジ

  • "1st Visit"の缶バッジを付けていた人に、どこでもらえるのですか?と聞いたら、キャストに言えば普通にもらえるよ!と言われた。キャストに貰いに行ってみるかーと思っていたら、「これ余ってるからどうぞ!」と缶バッジを分けてくれた。結構いっぱいもらっている人が多そう。
  • "Celebrating xxx"(xxxさんのお祝い) とか "Happyly ever after"(結婚系?)とかバリエーション色々あったので、試してみると良さそう。
  • TDRだと剥がれやすいシールだから、それと比べるとすごくいい。

混雑

  • 驚くほどに空いている。夏休み中の土日だから混む方だと思っていたが、全然そんなことはなかった。一番長く並ぶものでも80minとかで、シングルライダーファストパスを駆使すればメジャーどころは2日で全部回れる。

ファストパス

  • ファストパスは入園チケットを読み込ませて発券する。
    • カードスロットに差し込む感じなので、スマホとかでは無理っぽい。
  • 券が発見されるがそれ自体はただの時刻のメモに過ぎず、実際にファストパスで入るには、アトラクション入り口の機械に入園チケットを読み込ませる必要がある。
    • こちらは差し込まずにかざすタイプなのでスマホ利用可能。
    • 多分過渡期なのだろう。。。

警備

  • 入り口の荷物検査は結構厳重。金属探知機もあり。
  • リュックの中身をすべて出して確認+リュックの中身のケースとかもあればそれ全部開けて確認という厳重さだった。
  • 前に並んでいた中国人は、自撮り棒と大きめの手鏡でNG食らっていて、ホテルに持ち帰るように言われていた。
  • ディズニーランド、カリフォルニアアドベンチャーランド、ディズニーダウンタウン全体がこの荷物検査の内側なので、安全性は高いと思う。

年パス

  • 年パスには日本と違って写真が入らない。バーコードと名前だけ。
  • 最初に入場するときにスマホでパスポートのバーコードを読み取り、そのままスマホで写真が撮られる。移行はパスポートのバーコードを読み取ってもらうたびに画面にその写真が表示されるので、それで本人確認出来ていた。なるほど合理的。
  • 顔写真で確認できるので、再入園スタンプも必要なし。
    • ということは、すべてのパスで写真取られるようになっているかもしれない。
  • 飲食とお土産の購入が10%オフになる嬉しい特典つき。
    • STARBUCKS COFFEEでは利用できた。
    • ダウンタウン・ディズニーのお土産屋でも利用できた。
    • ビールはNGだった。アルコールはNGなのかもしれない。

Today

  • 案外しょっぱい

ダウンタウンディズニー

  • ディズニーリゾート内の商業施設モール
  • 要はイクスピアリですな。
  • 土産物を買うならここのWorld of Disneyが最適と思われる。
    • 両パーク内のお土産屋を垂直統合した感じ。ほぼすべてここで揃えられる。と思う。
    • 年パス10%割引も有効。