squidを透過プロクシーで使っていると、CDNを全くcacheしないんだけど
きっかけ
squidを利用して、リモートのCDNサーバーに置かれたzipファイルやdebなどをローカルに
キャッシュしようとしても毎回フェッチするので、おかしいなと感じ少し調べてみました。
産業で説明
CDN(コンテンツ配布)サーバーは負荷分散のためにDNSラウンドロビンなどを行なっていて
1つのURLに対して複数のIPアドレス(サーバー)を持っています
なので、squidの動作上そうなります。(リクエストしたIPアドレスと、URLから引いたIPアドレスが一致しない)
実際のところ何が起きてる?
src/client_side_request.cc: 556
ClientRequestContext::hostHeaderIpVerify(const ipcache_addrs* ia, const DnsLookupDetails &dns)
・・・
debugs(85, 3, HERE << "FAIL: validate IP " << clientConn->local << " possible from Host:");
hostHeaderVerifyFailed("local IP", "any domain IP");
}
OUCH!
同じファイルを何回ダウンロードしようが、DNSのラウンドロビンのIPアドレス全部をガチャ引きしようが、
透過プロクシーでsquidを叩く限り、このCDNサーバーのキャッシュオブジェクトは生成されません。
同一URLに対して、
運良く、端末が引いたIPアドレスとsquidが引いたIPアドレスが同じだったときだけ生成されます。
そして、運良く、もう一度端末が引いたIPアドレスでアクセスが発生し、なおかつその時点でもsquidが引いたIPアドレスと一致した場合に限りCACHE HITになります。(ベリーレアIPアイテム)
実験
#if 0
hostHeaderVerifyFailed("local IP", "any domain IP");
#else
http->request->flags.hostVerified = 1;
http->doCallouts();
#endif
//ぃぃのかょこんなことして
HIT OKでした。
真面目に対策を考える
- 許された サイトURLだけ、IPアドレス不一致を許すような実装。
- http-proxyポートも開いておいて、キャッシュしたい端末には、全部proxyを設定する。
http_port 3128
http_port 3129 intercept
- iptablesでLAN側80番portリクエストをlocalhost:3129 にNATする (必要ならば)
- http-proxy は GWサーバーの3128をアナウンスする
補足
http-proxyモードではCDNの配布ファイルをちゃんとキャッシュしてくれます。
これは、squidに渡されるのがURLのみなので、squid内部でdnsを引きに行き、dnsキャッシュもsquid側にあるので、url->ipの一貫性があるからです。
squid3 デバッグメッセージの出し方
squid3 -k debug
root権限でこれをやると、以後、/var/log/squid3/cache.log にdebugメッセージが大量に出る
squid3 -k reconfigure
で戻せます