nslookup 是一個查詢 Internet 域名伺服器的程序。我們通常使用nslookup工具來測試DNS解析,獲取DNS報文的詳細數據,這也是我們想要使用協議分析工具nslookup來分析DNS流量進行分析。
只要你上網,都會涉及DNS解析。簡單起見,我們這裡不會搭建一個DNS伺服器,而是使用Internet域名解析來分析驗證。
使用nslookup工具進行DNS查詢
nslookup 命令可用於許多作業系統,如 Windows、macOS 和 Linux 發行版。您可以使用它來執行 DNS 查詢並接收:域名或 IP 地址,或任何其他特定的 DNS 記錄。
nslookup命令可以在兩種模式下允許:交互式和非交互式。當需要返回單一查詢的結果,可以使用非交互式模式,語法如下:
nslookup [-option] [name | -] [server]
例如我們查詢一個baidu.com的命令結果如下
nslookup 後跟域名將顯示域的「A 記錄」(IP 地址)。使用此命令查找域的地址記錄。它查詢域名伺服器並獲取詳細信息。
如何檢查反向 DNS 查找?
很多時候您會檢查 A 記錄以查看域的 IP,但有時您需要驗證 IP 地址是否與特定域相關。為此,我們需要反向 DNS 查找。
下面來看看如何開啟nslookup調試模式。下面給出的是debug模式下部分代碼具體實現。
puts("--");
/*detailheader(query, msg);*/
detailsection(query, msg, 1, DNS_SECTION_QUESTION);
detailsection(query, msg, 1, DNS_SECTION_ANSWER);
detailsection(query, msg, 1, DNS_SECTION_AUTHORITY);
detailsection(query, msg, 1, DNS_SECTION_ADDITIONAL);
puts("--");static isc_result_t detailsection(dig_query_t *query, dns_message_t *msg, int headers,
dns_section_t section)
{
isc_result_t result, loopresult;
dns_name_t *name;
dns_rdataset_t *rdataset = NULL;
dns_rdata_t rdata = DNS_RDATA_INIT;
char namebuf[DNS_NAME_FORMATSIZE];
UNUSED(query);
debug("detailsection()");
if (headers)
{
switch (section)
{
case DNS_SECTION_QUESTION:
puts(" QUESTIONS:");
break;
case DNS_SECTION_ANSWER:
puts(" ANSWERS:");
break;
case DNS_SECTION_AUTHORITY:
puts(" AUTHORITY RECORDS:");
break;
case DNS_SECTION_ADDITIONAL:
puts(" ADDITIONAL RECORDS:");
break;
}
}
result = dns_message_firstname(msg, section);
if (result == ISC_R_NOMORE)
return (ISC_R_SUCCESS);
else if (result != ISC_R_SUCCESS)
return (result);
for (;;)
{
name = NULL;
dns_message_currentname(msg, section,
&name);
for (rdataset = ISC_LIST_HEAD(name->list);
rdataset != NULL;
rdataset = ISC_LIST_NEXT(rdataset, link))
{
if (section == DNS_SECTION_QUESTION)
{
dns_name_format(name, namebuf,
sizeof(namebuf));
printf("\t%s, ", namebuf);
dns_rdatatype_format(rdataset->type,
namebuf,
sizeof(namebuf));
printf("type = %s, ", namebuf);
dns_rdataclass_format(rdataset->rdclass,
namebuf,
sizeof(namebuf));
printf("class = %s\n", namebuf);
}
loopresult = dns_rdataset_first(rdataset);
while (loopresult == ISC_R_SUCCESS)
{
dns_rdataset_current(rdataset, &rdata);
dns_name_format(name, namebuf,
sizeof(namebuf));
printf(" -> %s\n", namebuf);
switch (rdata.type)
{
case dns_rdatatype_soa:
printsoa(&rdata);
break;
default:
printf("\t");
printrdata(&rdata);
}
dns_rdata_reset(&rdata);
printf("\tttl = %u\n", rdataset->ttl);
loopresult = dns_rdataset_next(rdataset);
}
}
result = dns_message_nextname(msg, section);
if (result == ISC_R_NOMORE)
break;
else if (result != ISC_R_SUCCESS)
{
return (result);
}
}
return (ISC_R_SUCCESS);
}nslookup的交互模式
nslookup在交互模式下使用,進入交互狀態並執行相應的子命令,交互命令如下:
static void setoption(char *opt)
{
size_t l = strlen(opt);
if (CHECKOPT("all", 3))
{
show_settings(1, 0);
}
else if (strncasecmp(opt, "class=", 6) == 0)
{
if (testclass(&opt[6]))
strlcpy(defclass, &opt[6], sizeof(defclass));
}
else if (strncasecmp(opt, "cl=", 3) == 0)
{
if (testclass(&opt[3]))
strlcpy(defclass, &opt[3], sizeof(defclass));
}
else if (strncasecmp(opt, "type=", 5) == 0)
{
if (testtype(&opt[5]))
strlcpy(deftype, &opt[5], sizeof(deftype));
}
else if (strncasecmp(opt, "ty=", 3) == 0) {
if (testtype(&opt[3]))
strlcpy(deftype, &opt[3], sizeof(deftype));
}
else if (strncasecmp(opt, "querytype=", 10) == 0)
{
if (testtype(&opt[10]))
strlcpy(deftype, &opt[10], sizeof(deftype));
}
else if (strncasecmp(opt, "query=", 6) == 0)
{
if (testtype(&opt[6]))
strlcpy(deftype, &opt[6], sizeof(deftype));
}
else if (strncasecmp(opt, "qu=", 3) == 0)
{
if (testtype(&opt[3]))
strlcpy(deftype, &opt[3], sizeof(deftype));
}
else if (strncasecmp(opt, "q=", 2) == 0)
{
if (testtype(&opt[2]))
strlcpy(deftype, &opt[2], sizeof(deftype));
}
else if (strncasecmp(opt, "domain=", 7) == 0)
{
strlcpy(domainopt, &opt[7], sizeof(domainopt));
set_search_domain(domainopt);
usesearch = 1;
}
else if (strncasecmp(opt, "do=", 3) == 0)
{
strlcpy(domainopt, &opt[3], sizeof(domainopt));
set_search_domain(domainopt);
usesearch = 1;
}
else if (strncasecmp(opt, "port=", 5) == 0)
{
set_port(&opt[5]);
}
else if (strncasecmp(opt, "po=", 3) == 0)
{
set_port(&opt[3]);
}
else if (strncasecmp(opt, "timeout=", 8) == 0)
{
set_timeout(&opt[8]);
}
else if (strncasecmp(opt, "t=", 2) == 0)
{
set_timeout(&opt[2]);
}
else if (CHECKOPT("recurse", 3))
{
recurse = 1;
}
else if (CHECKOPT("norecurse", 5))
{
recurse = 0;
}
else if (strncasecmp(opt, "retry=", 6) == 0)
{
set_tries(&opt[6]);
}
else if (strncasecmp(opt, "ret=", 4) == 0)
{
set_tries(&opt[4]);
}
else if (CHECKOPT("defname", 3))
{
usesearch = 1;
}
else if (CHECKOPT("nodefname", 5))
{
usesearch = 0;
}
else if (CHECKOPT("vc", 2) == 0)
{
tcpmode = 1;
}
else if (CHECKOPT("novc", 4) == 0)
{
tcpmode = 0;
}
else if (CHECKOPT("debug", 3) == 0)
{
short_form = 0;
showsearch = 1;
}
else if (CHECKOPT("nodebug", 5) == 0)
{
short_form = 1;
showsearch = 0;
}
else if (CHECKOPT("d2", 2) == 0)
{
debugging = 1;
}
else if (CHECKOPT("nod2", 4) == 0)
{
debugging = 0;
}
else if (CHECKOPT("search", 3) == 0)
{
usesearch = 1;
}
else if (CHECKOPT("nosearch", 5) == 0)
{
usesearch = 0;
}
else if (CHECKOPT("sil", 3) == 0)
{
/* deprecation_msg = 0; */
}
else if (CHECKOPT("fail", 3) == 0)
{
nofail=0;
}
else if (CHECKOPT("nofail", 5) == 0)
{
nofail=1;
}
else if (strncasecmp(opt, "ndots=", 6) == 0)
{
set_ndots(&opt[6]);
}
else
{
printf("*** Invalid option: %s\n", opt);
}
}
static void interactive_command(char *input)
{
char *ptr, *arg;
ptr = next_token(&input, " \t\r\n");
if (ptr == NULL)
return;
arg = next_token(&input, " \t\r\n");
if (strcasecmp(ptr, "set") == 0)
{
if (arg == NULL)
printf("Usage: set keyword=value, or set all\n");
else
setoption(arg);
}
else if ((strcasecmp(ptr, "server") == 0) ||
(strcasecmp(ptr, "lserver") == 0))
{
isc_result_t res;
if (arg == NULL)
printf("usage: server hostname\n");
else if ((res = set_nameserver(arg)))
{
printf("couldn't get address for '%s': %s\n",
arg, isc_result_totext(res));
}
else
{
check_ra = 0;
show_settings(1, 1);
}
}
else if (strcasecmp(ptr, "exit") == 0)
{
in_use = 0;
}
else if (strcasecmp(ptr, "help") == 0 ||
strcasecmp(ptr, "?") == 0)
{
printf("The '%s' command is not yet implemented.\n", ptr);
}
else if (strcasecmp(ptr, "finger") == 0 ||
strcasecmp(ptr, "root") == 0 ||
strcasecmp(ptr, "ls") == 0 ||
strcasecmp(ptr, "view") == 0)
{
printf("The '%s' command is not implemented.\n", ptr);
}
else
addlookup(ptr);
}常用的子命令為
nslookup [exit | finger | help | ls | lserver | root | server | set | view] [options]
exit :退出 nslookup 命令行工具finger :與當前計算機上的finger 伺服器連接help : 顯示子命令的簡短摘要ls: 列出 DNS 域的信息lserver : 改變默認域名伺服器root :將默認伺服器掛到DNS域名空間根的伺服器上server :指定域名伺服器set :此命令用於更改影響查找的狀態信息view:排序並列出前一個 ls 子命令或命令的輸出
在交互模式下正向解析,查詢域名信息。要中斷交互命令,可以使用ctrl + c組合鍵,要退出交互模式並返回到命令提示符,在命令提示符下輸入「exit」即可。
直接輸入要查詢的域名可返回域名的IP位址。輸入server可返回當前DNS伺服器的信息。
無論是交互式和非交互式,如果沒有指定DNS伺服器地址,nslookup命令將查詢當前計算機的默認DNS伺服器。
默認查詢主機地址,想要測試其他類型的資源記錄,先使用 set type命令設置要查詢的DNS記錄類型,然後輸入域名,可得到相應類型的域名測試結果。
類型值如下:
TYPE:
A IPv4 地址記錄
AAAA IPv6 地址記錄
AFSDB Andrew文件系統資料庫伺服器記錄
ATMA ATM地址記錄
CNAME 別名記錄
HINFO 硬體配置記錄,包括CPU、作業系統信息
ISDN 域名對應的ISDN號碼
MB 存放指定郵箱的伺服器
MG 郵件組記錄
MINFO 郵件組和郵箱的信息記錄
MR 改名的郵箱記錄
MX 郵件伺服器記錄
NS 名字伺服器記錄
PTR 反向記錄
RP 負責人記錄
RT 路由穿透記錄
SRV TCP伺服器信息記錄
TXT 域名對應的文本信息
X25 域名對應的X.25地址記錄舉例如下:
如何查找域的所有可用 DNS 記錄。
nslookup -type=any baidu.com
這個查找範圍很大。在這裡,我們要查看所有可用的 DNS 記錄。在看到所有這些之後,我們可以對不同類型的 DNS 記錄進行特定查找。
捕獲DNS流量驗證報文格式
網絡訪問只要涉及域名,都會執行DNS解析,如ping ,web訪問等等。下面我們使用nslookup命令查詢域名baidu.com 。
下圖是使用wireshark進行抓取DNS數據包
這是一個簡單的DNS解析過程,序號為56的數據包顯示的是DNS查詢報文,序號為57是數據包是DNS應答報文。
下面我們講講56序號的詳細數據。
這裡我們展開了Domain Name System節點。客戶端向伺服器發送DNS查詢報文,這是一個標準查詢(Standard Query),我們可以理解為正向解析。
查詢報文分為首部和問題兩個部分。首部包含ID,標誌和計數器3類欄位。Opcode值為0表示標準查詢。
Question為1表示只有一個查詢報文,其他3個資源記錄數均為0。問題部分給出了要查詢的域名、類型、和類。
這個報文封裝在UDP協議上,發往DNS伺服器,傳輸的目的埠號為53.
下面我們講講57序號的詳細數據。
這裡我們展開了Domain Name System節點。伺服器返回客戶端DNS應答報文。應答報文分為首部、問題、回答、權威、附加5個部分。
首部包含ID,標誌和計數器3類欄位。ID與查詢報文相同。Question為1表示只有一個查詢報文,其他3個資源記錄數給出了相應的數目,問題部分與查詢部分相同
在展開Answers節點。每條記錄都包括名稱、類型、類、生存時間、數據長度和數據6個欄位。
總結
nslookup 是流行的 DNS 探測命令行軟體之一。可以使用它來監控您的網絡並發現有問題的區域。如果大家感興趣,可以研究研究類似的工具,比如dig、traceroute 、ping等等。
看完一鍵三連在看,轉發,點讚。歡迎關注微信公眾號【程序猿編碼】,歡迎添加本人微信號(c17865354792)交流學習。