「芸能人やからってかしこまらんでええからね☺️」

部屋に入るとチュートリアルの徳井じゃない方に着席を促された。

「気にせんでええよ、おれもITとか勉強して行きたいなと思てたとこやし☺️」

部屋にはチュートリアルの徳井じゃない方しかいない。

「ほんで、なに?本書いてんの?Androidの、テスト?

 うーん、ええんちゃうかなと思うけどね俺は。

 ほんで、なに?下世話なハナシやけどどのぐらい売れんの?

 千?千かー。うーん。

 まあ、アレやん?書くことが大事いうかね。ほら名刺代わりにもなるし」

名刺代わりなぁ。

それからチュートリアルの徳井じゃない方は、芸人の根性を見せるために僕の目の前で本物の中華鍋を使ってアッツアツの八宝菜を炒めはじめ、直接素手で掴んで白菜をムシャムシャ食べ始めた。こっち!めっちゃこっち見てるから!

「まあITやろ?わかるわかる、ロンブー淳にも言うとくし☺️」

 

という夢を見たよ。

「Androidテスト全書」アーリーアクセス公開と査読のお願い

いま書いている「Androidテスト全書」は初稿がほぼ出揃い、アーリーアクセスが始まりました。僕の担当分では1, 2章をお読みいただけます。

お時間のある方は是非ともフィードバックください。少し時間を置いて読み直してみると、既に自分でも構成のまずい部分や言葉足らずなところが見えてきて忸怩たる思いです。ただ、ここから逃げずに真摯に向き合わないと本は良くなりません。どんな細かいところでも、感じた違和感でも良いので教えていただけると嬉しいです。

 

それから個人的には3章が僕の担当分の山場でして既に数人の友人に査読をお願いしたのですが、こちらももし僕の知人で興味のある方は是非査読していただけると嬉しいです。

  • 非同期処理のテスト
  • DBのテスト
  • RxJavaのテスト
  • 多層アーキテクチャ(MVP)のテスト
  • テストのないプロジェクトにテストを導入する

あたりを書いていて識者の意見を強く求めています。公開前原稿をお渡しする関係で、こちらに関しては知り合い限定となりますが、もしTwitter, Facebook, LinkedIn等でつながっている僕の知り合いでご協力いただける方はこそっと教えてください。

新規事業をひとりで作るノウハウ

生存報告も兼ねて。
 
カリフォルニアに来てもう半年ぐらい経った感覚ですが、実はまだ4ヶ月ほどでした。非常に多くの素敵な方々との出会いがあり、妻も僕も子供もこの皆さまの助けがあってどうにか生きております。どう感謝してよいか言葉にできないほどです。
 
さて、ビジネス上の僕のミッションは次の3つです。

  1. 主に投資や連携目的の交渉(の技術面のサポート)
  2. 日本との連携
  3. 新規事業の開発

どれもなかなか難しいです。会ってアポぐらいなら応じてくれる会社も多いですが、投資や連携といってもバブル崩壊以後経済成長できていない我が国はもはや「商習慣だけめんどくさいのに今やカネも持ってないから相手にしてられない連中」というのは肌で感じます。ご存知の通り、サンフランシスコ・ベイエリアはIT企業会社員が年収5000万円もらうような場所です。なかなか同じ規模感で会話するのが難しいレベルに達しています。

さて、クヨクヨもしていられないので、僕はプログラマの本分たるプログラミングによって少しでも生きた証を残すより他ありません。渡米以来自分の持ち時間の30-40%ぐらいを使って新規事業のプライベートアルファを公開するに至りました。対象ユーザが弊社内記者ということもあり、現時点でみなさまにお使いいただけないのは残念でしょうがないのですが、たったひとりでもサービスを公開まで持っていけるというのは我々にとって明るいニュースなので書いておこうと思います。
 

TL; DR いま新規事業やるならFirebase1択

今回自分が作ったのはウェブサービスですが、とにかくFirebaseが強いです。僕がこれから起業するなら、まずはFirebaseで作って運良く流行りそうならお金がかかる部分だけ書き換えるみたいなアプローチを間違いなく採るでしょう。今回使った技術スタックは次のとおりです。

TypeScript

後述するCloud FunctionsがNodeランタイムで動くのでJavaScriptは好むと好まざるとにかかわらず使わざるをえませんでした。僕は強い静的型付けが好きなのと、FunctionsにTypeScriptの例がたまたま載ってたのでTypeScriptを選びました。Flowを選ばなかったのは「店頭に並んでなかった」ぐらいのことで深い理由はありません。

まったく初めてでしたが次の2冊を読んで各30分の計60分でとりあえず書けるようになったのでおすすめです。そもそもC言語の子孫の言語なんてどれも青森弁と山形弁ぐらいの違いしかありません。

比較的快適に開発していますが、関数オーバーロードがさながらC言語のプロトタイプ宣言であるところや、これらで引数に取るインタフェース型がtype erasureによりinstanceofが使えないことから少し持って回ったようなハックが必要な点などいくつかまだ慣れないところはありますが、許容範囲というところです。

tsc watchは文句なく素晴らしく、息をするようにトランスパイルしてくれます。JSをまったく意識することがありません。

ユニットテスト

ユニットテストchai, mocha, ts-nodeを使っています。このエントリを真似しました。

Unit testing node applications with TypeScript — using mocha and chai

async/awaitを多様しているのでプラスしてchai-as-promisedを入れています。次のように使います。

import * as chai from "chai";
import { expect } from 'chai';
import * as chaiAsPromised from "chai-as-promised";
import 'mocha';
import { NLP } from '../nlp';

before(() => {
    chai.use(chaiAsPromised);
    chai.should();
});

describe('NLP', () => {
    const nlp = new NLP();

    it('should return [Amazon Alexa]', async () => {
        const keyword = "Amazon Alexa の取材";
        const list: string[] = await nlp.analyzeEntities(keyword, defaultFilter);
        expect(list).is.not.empty;
    });
});

ts-nodeでテストケースを個別に実行する方法がよくわからんかったので

{
  "name": "functions",
  "scripts": {
    "testall": "mocha -r ts-node/register src/**/*.spec.ts",
    "test": "mocha -r ts-node/register src/spec/$spec.spec.ts"
  }
}

みたいにして全体実行はnpm run testall, 個別実行はspec=[クラス名] npm run testみたいにしています。
もっといい方法があったら是非コメントください。

namespaceがイマイチ使いこなせない

なにぶん全てひとりでやっており誰もコードレビューしてくれないので経験者からすると眉をひそめるような作法で書いている可能性が高いです。
たとえばnamespaceはKotlinのpackageの感覚でディレクトリを掘ってファイルも分けていますが、次のようにfoo.tsとbar.tsを別ファイルに分けて同じ名前空間の下にぶら下げた場合、

// my_service/foo.ts
export namespace MyService {
    export class Foo {}
}

// my_service/bar.ts
export namespace MyService {
    export class Bar {}
}

利用する側で名前空間がバッティングしてるとimport * as aliasするしかなくてなんか不格好です。これはこういうもんなんでしょうか🤔
たぶんTSの作法がある気がするのでTS Wayをどなたか教えてください。

// import {MyService.Foo} from './my_service/foo'  no good!!
// import {MyService.Bar} from './my_service/bar'  no good!!

import * as foo from './my_service/foo'
import * as bar from './my_service/bar'

export class Baz {
    qux() {
        const hoge: foo.MyService.Foo = new foo.MyService.Foo()
        const fuga: bar.MyService.Bar = new bar.MyService.Bar()
    }
}

Cloud Functions

いわゆるサーバレスにファンクション単位でデプロイできるやつです。これはとにかく素晴らしいです。

export const foo = functions.https.onRequest(async (request, response) => {
    try {
        const token: Credentials = await readToken(request.query.account)
        const resp = doSomething(token)
        response.send(resp);
    } catch (error) {
        sendError(response, error)
    }
});

こんなの書いておくだけで設定したエンドポイントに対応するファンクションが起動します。
HTTPトリガの他にバックエンドで各種イベントトリガに応答して処理を行うことができます。後述の通りPub/Subも使えます。
これの何がいいって、フレームワークだのミドルウェアだのつまらない知識をためなくても一筆書きでとりあえずサービスを提供できるんですよね。

サーバレスというと弊社ではAWS Lambdaを使っていますが僕はCloud Functions 1択でした。それはFirebaseとの連携性です。FirebaseのリアルタイムDBであるFirestoreのドキュメントへのイベントを検知してFunctionをトリガできるのは便利です。他にも認証トリガなんてのもあってアツイです。

Cron Job

単独でcron jobはできませんが、これはGAEと組み合わせればできます。次のエントリに詳しいです。

developers-jp.googleblog.com

端的にいうとGAEの持つCron機能をPub/Subで購読するというものです。GAEを一切使ったことがなくてもこのエントリの通りにすれば'hourly-tick'だの'minutely-tick'だのに反応するファンクションを書いておけばトリガされます。

export const batch = functions.pubsub.topic('hourly-tick').onPublish(async (event) => {
 // do whatever you like
});
Local Emulation

ファンクションはデプロイする前にローカルでいくらでも試せます。

Run functions locally  |  Firebase

リンクにほとんど書いてあるので特に補足はないのですが、firebase serve でローカルにまるっきりfirebase hostingとcloud funcionsのローカル版が立ち上げるのでcurlなりブラウザなりで試すことができます。
firebase functions:shellとかするとTCP/IPではなく対話的シェルのような感じでファンクションごとにエミュレートができます。ここでFirestoreの読み書きもテストできます。
個人的には前者で実際にFirestoreにつなぎに行ってInstrumentedにテストできるので後者はほとんど使ってませんが便利な使い方を今後発見するかもしれません。

それから、OAuth2のリダイレクトとかをテストするときにLocal Emulator環境なのかデプロイ後だったのか区別する必要があり、これはちょっと簡単にわからなかったので環境変数のようなやつを使いました。

Environment configuration  |  Firebase

これはコマンドラインから設定できる環境変数的なものです。

firebase functions:config:set my_service.is_local=true

みたいにして設定するとサーバに直接設定されるんですが、ファンクションのディレクトリに.runtimeconfig.jsonという形式で置いておいて適宜中身を書き換えるとローカルエミュレータではその値が使われます。アクセスするのはローカルもデプロイ後も同様です。

firebase functions:config:get > .runtimeconfig.json
const IS_LOCAL: boolean = JSON.parse(functions.config().my_service.is_local);
const HOST_NAME = IS_LOCAL
    ? `http://localhost:5001/${process.env.GCLOUD_PROJECT}/us-central1`
    : `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com`;

Cloud Firestore

これはドキュメントベースのNoSQLなんですが、JSON状のデータ構造のあるパスを購読しておくとそこに対する読み/書き/削除/更新を全部通知してくれます。
オフライン対応してる、というか、利用者はすべてローカルコピーを真として読み書きする作りになっており、「オフラインになった!」という状態が存在しないと考えることができます。
結果、安全にデータの読み書きができます。
オンラインになるとこのローカルコピーは勝手にサーバのマスターデータともいうべきものと同期をかけます。同期後はそれが前述の更新イベントとして飛んでくるだけというわけです。

ここに敢えて貼りませんが、僕は2014-5年からFirebaseユーザでその頃はFirebaseといえばこのリアルタイムデータベース(いまのFirestoreはその後継)しかなく、僕はそれの連載記事を持っていたぐらい愛好者でした。
で、新規事業にあえてこのリアルタイムDBを使う必要もないんですが、別に使わない理由もなくて、割と雑になんでもデータを突っ込んでいます。ここも高くなったら置き換えるぐらいの気持ちです。早すぎる最適化は不要です。

Firebase Authentication

これは認証を楽ちんにしてくれるライブラリです。

Get Started with Firebase Authentication on Websites  |  Firebase

これもほとんどコメントの必要もないほど充実してるんですけど、認証時にFirebase内で一意なユーザ識別子を持って、あとからGoogleだのGitHubだの別の認証プロバイダで認証したときにそれらを全部ひもづけることができるので、複数の認証プロバイダに対応予定なら激つよです。

一点、この方法だとリフレッシュトークンがどうやらもらえない(リフレッシュ自体はできる)っぽくって、リフレッシュトークンがないと裏でCron Jobでトークンを更新しつつ他のAPIを叩くみたいなのができないので、僕は結局後述するGoogleのOAuthライブラリで手認証するのと組み合わせています。

Google APIs Node.js Client

これがとにかく素晴らしい。Google謹製のNodeライブラリ群ですけど、

  1. TypeScriptで書かれていて型情報がそのまま利用できるものがほとんど
  2. 非同期処理はほとんど余すところなくPromiseを返すようになっており、こちらが努力ゼロでasync/awaitできる

もう説明の必要もないですね。async/awaitできると同期的に待ち合わせるように非同期のコードが書けるし、他言語で同様の仕組みをもったプログラマが参入しやすいです。プログラムのバグと苦しみは非同期処理に根ざすものが非常に多いですからね。
一点、Listをmapしながら全てのasyncの完了を待ち合わせるような処理は書き方をすぐ忘れるのでメモしときます。

const tokens: [string, Credentials][] = await readTokens()
const resultAll = await Promise.all(
    tokens.map(async token => {
        const identifier = token[0]
        const credential = token[1]
        return result = await doSomethingWithToken(credential)
    })
)

あとは複数の非同期処理を一気にdispatchしてzipper関数で待ち合わせてまとめるzipみたいなのはちょっとまだ見つけてません。
まあそのものズバリのRxJSってのもあるしなんとでもなりそうです。

Cloud Natural Language

最後ですけどGoogle製の自然言語処理のライブラリを使いました。ノイズの多い文章から品詞ごとに取り出したりするのに非常に便利です。
この部分はサービスが大ヒットしたら自前のライブラリで置き換えても良いのだし、最初にNLP詳しくない僕みたいな者が曲がりなりにも実用に耐えうるデモを作れるのは、この分野では考えにくいことだったので、まったくありがたい話です。

まとめ

「ガチガチにロックインされてそうだけど大丈夫?」的な質問を飲み屋の会話(僕は一滴も飲めませんが)レベルでされたことがあったんですが、それが何か?という感じです。
言語、フレームワーク、思想とプログラマは色んなものにロックインされています。価値検証段階でそれらが何かにべったり依存していることは取るに足らないことだと思います。そもそも僕の稼働時間は僕一人が活動時間の3-4割で実質ひと月ぐらいで書いたので、本当にイケるとなったらいくらでも書き換えたらいいです。

最後にこの開発を開始して僕の人件費を仮にゼロと考えた場合の総コストは…!

f:id:fushiroyama:20180807042638p:plain

ジャーン!開発期間中0ドル、サービスインして本日までの合計は77セントでした!ありがとうございます!

フォーチュンクッキーは恋をしない

ジョジョのサブタイトル風に。

 

中華料理屋でもらえるフォーチュンクッキーマジでいらないんだけど捨てるほどではない。で、ほっとくとパンダエクスプレスヘビーユーザーの私の机の上には一生食われないフォーチュンクッキーがうず高く積み上がってそのうちカリン塔に届きそうである。

 

f:id:fushiroyama:20180526072702j:plain

 

これ何かに似てるなと思ったら、サービス開発時にユーザのことをよく考えずに"良かれと思って"機能を付け足しまくった挙げ句、捨てるには惜しいからそのまま残した結果、本当に必要な機能がウォーリーをさがせになるあの状況だ。要らないものは最初から付けないのがベストなのである。

 

サービス開発でもっとも重要なことは「足す」ことではなく「引く」勇気だ。従ってこれから僕は要るかどうか疑わしい自称・付加価値のことをフォーチュンクッキー・フィーチャーと呼称して、積極的に排除するキャンペーンを実施する。みんな積極的に使ってくれよな!

ドアは正面についてるとは限らない

siliconvalleyrw.com

を読んで「波が来たときにそれに乗れる準備をしておく」という部分に非常に共感したのでチャンスに対する自分の考えを残しておく。

ドアは正面についてるとは限らない

自分はこの事実に気付くまでに30年を要したが、物事を達成するために正面から玄関をノックしてお邪魔していく必要はない。自分がバカ正直に入り口の行列に並んでいる横で、風呂場の窓からひょいっと中に入っていく人を横目で眺めていた。昔は「あれは行儀が悪い。自分は絶対に待機列で耐える」と思っていたけど最近は違う。人生は短い。

 

これは架空の話だが、ある男がどうしても米国に行きたかったとする。会社でその枠を掴み取れるのは1名だとする。それに選ばれるにはどうするかという話だ。くじ引きで当選するのを待つ?いやいや。

自分が米国に行きたいことを1on1の度に、雑談の度に伝えるのだ。それだけじゃなくて、これこれしかじかのスキルを持つ自分を送り込むのがどれだけ会社にとって自然なことであり、将来的な利益になるのかストーリーを作るのだ。

エンジニアなら分かるだろう、

f:id:fushiroyama:20180519202721p:plain

こんなん理由がないとブロックするだろう。

で、後はそれがどのくらい真剣で深刻で他に選択肢がないことなのか伝えるのだ。たとえば米国企業の内定がもうあるとか、ね。これはすべてフィクションだけど、そういうことだ。

 

で、これだけだと自分の都合だけを考えたクソ野郎なのでもちろんそんな幸運は降ってこない。やっぱり自分が何かを求めるからには、それと同等以上のことを相手に与えなければならない。普段から自分の責務を果たし、相手が困っているときにはそれを助け、言い方は悪いけど「貸し」を作っておくといざ自分がどうしても何かを相手にしてもらいたい時に利子つきで返ってくることもある。

 

で、冒頭の話に戻るんだけど、やっぱりチャンスというのは与えられるものじゃなくて自分からわしづかみするもんだと思うんだよね。みささんが

やっぱり波が来たときにちゃんとそれに乗れる準備をしとかないといけないと思うんですよね。

 といみじくも仰ってるように、やはり帆を張ってるからこそ追い風は吹くのである。

 

ここまで書いたところで寝室のドアから愛娘がうなされる声が聞えるので添い寝してきます…じゃあの

拠点間VPNで日米それぞれのネット環境を活用する

様々な理由で日本経由でインターネットに接続したいケースがある*1
ここでは日本(Bフレッツ)と米国(Xfinity)間でVPN接続し、ユーザは接続するWiFi SSIDを変えることで透過的にそれぞれの経路でインターネットに出ていけるようにすることをゴールとする。

なお、自分がたまたまYAMAHA RTX1100を2つ持っていたという理由だけでこれらを日米に配して拠点間VPNを構築したが、RTX1200以降のモデルは2つの拠点間で同一セグメントを構築できるらしい*2ので、もう少し簡略化できる可能性がある。また、最近はEdgeRouterXというルータが低価格かつ高性能らしいので、そういったものを使ったほうが近代的かも知れない。
ただ、基本的なルーティングの考え方は製品に依らず普遍的なので、同じようなことを検討している方には参考になるかも知れない。

Xfinity設定

Xfinity(Comcast)は本質的にケーブルテレビ網を使ったインターネット接続なので、WAN側アドレスはDHCPで割り振られる。そこを押さえておけば設定は容易い。

ComcastモデムのBridge Modeを有効化

Comcastのモデム(兼ルータ+WiFiスポット)はデフォルトで 10.0.0.0/24 のLANなので 10.0.0.1 でモデムの管理画面に入る。認証は初期状態で admin/password

Bridge ModeEnable へ。
Turn Bridge Mode On and Off on Your Wireless Gateway

この時点でモデムはグローバルIPを失う(当然)ので注意。

ルータをとりあえずネット接続

前述の通りWAN側アドレスをDHCPでもらう。ここではLAN2ポートをモデムのLAN1*3に接続する。
LAN1の4ポートを室内LANとしてこのセグメントを 192.168.22.0/24 ゲートウェイ192.168.22.1 とした。

ip lan1 address 192.168.22.1/24
ip lan2 address dhcp
ip lan2 nat descriptor 1
ip route default gateway dhcp lan2
nat descriptor type 1 masquerade
nat descriptor address outer 1 primary
dhcp service server
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.22.100-192.168.22.199/24 expire 12:00 maxexpire 12:00
dns server 8.8.8.8 8.8.4.4 1.1.1.1
dns server dhcp lan2
dns private address spoof on

Bridge Modeを有効化した直後は設定が合っているのになぜかうまくWAN側アドレスをもらえなかったのでモデムを再起動したりしてるうちに5分ほどで降ってきた。

拠点間VPN設定

ネットボランチDNS

YAMAHAが無料で提供するDDNSサービス。VPNを利用するためには両拠点にグローバル固定IPが必要だけどこれでほぼ解決できる。
僕がYAMAHAのルータの大ファンなのはこのネットボランチDNSも理由のひとつ。

[PPPoEの場合]
netvolante-dns hostname host pp [希望するアカウント名]
netvolante-dns go pp 1
[CATVの場合]
netvolante-dns hostname host lan2 [希望するアカウント名]
netvolante-dns go lan2

振り出されたホスト名をメモしておく。

VPN設定

ここではまず簡易的にIPSecトンネルで設定しているが、適宜L2TP等利用して欲しい。
なお日本側LANは 192.168.11.0/24 ゲートウェイ192.168.11.1 とした。

[米国側]

tunnel select 1
 tunnel name VPN-USA
 ipsec tunnel 1
  ipsec sa policy 1 1 esp 3des-cbc sha-hmac
  ipsec ike hash 1 sha
  ipsec ike keepalive log 1 off
  ipsec ike keepalive use 1 on
  ipsec ike local address 1 192.168.22.1
  ipsec ike pre-shared-key 1 [passphrase]
  ipsec ike remote address 1 tokyo.foo.netvolante.jp
 tunnel enable 1

nat descriptor masquerade static 1 1 192.168.22.1 udp 500
nat descriptor masquerade static 1 2 192.168.22.1 esp
ipsec auto refresh on

ip route 192.168.11.0/24 gateway tunnel 1
[日本側]

tunnel select 1
 tunnel name VPN-USA
 ipsec tunnel 1
  ipsec sa policy 1 1 esp 3des-cbc sha-hmac
  ipsec ike hash 1 sha
  ipsec ike keepalive log 1 off
  ipsec ike keepalive use 1 on
  ipsec ike local address 1 192.168.11.1
  ipsec ike pre-shared-key 1 [passphrase]
  ipsec ike remote address 1 usa.bar.netvolante.jp
 tunnel enable 1

nat descriptor masquerade static 1 1 192.168.11.1 udp 500
nat descriptor masquerade static 1 2 192.168.11.1 esp
ipsec auto refresh on

ip route 192.168.22.0/24 gateway tunnel 1

これでトンネルと相手側LANとのルーティングは完了。対向側にpingを投げてみて応答があるか確認する。
うまく通らない場合は show status tunnel 1 でトンネルインタフェースの状態確認してみたり nslookuptraceroute でどこに問題ががあるか切り分けていこう。
後述するが、フィルタの設定が不適切でネットボランチDNSで相手側ホストが名前解決できなかったりしたので、VPN対向側のネットボランチDNSホスト名と解決後のグローバルIPに対してそれぞれpingを打ってみても良い。
syslog debug on して show log すると名前解決ができなかったような事情もログに出ている。

VPN(IPsec)接続ができない

米国のLAN3セグメントを日本経由にする

さて、VPNトンネル越しにお互いのセグメントを行き来できるようになったら、いよいよ本題の「特定のSSIDWiFiに接続すれば何も考えずとも日本経由でインターネットに出ていく」件を設定する。

  1. LAN3セグメントを 192.168.33.0/24 ゲートウェイ192.168.33.1 とする
  2. ソースアドレス 192.168.33.0/24 はトンネルインタフェースをゲートウェイとしてインターネットに出る

これを念頭に設定する。繰り返しになるが最近のルータは拠点間で同一セグメントを利用できたりするらしいので、その場合はこの設定は必要ない可能性がある。

[米国側]

ip route default gateway dhcp lan2 filter 1 2 3 4 gateway tunnel 1
ip lan3 address 192.168.33.1/24

ip filter 1 pass * * udp * 500
ip filter 2 pass * * esp * *
ip filter 3 pass * * udp,tcp domain *
ip filter 4 pass 192.168.22.0/24 *

dhcp scope 2 192.168.33.100-192.168.33.199/24 expire 12:00 maxexpire 12:00
[日本側]

ip route 192.168.33.0/24 gateway tunnel 2

見ての通り、フィルタ1, 2でVPNネゴシエーション用のパケットを、フィルタ3でDNS問い合わせのパケットを、フィルタ4でソースアドレス 192.168.22.0/24 のパケットをComcast側に通し、それ以外は全部トンネル経由で日本側から出すルールを書いた。
当初DNSを見落としており、なぜかVPN接続が確立できなくてログをみていたら、対向側ホスト名の名前解決に失敗していた^^;

あとは適当な無線LANルータを買ってきて米国側LAN3ポートにぶらさげれば*4、このWiFiルータに接続した端末は特に何も意識しなくても日本経由でインターネットに出ることができる。この方法だとデスティネーションアドレスごとにルーティングの設定を変えたりする必要がなくて非常に楽である。めでたしめでたし。

全体像

一応全体を見渡せるように。
言うまでもなく、これは必要な部分だけを抜粋しているので、実際の運用はご自身でルールを追加してください。当方は結果に一切責任を負いません。

[日本側]

login password *
administrator password *
login user foo *
security class 2 off on
timezone +09:00
console character ascii
console prompt [RTX]
login timer 3600
ip route default gateway pp 1
ip route 192.168.22.0/24 gateway tunnel 1
ip route 192.168.33.0/24 gateway tunnel 1
ip lan1 address 192.168.11.1/24
pp select 1
 pp name [Provider]
 description pp [Provider]
 pp always-on on
 pppoe use lan2
 pppoe auto connect on
 pppoe auto disconnect off
 pp auth accept pap chap
 pp auth myname *** ***
 ppp lcp mru on 1454
 ppp ipcp ipaddress on
 ppp ipcp msext on
 ppp ccp type none
 ip pp mtu 1454
 ip pp nat descriptor 1
 netvolante-dns hostname host pp server=1 japan.foo.netvolante.jp
 pp enable 1
tunnel select 1
 tunnel name VPN-USA
 ipsec tunnel 1
  ipsec sa policy 1 1 esp 3des-cbc sha-hmac
  ipsec ike hash 1 sha
  ipsec ike keepalive log 1 off
  ipsec ike keepalive use 1 on
  ipsec ike local address 1 192.168.11.1
  ipsec ike pre-shared-key 1 ***
  ipsec ike remote address 1 usa.bar.netvolante.jp
 tunnel enable 1
nat descriptor type 1 masquerade
nat descriptor address outer 1 ipcp
nat descriptor address inner 1 auto
nat descriptor masquerade incoming 1 discard
nat descriptor masquerade static 1 1 192.168.11.1 udp 500
nat descriptor masquerade static 1 2 192.168.11.1 esp
ipsec auto refresh on
telnetd service off
dhcp service server
dhcp duplicate check 100 off
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.11.100-192.168.11.199/24 expire 12:00 maxexpire 12:00
dns server 8.8.8.8 8.8.4.4 1.1.1.1
dns server pp 1
dns private address spoof on
httpd host lan
sshd service on
sshd host 192.168.11.1-192.168.11.254
sshd host key generate *
[米国側]

login password *
administrator password *
login user foo *
security class 2 off on
timezone -07:00
console character ascii
console prompt [RTX]
login timer 3600
ip route default gateway dhcp lan2 filter 1 2 3 4 gateway tunnel 1
ip route 192.168.11.0/24 gateway tunnel 1
ip lan1 address 192.168.22.1/24
ip lan2 address dhcp
ip lan2 nat descriptor 1
netvolante-dns hostname host lan2 server=1 usa.bar.netvolante.jp
ip lan3 address 192.168.33.1/24
tunnel select 1
 tunnel name VPN-USA
 ipsec tunnel 1
  ipsec sa policy 1 1 esp 3des-cbc sha-hmac
  ipsec ike hash 1 sha
  ipsec ike keepalive log 1 off
  ipsec ike keepalive use 1 on
  ipsec ike local address 1 192.168.22.1
  ipsec ike pre-shared-key 1 *
  ipsec ike remote address 1 japan.foo.netvolante.jp
 tunnel enable 1
ip filter 1 pass * * udp * 500
ip filter 2 pass * * esp * *
ip filter 3 pass * * udp,tcp domain *
ip filter 4 pass 192.168.22.0/24 ***
nat descriptor type 1 masquerade
nat descriptor address outer 1 primary
nat descriptor masquerade static 1 1 192.168.22.1 udp 500
nat descriptor masquerade static 1 2 192.168.22.1 esp
ipsec auto refresh on
telnetd service off
dhcp service server
dhcp server rfc2131 compliant except remain-silent
dhcp scope 1 192.168.22.100-192.168.22.199/24 expire 12:00 maxexpire 12:00
dhcp scope 2 192.168.33.100-192.168.33.199/24 expire 12:00 maxexpire 12:00
dns server 8.8.8.8 8.8.4.4 1.1.1.1
dns server dhcp lan2
dns private address spoof on
httpd host lan
sshd service on
sshd host 192.168.22.1-192.168.22.254
sshd host key generate *

その他

久しぶりにRTXを触ったのと、シリアルクロスケーブルとかも忘れてきたので、その状態で設定をリセットしてIPを振ってファームウェアを更新するまでにちょっと苦労した。
自分のためにメモを残す。

リセット

背面INIT近くの穴をピンで推しながら電源を入れる。LAN側IPアドレスも失うので注意。

IPを振る

シリアルクロスケーブルがあれば最も話が早いんだけどそれがない場合、RARPを使って設定してもいいんだけどこれが結構面倒くさいのでIPv6マルチキャストを使う。
RTX1100と自機をLANケーブルで接続して

# eth0はケーブルを挿したネットワークインターフェース名

ping6 -I eth0 ff02::2

すると 64 bytes from xxx::xxx:xxx:xxx:xxx%eth0: icmp_seq=1 ttl=64 time=1.00 ms みたいに応答があるので telnet xxx::xxx:xxx:xxx:xxx%eth0 するだけ。あとは好きなように設定できる。超簡単!

ファームウェア更新

tftpを使うのが簡単。

  1. firmware release for Yamaha Network Products ここからファームウェアをダウンロード。md5sumを取って念の為確認。
  2. ルータで tftp host any or tftp host クライアントPCのIP で許可
  3. 次のコマンドの通り
tftp ルータのIP
tftp> mode binary
tftp> put rtx1100.bin exec

mode binary がミソ

僕が2005年ぐらいにプロになって初めて使ったルータなのでつい思い入れを持って10年以上愛用してしまっている。まあ良いルータですね!

*1:理由は察して欲しい

*2:2つの拠点間で同一セグメントのネットワークを構築する

*3:どこでも良い。ただし接続するのは1ポートのみ。

*4:VLANをサポートするWiFiルータを持っていればハードウェアを買い足す必要もないとの指摘を受けた。

Burlingameで子育て世代と友達になりたい

カリフォルニア州バーリンゲームに引っ越した。

f:id:fushiroyama:20180518085404j:plain (庭にリスが住んでる)

主題

最初に最も伝えたいことを書く。
バーリンゲーム近郊で子育てをしている日本人の親御さんがいらっしゃったら是非友達になってください。
妻と子供は英語がまだ苦手で何をするにも苦労をしています。とにかく似たような境遇の友人を求めています。
https://www.facebook.com/fumihiko.shiroyama
当方連絡先です。よかったらメッセージください!ご連絡いただけたらこちらから遊びに参ります。

バーリンゲームについて

バーリンゲームはサンフランシスコ半島の中程にあるサンマテオ郡を構成する市のひとつで、北はミルブレー市、南はサンマテオ市に隣接している*1
仕事柄オフィスのあるパロアルト市に週3ほど、コワーキングオフィスのあるサンフランシスコ市内に週2ほど行く必要があるので、ちょうど中間地点のこの街を選んだ。
ダウンタウンは美しく、小学校の学区は非常に良く*2、カルトレインも利用できるのでとても良い街だと感じる。

新生活

とにかくこのひと月はひたすら引っ越しと住環境の構築をしていた。

f:id:fushiroyama:20180518085436j:plain

こちらはユニットバスなのでどうやってアカチャンを風呂に入れてよいかも分からない。
とりあえずシャワーヘッドは手に持って使えるタイプに交換した。一体こちらの人はどうしているのか。

f:id:fushiroyama:20180518085504j:plain

お尻に致命的な脆弱性を抱えているので便座はもちろんウォシュレットに交換した。
電源はドライヤー用のものを延長コードで引きつつ、管理人さんには便器裏にアウトレットの増設を相談したが、水回りに近すぎるということであっさり断られた。

f:id:fushiroyama:20180518085521j:plain

キッチンも勝手が全く違う。電熱線はすぐに温まって便利かと思ったが、火力を半分に調整してみたら熱源の出力が半分になるのではなく、フルパワーの電熱線が定期的にON/OFFを繰り返すことで結果的に半分の出力を実現していた。そんな設計ある…?

f:id:fushiroyama:20180518085537j:plain f:id:fushiroyama:20180518085559j:plain

リビングは一般的にどの物件も広い。2 Bedroomで探すとだいたい日本の2LDKに相当する。

f:id:fushiroyama:20180518085645j:plain

こちらでは相当小さいうちから子どもたちだけで寝るらしい*3が、我々は日本人なのでキングサイズベッドに家族4人でねんねすることにした。

f:id:fushiroyama:20180518085841j:plain

車も2台買った。
うちは駅から徒歩3分ぐらいなんだけど、やっぱり東京とはまったく勝手が違ってJR予讃線ぐらいの頻度でしか電車が走ってないので、どうしても大人の人数ぶん車が必要になる。
それだけ燃料代も維持費も保険料もかかるわけで、正直ベイエリアで16万ドルぐらいもらっても東京の年収800万ほどの暮らししかできないと感じる*4。だからインターネッツで「シリコンバレーのエンジニアはこんなに給料をもらっている!」みたいな記事を見かけてもハイハイワロタと思って流して欲しい。そのぐらいもらわないと生きていけないのだから。

雑感

ベイエリアで暮らしていてこれだけは文句なしに良いなと思うことが2つある。
1つは「天気」、もうひとつは「起業と成功のサイクルが確立されていること」

f:id:fushiroyama:20180518090651j:plain

天気は本当に素晴らしい。この地で家賃40万も毎月払って歯を食いしばって暮らしているのは天気に課金しているといっても過言ではない(過言)。

もうひとつは「起業と成功のサイクルが確立されていること」
ベイエリアの成功者が自分の母校−たとえばスタンフォードやUCバークレーの後輩に積極的にカネを出し、のみならずアドバイスやネットワーキングなど全面的にサポートする土壌がある。
これが次の成功者をうみ、次のエンジェルをうみ、彼らが大学に寄付をし…そうやって回っている*5

僕は起業したいという気持ちはさっぱりないんだけど、この地で自分のソフトウェア技術者としての可能性を試したいし、その旅はまだ始まったばかりで何も達成していない。
とにかくまずは最初の一年をしっかり過ごしたい。色々ご指導ください!

*1:サンフランシスコ国際空港から南に車で10分という方が伝わりやすいかもしれない。

*2:「学区が良い」というのは意味が分からん日本語かもしれないが、カリフォルニア州では学区を超えて勝手に公立小学校を選ぶことができないため、学区内の小学校がどれも成績優秀な地域は子育て世代に大変人気となる。

*3:ただし情報ソースはモンスターズインク

*4:家賃も医療費も東京の4倍ぐらいかかる。保育園もこども1人につき20万以上/月かかる

*5:尤も、これも表の面と裏の面がある。実際には「白人」「男性」「スタンフォードコンピュータサイエンス卒」みたいな判を押したようなパターンしか舞台に上らせてもらえないという批判もあるようだ。