socket编程实现简单DNS协议实现获取域名ip(TCP)

2024-06-18 12:48

本文主要是介绍socket编程实现简单DNS协议实现获取域名ip(TCP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上次在文章《socket编程实现简单DNS协议实现获取域名ip(UDP)》中提到使用udp协议发送dns数据包查询站点ip,这次带来TCP版本的查询代码。

其实不管是tcp协议还是udp协议,都是构造dns报文,填写查询方式,发送数据包即可。

然而,在dns协议中有个特殊的地方需要重点强调!使用tcp协议和udp协议发送的dns报文有个很容易被忽略的问题:在tcp协议时,除了udp协议时的dns报文数据,还要在原有的报文数据之前添加两个字节,这两个字节指名其后的dns报文数据有多少字节!

除了上述的区别,其他的都一样。

另外,再提个问题,其实在dns服务器返回的数据包中可能包含了同一个域名的多个ip地址,我们在UDP的那篇文章中只解析了最后一个提供的ip地址~,这次的tcp模式同时解析了所有返回的ip地址~

这次的代码使用了文章《socket编程之TCP通信模块》中的头文件。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 id;U16 tag;U16 numq;U16 numa;U16 numa1;U16 numa2;
}DNS_HDR;*/
typedef struct
{unsigned short id;       // identification numberunsigned char rd :1;     // recursion desiredunsigned char tc :1;     // truncated messageunsigned char aa :1;     // authoritive answerunsigned char opcode :4; // purpose of messageunsigned char qr :1;     // query/response flagunsigned char rcode :4;  // response codeunsigned char cd :1;     // checking disabledunsigned char ad :1;     // authenticated dataunsigned char z :1;      // its z! reservedunsigned char ra :1;     // recursion availableunsigned short q_count;  // number of question entriesunsigned short ans_count; // number of answer entriesunsigned short auth_count; // number of authority entriesunsigned short add_count; // number of resource entries
}DNS_HDR;
/*typedef struct _DNS_QER
{U16 type;U16 classes;
}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_tcp google.com 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


需要的头文件在文章《socket编程之TCP通信模块》中下载!

转自:https://blog.csdn.net/bytxl/article/details/10395089

这篇关于socket编程实现简单DNS协议实现获取域名ip(TCP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072039

相关文章

关于DNS域名解析服务

《关于DNS域名解析服务》:本文主要介绍关于DNS域名解析服务,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录DNS系统的作用及类型DNS使用的协议及端口号DNS系统的分布式数据结构DNS的分布式互联网解析库域名体系结构两种查询方式DNS服务器类型统计构建DNS域

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os