文档章节

实现一个whois工具

Force武装卫队
 Force武装卫队
发布于 2015/05/18 23:21
字数 828
阅读 286
收藏 1

whois是一个查询注册域名的命令,如果要在Ubuntu上安装可以键入

sudo apt-get install whois 

一般whois的语法如下:

whois oschina.net

通过此命令就可以得到oschina.net域名的注册信息以及版权信息.

whois并不是个复杂的东西,实际上,网络上有很多在线工具提供whois查询. 在Windows上并没有whois命令,ReactOS使用 Ted Felix(The Regents of the University of California.) 开发的whois程序,基于BSD协议. 这个whois不支持IPv6,用的是比较老的API,于是我将其重写了,代码如下:

/*********************************************************************************************************
* whois.cpp
* Note: Phoenix whois tools
* Date: @2015.05
* Author: Force Charlie
* E-mail:<forcemz@outlook.com>
* Copyright (C) 2015 The ForceStudio All Rights Reserved.
**********************************************************************************************************/
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <codecvt>
#include <vector>
#pragma comment(lib,"ws2_32")


static wchar_t whoisList[] =L"whois.internic.net";
wchar_t *host = nullptr;
wchar_t other[2048] = { 0 };
int optset = 0;

static bool Whois(const wchar_t *domian);
static void usage()
{
	printf("usage: whois [-h hostname] name ....\n");
}

bool StringToWideString(const std::string& src, std::wstring &wstr)
{
	std::locale sys_locale("");
	const char* data_from = src.c_str();
	const char* data_from_end = src.c_str() + src.size();
	const char* data_from_next = 0;

	wchar_t* data_to = new wchar_t[src.size() + 1];
	wchar_t* data_to_end = data_to + src.size() + 1;
	wchar_t* data_to_next = 0;

	wmemset(data_to, 0, src.size() + 1);

	typedef std::codecvt<wchar_t, char, mbstate_t> convert_facet;
	mbstate_t in_state = { 0 };
	auto result = std::use_facet<convert_facet>(sys_locale).in(
		in_state, data_from, data_from_end, data_from_next,
		data_to, data_to_end, data_to_next);
	if (result == convert_facet::ok)
	{
		wstr = data_to;
		delete[] data_to;
		return true;
	}
	delete[] data_to;
	return false;
}

int main(int argc, char **argv)
{
	if (argc < 2)
	{
		usage();
		return 0;
	}
	host = whoisList;
	std::vector<std::string> domainV;
	for (int i = 1; i < argc; i++){
		switch (argv[i][0]){
		case '-':
		case '/':
			if (strlen(argv[i]) < 2)break;
			if (strcmp(&argv[i][1], "h") == 0){
				if (i + 2 < argc)
				{
					std::string str = argv[i + 1];
					std::wstring wstr;
					if (!StringToWideString(str, wstr))
						return 1;
					wcsncpy_s(other, wstr.c_str(), 2048);
					host = other;
					i++;
				}
			}
			break;
		default:
			domainV.push_back(argv[i]);
			break;
		}
	}
	char ch;
	DWORD dwRetval;
	ADDRINFOW *result = NULL;
	ADDRINFOW hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	WSADATA wsaData;
	auto iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if ((dwRetval = GetAddrInfoW(host, nullptr, &hints, &result)) != 0){
		wprintf(L"whois: GetAddrInfoW failed with error: %d\n", dwRetval);
		WSACleanup();
		return 1;
	}
	if (result == nullptr){
		WSACleanup();
		return 1;
        }
	SOCKET sock;
	sock = socket(result->ai_family, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET) {
		wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
		FreeAddrInfoW(result);
		WSACleanup();
		return 1;
	}
	wchar_t ipstringbuffer[46];
	DWORD ipbufferlength = 46;
	WSAAddressToString(result->ai_addr, (DWORD)result->ai_addrlen, NULL,
		ipstringbuffer, &ipbufferlength);
	sockaddr_in sin;
	memset(/*(caddr_t)*/&sin, 0, sizeof(sin));
	sin.sin_family = result->ai_family;
	ULONG iaddr;
	InetPtonW(result->ai_family, ipstringbuffer, &iaddr);
	sin.sin_addr.s_addr = iaddr;
	sin.sin_port = htons(43);
	iResult = connect(sock, (sockaddr *)&sin, sizeof(sin));
	if (iResult == SOCKET_ERROR) {
		wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
		iResult = closesocket(sock);
		if (iResult == SOCKET_ERROR)
			wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
		FreeAddrInfoW(result);
		WSACleanup();
		return 1;
	}
	auto i = domainV.size();
	while (i-- > 1){
		auto dm = domainV[i-1];
		send(sock, dm.c_str(), dm.size(), 0);
		send(sock, " ", 1, 0);
	}
	send(sock, domainV[0].c_str(), domainV[0].size(), 0);
	send(sock, "\r\n", 2, 0);
	wprintf(L"[%s]\n", host);
	while (recv(sock, &ch, 1, 0) == 1)
		putchar(ch);
	FreeAddrInfoW(result);
	WSACleanup();
	return 0;
}

对于一个whois工具来说,第一步是获得whois服务器,一般而言,常见的whois有

  • whois.internic.net
  • whois.apnic.net
  • whois.edu.cn
  • whois.twnic.net
  • whois.nic.ad.jp
  • whois.lacnic.net
  • whois.ripe.net
  • whois.arin.net

当然用户可以使用 -h参数指定whois服务器.

原有的whois程序使用gethostbyname获取ip地址,但gethostbyname并不支持ipv6,而且被标记为废弃的函数,所以使用GetAddrInfoW 替代,GetAddrInfoW或得一个地址链表,我们只要第一个地址就行,我们将result的数据整理到sockaddr_in中,然后连接到ip的43端口,whois服务默认就是43端口.

Windows不像BSD可以直接用fread fprintf之类,我们使用send和recv发送和接受数据. whois需要发送域名类似如下格式:

domain.net domain.com\r\n

空格分割域名,最后一"\r\n"结束.

一个whois的实现就大体如此了.

© 著作权归作者所有

Force武装卫队

Force武装卫队

粉丝 190
博文 40
码字总数 80436
作品 3
深圳
高级程序员
私信 提问
java验证域名是否有效

如果解析一个域名是否有效的, 站长之家工具里面用的是whois命令, 但是它们没有提供对外的借口, 只能自己写, 在apache上面找到一个叫common net的开源项目, 但是跑了后发现跟查询Whois命令里面...

Chasel-Li
2013/06/28
1K
3
使用 DNSTrails 自动找出每个域名的拥有者

今天,我们很高兴地宣布我们最近几周做的新功能。它是 Whois 聚合工具,现在可以在 DNSTrails 上获得。 在过去,查找一个域名的所有者会花费很多时间,因为大部分时间你都需要把域名翻译为一...

作者: Securitytrails Team
2017/12/06
0
0
网络应用简记(4):DNS使用

dns,domain name system,域名系统,把域名转化成ip的系统。 先来看几上工具的使用,这几个工具都能把域名转换成ip,都使用了dns。dns就好比数据库,通过对它的查询,能给url找到对应的ip。...

jonlan
2018/12/11
0
0
Footprinting:踩点方面的一些资料分享

  上面是百科的描述,但其实踩点是踩点,扫描是扫描,扫描部分的学习资料下次分享,踩点只有一个宗旨就是不放过任何一个细节。    热点关注   对收集对象的近半年,一个月,或者一年,...

FreeBuf
2018/08/17
0
0
使用WHOIS协议查询domain信息

一、 原理 原理非常简单,域名的查询主要是基于RFC 954提供的WHOIS协议。在上述过程中,我们实际上是访问了InterNIC站点的WHOIS服务器,该服务器从WHOIS数据库中查询我们所需要的内容。 WHOI...

IamOkay
2016/05/07
176
0

没有更多内容

加载失败,请刷新页面

加载更多

匈牙利命名法、骆驼命名法、帕斯卡(pascal)命名法 C#命名规范

一、匈牙利命名法:广泛应用于象Microsoft Windows这样的环境中。 Windows 编程中用到的变量(还包括宏)的命名规则匈牙利命名法,这种命名技术是由一位能干的 Microsoft 程序员查尔斯·西蒙...

南风末
35分钟前
1
0
多线程安全(synchronized、三大特性、Java内存模型)

线程安全问题? 什么是线程安全问题?简单的说,当多个线程在共享同一个变量,做读写的时候,会由于其他线程的干扰,导致数据误差,就会出现线程安全问题。 比如说,多个窗口同时卖票这个案例...

天王盖地虎626
37分钟前
4
0
jenkins备份和自动部署

jenkins备份使用的是thinbackup插件。 安装完后在系统管理里滑动到最下面有个thinbackup菜单 点击进去即可开始备份。 backup Now是备份数据。 在填完settings里面的数据后 点击即可开始备份。...

起名字什么的太麻烦了
38分钟前
3
0
RDP服务之GoldBrute僵尸网络

最近的网络攻击活动中,可能要数BlueKeep漏洞的讨论热度最高了。但近日研究人员警告称,新发现的GoldBrute僵尸网络目前对Windows系统构成了不亚于BlueKeep带来的威胁。 1. 概览 安全研究人员...

Linux就该这么学
38分钟前
2
0
好程序员web前端教程分享JavaScript验证API

好程序员web前端教程分享JavaScript验证API,小编每天会分享一下干货给大家。那么今天说道的就是web前端培训课程中的章节。 JavaScript验证API   约束验证DOM方法 PropertyDescription ch...

好程序员IT
39分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部