WHOIS 協議(RFC 3912)基於 TCP 43 埠,客戶端連線伺服器發送域名字串(以 CRLF 結尾),伺服器回傳註冊資訊純文字。無加密、無驗證、無狀態。核心挑戰在於:**不同頂級域(TLD)對應不同 WHOIS 伺服器**,需建立路由表或遞迴查詢。
// query_internic.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Net.Sockets" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.IO" %>
// query_registries.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Net.Sockets" %>
<%@ Import Namespace="System.Text" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Collections" %>
\r\n(必須 CRLF)| 策略 | 說明 | 優/缺點 |
|---|---|---|
| 靜態對照表 | 硬編碼常用 TLD 伺服器 | 快、簡單,但需維護 |
| IANA 根區查詢 | 查詢 whois.iana.org 取得 referral | 權威、自動更新,但多一次 RTT |
| DNS SRV 記錄 | 查詢 _whois._tcp.tld | 標準化,但部署率低 |
| 遞迴 Referral 追蹤 | 解析回應中的 "refer:" 或 "whois:" 欄位 | 通用,需解析非結構化文字 |
// 簡易欄位提取範例
var dict = new Dictionary();
foreach (var line in rawResponse.Split('\n'))
{
var idx = line.IndexOf(':');
if (idx > 0)
{
var key = line.Substring(0, idx).Trim().ToLower();
var val = line.Substring(idx + 1).Trim();
if (!dict.ContainsKey(key)) dict[key] = val;
}
}
// 常見欄位:domain name, registrar, creation date, expiration date, name server, status
MemoryCache/Redis)TcpClient.ConnectAsync + CancellationToken 設定 10 秒逾時IdnMapping.GetAscii 轉 Punycode 再查詢using System;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
class WhoisClient
{
static readonly Dictionary Servers = new()
{
["com"] = "whois.verisign-grs.com",
["net"] = "whois.verisign-grs.com",
["org"] = "whois.pir.org",
["io"] = "whois.nic.io",
["ai"] = "whois.nic.ai",
["cn"] = "whois.cnnic.cn",
["tw"] = "whois.twnic.net.tw",
["jp"] = "whois.jprs.jp",
["kr"] = "whois.kr",
["de"] = "whois.denic.de",
["uk"] = "whois.nic.uk",
["fr"] = "whois.nic.fr",
["eu"] = "whois.eu",
["app"] = "whois.nic.google",
["dev"] = "whois.nic.google"
};
static void Main(string[] args)
{
if (args.Length == 0) { Console.WriteLine("Usage: WhoisClient domain.com"); return; }
string domain = args[0].ToLower();
string tld = domain.Split('.')[^1];
string server = Servers.ContainsKey(tld) ? Servers[tld] : "whois.iana.org";
Console.WriteLine($"查詢 {domain} @ {server} ...");
string result = Query(server, domain);
Console.WriteLine(result);
}
static string Query(string server, string domain)
{
try
{
using (var tcp = new TcpClient())
{
tcp.Connect(server, 43);
tcp.ReceiveTimeout = 10000;
byte[] req = Encoding.ASCII.GetBytes(domain + "\r\n");
tcp.GetStream().Write(req, 0, req.Length);
using (var sr = new StreamReader(tcp.GetStream(), Encoding.UTF8))
return sr.ReadToEnd();
}
}
catch (Exception ex) { return $"Error: {ex.Message}"; }
}
}
WHOIS 查詢雖協議簡單,但 TLD 路由、編碼差異、速率限制、非結構化回應解析等工程細節決定了可用性。本文提供從基礎 ASPX 頁面到生產級主控台元件的完整演進路徑,並指向現代 RDAP 協議作為長期演進方向。