address Logo

Everything is a file

2007/10/29

"Everything is a file" は Plan 9 のコンセプトの一つである。システムコールを増やさずに、OS にとっての必要な情報をファイルインターフェースでプログラマに提供するやりかたは本当に良いと思う。

以下に紹介するのは Python で書いた dnsquery 関数である。UNIX であれば DNS の呼び出しに独立した大きなモジュールが必要となるだろう[1]

Plan 9 では次の(コメントを除けば) 8 行程度の関数で十分である。

def dnsquery(name,s):
        """
        usage:
        print dnsquery("/net/dns","ar.aichi-u.ac.jp ip")
        print dnsquery("/net/dns","202.250.160.40 ptr")
        """
        f = open(name,"w+")
        f.seek(0)
        t = split(s)
        if t[1] == "ptr":
                u = split(t[0],".")
                s = join((u[3],u[2],u[1],u[0]),".")+".in-addr.arpa ptr"
        f.write(s)
        f.seek(0)
        return f.readline() # "" if not answered

このコードの半分は IP から FQDN を求める場合に費やされている。

Plan 9 のコマンド

	ndb/dnsquery

において、IP から FQDN を求めたい場合には(例えば)

	202.250.160.40 ptr

とする。Python の関数 dnsquery() でもこの形式を保ちたいと考えるのは当然である。
しかし。この要求は /net/dns に対しては何故か

	40.160.250.202.in-addr.arpa ptr

として渡さなくてはならないのだ。(ちょっと不便だね...)
このような事になっていなければ、たったの 4 行で済んだのに!

ところで Python は利口だね。どうやら f.close() が自動実行されるらしい。"/net/dns" はオプションにした方が良かったかな...

追記

2007/10/31

先に紹介した dnsquery() はバグがある事に気付いた。1つの IP に複数の FQDN がある場合に対応していないのだ。その解決のために、f.readline() を f.readlines() に置き換えれば良いように思われるかも知れないが、そうするとレコードの区切りが明示的に与えられない。問題の解決には Plan 9 の read() を使う必要がある。

ついでに "/net/ndb" をオプションにし、さらに戻り値を簡潔にした。読み取りのバッファサイズは 256 にして置いたが、これで十分かどうかは知らない注1

#!/bin/env python
import sys,os
import re
from string import *

def dnsquery(q,name="/net/dns"):
        """
        usage:
        print dnsquery("ar.aichi-u.ac.jp ip")
        print dnsquery("ar.aichi-u.ac.jp ip","/net/dns")
        print dnsquery("202.250.160.40 ptr")
        """
        f = os.open(name,os.ORDWR)
        os.seek(f,0,0)
        t = split(q)
        if t[1] == "ptr":
                u = split(t[0],".")
                q = join((u[3],u[2],u[1],u[0]),".")+".in-addr.arpa ptr"
        r = []
        try:
                os.write(f,q)
                os.seek(f,0,0)
                v = os.read(f,256) # "" if not answered
                while v:
                        r = r + [v.split()[2]]
                        v = os.read(f,256)
        except:
                pass
        os.close(f)
        return r


print dnsquery("202.250.160.40 ptr")
print dnsquery("ar.aichi-u.ac.jp ip","/net/dns")
print dnsquery("129.79.115.30 ptr","/net/dns")
print dnsquery("207.210.94.66 ptr")
print dnsquery("67.122.237.50 ptr")
print dnsquery("63.236.211.155 ptr")
print dnsquery("130.203.4.6 ptr")
print dnsquery("13.203.4.6 ptr")

sys.exit()
"""-------------------------------------------
term% query.py
['ar.aichi-u.ac.jp']
['202.250.160.40']
['129-79-115-30.dhcp-bl.indiana.edu']
['cpanel100.atl.wiresix.com', 'vparent100.atl.wiresix.com']
['adsl-67-122-237-50.dsl.scrm01.pacbell.net', 'adsl-67-122-237-50.dsl.pltn13.pacbell.net']
['serv155.datamatrox.com', '63-236-211-155.dia.static.qwest.net']
['psuvax1.cse.psu.edu']
[]
-------------------------------------------"""
注1: Wikipedia によると FQDN の最大長は 255B である[2]。だから ndsquery() での読み取りフーバッファの大きさは 512B にまで上げた方が良い。

[1] Python DNS Library
http://sourceforge.net/projects/pydns/
[2] Fully qualified domain name
http://en.wikipedia.org/wiki/FQDN