求助,如何一边捕获者一边预览

2751人阅读
网络(200)
上次在文章《》中提到使用udp协议发送dns数据包查询站点ip,这次带来TCP版本的查询代码。
其实不管是tcp协议还是udp协议,都是构造dns报文,填写查询方式,发送数据包即可。
然而,在dns协议中有个特殊的地方需要重点强调!使用tcp协议和udp协议发送的dns报文有个很容易被忽略的问题:在tcp协议时,除了udp协议时的dns报文数据,还要在原有的报文数据之前添加两个字节,这两个字节指名其后的dns报文数据有多少字节!
除了上述的区别,其他的都一样。
另外,再提个问题,其实在dns服务器返回的数据包中可能包含了同一个域名的多个ip地址,我们在UDP的那篇文章中只解析了最后一个提供的ip地址~,这次的tcp模式同时解析了所有返回的ip地址~
这次的代码使用了文章《》中的头文件。main函数文件代码如下:
#include &stdio.h& #include &string.h& #include &tcp_client.h& typedef unsigned short
U16; const char srv_ip[] = &8.8.8.8&; #define
R_OK & &0 #define R_ERROR -1 /*typedef
struct _DNS_HDR { & & & U16 & & U16 &
& U16 & & U16 & & U16 numa1; & & U16 numa2; }DNS_HDR;*/ typedef struct { unsigned short
id; & & & // identification number unsigned char
rd :1; & & // recursion desired unsigned char
tc :1; & & // truncated message unsigned char
aa :1; & & // authoritive answer unsigned char
opcode :4; // purpose of message unsigned char
qr :1; & & // query/response flag unsigned char
rcode :4; &// response code unsigned char
cd :1; & & // checking disabled unsigned char
ad :1; & & // authenticated data unsigned char
z :1; & & &// its z! reserved unsigned char
ra :1; & & // recursion available unsigned short
q_count; &// number of question entries unsigned short
ans_count; // number of answer entries unsigned short
auth_count; // number of authority entries unsigned short
add_count; // number of resource entries }DNS_HDR; /*typedef
struct _DNS_QER { & & U16 & & U16 }DNS_QER;*/ typedef struct { unsigned short
type; unsigned short classes; }DNS_QES; int
main(int argc, char **argv) { &
& unsigned char buff[1024]; &
& unsigned char *buf = buff + 2; &
& unsigned char *p; &
& int len, i; & & DNS_HDR &*dnshdr = (DNS_HDR *)buf; &
& DNS_QES &*dnsqes = NULL; & & &
& if (R_ERROR == tcp_client_init(argv[2], 53)) &
& { & & & & printf(&Conn Error!\n&); &
& & & return -1; & & } &
& else & & { & & & & printf(&Conn
OK!\n&); & & } & & &
& memset(buff, 0, 1024); &
& dnshdr-&id = htons(0x2000);//(U16)1; &
& dnshdr-&qr = 0; & & dnshdr-&opcode = 0; &
& dnshdr-&aa = 0; & & dnshdr-&tc = 0; &
& dnshdr-&rd = 1; & & dnshdr-&ra = 1; &
& dnshdr-&z &= 0; & & dnshdr-&ad = 0; &
& dnshdr-&cd = 0; & & dnshdr-&rcode = 0; &
& dnshdr-&q_count = htons(1); &
& dnshdr-&ans_count = 0; &
& dnshdr-&auth_count = 0; &
& dnshdr-&add_count = 0; &
& strcpy(buf + sizeof(DNS_HDR) + 1,
argv[1]); & & p = buf + sizeof(DNS_HDR) + 1;
i = 0; & & while (p & (buf + sizeof(DNS_HDR) + 1 +
strlen(argv[1]))) & & { &
& & & if ( *p == '.') &
& & & { & & & & & & *(p - i - 1) =
i; & & & & & & i = 0; &
& & & } & & & & else & & & & { &
& & & & & i++; & & & & } & & & & p++; &
& } & & *(p - i - 1) =
i; & & & & & & & & & & & & & & & & & & & & dnsqes = (DNS_QES *)(buf + sizeof(DNS_HDR) + 2 +
strlen(argv[1])); & & dnsqes-&classes =
htons(1); & & dnsqes-&type =
htons(1); & & buff[0] = 0;
buff[1] = sizeof(DNS_HDR) + sizeof(DNS_QES) +
strlen(argv[1]) + 2; &
& if (R_ERROR == tcp_client_send(buff, sizeof(DNS_HDR) + sizeof(DNS_QES) +
strlen(argv[1]) + 4)) &
& { & & & & printf(&Send Error!\n&); &
& & & return -1; & & } &
& else & & { & & & & printf(&Send
OK!\n&); & & } & & &
& len = tcp_client_recv(buff, 1024); &
& if (len & 0) &
& { & & & & printf(&Recv Error!\n&); &
& & & return -1; & & } &
& else & & { & & & & printf(&Recv
OK!\n&); & & } & & &
& if (dnshdr-&rcode !=0 ||
dnshdr-&ans_count == 0) &
& { & & & & printf(&Ack Error\n&); &
& & & return -1; & & } &
& p = buff + 2 + sizeof(DNS_HDR) + sizeof(DNS_QES) +
strlen(argv[1]) + 2; &
& printf(&Ans Count = %d\n&, ntohs(dnshdr-&ans_count)); &
& for (i = 0; i &
ntohs(dnshdr-&ans_count); i++) &
& { & & & & p = p + 12; &
& & & printf(&%s ==& %u.%u.%u.%u\n&, argv[1], (unsigned char)*p, (unsigned char)*(p + 1), (unsigned char)*(p + 2), (unsigned char)*(p + 3)); &
& & & p = p + 4; & & } &
& tcp_client_close(); & & return 0; }
执行结果如下:
[root@isayme socket]# ./dns_tcp isayme.org 8.8.8.8 Conn
OK! Send OK! Recv
OK! Ans Count = 1 isayme.org ==& 173.231.29.114 [root@isayme
socket]# ./dns_ 8.8.8.8 Conn OK! Send
OK! Recv OK! Ans Count = 6 google.com ==& 74.125.71.106 google.com ==& 74.125.71.103 google.com ==& 74.125.71.147 google.com ==& 74.125.71.105 google.com ==& 74.125.71.104 google.com ==& 74.125.71.99
需要的头文件在文章《》中下载!
转载本站文章请注明转载自:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1432949次
积分:18986
积分:18986
排名:第423名
原创:251篇
转载:1577篇
评论:37条
(15)(15)(73)(34)(33)(54)(70)(68)(59)(76)(55)(47)(29)(24)(65)(30)(24)(37)(24)(33)(41)(61)(75)(45)(41)(27)(41)(49)(32)(31)(39)(64)(10)(65)(39)(34)(30)(33)(27)(20)(23)(20)(24)(19)(15)(11)(7)(1)(3)(1)(3)(2)(7)(8)(5)(2)(4)(1)您的位置: &
使用Win Socket实现域名和IP的查询
优质期刊推荐简单分析一下socket中的bind - 守夜者 - 博客园
灵感来自于积累
  在最开始接触bind的时候,只是在写基于tcp的server端的时候,知道在listen之前需要先bind一下,用来确保socket能在某个固定的端口监听。而bind的时候,函数参数中的端口填自己将要绑定的端口就行;而IP地址,需要填本机的IP,但是也可以用一个宏INADDR_ANY代替,用这个宏就可以不用查找本机的IP,它就可以代替本机的IP。当时只觉得这个INADDR_ANY比较神奇,但是由于当时觉得用起来很方便,也没出啥问题,也就没有再深究。  但是最近在做RTSP服务器的时候,有种特殊的应用,导致我不得不对bind这个函数仔细地看一下。  我们知道无论是UDP还是TCP,socket都会与一个本地的IP和端口想对应,我们往往把这个IP和端口称之为socket的源地址和源端口。当我们作为客户端利用socket去发送数据时,很少会去考虑这个源地址和源端口到底是什么,我们更关心的是它的目的地址和端口。我们往往只有在监听的时候,才去考虑这个源端口,所以我们在监听的时候会去用bind。当我们bind之后,内核就会将这个socket的源端口锁定到我们设定的端口上。但是这就有一个问题,这个bind绑定端口,是将本来没有源端口的socket绑定到我们指定的端口上,还是将一个已经分配了端口的socket重定向到我们指定的端口上呢?  在《UNIX网络编程》这本书中提到:&如果一个TCP客户或者服务器未曾调用bind捆绑一个端口,当调用connect或listen时,内核就要为相应的套接字选择一个临时接口。&从这句话中可以判断出,其实在调用socket函数创建socket时,内核还并未给socket分配源地址和源端口。而对于UDP,我猜测在调用sendto发送数据时,在未捆绑端口的情况下,内核也会随机分配端口。  而我遇到的特殊应用要求我在用UDP发送数据之前要告诉对方我的发送端口,这也就意味着我在sendto之前必须要捆绑端口,因此我在发送数据之前就得调用bind函数绑定一下端口了。但是我就在想内核既然有随机分配端口的能力,而我需要的也只是让它绑定一下而不用绑定在固定端口的业务,socket中应该能够提供这种业务。然后果然我发现bind就具备这种能力,当bind的参数中端口地址为0的时候,这时候就是由内核分配端口。这样我就不用考虑端口地址重复的问题,而放心的把这个问题交给内核处理了。  就在发现bind的这个机制的同时,我发现其实bind对于源地址也同样具备这种处理方式,当系统具有多IP(多网卡)的情况,当我们把bind函数中的ip参数置0时,就是由内核自己选择分配IP。而之前一直觉得很神奇的INADDR_ANY其实一点也不神奇,它的值其实就是0。所以当我们只有单一IP的时候,我们就可以用INADDR_ANY去代替那个单一的IP,因为内核分配的时候只能选择这一个IP。从而造成了INADDR_ANY就是本机IP的现象。c/c++实现获取域名的IP地址
投稿:hebedich
字体:[ ] 类型:转载 时间:
本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下。
c/c++实现获取域名的IP地址
// GetHostIP.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include &winsock2.h&
#include &ws2tcpip.h&
#include &stdio.h&
#include &windows.h&
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char **argv)
//-----------------------------------------
// Declare and initialize variables
WSADATA结构被用来储存调用AfxSocketInit全局函数返回的Windows Sockets初始化信息。
这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。它包含Winsock.dll执行的数据。
WSADATA wsaD
DWORD dwE /*每个word为2个字节的长度,DWORD 双字即为4个字节,每个字节是8位*/
int i = 0;
struct hostent *remoteH
char *host_
/*主机名*/
struct in_
// Validate the parameters
if (argc != 2) {
printf("usage: GetHostIP hostname\n");
// 此处应添加的程序如下
// 1. 当初始化winsocket
iResult = WSAStartup(MAKEWORD(2,2),&wsaData);/* & 取地址*/
// 2. 检查该socket是否初始化成功,即该socket是否等于0;如果初始化不成功,应当给出错误报警,并结束程序。
if(iResult!=0){
printf("初始化失败!\n");
/////////////////结束///////////////////////////////////
host_name = argv[1];
printf("Calling gethostbyname with %s\n", host_name);
// 此处应添加的程序如下
// 1. 利用函数gethostbyname(),获取给定主机名的指针。
remoteHost = gethostbyname(host_name);
// 2. 应当熟悉该结构指针的结构
// 其中该函数申明如下:struct hostent* gethostbyname(const char *name)
// 此处应添加的程序如下
// 1. 如果上面函数返回的主机结构指针为空(NULL),则做如下处理:
a. 利用函数 int WSAGetLastError ( void ) 检查当前是否发生网络错误,
b. 返回的发生的错误类型并作相应的处理,比如,若没有找到主机的错误(此时该函数返回WSAHOST_NOT_FOUND)
if(remoteHost == NULL){
//printf("gethostbynameError:%d",WSAGetLastError());
// 2. 如果返回的主机指针不为空,则做如下处理:
a. 打印出如下参数:主机名和IP地址,若该主机对应于多个ip地址,应当分别列出。
printf("主机名:%s\n",remoteHost-&h_name);
for(i=0;;i++){
if(remoteHost-&h_addr_list[i]!=0)
/*从缓存中把 p 拷贝到addr中
*同时addr.S_un.Saddr
* in_addr ipA
* ipAddr.S_un.S_addr = inet_addr("127.0.0.1");
* 就是把字符串形式的ip地址转化为0xXXXXXXXX形式的地址格式。
addr.s_addr = *(u_long*)remoteHost-&h_addr_list[i];
printf("ip #%d:%s\n",i,inet_ntoa(addr)); /* inet_ntoa() 函数将网络地址转成二进制的数字相关函数:inet_aton, inet_ntoa */
for(i=0;;i++){
char *p = remoteHost-&h_addr_list[i];
if(p==NULL)
/*从缓存中把 p 拷贝到addr中
*同时addr.S_un.Saddr
* in_addr ipA
* ipAddr.S_un.S_addr = inet_addr("127.0.0.1");
* 就是把字符串形式的ip地址转化为0xXXXXXXXX形式的地址格式。
memcpy(&addr.S_un.S_addr,p,remoteHost-&h_length);
printf("ip地址为:%s\n",inet_ntoa(addr));
// 此处应添加的程序如下
// 程序完成后应当适当测试,需要进行的测试如下:
// 1. 测试主机结构指针获取失败
// 2. 测试包含多个IP地址的主机
// 3. 你能想到的任何可能出现的异常情况
/////////////////结束///////////////////////////////////
system("pause"); /*防止窗体关闭函数*/
下面给大家详细介绍下上面代码的核心gethostbyname的详细用法
使用这个东西,首先要包含2个头文件:
#include &netdb.h&
#include &sys/socket.h&
struct hostent *gethostbyname(const char *name);
这个函数的传入值是域名或者主机名,例如""等等。
传出值,是一个hostent的结构(如下)。如果函数调用失败,将返回NULL。
struct hostent {
char **h_addr_
解释一下这个结构, 其中:
char *h_name 表示的是主机的规范名。例如的规范名其实是。
char **h_aliases 表示的是主机的别名。就是google他自己的别名。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。
int h_addrtype 表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是ipv6(AF_INET6)
int h_length 表示的是主机ip地址的长度
int **h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。千万不要直接用printf带%s参数来打这个东西,会有问题的哇。所以到真正需要打印出这个IP的话,需要调用inet_ntop()。
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) :
这个函数,是将类型为af的网络地址结构src,转换成主机序的字符串形式,存放在长度为cnt的字符串中。
这个函数,其实就是返回指向dst的一个指针。如果函数调用错误,返回值是NULL。
下面是例程,有详细的注释。
#include &netdb.h&
#include &sys/socket.h&
int main(int argc, char **argv)
char *ptr,**
struct hostent *
char str[32];
/* 取得命令后第一个参数,即要解析的域名或主机名 */
ptr = argv[1];
/* 调用gethostbyname()。调用结果都存在hptr中 */
if( (hptr = gethostbyname(ptr) ) == NULL )
printf("gethostbyname error for host:%s/n", ptr);
return 0; /* 如果调用gethostbyname发生错误,返回1 */
/* 将主机的规范名打出来 */
printf("official hostname:%s/n",hptr-&h_name);
/* 主机可能有多个别名,将所有别名分别打出来 */
for(pptr = hptr-&h_ *pptr != NULL; pptr++)
printf(" alias:%s/n",*pptr);
/* 根据地址类型,将地址打出来 */
switch(hptr-&h_addrtype)
case AF_INET:
case AF_INET6:
pptr=hptr-&h_addr_
/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数 */
for(;*pptr!=NULL;pptr++)
printf(" address:%s/n", inet_ntop(hptr-&h_addrtype, *pptr, str, sizeof(str)));
printf("unknown address type/n");
另外附上获得公网与内网ip的代码:
bool getPublicIp(string& ip)
char **pptr = NULL;
struct sockaddr_in
struct hostent
*ptr = NULL;
char destIP[128];
sock = socket(AF_INET,SOCK_STREAM,0);
if( -1 == sock ){
perror("creat socket failed");
bzero((void *)&destAddr,sizeof(destAddr));
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(80);
ptr = gethostbyname("");
if(NULL == ptr){
perror("gethostbyname error");
for(pptr=ptr-&h_addr_ NULL != * ++pptr){
inet_ntop(ptr-&h_addrtype,*pptr,destIP,sizeof(destIP));
printf("addr:%s\n",destIP);
ip = destIP;
获取内网IP
int getlocalip(char* outip)
#ifndef WIN32
char buf[512];
struct ifreq *
//初始化ifconf
ifconf.ifc_len = 512;
ifconf.ifc_buf =
strcpy(outip,"127.0.0.1");
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0))&0)
return -1;
ioctl(sockfd, SIOCGIFCONF, &ifconf);
//获取所有接口信息
close(sockfd);
//接下来一个一个的获取IP地址
ifreq = (struct ifreq*)
for(i=(ifconf.ifc_len/sizeof(struct ifreq)); i&0; i--)
ip = inet_ntoa(((struct sockaddr_in*)&(ifreq-&ifr_addr))-&sin_addr);
if(strcmp(ip,"127.0.0.1")==0) //排除127.0.0.1,继续下一个
strcpy(outip,ip);
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 捕获者 的文章

 

随机推荐