我正在学习有关TCP和UDP编程的知识。为了更好地理解和使用这些协议,我编写了一个小程序,其中的一个模块将发送DNS查询请求,这是我的代码的一部分。
我将自己定义IP标头,UDP标头和DNS标头,然后定义DNS查询的数据部分,如下所示:
typedef struct query
{
// 0123456789
// test name github.com
char name[10];
struct question *question;
} Query, *pQuery;
typedef struct question
{
unsigned short int qtype;
unsigned short int qclass;
} Question, *pQuestion;
// DNS header structure
typedef struct dns_header
{
unsigned short int id; // identification number
// flag
// unsigned short int == uint16_t
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned short int qr : 1;
unsigned short int opcode : 4;
unsigned short int aa : 1;
unsigned short int tc : 1;
unsigned short int rd : 1;
unsigned short int ra : 1;
unsigned short int z : 3;
unsigned short int rcode : 4;
#elif __BYTE_ORDER == __LITTLE_ENDIAN
unsigned short int rd : 1;
unsigned short int tc : 1;
unsigned short int aa : 1;
unsigned short int opcode : 4;
unsigned short int qr : 1;
unsigned short int rcode : 4;
unsigned short int z : 3;
unsigned short int ra : 1;
#endif
unsigned short qcount; // question count
unsigned short ancount; // answer record count
unsigned short nscount; // name server count
unsigned short adcount; // additional record count
} DNSHeader, *pDNSHeader;
static int SendDNS(const pDNSStruct ds, const int debug_level)
{
// Perform a DNS query by sending a packet
int socket_fd;
socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (socket_fd < 0)
{
return 1;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
// dst
sin.sin_port = htons((int)ds->src_port); // set the destination address
sin.sin_addr.s_addr = inet_addr(ds->src_ip); // set the port
char *datagram;
//char *data;
size_t pksize = sizeof(struct ip) + sizeof(struct udphdr) + sizeof(DNSHeader) + sizeof(Query);
datagram = (char *)malloc(pksize);
struct ip *iph;
iph = (struct ip *)datagram;
struct udphdr *udph;
memset(datagram, 0, pksize);
// filed the data
int one = 1;
const int *val = &one;
if (setsockopt(socket_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
//exit(0);
return 1;
}
// entete ip
iph->ip_v = 4;
iph->ip_hl = 5;
iph->ip_tos = 0;
iph->ip_len = pksize;
iph->ip_ttl = 255;
iph->ip_off = 0;
iph->ip_id = sizeof(45);
iph->ip_p = IPPROTO_UDP;
iph->ip_sum = 0; // a remplir aprés
iph->ip_src.s_addr = inet_addr(ds->src_ip);
iph->ip_dst.s_addr = inet_addr(ds->dst_ip);
udph = (struct udphdr *)(datagram + sizeof(struct ip));
// entete udp
udph->uh_sport = htons(ds->src_port);
udph->uh_dport = htons(ds->dst_port);
udph->uh_ulen = htons(sizeof(struct udphdr));
// use the UDP to send the data
pDNSHeader dnsh = (pDNSHeader)(datagram + sizeof(struct ip) + sizeof(struct udphdr));
// set the DNS structure to standard queries
dnsh->id = (unsigned short)htons(getpid());
dnsh->qr = 0; // this is a query
dnsh->opcode = 0; // this is a standard query
dnsh->aa = 0; // not authoritative
dnsh->tc = 0; // this message is not truncated
dnsh->rd = 1; // recursion desired
dnsh->ra = 0; // recursion not available! hey we dont have it (lol)
dnsh->z = 0;
dnsh->rcode = 0;
dnsh->qcount = htons(1); //we have only 1 question
dnsh->ancount = 0;
dnsh->nscount = 0;
dnsh->adcount = 0;
// point to the query portion
// filed the data
pQuery query = (pQuery)(datagram + sizeof(struct ip) + sizeof(struct udphdr) + sizeof(DNSHeader));
// DNS_QUERY_NAME_DEFAULT in here is "github.com"
memcpy(query->name, DNS_QUERY_NAME_DEFAULT, strlen(DNS_QUERY_NAME_DEFAULT));
pQuestion question = (pQuestion)(datagram + sizeof(struct ip) + sizeof(struct udphdr) + sizeof(DNSHeader) + sizeof(Query));
question->qtype = htons(DNS_QUERY_TYPE_DEFAULT); //type of the query , A , MX , CNAME , NS etc
question->qclass = htons(1); //its internet (lol)
if (sendto(socket_fd, datagram, pksize, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
return 1;
}
free(datagram);
close(socket_fd);
return 0;
}
现在,该程序运行良好,但是有一个尚未解决的问题。当我使用Wireshark
检查发送的数据包时,发现了一些问题。
这是程序发送的数据包。
0000 dc fe 18 84 cb e4 3c f8 62 7b 0f d9 08 00 45 00 Üþ..Ëä<øb{.Ù..E.
0010 00 40 04 00 00 00 ff 11 11 1f c0 a8 01 01 72 72 .@....ÿ...À¨..rr
0020 72 72 00 50 00 35 00 08 ff 72 75 6a 01 00 00 01 rr.P.5..ÿruj....
0030 00 00 00 00 00 00 67 69 74 68 75 62 2e 63 00 01 ......github.c..
0040 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ..............
您可以看到此数据未被识别为DNS,仅是UDP。
这是使用命令nslookup github.com
生成的数据包。
0000 dc fe 18 84 cb e4 3c f8 62 7b 0f d9 08 00 45 00 Üþ..Ëä<øb{.Ù..E.
0010 00 38 3d 03 40 00 40 11 7a 54 c0 a8 01 0c c0 a8 .8=.@.@.zTˬ..ˬ
0020 01 01 bd a0 00 35 00 24 aa de 07 cd 01 00 00 01 ..½ .5.$ªÞ.Í....
0030 00 00 00 00 00 00 06 67 69 74 68 75 62 03 63 6f .......github.co
0040 6d 00 00 01 00 01 m.....
这看起来非常相似,但是在Wireshark
中却完全不同。我的程序发送的数据包只能被Wireshark
识别为UDP,DNS服务器无法返回结果(我认为DNS服务器可能不理解此请求),但是我使用的数据包{{1 }}可以识别为DNS,并且还返回了结果。
问题是,我的代码有问题吗?
谢谢。