我正在尝试编写一个程序,在不使用c中的任何DNS功能的情况下从DNS回复中删除一个IP地址。出于某种原因,此代码可用,但仅适用于谷歌,脸书和imgur.com。同样,如果我输入“www.facebook.com”,它会提供正确的IP地址,并且与其他两个站点相同,但输入的任何其他站点都会提供错误的IP地址。有谁知道我做错了什么?
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define PORT 53
#define SITEMAXLEN 40
#define QUERYMAXLEN SITEMAXLEN + 16
#define DNSRESULTMAXLEN 100
#define IPARRAYLEN 20
typedef unsigned char char_type;
void enter_record(char_type* query, char_type* site, int* let_set);
void print_query(char_type* query, int len);
void send_query(char_type* query, char_type* result, int len, int* answer_set);
char_type* parse_result(char_type* result, int query_len, char_type* ip);
void print_ip(int* ip);
int sock;
struct sockaddr_in server_addr;
struct sockaddr_in from_addr;
int main(int argc, char_type** argv) {
char_type* site;
char_type* query;
char_type* dns_result;
char_type* ip;
int query_len;
int answer_len;
site = (char_type*)malloc(SITEMAXLEN * sizeof(char_type));
query = (char_type*)malloc((QUERYMAXLEN) * sizeof(char_type));
dns_result = (char_type*)malloc(DNSRESULTMAXLEN * sizeof(char_type));
ip = (char_type*)malloc(IPARRAYLEN * sizeof(char_type));
if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
fprintf(stderr, "error creating socket to the name server\n");
return 1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("208.67.220.220");
server_addr.sin_port = htons(PORT);
printf("enter in website name\n");
scanf("%s", site);
enter_record(query, site, &query_len);
print_query(query, query_len);
send_query(query, dns_result, query_len, &answer_len);
printf("\n\nresult is\n");
print_query(dns_result, answer_len);
parse_result(dns_result, query_len, ip);
printf("\n\nip address is: %s", ip);
return 0;
}
void enter_record(char_type* query, char_type* site, int* len_set) {
char_type* loc;
char_type* len;
char_type* tld;
int query_end;
loc = strchr(site, '.'); //. after www
len = strchr(loc + 1, '.'); //. after the hostname
*loc = (char_type)(len - loc - 1);
*len = (char_type)0x0003;
query[0] = 'B';
query[1] = 'L';
query[2] = (char_type)0x0001;
query[3] = (char_type)0x0000;
query[4] = (char_type)0x0000;
query[5] = (char_type)0x0001;
query[6] = (char_type)0x0000;
query[7] = (char_type)0x0000;
query[8] = (char_type)0x0000;
query[9] = (char_type)0x0000;
query[10] = (char_type)0x0000;
query[11] = (char_type)0x0000;
query[12] = (char_type)0x0003;
strncat(query + 13, site, strlen(site));
query_end = 13 + strlen(site);
query[query_end] = 0x0000;
query[query_end + 1] = 0x0000;
query[query_end + 2] = 0x0001;
query[query_end + 3] = 0x0000;
query[query_end + 4] = 0x0001;
*len_set = query_end + 5;
}
void print_query(char_type* query, int len) {
int i;
printf("in hex\n");
for(i = 0; i < len; i++) {
printf("%02hhX ", query[i]);
if(i % 16 == 0 && i != 0) {
printf("\n");
}
}
printf("\nin ascii\n");
for(i = 0; i < len; i++) {
printf("%c ", query[i] < (char_type)0x21 ? '.' : query[i]);
if(i % 16 == 0 && i != 0) {
printf("\n");
}
}
printf("\n");
}
void send_query(char_type* query, char_type* result, int len, int* set_len) {
int from_size;
int response_len;
if(sendto(sock, query, len, 0,
(struct sockaddr*)&server_addr, sizeof(server_addr)) != len) {
//message couldn't be sent
fprintf(stderr, "couldn't send the query\n");
return;
}
from_size = sizeof(from_addr);
while((response_len = recvfrom(sock, result, DNSRESULTMAXLEN, 0,
(struct sockaddr*)&from_addr, &from_size)) < 0) {
}
//null terminate the buffer
//printf("%d\n", response_len);
//result[response_len] = '\0';
*set_len = response_len;
}
char_type* parse_result(char_type* result, int query_len, char_type* ip) {
/*int offset = -1;
//offset = query_len + 32;
int count = 0;
while(count < 3) {
offset++;
if(result[offset] == 0x00C0) {
count++;
}
}
offset += 32;*/
int offset = -1;
int found = 0;
while(found == 0) {
offset++;
if(result[offset] == 0x00C0) {
if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
offset = offset + result[offset + 1];
found = 1;
}
}
}
sprintf(ip, "%d.%d.%d.%d\n",
result[offset], result[offset + 1],
result[offset + 2], result[offset + 3]);
return ip;
}
答案 0 :(得分:0)
在parse_result()
中,而不是跳跃result[offset + 1]
个字节,跳转12个字节。
if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
/* ********
offset = offset + result[offset + 1];
******** */
offset = offset + 12;
found = 1;
}
result [offset + 1]的值是从消息开头到名称的偏移量,而不是ip地址。在雅虎的情况下,偏移量最终指向"any-fp.wa1.b.yahoo.com"
。
它适用于facebook(及其他人),因为答案中名称的偏移量为12.当问题中的名称与答案中的名称相同时,偏移量为12。
<强>更新强>
并非所有DNS答案都会使用指针(0xC0 0x??
)启动每个答案部分。他们可能会有一个标签而你的程序会失败。即使指针的第一个字节也不需要0xC0
:要求设置前2位。