通过本地DNS域名服务器寻找域名对应IP地址C/C++
来源:互联网 发布:中锐网络招聘 编辑:程序博客网 时间:2024/05/18 00:22
输入域名即可获取IP地址
/* *模拟DNS协议的工作 */#include<stdlib.h>#include<stdio.h>#include<Winsock2.h>#include<Iphlpapi.h>#include<windows.h>#include<string.h>#pragma comment(lib , "ws2_32.lib")#pragma comment(lib , "IPHLPAPI.LIB")#pragma pack(2) //设置字节对齐属性#define PORT 53 //定义端口号#define TIMEOUT 3000 //超时时间typedef struct //DNS报文首部{ unsigned short id ; unsigned short flags ; unsigned short questNum ; unsigned short answerNum ; unsigned short authorNum ; unsigned short additionNum ;} DNSHDR , *pDNSHDR ;typedef struct //DNS报文查询记录{ unsigned short type ; unsigned short queryclass ;} QUERYHDR , *pQUERYHDR ;typedef struct //DNS报文应答记录{ unsigned short type ; unsigned short classes ; unsigned long ttl ; unsigned short length ;} RESPONSE , *pRESPONSE ;/* *生成一个DNS请求报文 */int genDNSPacket(pDNSHDR pDnsHdr , pQUERYHDR pQueryHdr , char *hostname , char *DNSsendBuff) ;/* *对接收到的DNS应答报文进行解析得到需要的IP地址信息 */void decodeDNSPacket(char *DNSrecvBuff) ;/* *获取本机配置的DNS服务器 */void getDnsServer(char *dnsServer) ;/* *测试主函数 */int main(){ sockaddr_in addr ; //绑定地址 SOCKET ListenSocket ; //发送与接收用的SOCKET int len = 0 ; //初始化WinSock WORD wVersionRequested = MAKEWORD(2,2); WSADATA wsaData; if(WSAStartup(wVersionRequested,&wsaData) != 0) { printf("初始化WinSock失败!\n") ; return 0 ; } ListenSocket = socket(PF_INET , SOCK_DGRAM , 0) ; if(ListenSocket == INVALID_SOCKET) { printf("Error : socket create failed ! \n") ; fflush(0) ; return 0 ; } addr.sin_family = PF_INET ; addr.sin_addr.s_addr = htonl(INADDR_ANY) ; //任何地址 addr.sin_port = htons(PORT) ; //进行监听端口的绑定 if(bind(ListenSocket , (struct sockaddr*)&addr , sizeof(addr)) != 0) { printf("Error : bind failed !\n") ; fflush(0) ; closesocket(ListenSocket) ; return 0 ; } char dnsip[20] ; getDnsServer(dnsip) ; //进行UDP数据报的发送 int sent ; hostent *hostdata ; if(atoi(dnsip)) //是否为IP地址的标准形式 { u_long ip = inet_addr(dnsip) ; hostdata = gethostbyaddr((char*)&ip , sizeof(ip) , PF_INET) ; } else { printf("The DNS IP is not correct ! \n") ; return 0 ; } if(!hostdata) { printf("Get the name error ! \n") ; fflush(0) ; return 0 ; } sockaddr_in dest ; //填写目的地址信息 dest.sin_family = PF_INET ; //将hostent结构体里面的h_addr_list转化为in_addr类型的地址信息 dest.sin_addr = *(in_addr*)(hostdata->h_addr_list[0]) ; dest.sin_port = htons(PORT) ; //获取DNS报文 char hostname[30] , buffer[100] ; DNSHDR dnsHdr ; QUERYHDR queryHdr ; printf("Please input domain name (no more than 30) : ") ; scanf("%s" , hostname) ; len = genDNSPacket(&dnsHdr , &queryHdr , hostname , buffer) ; sent = sendto(ListenSocket , buffer , len , 0 , (sockaddr*)&dest , sizeof(sockaddr_in)) ; if(sent != len) { printf("Error : send error !\n") ; fflush(0) ; return 0 ; } //进行数据的接收 char buf[400] ; sockaddr_in dnsServer ; int addr_len = sizeof(dnsServer) ; int result ; while(1) //接收到数据时退出 { result = recvfrom(ListenSocket , buf , sizeof(buf) - 1 , 0 , (sockaddr*)&dnsServer , &addr_len) ; if(result > 0) { buf[result] = 0 ; decodeDNSPacket(buf) ; break ; } } return 0 ;}/* *生成一个DNS请求报文 *生成的DNS请求报文保存在DNSsendBuff中 *hostname为需要查询的域名字符串 *返回值为生成请求报文的长度,单位为字节 */int genDNSPacket(pDNSHDR pDnsHdr , pQUERYHDR pQueryHdr , char *hostname , char *DNSsendBuff){ if( ! strcmp(hostname , "exit")) { return -1 ; //输入exit时结束 } else //正常的DNS查询请求 { int iSendByte = 0 ; ZeroMemory(DNSsendBuff , sizeof(DNSsendBuff)) ; pDnsHdr->id = htons(0x0000) ; //"标识"字段设置为0 pDnsHdr->flags = htons(0x0100) ; //"标志"字段设置为0x0100, 即RD位为1期望递归查询 pDnsHdr->questNum = htons(0x0001) ; //1个查询记录 pDnsHdr->answerNum = htons(0x0000) ; //没有回答记录和其它的记录 pDnsHdr->authorNum = htons(0x0000) ; pDnsHdr->additionNum = htons(0x0000) ; //将生成的DNS查询报文首部复制到DNSsendBuff中 memcpy(DNSsendBuff , pDnsHdr , sizeof(DNSHDR)) ; iSendByte += sizeof(DNSHDR) ; //记录当前的数据量 //对域名字符串进行解析并且进行形式的变换 char *pTrace = hostname ; char *pHostname = hostname ; int iStrLen = strlen(hostname) ; unsigned char iCharNum = 0 ; //将指针指向的字符串向后移动一个字节 while( *pTrace != '\0') { pTrace++ ; } while(pTrace != hostname) { *(pTrace + 1) = *pTrace ; pTrace-- ; } *(pTrace + 1) = *pTrace ; //将第一个字符移动到第二个字符的位置 pTrace++ ; //第一个字符无实际意义,移动到第二个字符位置 while( *pTrace != '\0') { if( *pTrace == '.') { *pHostname = iCharNum ; iCharNum = 0 ; pHostname = pTrace ; } else { iCharNum++ ; } pTrace++ ; } //将最后一个字符'.'之后的字符树写入 *pHostname = iCharNum ; memcpy(DNSsendBuff + sizeof(DNSHDR) , hostname , iStrLen + 2) ; iSendByte += (iStrLen + 2) ; //解析完之后会多出两个字符 //在域名字段之后填入“查询类型”和“查询类” pQueryHdr->type = htons(0x0001) ; pQueryHdr->queryclass = htons(0x0001) ; memcpy(DNSsendBuff + sizeof(DNSHDR) + (iStrLen + 2) , pQueryHdr , sizeof(QUERYHDR)) ; iSendByte += sizeof(QUERYHDR) ; // 累加得到的字节数 return iSendByte ; //返回最终得到的字节数 }}/* *解析收到的DNS报文DNSrecvBuff *应答记录字段中类型为5时即为域名的一个别名,跳过此段应答记录,类型为1时即显示出来 */void decodeDNSPacket(char *DNSrecvBuff){ pDNSHDR pDnsHdr = (pDNSHDR)DNSrecvBuff ; //指针pDnsHdr指向接收到的DNS应答报文首部 //保存所有附加信息 int iQueryNum , iRespNum , iAuthRespNum , iAdditionNum ; iQueryNum = ntohs(pDnsHdr->questNum) ; iRespNum = ntohs(pDnsHdr->answerNum) ; iAuthRespNum = ntohs(pDnsHdr->authorNum) ; iAdditionNum = ntohs(pDnsHdr->additionNum) ; //将DNS应答报文的“标志”字段右移15位即取最高位 , 0 为DNS查询报文,1为应答报文 if(pDnsHdr->flags >> 15) { //flags低位值为3,标识服务器没有与请求域名相应的记录 if((pDnsHdr->flags & 0x0007) == 3) { printf("No corresponding domain name entry . \n") ; return ; } if((pDnsHdr->flags>>10) & 0x0001) //查看标志位AA,看是否时权威应答 { printf("Authoritative anwser : \n") ; } else { printf("None-authoritative anwser : \n") ; } char *pTraceResponse ; //指针移向应答报文中的第一个查询记录,因为一般情况下应答报文均会首先附带一个对应的查询记录 pTraceResponse = DNSrecvBuff + sizeof(DNSHDR) ; //将指针移动到查询记录的域名字段之后 while(*pTraceResponse) { pTraceResponse++ ; } pTraceResponse++ ; //跳过查询类型和查询类两个字段,指针指向第一个应答记录 pTraceResponse += sizeof(long) ; in_addr address ; pRESPONSE pResponse ; printf("Addresses : ") ; for(int i = 0 ; i < iRespNum ; i++) { //指针跳过应答记录的“域名”字段,此域名字段一般为一个域名指针,以0xC0开始 pTraceResponse += sizeof(short) ; pResponse = (pRESPONSE)pTraceResponse ; if(ntohs(pResponse->type) == 1) //这条应答记录返回的是与之前查询所对应的IP地址 { pTraceResponse += sizeof(RESPONSE) ; unsigned long ulIP = *(unsigned long *)pTraceResponse ; address.s_addr = ulIP ; if(i == iRespNum - 1) //最后一条记录显示句号,否则显示分号 { printf("%s . " , inet_ntoa(address)) ; } else { printf("%s ; " , inet_ntoa(address)) ; } //指针移过应答记录的IP地址字段,指向下一条应答记录 pTraceResponse += sizeof(long) ; } else if(ntohs(pResponse->type) == 5) //这条应答记录为所查询主机的一个别名,这里本程序直接跳过这条记录 { pTraceResponse += sizeof(RESPONSE) ; pTraceResponse += ntohs(pResponse->length) ; } } printf("\n") ; } else //标志字段最高位不为1,表示不是一个DNS应答报文,不做任何处理 { printf("Invalid DNS resolution ! \n\n") ; }}/* *获得本机设置的DNS服务器信息并保存到dnsServer里面 */void getDnsServer(char *dnsServer){ //获得需要的缓冲区大小 DWORD nLength = 0 ; if(GetNetworkParams(NULL , &nLength) != ERROR_BUFFER_OVERFLOW) { return ; } FIXED_INFO *pFixedInfo = (FIXED_INFO*)new BYTE[nLength] ; //获得本地的网络参数 if(GetNetworkParams(pFixedInfo , &nLength) != ERROR_SUCCESS) { delete [] pFixedInfo ; return ; } IP_ADDR_STRING *pCurrentDnsServer = &pFixedInfo->DnsServerList ; if(pCurrentDnsServer != NULL) { //pCurrentDnsServer->IpAddress.String 即为所需要字符串形式的DNS服务器 char *tmp = pCurrentDnsServer->IpAddress.String ; strcpy(dnsServer , tmp) ; }}
0 0
- 通过本地DNS域名服务器寻找域名对应IP地址C/C++
- Linux C 网络编程 - 获取本地 ip 地址,mac,通过域名获取对应的 ip
- Linux C 获取本地 ip mac 域名对应 ip
- Java InetAddress根据域名获取该域名对应的IP地址及本地IP地址
- 如何查找域名对应IP地址?
- 子网掩码与IP地址;网关;DNS域名服务器;DHCP;
- win10通过自己设置域名访问对应的IP地址
- C/C++ 根据域名获取IP地址
- C++——通过域名获取ip
- 通过域名获取IP地址
- 查看ip地址 通过域名
- 通过域名获取ip地址
- 通过域名获取ip地址
- 通过域名获取IP地址
- c-ares DNS域名异步解析成IP
- dns服务器--域名IP匹配--安装配置域名服务器
- 网络DNS域名转换成IP地址
- 域名DNS和IP地址查询
- 【Leetcode】12. Integer to Roman
- freearker相当重要的一节指令macro也是自定义函数指令
- 解决crond引发大量sendmail、postdrop进程问题
- Back键直接退出程序
- Ext清空from表单中输入的值
- 通过本地DNS域名服务器寻找域名对应IP地址C/C++
- 文件搜素神器-everthing 快
- arcgis api for js入门开发系列七图层控制(含源代码)
- 字符串、Json对象和Java对象之间的转换
- HDF5在python上的使用
- 如何提高自己的设计水平(一)
- Java之异常
- npm 查看全局安装过的包
- static关键字