Go製whoisクライアントの実装をみてみた
https://github.com/domainr/whois
Go製のwhoisクライアントを見かけたので実装を見てみた。 Ruby製のものにインスパイアされているらしい。
Trending Go repositories on GitHub today で見かけた ditto というツールの中で使われていて興味を持った。
利用方法
以下のようにするだけで指定したクエリに対するドメイン情報の出力が得られる。
query := "example.com" response, _ := whois.Fetch(query) fmt.Println(response.String()) // Domain Name: EXAMPLE.COM // ...
whois-parser-go を使えば出力をパースすることができる。1
import ( whoisparser "github.com/likexian/whois-parser-go" "github.com/k0kubun/pp" ) parsed, err := whoisparser.Parse(res.String()) pp.Println(parsed) // whoisparser.WhoisInfo{ // ... // }
実装について 2
zonedb というライブラリを使ってWhoisサーバを識別しているところが特徴。上記例ではクエリに "example.com"
を与えているが、その場合は "whois.verisign-grs.com"
というホストが得られる。ここのポート43にTCP接続してクエリをやり取りすることでドメイン情報が得られる。
以下にソースコードの一部を抜粋しておく。
Whoisサーバを識別してホスト(とURL)を得る箇所が以下。
req.Host, req.URL, err = Server(req.Query)
Server
関数の内容
// Server returns the whois server and optional URL for a given query. // Returns an error if it cannot resolve query to any known host. func Server(query string) (string, string, error) { // Queries on TLDs always against IANA if strings.Index(query, ".") < 0 { return IANA, "", nil } z := zonedb.PublicZone(query) if z == nil { return "", "", fmt.Errorf("no public zone found for %s", query) } // Try whois URL first (these are relatively rare) wu := z.WhoisURL() if wu != "" { u, err := url.Parse(wu) if err == nil && u.Host != "" { return u.Host, wu, nil } } // Then try host (more common) h := z.WhoisServer() if h != "" { return h, "", nil } return "", "", fmt.Errorf("no whois server found for %s", query) }
指定したクエリに .
が含まれていなければ、リクエスト先は常に IANA
("whois.iana.org"
という文字列の定数) になる。
.
が含まれる場合は後続の処理を行う。先にレアケースであるWhois URL3が得られるか確認し、なければWhoisサーバを取得する。取得できなければここでエラーとなる。