REST API フレームワーク Connexion のススメとその作例

Python の Connexion というフレームワークとそのサンプルアプリケーションを書いたのでその紹介です。


Connexion は「API (spec) First」を謳うフレームワークです。

API First」とは、 ご存じ The Twelve-Factor App の追補として 2016 年に Pivotal 社が提唱したガイドライン Beyond the Twelve-Factor App の中のひとつです。

簡単にいうと、コードを書き始める前にまずAPIの仕様を定める。たとえば昨今のマルチデバイス対応のような複数チームで開発を進めるような現場で、お互いこのAPI仕様を拠り所とすることで、他方の開発プロセスに干渉することなく、円滑に開発を進めることができる、というものです。 (たぶん)

Connexion はこの API First を実践するのを助けてくれるプロダクトで、OpenAPI (過去に Swagger spec と呼ばれていたものです)で記述した仕様を軸として次のことが実現できます。

  • API 利用者向けのドキュメントを生成できる
  • 仕様に記述した入力パラメータの validation ルール(必須パラメータのあり/なしとか、正規表現で記述した値の形式チェックとか)を自動で実施してくれるので、適用コードを一切書く必要がない

現職で API サーバーを 3 つ実装して、今は Connexion で 4 つめを実装しているのですが、ドキュメントと実装の乖離は頭の痛い問題でした。具体的にいうと、値の形式チェックのルールをちょっと変えたんだけどドキュメントに反映しわすれていたとか、初期に書いたドキュメントの一部が実装から漏れていたとか、みなさんも容易に想像できるんじゃないでしょうか。

また、エンドポイントの情報(HTTPのメソッドとパス)をドキュメントと controller を呼ぶ router の両方に書かないといけないのが常々無駄だと思っていたのですが、Connexion が仕様を読んで所定の controller のメソッドを呼んでくれるので router を記述する必要がなくなったのもよい点の1つです。

Connexion を使うことでこういった問題から解放されたので本当に助かっています。

ほかにも API の動作をちょっと試したりデモするのに便利な Web UI のダッシュボードがついていたり、OAuth 2 のトークンベースの認証に対応していたりといろいろと特徴があるので詳しくは Connexion のサイトをみてみてください。


そんなこんなでここしばらく Connexion の試し書きをしていました。

などのサンプル実装を大いに参考にさせてもらったのですが、もうちょっと実践的な作例を書いてみました。

  • データストアは RDBMS で、 SQLAlchemy ORM の declarative mapping を使用
  • Connexion (の内部の Flask )との連携は Flask-Alchemy を使用
  • ORM のシリアライズ(dict化)には sqlathanor を使用
  • サンプルとして 2 つのテーブル(リソース)を定義して、one-to-many のリレーション
  • 検索条件の処理は、所定の SQL っぽい記法(JSON)でリクエストをすると、いい感じに SQLAlchemy の query オブジェクトを返してくれる簡易 query builder を書いた
  • pytest と WebTest を使ってテストも用意した

まだまだ Python は B- ぐらいウデマエの上に SQLAlchemy なども使ったことがなかったので、「こう書いたほうがいいでし!」とかあったらぜひ プルリ お待ちしています!

たくさんのホストにpingするのに便利なツールpingerを書きました

たくさんのホストにpingするのに便利なツールpingerをgoで書きました。

こちらから Linux, macOS, Windows 用のバイナリがダウンロードできるので是非お試しください。(手元に環境がないのでWindowsでは動作確認していません)

メンテナンス時、特にネットワーク関連のメンテには、多数のホストへの到達性をモニタリングしがら作業したいことがあると思いますが、(自分が知ってる限りの)既存のツールでは一覧性がよいものがなかったのがこのpingerを書いた動機です。

pingerを実行すると、このように上部には指定したホストの状況を2カラムで表示し、下部に失敗したホストの履歴を表示するので、現在の状況(上部)と過去の状況(下部)を同時に把握できるのが便利ポイントです。




ping対象のホストはpingerの引数にホスト名かIPアドレスで指定してください。思うがままにたくさん指定してください。

pingerの実行にはroot権限が必要なので、いずれかの方法で実行してください。

  • sudo pingerで実行する
  • rootで実行する
  • root で chown root pinger; chmod 4755 pinger しておいてから実行する
  • Linuxの場合、root で setcap cap_net_raw=ep pinger しておいてから実行する (azs! id:mapk0y

ESCかC-cをタイプすると終了します。

終了すると画面がクリアされてしまいます。pingに失敗した履歴を保存しておきたい場合は、標準エラー出力をファイルにリダイレクトしてください。

$ sudo pinger example.com example.net 192.0.2.1 192.0.2.2 192.0.2.3 2> pinger.log

ホスト名(IPアドレス)の横に2つの数値が表示されますが、左のはRTT、右の括弧内のは最大10個の直近の結果の平均RTTで、どちらも単位は ms です。


それではよいpingライフを!

hardware clockがずれる件と 11 minute mode

localtimeにしていたhardware clockをなんとなくUTCにしてみたら10分ぐらいで元に戻っちゃうというお話です。環境は Ubuntu 16.04 です。

結局、reboot しないとダメだったんですが、いい方法あったら教えてください><



hardware clockがlocaltimeになっているかUTCになっているかは、timedatectl の "RTC time" や "RTC in local TZ" のところを見るか、

### UTCの場合
$ sudo timedatectl
      Local time: Wed 2016-12-14 19:19:46 JST
  Universal time: Wed 2016-12-14 10:19:46 UTC
        RTC time: Wed 2016-12-14 10:19:46 # ココ
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no # ココ
      DST active: n/a

### localtimeの場合
$ sudo timedatectl
      Local time: Wed 2016-12-14 19:34:20 JST
  Universal time: Wed 2016-12-14 10:34:20 UTC
        RTC time: Wed 2016-12-14 19:34:20 # ココ
        Timezone: Asia/Tokyo (JST, +0900)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: yes # ココ
      DST active: n/a

Warning: The RTC is configured to maintain time in the local time zone. This
         mode is not fully supported and will create various problems with time
         zone changes and daylight saving adjustments. If at all possible use
         RTC in UTC, by calling 'timedatectl set-local-rtc 0'.

hwclock --show --debug でも確認できます。

### UTCの場合
$ sudo hwclock --show --debug
hwclock from util-linux 2.20.1
Using /dev interface to clock.
Last drift adjustment done at 1478666918 seconds after 1969
Last calibration done at 1478666918 seconds after 1969
Hardware clock is on UTC time
Assuming hardware clock is kept in UTC time. # ココ
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2016/12/14 10:36:58
Hw clock time : 2016/12/14 10:36:58 = 1481711818 seconds since 1969
Wed Dec 14 19:36:58 2016  -0.074581 seconds

### localtimeの場合
$ sudo hwclock --show --debug
hwclock from util-linux 2.20.1
Using /dev interface to clock.
Last drift adjustment done at 1481708948 seconds after 1969
Last calibration done at 1481708948 seconds after 1969
Hardware clock is on local time
Assuming hardware clock is kept in local time. # ココ
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 2016/12/14 19:37:03
Hw clock time : 2016/12/14 19:37:03 = 1481711823 seconds since 1969
Wed Dec 14 19:37:03 2016  -0.031894 seconds


hwclock --systohc --utc や timtdatectl set-local-rtc 0 で hardware clock を localtime から UTC に変更できるのですが、10分ぐらいするとなぜか元に戻っちゃいました。

これは hwclock(8) に依れば "11 minute mode" という、system clockがずれていないと信頼できるような環境で有益な、11分ごとにhardware clockをsystem clockの時刻に合わせるモードが原因でした。

"11 minute mode" が有効になっているかどうかは、ntptime の実行結果の status 行を見れば確認できます。ここにUNSYNCがなければ有効、あれば無効です。

### "11 minute mode" が有効になっている(=UNSYNCがない)
$ ntptime | grep status
  status 0x2001 (PLL,NANO),

### "11 minute mode" が無効になっている(=UNSYNCがある)
$ ntptime | grep status
  status 0x41 (PLL,UNSYNC),

もしくは adjtimex --print の実行結果の status の数値の 64 ビット目が0(STA_UNSYNC)ならば "11 minute mode" が有効になっていることを示します。


hwclock(8) にも書いてありますが、手元の環境でも ntpd を起動すると "11 minute mode" が有効になりました。(落とすと無効になる)


というわけで、ntpd を起動すると "11 minute mode" が有効になり kernel(?) が認識しているタイムゾーンと異なるのか、10分ぐらいすると hardware clock の時刻がずれてしまいました。

いろいろ

  • /etc/adjtime を消して hwclock --systohc --utc
  • timtdatectl set-local-rtc 0

やってみたんですが、解消できず、結局は ntpd を落として hardware clock を UTC にして reboot したら直りました。(起動後に ntpd を起動してももうずれない)

MySQL 5.7のmysqld --initializeと鶏卵問題

MySQLのデータディレクトリの初期化にはこれまで mysql_install_db が使われてきましたが、MySQL 5.7からは mysqld --initialize を使うことが推奨されています。

mysqld --initialize は datadir 配下にファイルやサブディレクトリがあるとエラー終了します。

# mysqld --initialize --user=mysql
2016-10-04T11:39:01.313174Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.
2016-10-04T11:39:01.313222Z 0 [ERROR] Aborting

なので datadir をスッカラカンにして再度実行してみます。my.cnf はこんな内容で、datadir の下に tmpdir、InnoDBのデータとログのディレクトリがある構成です。

datadir  = /data/mysql
tmpdir   = /data/mysql/tmp
innodb_data_home_dir            = ibdata
innodb_log_group_home_dir       = iblog
# rm -fr /data/mysql/*
# mysqld --initialize --user=mysql
# echo $?
1
# cat /data/mysql/mysqld.err
mysqld: Can't create/write to file '/data/mysql/tmp/ibSY07SU' (Errcode: 2 - No such file or directory)
2016-10-04T11:41:18.876953Z 0 [ERROR] InnoDB: Unable to create temporary file; errno: 2
2016-10-04T11:41:18.876965Z 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error
2016-10-04T11:41:18.876971Z 0 [ERROR] Plugin 'InnoDB' init function returned error.
2016-10-04T11:41:18.876975Z 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2016-10-04T11:41:18.876980Z 0 [ERROR] Failed to initialize plugins.
2016-10-04T11:41:18.876983Z 0 [ERROR] Aborting

/data/mysql/tmp が存在しないので /data/mysql/tmp/ibSY07SU が作れずエラー終了しています。

InnoDBのデータ、ログディレクトリについても同様で、自動ではサブディレクトリを作ってくれません。

[ERROR] InnoDB: Operating system error number 2 in a file operation.
[ERROR] InnoDB: The error means the system cannot find the path specified.
[ERROR] InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them.
[ERROR] InnoDB: File ibdata/ibdata1: 'create' returned OS error 71. Cannot continue operation
[ERROR] InnoDB: Cannot continue operation.
[ERROR] InnoDB: Operating system error number 2 in a file operation.
[ERROR] InnoDB: The error means the system cannot find the path specified.
[ERROR] InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them.
[ERROR] InnoDB: File iblog/ib_logfile101: 'create' returned OS error 71.
[ERROR] InnoDB: Cannot create iblog/ib_logfile101
[ERROR] InnoDB: InnoDB Database creation was aborted with error Generic error. You may need to delete the ibdata1 file before trying to start up again.
[ERROR] Plugin 'InnoDB' init function returned error.
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[ERROR] Failed to initialize plugins.
[ERROR] Aborting


というわけで、初期化にはサブディレクトリが必要なわけですが、サブディレクトリがあると mysqld --initialize はエラー終了します。

_人人人人人人人人人人人人人人人人人人_
> どうすりゃいいねん!!!!!!! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄



途方に暮れそうになりましたが、ドキュメントにちゃんと書いてありました。

As of MySQL 5.7.11, an existing data directory is permitted to be nonempty if every entry either has a name that begins with a period (.) or is named using an --ignore-db-dir option.

https://dev.mysql.com/doc/refman/5.7/en/data-directory-initialization-mysqld.html

というわけで、予め必要なサブディレクトリを作っておいて、必要なだけ --ignore-db-dir で繰り返しそれを指定すればOKです。

# rm -fr /data/mysql/*
# install -d -o mysql -g mysql -m 750 /data/mysql/{tmp,ibdata,iblog}
# mysqld --initialize  --user=mysql --ignore-db-dir=tmp --ignore-db-dir=ibdata --ignore-db-dir=iblog
# echo $?
0

追記 2023-03-06

--ignore-db-dir は 5.7 で deprecated だったのですが、8.0 で廃止されて使えなくなりました。

8.0 ではどうすればいいのでしょうか。。。

LXD 2.0でlive migrationしてみる

基本的には

に書いてある通りなんで、これの補足という形になります。


まず、live migrationを行う(ホストh1にあるコンテナc1をホストh2にlive migrationする場合)のにこのようなコマンドを実行すると

hirose31@h1$ lxc move c1 h2:

「error: Error transferring container data: websocket: bad handshake」というエラーで失敗し、以下のようにlocalの場合でもremote名を添えて実行すれば成功しました。

hirose31@h1$ lxc move h1:c1 h2:

従って、予め自ホストの分もremoteの登録が必要でした。

hirose31@h1$ lxc remote add h1 192.168.33.21
hirose31@h1$ lxc remote add h2 192.168.33.22

hirose31@h2$ lxc remote add h1 192.168.33.21
hirose31@h2$ lxc remote add h2 192.168.33.22

次にハマったのは、lxc moveするとこのようなエラーで失敗した点です。

hirose31@h1$ lxc move h1:c1 h2:
error: Error transferring container data: checkpoint failed:
(00.093894) Error (sockets.c:129): Diag module missing (-2)
(00.173958) Error (sockets.c:339): Sockets (family 16, proto 0) are not collected
(00.173977) Error (cr-dump.c:1303): Dump files (pid: 8476) failed with -1
(00.178203) Error (cr-dump.c:1600): Dumping FAILED.

エラーメッセージを見て、てっきりエラーの原因を表示するためのGo(LXDのlxcコマンドはGoで書かれています)のソケット関連のdiagnostic(診断)ライブラリが足りてないのかな?と思い、いろいろ調べたのですが、結局原因はGoは関係なく、netlink_diag.koというkernel moduleがなかったためでした。思い込みはよくないですね!

Ubuntu 16.04ではnetlink_diag.koは別パッケージに収録されているのでそれをインストールします。

sudo apt-get install linux-image-extra-$(uname -r)

これでlive migrationが成功しました!

ちなみにですけど、netlink_diag.koがないとstateful stop/start やstateful snapshotsも失敗します。


他に気をつける点は、ググるとひっかかる古い情報ではprofileを変更してたりしますが、デフォルトのdefault profileだけで動きました。むしろ、下手にいじると動かない場合がありました。

LXDの感想

システムコンテナとしてDockerを使い、CentOS 6とUbuntu 14.04を動かそうとしたときはいろいろハマった(gettyがCPU食いつぶすとかudevadm settleでbootが止まるとかとか)んですが、LXDでは images.linuxcontainers.org のイメージを使った限りではすんなりCentOS 6やUbuntu 16.04が動かせていまのところはだいぶ好印象です。

LXDはOpenStackとの連携もできるようですし、より軽量なKVMの代替としてよい選択肢になるんじゃないかと思います。

追記 2017-02-10

live migration元と先とでlxdのバージョンが違うと(例えば2.0.5と2.0.8)このようなエラーで失敗する。

move: error: Bad key: volatile.idmap.base

バージョンを揃えれば成功する。apt-get install lxd でコンテナは稼働したままバージョンを上げられた。

www.twitch.tvの名前が引けない、もしくはチェックサムが0x0000のUDPパケットの件のまとめ

先に原因を書いておくと、
チェックサムが 0x0000 のUDPパケットが戻ってくると、自分の環境では「どこか」で再計算された誤ったチェックサムが付与され、チェックサムが合わないのでユーザーランドに届く前に破棄されていました。



以下、詳しく。

ことの始まりは、自宅でtwitchでSplatoon(先日ようやくSになりました!)の動画配信を見ようとしたのですがアクセスできないのに気づいたことでした。

ブラウザに表示されるエラーメッセージからして名前が引けないようなので、digで試してみたら引けませんでした。(10.6.25.2は宅内のキャッシュサーバー(djbdns))

$ dig www.twitch.tv @10.6.25.2
(しばらくだんまり)
; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> www.twitch.tv @10.6.25.2
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 37843
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.twitch.tv.                 IN      A

;; Query time: 54 msec
;; SERVER: 10.6.25.2#53(10.6.25.2)
;; WHEN: Wed Jan 27 12:13:35 JST 2016
;; MSG SIZE  rcvd: 31

引ける環境でtwitch.tvのネームサーバーを調べて問い合わせてみても引けない。

### 引ける環境
$ dig -t ns twitch.tv

; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> -t ns twitch.tv
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5068
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 12

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;twitch.tv.                     IN      NS

;; ANSWER SECTION:
twitch.tv.              10781   IN      NS      ns1.p18.dynect.net.
twitch.tv.              10781   IN      NS      a3.verisigndns.com.
twitch.tv.              10781   IN      NS      a2.verisigndns.com.
twitch.tv.              10781   IN      NS      ns3.p18.dynect.net.
twitch.tv.              10781   IN      NS      ns2.p18.dynect.net.
twitch.tv.              10781   IN      NS      a1.verisigndns.com.

;; ADDITIONAL SECTION:
ns1.p18.dynect.net.     9110    IN      A       208.78.70.18
ns1.p18.dynect.net.     281     IN      AAAA    2001:500:90:1::18
a3.verisigndns.com.     3571    IN      A       69.36.145.33
a3.verisigndns.com.     1940    IN      AAAA    2001:502:cbe4::33
a2.verisigndns.com.     3573    IN      A       209.112.114.33
a2.verisigndns.com.     3581    IN      AAAA    2620:74:19::33
ns3.p18.dynect.net.     10186   IN      A       208.78.71.18
ns3.p18.dynect.net.     281     IN      AAAA    2001:500:94:1::18
ns2.p18.dynect.net.     17914   IN      A       204.13.250.18
a1.verisigndns.com.     2571    IN      A       209.112.113.33
a1.verisigndns.com.     3499    IN      AAAA    2001:500:7967::2:33

;; Query time: 1 msec
;; SERVER: 172.24.64.100#53(172.24.64.100)
;; WHEN: Wed Jan 27 12:31:30 JST 2016
;; MSG SIZE  rcvd: 408
$ dig www.twitch.tv @209.112.113.33
(しばらくだんまり)
; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> www.twitch.tv @209.112.113.33
;; global options: +cmd
;; connection timed out; no servers could be reached

ぬーんと思っていたらアドバイスもらったので、

tcpdumpしながらstraceでdigを実行してみる。

# tcpdump -nlSxX -i any host 209.112.113.33
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
12:51:30.078313 IP 10.6.25.39.39302 > 209.112.113.33.53: 58570+ [1au] A? www.twi
tch.tv. (42)
        0x0000:  4500 0046 77c5 0000 4011 9d23 0a06 1927  E..Fw...@..#...'
        0x0010:  d170 7121 9986 0035 0032 be51 e4ca 0120  .pq!...5.2.Q....
        0x0020:  0001 0000 0000 0001 0377 7777 0674 7769  .........www.twi
        0x0030:  7463 6802 7476 0000 0100 0100 0029 1000  tch.tv.......)..
        0x0040:  0000 0000 0000                           ......
12:51:30.090812 IP 209.112.113.33.53 > 10.6.25.39.39302: 58570*- 1/0/1 CNAME ssl
.cdn.twitch.tv.c.footprint.net. (89)
        0x0000:  4500 0075 01ca 0000 3711 1bf0 d170 7121  E..u....7....pq!
        0x0010:  0a06 1927 0035 9986 0061 f393 e4ca 8500  ...'.5...a......
        0x0020:  0001 0001 0000 0001 0377 7777 0674 7769  .........www.twi
        0x0030:  7463 6802 7476 0000 0100 01c0 0c00 0500  tch.tv..........
        0x0040:  0100 0000 0f00 2303 7373 6c03 6364 6e06  ......#.ssl.cdn.
        0x0050:  7477 6974 6368 0274 7601 6309 666f 6f74  twitch.tv.c.foot
        0x0060:  7072 696e 7403 6e65 7400 0000 2910 0000  print.net...)...
        0x0070:  0000 0000 00                             .....
...
$ strace -f -s 100 dig www.twitch.tv @209.112.113.33
[pid  1162] sendmsg(20, {msg_name(16)={sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("209.112.113.33")}, msg_iov(1)=[{"Oh\1 \0\1\0\0\0\0\0\1\3www\6twitch\2tv\0\0\1\0\1\0\0)\20\0\0\0\0\0\0\0", 42}], msg_controllen=0, msg_flags=0}, 0 <unfinished ...>
...
[pid  1162] recvmsg(20, 0x7fb7f1ca5c90, 0) = -1 EAGAIN (Resource temporarily unavailable)
...
[pid  1162] sendmsg(20, {msg_name(16)={sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("209.112.113.33")}, msg_iov(1)=[{"Oh\1 \0\1\0\0\0\0\0\1\3www\6twitch\2tv\0\0\1\0\1\0\0)\20\0\0\0\0\0\0\0", 42}], msg_controllen=0, msg_flags=0}, 0) = 42
...
[pid  1162] recvmsg(20, 0x7fb7f1ca5c90, 0) = -1 EAGAIN (Resource temporarily unavailable)
...

なんと、ユーザーランド(digコマンド)には応答が届いてないけど、kernelにはUDPパケットが届いてるご様子。

うーんなんでユーザーランドに届かないんだろう。。。と思っていたらまたアドバイスが。

確かに、引ける環境ではチェックサムが 0x0000 になっているけど、引けない環境では 0xf393 になっている。

### 引ける環境
04:09:08.940710 IP 209.112.113.33.53 > 10.0.0.211.35082: 12580*- 1/0/1 CNAME ssl.cdn.twitch.tv.c.footprint.net. (89)
        0x0000:  4500 0075 bc5c 0000 3a11 76b7 d170 7121  E..u.\..:.v..pq!
        0x0010:  0a00 00d3 0035 890a 0061 0000 3124 8500  .....5...a..1$..
        0x0020:  0001 0001 0000 0001 0377 7777 0674 7769  .........www.twi
        0x0030:  7463 6802 7476 0000 0100 01c0 0c00 0500  tch.tv..........
        0x0040:  0100 0000 0f00 2303 7373 6c03 6364 6e06  ......#.ssl.cdn.
        0x0050:  7477 6974 6368 0274 7601 6309 666f 6f74  twitch.tv.c.foot
        0x0060:  7072 696e 7403 6e65 7400 0000 2910 0000  print.net...)...
        0x0070:  0000 0000 00                             .....

### 引けない環境
12:51:30.090812 IP 209.112.113.33.53 > 10.6.25.39.39302: 58570*- 1/0/1 CNAME ssl
.cdn.twitch.tv.c.footprint.net. (89)
        0x0000:  4500 0075 01ca 0000 3711 1bf0 d170 7121  E..u....7....pq!
        0x0010:  0a06 1927 0035 9986 0061 f393 e4ca 8500  ...'.5...a......
        0x0020:  0001 0001 0000 0001 0377 7777 0674 7769  .........www.twi
        0x0030:  7463 6802 7476 0000 0100 01c0 0c00 0500  tch.tv..........
        0x0040:  0100 0000 0f00 2303 7373 6c03 6364 6e06  ......#.ssl.cdn.
        0x0050:  7477 6974 6368 0274 7601 6309 666f 6f74  twitch.tv.c.foot
        0x0060:  7072 696e 7403 6e65 7400 0000 2910 0000  print.net...)...
        0x0070:  0000 0000 00                             .....

引けない環境のを Wireshark でみてみると、incorrectと表示されています。

0x0000 のチェックサムは、(それをパブリックなネットワークで使うかはさておき)仕様的には妥当な値ではあります。

An all zero transmitted checksum value means that the transmitter generated no checksum (for debugging or for higher level protocols that don't care).

https://tools.ietf.org/html/rfc768

余談ですが、チェックサムについてこれがおもしろかったです。


というわけで、恐らく、自分の環境の「どこか」でUDPチェックサムの再計算をしていて、その計算ロジックが間違っているんじゃないかと思っています。

「どこか」はNATしている民生用のBUFFALOのブロードバンドルーターが怪しいんじゃないかと思っていて問い合わせ中です。続報があればここに書き足します。

補足

0x0000なチェックサムUDPパケットを返すのは a1.verisigndns.com [209.112.113.33] だけではなく、

も0x0000なチェックサムを返していました。(2016-01-27現在)


twitch.tvドメインのネームサーバーは ns1.p18.dynect.net 等はチェックサムつきのパケットを返すので、当座は

echo 208.78.70.18 > dnscache/root/servers/twitch.tv

して凌ぐことにしました。。

続報

Verisign


ふろく