Rubyで直前の日曜日の日時を求める

rrdgraphで日曜日始まりの1週間グラフを書きたい時に必要なので.

UNIX時間で0,Time.at(0)がGMTで木曜日の0時なので3日とgmt_offset分だけ平行移動すると,日曜日の0時が1週間(7*86400)で割り切れる値になるので端数を除去,ずらした分だけ元に戻すと直前の日曜日の0時の時刻が得られる.

def last_sunday(t)
	slide = 3*86400 - t.gmt_offset
	t = t.to_i - slide
	return Time.at(t-t%(7*86400)) + slide
end

p Time.now
p last_sunday(Time.now)
p last_sunday(Time.now-86400)
% ruby last_sunday.rb
Sun Aug 21 17:13:42 +0900 2011
Sun Aug 21 00:00:00 +0900 2011
Sun Aug 14 00:00:00 +0900 2011

Rubyでdijkstra法

Rubyダイクストラ法を使って始点からの最短経路を求めることができるかもしれないコード

nodes = ["A", "B", "C", "D", "E"]
connections = [
	# [node1, node2, cost(1->2), cost(2->1)]
	["A", "B", 6, 9],
	["A", "C", 3, 2],
	["B", "C", 2, 3],
	["B", "D", 4, 1],
	["C", "E", 3, 8],
	["B", "E", 3, 2],
]
require 'pp'

def dijkstra(nodes, connections, start)
	inf = 100000
	d = {}
	cost = {}
	used = {}
	prev = {}
	nodes.each{|n|
		d[n] = {}
		nodes.each{|m|
			d[n][m] = inf
		}
		cost[n] = inf
		used[n] = 0
	}
	connections.each{|c|
		d[c[1]][c[0]] = c[2] ? c[2] : 1
		d[c[0]][c[1]] = c[3] ? c[3] : (c[2]?c[2]:1)
	}
	cost[start] = 0
	while true
		min_cost = inf
		nodes.each{|node|
			if used[node] == 0 && min_cost > cost[node]
				min_cost = cost[node]
			end
		}
		break if min_cost == inf
		nodes.each{|src|
			next if min_cost != cost[src]
			nodes.each{|dst|
				next if cost[dst] <= d[dst][src] + cost[src]
				cost[dst] = d[dst][src] + cost[src]
				prev[dst] = src
			}
			used[src] = 1
		}
	end
	routes = {}
	nodes.each{|dst|
		route = []
		node = dst
		while node != nil && node != start
			route << node
			node = prev[node]
		end
		routes[dst] = route.reverse
	}
	return routes
end

routes = {}
nodes.each{|st|
	rs = dijkstra(nodes, connections, st)
	rs.each{|d,r|
		k = st+'-'+d
		routes[k] = []
		m = st
		r.each{|n|
			routes[k] << m+'-'+n
			m = n
		}
	}
}

pp routes
{"B-A"=>["B-C", "C-A"],
 "A-B"=>["A-B"],
 "C-A"=>["C-A"],
 "B-B"=>[],
 "A-C"=>["A-C"],
 "D-A"=>["D-B", "B-C", "C-A"],
 "C-B"=>["C-B"],
 "B-C"=>["B-C"],
 "A-D"=>["A-B", "B-D"],
 "E-A"=>["E-B", "B-C", "C-A"],
 "D-B"=>["D-B"],
 "C-C"=>[],
 "B-D"=>["B-D"],
 "A-E"=>["A-C", "C-E"],
 "E-B"=>["E-B"],
 "D-C"=>["D-B", "B-C"],
 "C-D"=>["C-B", "B-D"],
 "B-E"=>["B-E"],
 "E-C"=>["E-B", "B-C"],
 "D-D"=>[],
 "C-E"=>["C-E"],
 "E-D"=>["E-B", "B-D"],
 "D-E"=>["D-B", "B-E"],
 "E-E"=>[],
 "A-A"=>[]}

Cisco1812JでNATしている時にDNSの特定のレスポンスのパケットが落ちる件

環境

  • 1812J(IOS15.1)がゲートウェイ&NAT箱として機能している.
  • NAT下(inside)にDNSサーバがある
  • static natとroute-mapでtcp/udp53の通信はDialer2 IF経由でDNSサーバに到達するようになっている.
  • 外部(outside)からインターネットを経由してDNSサーバにリクエストをIPv4で送っている.

症状

IPv4の通信でNAT下(inside)のDNSサーバに名前解決(A)やゾーン転送(AXFR)の問い合わせを行ったときに,レスポンス(dst addressは問い合わせ元,src portはtcp/udp53)に問い合わせ元のIPv4アドレスが含まれていた場合にパケットが1812J内部で落ちる.

セカンダリへのゾーン転送が失敗する原因を調べていてたどり着いた.

以下はAXFRを要求したときの1812Jでのパケットダンプ.

http://www.yuyarin.net/screenshot/20110623040840.png

右が正常な通信.レスポンスとして送られるゾーン情報に問い合わせ元(セカンダリ)のアドレスのAレコードが載っていない場合は,VlanIFからDialerIFへパケットが送られている.

左が異常な通信.レスポンスとして送られるゾーン情報に問い合わせ元(セカンダリ)のアドレスのAレコードが載っている場合は,VlanIFに届いたパケットがどこにも行かずに破棄されている模様.

コメント

とりあえず送信元アドレスのバイナリ表現が含まれたパケットをTCPの適当なポートでやりとりするプログラムを試してみたが,これは問題なく通信できた.なのでDNSの通信固有の問題なのか...

ペイロードを見て落としているとしか思えない挙動.ルータで結構複雑なことをやっているので問題の切り分けが難しい.

NATに守られているので特にファイアウォールのような設定,とりわけペイロードまで除くような設定は入れたいないのだが,いったい何が原因なんだろう...

ip cef や ip domain-name などは調べてみたけど問題なさそう.

分析

NATに失敗しているみたい.

ns2.yuyarin.net(49.212.49.25) から ns.yuyarin.net(221.189.114.163) を引いたもの(成功)とns2.yuyarin.netを引いたもの(失敗).NATの変換テーブルはどちらでも一見正常に作成されている.

DNSパケットをNATに通すときにペイロード書き換えが行われているらしい

// succeeded
Jun 28 01:21:34.189: NAT: o: udp (49.212.49.25, 36960) -> (221.189.114.163, 53) [235]    
Jun 28 01:21:34.189: NAT (UDP-DNS): Before Translation
Jun 28 01:21:34.189: NAT: Translation of UDP DNS src 49.212.49.25, dst 221.189.114.163
Jun 28 01:21:34.189: NAT: Dns type of Query
Jun 28 01:21:34.189:    : dns len=20, id=36929, aa=0, tc=0, rd=1, ra=0
Jun 28 01:21:34.189:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:34.189:    : ancount=0, nscount=0, arcount=0
Jun 28 01:21:34.189: NAT (UDP-DNS): After Translation
Jun 28 01:21:34.189: NAT: Translation of UDP DNS src 49.212.49.25, dst 221.189.114.163
Jun 28 01:21:34.189: NAT: Dns type of Query
Jun 28 01:21:34.189:    : dns len=20, id=36929, aa=0, tc=0, rd=1, ra=0
Jun 28 01:21:34.189:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:34.189:    : ancount=0, nscount=0, arcount=0
Jun 28 01:21:34.189: NAT: s=49.212.49.25, d=221.189.114.163->192.168.0.4 [235]
Jun 28 01:21:34.189: NAT: i: udp (192.168.0.4, 53) -> (49.212.49.25, 36960) [14138]    
Jun 28 01:21:34.189: NAT (UDP-DNS): Before Translation
Jun 28 01:21:34.189: NAT: Translation of UDP DNS src 192.168.0.4, dst 49.212.49.25
Jun 28 01:21:34.189: NAT: Dns type of Response
Jun 28 01:21:34.189:    : dns len=78, id=36929, aa=1, tc=0, rd=1, ra=0
Jun 28 01:21:34.189:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:34.189:    : ancount=1, nscount=1, arcount=1
Jun 28 01:21:34.189:      query name is ns.yuyarin.net, qtype=1, class=1
Jun 28 01:21:34.189: Answer section:
Jun 28 01:21:34.189:    Name='ns.yuyarin.net'
Jun 28 01:21:34.193:    RR type=1, class=1, ttl=300, data length=4
Jun 28 01:21:34.193:      IP=221.189.114.163
Jun 28 01:21:34.193: Authority section:
Jun 28 01:21:34.193:    Name='yuyarin.net'
Jun 28 01:21:34.193:    RR type=2, class=1, ttl=300, data length=2
Jun 28 01:21:34.193:      NS='ns.yuyarin.net'
Jun 28 01:21:34.193: Additional record section:
Jun 28 01:21:34.193:    Name='ns.yuyarin.net'
Jun 28 01:21:34.193:    RR type=28, class=1, ttl=300, data length=16
Jun 28 01:21:34.193:      IPv6=0x75F627E
Jun 28 01:21:34.193: NAT (UDP-DNS): After Translation
Jun 28 01:21:34.193: NAT: Translation of UDP DNS src 192.168.0.4, dst 49.212.49.25
Jun 28 01:21:34.193: NAT: Dns type of Response
Jun 28 01:21:34.193:    : dns len=78, id=36929, aa=1, tc=0, rd=1, ra=0
Jun 28 01:21:34.193:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:34.193:    : ancount=1, nscount=1, arcount=1
Jun 28 01:21:34.193:      query name is ns.yuyarin.net, qtype=1, class=1
Jun 28 01:21:34.193: Answer section:
Jun 28 01:21:34.193:    Name='ns.yuyarin.net'
Jun 28 01:21:34.193:    RR type=1, class=1, ttl=300, data length=4
Jun 28 01:21:34.193:      IP=221.189.114.163
Jun 28 01:21:34.193: Authority section:
Jun 28 01:21:34.193:    Name='yuyarin.net'
Jun 28 01:21:34.193:    RR type=2, class=1, ttl=300, data length=2
Jun 28 01:21:34.193:      NS='ns.yuyarin.net'
Jun 28 01:21:34.193: Additional record section:
Jun 28 01:21:34.193:    Name='ns.yuyarin.net'
Jun 28 01:21:34.193:    RR type=28, class=1, ttl=300, data length=16
Jun 28 01:21:34.193:      IPv6=0x75F627E
Jun 28 01:21:34.193: NAT: s=192.168.0.4->221.189.114.163, d=49.212.49.25 [14138]

// failed
Jun 28 01:21:38.594: NAT: o: udp (49.212.49.25, 57410) -> (221.189.114.163, 53) [247]    
Jun 28 01:21:38.594: NAT (UDP-DNS): Before Translation
Jun 28 01:21:38.594: NAT: Translation of UDP DNS src 49.212.49.25, dst 221.189.114.163
Jun 28 01:21:38.594: NAT: Dns type of Query
Jun 28 01:21:38.594:    : dns len=21, id=38605, aa=0, tc=0, rd=1, ra=0
Jun 28 01:21:38.594:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:38.594:    : ancount=0, nscount=0, arcount=0
Jun 28 01:21:38.594: NAT (UDP-DNS): After Translation
Jun 28 01:21:38.594: NAT: Translation of UDP DNS src 49.212.49.25, dst 221.189.114.163
Jun 28 01:21:38.594: NAT: Dns type of Query
Jun 28 01:21:38.594:    : dns len=21, id=38605, aa=0, tc=0, rd=1, ra=0
Jun 28 01:21:38.594:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:38.594:    : ancount=0, nscount=0, arcount=0
Jun 28 01:21:38.594: NAT: s=49.212.49.25, d=221.189.114.163->192.168.0.4 [247]
Jun 28 01:21:38.594: NAT: i: udp (192.168.0.4, 53) -> (49.212.49.25, 57410) [30793]    
Jun 28 01:21:38.594: NAT (UDP-DNS): Before Translation
Jun 28 01:21:38.598: NAT: Translation of UDP DNS src 192.168.0.4, dst 49.212.49.25
Jun 28 01:21:38.598: NAT: Dns type of Response
Jun 28 01:21:38.598:    : dns len=98, id=38605, aa=1, tc=0, rd=1, ra=0
Jun 28 01:21:38.598:    : opcode=0, rcode=0, qdcount=1
Jun 28 01:21:38.598:    : ancount=1, nscount=1, arcount=2
Jun 28 01:21:38.598:      query name is ns2.yuyarin.net, qtype=1, class=1
Jun 28 01:21:38.598: Answer section:
Jun 28 01:21:38.598:    Name='ns2.yuyarin.net'
Jun 28 01:21:38.598:    RR type=1, class=1, ttl=300, data length=4
Jun 28 01:21:38.598:      IP=49.212.49.25
Jun 28 01:21:38.598: Authority section:
Jun 28 01:21:38.598:    Name='yuyarin.net'
Jun 28 01:21:38.598:    RR type=2, class=1, ttl=300, data length=5
Jun 28 01:21:38.598:      NS='ns.yuyarin.net'
Jun 28 01:21:38.598: Additional record section:
Jun 28 01:21:38.598:    Name='ns.yuyarin.net'
Jun 28 01:21:38.598:    RR type=1, class=1, ttl=300, data length=4
Jun 28 01:21:38.598:      IP=221.189.114.163
Jun 28 01:21:38.598:    Name='ns.yuyarin.net'
Jun 28 01:21:38.598:    RR type=28, class=1, ttl=300, data length=16
Jun 28 01:21:38.598:      IPv6=0x7924E72
Jun 28 01:21:38.598:  mapping pointer available mapping:0
Jun 28 01:21:38.598: NAT: translation failed (A), dropping packet s=192.168.0.4 d=49.212.49.25
c1812j#show ip nat translations
Pro Inside global         Inside local          Outside local         Outside global
udp 221.189.114.163:53    192.168.0.4:53        49.212.49.25:39068    49.212.49.25:39068 (ns
udp 221.189.114.163:53    192.168.0.4:53        49.212.49.25:52767    49.212.49.25:52767 (ns2

解決策

no-payload optionでペイロード書き換えを行わないようにする.interfaceを指定する記述では no-payloadは使えないのでglobalアドレスを直書きする.

Before
ip nat inside source static udp 192.168.0.4 53 interface Dialer2 53
ip nat inside source static tcp 192.168.0.4 53 interface Dialer2 53
after
ip nat inside source static tcp 192.168.0.4 53 221.189.114.163 53 extendable no-payload
ip nat inside source static udp 192.168.0.4 53 221.189.114.163 53 extendable no-payload

Time Machineで/var/logのログファイルもバックアップする

Mac OS X のシステムログは /var/log (/private/var/log) に保存されているが,デフォルトでは Time Machine でこのディレクトリの中のファイルはバックアップされない.

これらのログファイルをバックアップの対象にするためには /System/Library/CoreServices/backupd.bundle/Contents/Resources/StdExclusions.plist の FileContentsExcluded (ディレクトリ内のファイルをバックアップしない)という項目に /private/var/log が含まれているので,この行を削除するかコメントアウトすれば良い.

        <key>FileContentsExcluded</key>
        <array>
                <!-- <string>/private/var/log</string> -->
                <string>/private/var/spool/cups</string>

ただし,意図的にバックアップ対象から外されているので*1,これらをバックアップすることによって何らかの問題が生じる可能性があるので自己責任で行うように.

*1:恐らくTime Machineのバックアップのログが保存されるため.

Mac OS X 用スクリーンショット アップロード スクリプト

スクリーンショットを撮って,自分のサーバにアップロードして,Firefox で開いて,クリップボードにURLをコピーするだけの簡単なスクリプト.いつもはてダにスクリーンショットを張るときに使ってます.

QuickSilver に ss って名前で登録して使ってます.

ちなみにウィンドウキャプチャ,矩形キャプチャの切り替えはスペースです.

http://www.yuyarin.net/screenshot/20110516235136.png

QuickSilverで起動

http://www.yuyarin.net/screenshot/20110516235303.png

スペースを押して矩形選択でキャプチャ

ソースコード

#!/bin/sh
DATE=`date '+%Y%m%d%H%M%S'`
FILENAME="$DATE.png"
LOCAL_FILE="/Users/you/Pictures/Capture/$FILENAME"
REMOTE_DIR="host:/path/to/the/directory/of/httpd/"
URI="http://www.example.com/screenshot/$FILENAME"

screencapture -W $LOCAL_FILE 2>&1 > /dev/null

if [ -e $LOCAL_FILE ];
then
	scp $LOCAL_FILE $REMOTE_DIR 2>&1 > /dev/null
	if [ $? -eq 0 ];
	then
		/bin/echo -n $URI | pbcopy
		open -a Firefox $URI
	fi
fi

apache2/php5 of macports seem heavy for cacti

http://www.yuyarin.net/screenshot/20110424034956.png

Problem

It takes about 15 sec to draw each graph out by cacti. The web server gets high-load, very heavy, and sometime httpd processes become uninterruptible zombie.

Environment

Hardware.

OS Mac OS X 10.6
Hardware MacMini
CPU Intel Core 2 Duo 2.4GHz
Memory DDR3 8GB

Softwares, from Macports

apache2 2.2.17_1+preforkmpm
php5 5.3.6_0+apache2+pear
cacti 0.8.7g_1+plugins
rrdtool 1.4.4

Investigation

In cacti, the graphs are generated by rdtool_execute() at line 61 in lib/rrd.php, called by rrdtool_function_graph() at line 553. As the result of my debug, the bottleneck is first fgets() at line 172 after popen(), executing a rrdtool graph command. I tried the same rrdtool command in the shell and a php cli script, but it took less than 1 sec. Then I tried system() function in a php script from cli. The result was same. Next, I moved the php script to a directory of apache and accessed the script through my web browser, it took about 15sec.

So, the bottleneck is process execution in php5 on apache2, installed from macports. This problem will be identical to my Mac OS X because my another cacti works well on FreeBSD.

I can suspect my httpd configuration as the cause, but I just inserted one line into httpd.conf:

LoadModule php5_module modules/libphp5.so

or, 32/64-bit mode of Mac OS X, or php module configuration and apache configuration of macports, or else...

I'm now investigating the cause of this bad performance...

If you are onto something about this problem, please let me know.

KDDIとniftyがauひかりにIPv6割り当て開始

2011年04月18日,KDDI光ファイバーサービス「auひかり」のユーザ向けにIPv6アドレスの割り当てを追加料金なしで行っていくと発表した.同様にniftyも「@nifty auひかり」のIPv6対応開始を発表した(pdf).接続はIPv4/IPv6デュアルスタック方式となる.@niftyIPv6ネイティブ接続も提供する.

KDDIは「auひかりホーム」と「auひかりマンション ミニ」の加入者に対して,最初は関東エリア,他の地域は2012年1月以降に順次対応するとしている.niftyKDDIの設備を利用しているためこれに準ずる.

ユーザ環境のIPv6への対応はホームゲートウェイファームウェアをアップデートすることで対応する.また,KDDI側のネットワーク設備の更新も順次行われる.

DHCPv6サーバとして株式会社XACKのXACK_DHCPが採用されたとのこと.

コメント

APNIC,JPNICIPv4アドレスの枯渇を受けて各プロバイダでIPv6デプロイの流れが表面化してきたように感じる.このニュースはその中でも先陣を切った感じだろう.

@niftyは最低限の自社設備のアップデートは完了した模様で,Webサイトは6月以降順次対応する予定.同社のwebサイトではIPv6のメリットが強調されている.KDDIは3月に106.128.0.0/10を取ってるのでまだIPv4は無くならなさそう.だからIPv6が追加されたときにメリットだけ述べられるのかな.

[Network Number]                106.128.0.0/10
[Organization]                  KDDI CORPORATION
[Allocated Date]                2011/03/15