实现一个whois工具

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的实现就大体如此了.

转载于:https://my.oschina.net/GIIoOS/blog/416491

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值