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)交流学习。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐