ʍoɹɐɥsのブ口グ

ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็

はてなから引っ越すことにする 又はCDNの遅さについて

重い。markdownはいいが、昔のはてなの方がよかった。

はてなが重いのはダイアリだけじゃなくて、全体的に重い。例えばCDNを使うことによって、負荷の一部はcdnに分散させれるが、このCDNというのは見る側にとっては遅くなる要因になりやすい。

言ってみればCDNは郵便物の中身に次の郵便物への請求先が書いてあるようなもので、そこへのコネクションの確立から始めなければいけない。これははてなの静的コンテンツ用CDNだけじゃなくて、GoogleAnalyticsのような第3者オリジン(クロスドメイン)でも同様。基本的に第3者オリジンが増えるとレイテンシが積もり積もってとっても遅いページになる。はてなはbigminingやらAudienceSearchなどなど、多数のユーザー嗅ぎまわり系を使っているのでそれも遅さに加担していそう。

たぶん・・そもそも今のはてなの人は軽いページは頭にない。軽さが使いやすさにつながるのではなくて、新機能や機能改善で使いやすさを求めていく方向なんだと思う。あるいは、行き過ぎではないが富豪主義なのだろうか。

単純な例でいうと、はてブfavicon

http://b.hatena.ne.jp/favicon.ico

このfaviconの容量、352126bytes(344KiB)。健全な人間ならcontent-encodingでgzipとか適用されるかと思うじゃん。それが素のまま送ってきやがる。ちなみに手元でgzip圧縮すると5.5KiBになる。

移動先は未定、どうせ見ている人はほとんどいないので気軽にいく。PythonAywareあたりで静的サイトジェネレータも悪くないかもと思ってる。が、それ自体が存続するかも危ういし、github.ioやS3のほうがいいかな・・。


ひっそり移動。 http://sharow.org/ はてなはもういらないかな。

簡単にできるチャレンジ/レスポンス認証

 チャレンジ/レスポンス認証自体はとても簡単な認証方式だが、通信路に秘密文の平文を流すことなく認証できるのでけっこういろいろなところに使われている。有名どころではPPPのCHAPもそうだし、Digest認証もそうですね。

SSHもチャレンジ/レスポンス認証に対応しているらしい(SSH-1ではチャレンジ256bit、ハッシュはMD5)。というか、ハイブリッド暗号(公開鍵暗号+共有鍵暗号)において、セッション鍵を生成するまでの仕組みはチャレンジ/レスポンス認証とちょっと似てます。

素材

  • 良質なハッシュ関数
  • 良質な疑似乱数生成器(できれば天然のもの、再現不可能なソースをかけたエントロピープールを持つものが理想)

レシピ

 サーバは要求に応じてランダムな文字列(チャレンジ、広い意味ではNonceともいう)をクライアントに返し、クライアントはチャレンジと秘密文を混ぜてハッシュ値を返し、サーバが同じハッシュ関数で一致するか検証するだけ。コードにしても結構短い。

#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; coding: utf-8; -*-

import os
import hashlib
import base64

try:
    from Crypto.Random import random
except ImportError:
    import random
    random.seed(os.urandom(16))


def gen_challenge(length=256) -> bytes:
    return bytes(random.randint(0, 255) for _ in range(length))

def hash_fn(secret: bytes, challenge: bytes) -> bytes:
    return hashlib.sha512(secret + challenge).digest()


if __name__ == '__main__':
    # 秘密のパスワード
    secret = 'hogehoge'.encode('ascii')

    # 1. クライアントはサーバにchallengeを要求する
    challenge = gen_challenge()
    print('challenge(base64):', base64.standard_b64encode(challenge))

    # 2. クライアントは受け取ったchallengeとsecret(パスワード等)を合わせたハッシュ値を返す
    user_input = input('password:')
    response = hash_fn(user_input.encode('ascii'), challenge)
    print('response(base64):', base64.standard_b64encode(response))

    # 3.サーバは返されたハッシュ値を確認し、一致すれば認証成功とする
    # challegeはクライアントがresponseといっしょに返しても問題ない
    success = hash_fn(secret, challenge) == response
    print(['login failed', 'login success'][success])

 ハッシュ関数にSHA512、疑似乱数生成器にPython Cryptography Toolkit(Crypto)のを使っている(無い場合は標準のrandom)。CHAP(RFC1994)ではMD5なのだが、今時MD5ではドン引きされてしまいそうだ。チャレンジが十分に長ければそんなに気にするほどでもないのかもしれない(それはそれで「十分に長い」とはどの程度か、という問題になるのだが…)。

チャレンジ/レスポンス認証は脆弱?

 素人目にはチャレンジ/レスポンス認証の仕組み自体には問題は無いように思われる。時代に合わせて正しく設計/運用するかどうかだと思う。チャレンジ/レスポンス認証の脆弱性が有名なのは主にマイクロソフトのPPP接続時のCHAP(MS-CHAP)によるもので、これってばチャレンジがなんと64bit(8バイト!)。ハッシュ関数はMD4。今の時代で見たら脆弱そのもの。チャレンジが256bit以上でハッシュ関数がSHA2またはSHA3系だったら今でも安全に運用できるのではないだろうか。

 気を付ける部分は「サーバが秘密文(パスワードの平文)を知っている」という前提があること。これは脆弱性ではなく、そういう前提で作られている。最近ではサーバでパスワード等は平文で持たずハッシュ化して持つのが普通なので平文は知らない。とはいえクライアントで同じハッシュ関数を先頭に噛ませればいけないこともないが、なんかダサい。それにサーバで使っているパスワードのハッシュ方法やソルトがバレてしまう。Digest認証ではそんな感じになっている*1


 グローバルIPアドレスオプション(WiMAX 2+用)を見ていたら、設定ドキュメントにちょっとPPP接続を匂わせることが書いてあったのでなんとなく。CHAPは信用していないらしく、パスワードは0000固定、たぶんそれより下のレイヤー(MACアドレスとかハードウェアアドレス)で認証していると思われる。低レベルではまだPPPとかCHAPが健在なのだなぁ。

*1:ただしDigest認証はソルトは無い

ノーリミットモード(WiMAX)でも制限にかかる

VirtualBoxの5.0.16が出た。これまでWindows10でインスコすらできなかったのがついに解決された。今日からLinux仮想マシン作りまくるぞ~と思って最新のISOを落としまくる一日だった。

・・で、その数々のISOをノーリミットモードで落としてたらWiMAXの制限くらってしまった。だいたい実測で1Mbps(120Kib/sちょい)しかでない。名前からは制限かからないと思いがちだが、ノーリミットモードでも一日にブートイメージのISOを落としまくると制限くらうことが分かった。だいたい14GiBくらいを1日で落としたらこうなった(AlphaGoの対局中継の観覧も重なった)。きっとちゃんと読めば利用規約の端っこに「サービスを維持するため云々で制限をかけさせていただく場合がございます」とか書いてあるんだろう。ちなみにハイスピードモード(LTE)はOFFにしていた。でかいISOだと1つで3GiBを超えてしまうため。

どれくらいが制限のボーダーなのかが分からないが、14GiB/日で制限かかるってことは確認できた。ボーダーは10GiBとか12GiBだろうか。ていうか、これいつ解除されるんだろうか。ちなみに、WiMAXで制限かかってもハイスピードモード(LTE)*1には関係ないようだ。たぶん機材が物理的にまったく別で、その辺の制限の連携などはされてないのだろう。

ところでルーターはURoadHome2+なのだが、URoadHome2+をターミナルから操作するスクリプト*2をこさえたのでモード切替や通信量の確認がとても楽だ。こんなユーザーは珍しいんだろうが、正直CiscoルーターみたいにTelnet接続やSSH接続でターミナルからいろいろできればいいのに、と思ってる。あるいはルーティング機能やWiFiなんか捨てて据え置きWiMAX終端装置に徹するとか。そうすれば例えば中小企業のWAN側バックアップ回線としても悪くない選択肢になると思うんですけどね。細いっちゃ細いが、全く繋がらないのとは雲泥の差だし。

・・・うん、売れないね。出ないな。

*1:ハイスピードモードの中身はLTE。ハイスピードモードプラスの中身もLTE。違いは3.9G/4Gの違いとか?よーわからん。

*2:ちなみにこの機種はハイスピードモードプラスには対応していない

LinuxがDHCPサーバからアドレスを貰えない時

これでハマって1日潰したのでメモ。

おそらくクライアントがDHCPv6を話している

当たり前だが純DHCPv4のサーバとは通じない。でもそのための設定が分散していて面倒くさかったのでメモ。例えばArchLinuxのnetctl/etc/netctl/examples/ethernet-dhcpは以下のようになっている。

Description='A basic dhcp ethernet connection'
Interface=eth0
Connection=ethernet
IP=dhcp
#DHCPClient=dhcpcd
#DHCPReleaseOnStop=no
## for DHCPv6
#IP6=dhcp
#DHCP6Client=dhclient
## for IPv6 autoconfiguration
#IP6=stateless

IP6をコメントアウトしなければDHCPv4が使われると思うじゃん?

netctlはデフォルトでdhcpcdクライアントを立ち上げる。それのdhcpcd.confはこうなっている。

# Use the hardware address of the interface for the Client ID.
#clientid
# or
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
# Some non-RFC compliant DHCP servers do not reply with this set.
# In this case, comment out duid and enable clientid above.
duid

デフォルトでduidを送る設定になっているのだ。duidコメントアウトしてclientidを追加にするとRFC2131でいうclient identifierとしてMACアドレスが使われるようになる(どうなんだこの設定でこの名前)。 DHCPv4/v6両方に対応したDHCPサーバ(RFC4361)だとduidでOKらしい。

ちなみにsystemd-networkdの場合は以下のようにする。

[Match]
Name=eth0

[Network]
DHCP=ipv4

[DHCP]
ClientIdentifier=mac

こっちのほうがdhcpcdよりも設定がキレいだよね。RFC2131でいうclient identifierとしてMACアドレスを送る、というそのまんまの意味になっている。


そういえばOSXで一部のサイトが見れない、とかいう症状をきいたことがある。ルーターやプロバイダがDHCPv6/IPv6に対応しているのだが、観覧先のサイトが対応していないというケース。Googleは見れるがYomiuriやWikipediaが見れない、みたいな現象になるらしい。

OS X Yosemiteに変えてから、あるWebサイトにアクセスできなくなった。Chrome… | Apple サポートコミュニティ

C11 _Generic(Generic selection) の落とし穴

C11で追加されたGenericにはちょっとした落とし穴があります。Generic(というかC言語の基本型)が名前ではなく構造で同値性を判定すること(構造同値)を確認して次のコードを見てみましょう*1*2

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    const char *s = _Generic((uint64_t)0,
                             uint64_t: "uint64_t",
                             uintmax_t: "uintmax_t");
    printf("%s\n", s);
    return 0;
}

ぱっと見て出力はuint64_tになるだろ、と思った方ビンゴー! x84_64上のgcc 5.3.0、clang 3.7.1 では以下のようになります。

 $ gcc -std=c11 test.c
test.c: In function ‘main’:
test.c:11:30: error: ‘_Generic’ specifies two compatible types
                              uintmax_t: "uintmax_t");
                              ^
test.c:10:30: note: compatible type is here
                              uint64_t: "uint64_t",
                              ^
test.c:11:30: error: ‘_Generic> selector matches multiple associations
                              uintmax_t: "uintmax_t");
                              ^
test.c:10:30: note: other match is here
                              uint64_t: "uint64_t",
                              ^
$
$ clang -std=c11 test.c
test.c:11:30: error: type 'uintmax_t' (aka 'unsigned long long') in generic association compatible with previously
      specified type 'uint64_t' (aka 'unsigned long long')
                             uintmax_t: "uintmax_t");
                             ^~~~~~~~~
test.c:10:30: note: compatible type 'uint64_t' (aka 'unsigned long long') specified here
                             uint64_t: "uint64_t",
                             ^~~~~~~~
1 error generated.
$

はい、コンパイルすら通りません。コンパイラuintmax_tuint64_tの構造(大きさ)が同じだから、「同じ型が重複しているよ」と言ってるのです。

その他にも落とし穴があるようです。というか、落とし穴だらけな気がしてきました。

The controlling expression of _Generic | Jens Gustedt's Blog

※ おそらくclangの_Genericがおかしい。


関係ありませんが、gcc 5.2.0~5.3.0の_Genericには誤った警告を出すバグがあります。

Bug 68193 - _Generic -Woverflow false alarm

*1:もちろんここで言ってるのは型の同値性

*2:構造同値ではtypedef int A; typedef int B;でAとBが同じ型と判定する. 名前同値だと名前が違うから同じ型とはないと判定する.C言語は基本型に関しては構造同値をとっている. 派生型に関しては構造同値ではない、かといって名前同値ともスッキリ言い切れない….

本当は怖いメモリ

TL;DR

ちょっと前から消費メモリが増えると不安定になるなぁと思っていた。

f:id:sharow:20160220205539j:plain f:id:sharow:20160220212823j:plain

もちろん買った時にmemtestでテストはしていた。エイジングにより不良が出ることを知ってはいたが、めんどくさいので2年以上テストせずにいた。久々にテストしたらこのありさま。

物はCORSAIRの永久保証メモリを新品で買ったものなので、新品or同等品への交換が受けられる筈。レシートが見つかり次第事を進める予定。

幸い虫が巣食ってる物理アドレスが後方なので後ろの物理アドレスを使わないようにすることで当分はしのげるだろう。

Windowsの場合、こういう設定はbcdeditで行う。これはブートエントリなどを設定をするツールだが、低レベルなメモリの設定も行える。そういえばLinuxの場合もmaxmemはGRUBの設定だったような。

物理アドレスの最大値はTRUNCATEMEMORYで指定する。今回のうちの例では

bcdedit /set TRUNCATEMEMORY 0x785b00000

を管理コンソールで実行して再起動。あとはsysinternalのRamMapとかで物理アドレスが制限されているか確認する。 ({ID}は省略すると現在の{ID}になる)

f:id:sharow:20160223153637p:plain

尻尾の1GiB程度を失ったが、4年ほど使ってるPCでこの程度なら合格点かな。

何が怖いのか

ソフトウェアやOSが落ちる程度ならかわいい。最悪、ファイルキャッシュにこの物理メモリが使われるとファイルが壊れる(Linuxで言うところのバッファキャッシュのこと)。幸い、大量のメモリを使わないと後方の物理メモリはあまり使われないようで、目に見える被害は今のところない。というか、Windows8から10にアップグレードしたときに直ってしまった。Windows8の時はイベントビューワのイベントファイルがぶっ壊れてたようで、イベントビューワが100%落ちるという状況だった。メモリ起因のファイル破損が原因だったと思われる。ああ怖い。

ECCメモリ

今回のように物理アドレスの後方だけが集中して壊れた場合はTRUNCATEMEMORYで対応できるが、いろんな箇所が分散して壊れた場合には対応できない。とてもよく分散して壊れた場合はTRUNCATEMEMORYではなくてBADMEMORYでページ(4KiB単位)ごとにブラックリストに手動で入れていくことができる・・が、本来はこれは自動で登録されるものだ。ECCメモリとECCメモリに対応したCPUを使っていれば、ECCエラーを検出したページをOSがBADMEMORYに登録してくれる。もちろん、これはLinuxでも対応している

もし長く使える堅牢な環境が欲しいなら、ECCメモリを狙うのもいいかもしれない。XeonE3あたりはそんなに高くない。・・・PC組んだ時にこっちにしておくべきだったと今更後悔している。組んだ当時は堅牢なPCが目的だったのになぁ。

PS

そういえば3か月前にはEIZOのモニタがぶっ壊れてお陀仏になったんだった。最近壊れるものが多い気がする。

ソードフィッシュ (プログラマの映画 Advent Calendar 2015)

この記事はプログラマの映画 Advent Calendar 2015の10日目の記事です。

ソードフィッシュ は2001年の映画です。ちょっと古いですね。

2001年というとGoogleが日本語の検索に対応して2年たった頃、くらいでしょうか。

絵に描いたようなハリウッド資本の大好きなハッカー像を楽しむには良い映画だと思います。 映画ではハッカーの就職からその活躍までが描かれています。それがどんなものか少し見てみましょう。

転職エージェント

www.youtube.com

ハッカーは貴重なので転職エージェントも普通じゃないのです。私もトニー・モリスじゃなくて、ジンジャー・ノウルズがアプローチしてきたらいろいろ考えてしまうんですけどねぇ。

面接

www.youtube.com

ハッカーを雇う時は面接も色が違います。3分くらいで採用が決まるのでスピード感がありますね。聞くところによると、某Googなんとか社や某マイクロなんとか社も、このように面接(会話)しながらコーディングするような方式だそうですよ。

ちなみに、DELLですね。

仕事風景

www.youtube.com

私にはキューブ状のフレームに箱をはめるゲームをしているようにしか見えないのですが、これが一応ワームとかウィルスを作っている最中のようです。お酒OKな職場というのは、さすがハッカーです。

ディスプレイにSGIの文字がありますね。ということはIRIXでしょうか?2001年にはまだSGIはそんなに落ちぶれてなかったのですね(Windows機も出してましたし)。

その他

他にも、社内にはビキニの女の子ばっかりいたり、高級そうな車がタダで借りれたりといろいろ凄いです。 こうして世間に知れ渡るハッカー像を見るのも楽しみ方のひとつではないでしょうか。

この映画の見所はガブリエルの「思い込み」を使ったトリックでしょう。実はスタンリーのハッキングは駒でしかありませんでした。しかし、最後の最後で・・・。DVD/Blu-rayのエディションによっては別バージョンのエンディングが収録されているので見比べるのも一興です。