Andoroid下检测DNS错误
思路:首先是抓取端口53的包,然后对包进行解析:
有问题的dns回复:
可以看出Answer RRs是0 ,这个值代表dns服务器返回的域名ip应答数。
下面是正常的dns应答包:
可以看出Answer RRs为12,说明有12个ip答复。
所以可以通过Answer RRs来判断是否发生了dns错误。
/*循环抓包,在got_packet()中处理抓到的包*/
int main(int argc, char **argv)
{
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "dst 202.114.85.31 and tcp"; /* filter expression [3] */
printf("input filter:");
gets(filter_exp);
// char filter_exp[] = "(src port 53) or (dst port 53)";
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
Ping ping = Ping();
if(ping.isConnection(PING_IP, 4) && !ping.isConnection(PING_HOST, 4))
printf("DNS ERROR\n\n");
else
printf("NET ACCESS\n\n");
print_app_banner();
/* check for capture device name on command-line */
if (argc == 2)
{
dev = argv[1];
}
else if (argc > 2)
{
fprintf(stderr, "error: unrecognized command-line options\n\n");
print_app_usage();
exit(EXIT_FAILURE);
}
else
{
/* find a capture device if not specified on command-line */
dev = pcap_lookupdev(errbuf);
if (dev == NULL)
{
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
exit(EXIT_FAILURE);
}
}
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1)
{
fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL)
{
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* make sure we're capturing on an Ethernet device [2] */
if (pcap_datalink(handle) != DLT_EN10MB)
{
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1)
{
fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1)
{
fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
udpErrorCount = 0;
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
printf("\nCapture complete.\n");
return 0;
}
/*解析包*/
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
static int count = 1;
const struct sniff_ethernet *ethernet;
const struct sniff_ip *ip;
int size_ip;
printf("\nPacket number %d:\n", count);
count++;
ethernet = (struct sniff_ethernet*)(packet);
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip) * 4;
if (size_ip < 20)
{
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
switch(ip->ip_p)
{
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
DecodeTCPPacket(packet + SIZE_ETHERNET + size_ip, ntohs(ip->ip_len) - size_ip);
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
DecodeUDPPacket(packet + SIZE_ETHERNET + size_ip, ntohs(ip->ip_len) - size_ip);
break;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
break;
case IPPROTO_IP:
printf(" Protocol: IP\n");
break;
default:
printf(" Protocol: unknown\n");
break;
}
}
/*解析UDP包*/
void DecodeUDPPacket(const u_char *packet, int size_packet)
{
const struct sniff_udp *udp;
udp = (struct sniff_udp *)packet;
printf("UDPPort: %d -> %d \nUDPlength: %d\n", ntohs(udp->sourcePort), ntohs(udp->destinationPort), ntohs(udp->len));
ParseDNSPacket(packet + sizeof(struct sniff_udp), size_packet - sizeof(struct sniff_udp));
}
/*解析DNS包,并通过ping来判断是否发生dns错误*/
void ParseDNSPacket(const u_char *packet, int size_packet)
{
const struct sniff_dns *dns;
dns = (struct sniff_dns *)packet;
if(QR(dns))
{
printf(" DNS type: response\n");
if((ntohs(dns->dns_Answer) == 0) && (++udpErrorCount) >= UDP_ERROR_COUNT)
{
Ping ping = Ping();
if(!ping.isConnection(PING_HOST, 4) && ping.isConnection(PING_IP, 4))
{
//DNS ERROR
printf("DNS(Packet) ERROR\n");
}
}
else
{
udpErrorCount = 0;
}
}
else
{
printf(" DNS type:request\n");
}
printf(" Questions: %d\n", ntohs(dns->dns_Questions));
printf(" Answer RRs: %d\n", ntohs(dns->dns_Answer));
printf(" Authority RRs: %d\n", ntohs(dns->dns_Authority));
printf(" Additional RRs: %d\n", ntohs(dns->dns_Additional));
print_payload(packet + sizeof(struct sniff_dns), size_packet - sizeof(struct sniff_dns));
}
最终又经过ping来判断是否发生dns错误,不过未能复现错误环境所以没能实际检测。
源码地址:
http://download.csdn.net/download/bgylde/9725375
最后希望可以顺便解决dns错误,但是在现在的android上通过代码方式修改dns未能成功,最后的思路是实用iptable来访问正确的dns地址,还未实际尝试,欢迎交流
最后希望可以顺便解决dns错误,但是在现在的android上通过代码方式修改dns未能成功,最后的思路是实用iptable来访问正确的dns地址,还未实际尝试,欢迎交流