linux c实现dns域名解析

来源:互联网 发布:mac怎么下载音悦台 编辑:程序博客网 时间:2024/05/22 00:19
//DNS Query Program on Linux//Author : Silver Moon (m00n.silv3r@gmail.com)//Dated : 29/4/2009//Header Files#include<stdio.h> //printf#include<string.h>    //strlen#include<stdlib.h>    //malloc#include<sys/socket.h>    //you know what this is for#include<arpa/inet.h> //inet_addr , inet_ntoa , ntohs etc#include<netinet/in.h>#include<unistd.h>    //getpid//List of DNS Servers registered on the systemchar dns_servers[10][100];int dns_server_count = 0;//Types of DNS resource records :)#define T_A 1 //Ipv4 address#define T_NS 2 //Nameserver#define T_CNAME 5 // canonical name#define T_SOA 6 /* start of authority zone */#define T_PTR 12 /* domain name pointer */#define T_MX 15 //Mail server//Function Prototypesvoid ngethostbyname(unsigned char*, int);void ChangetoDnsNameFormat(unsigned char*, unsigned char*);unsigned char* ReadName(unsigned char*, unsigned char*, int*);void get_dns_servers();//DNS header structurestruct DNS_HEADER {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};//Constant sized fields of query structurestruct QUESTION {unsigned short qtype;unsigned short qclass;};//Constant sized fields of the resource record structure#pragma pack(push, 1)struct R_DATA {unsigned short type;unsigned short _class;unsigned int ttl;unsigned short data_len;};#pragma pack(pop)//Pointers to resource record contentsstruct RES_RECORD {unsigned char *name;struct R_DATA *resource;unsigned char *rdata;};//Structure of a Querytypedef struct {unsigned char *name;struct QUESTION *ques;} QUERY;int main(int argc, char *argv[]) {unsigned char hostname[100];//Get the DNS servers from the resolv.conf fileget_dns_servers();//Get the hostname from the terminalprintf("Enter Hostname to Lookup : ");scanf("%s", hostname);//Now get the ip of this hostname , A recordngethostbyname(hostname, T_A);return 0;}/* * Perform a DNS query by sending a packet * */void ngethostbyname(unsigned char *host, int query_type) {unsigned char buf[65536], *qname, *reader;int i, j, stop, s;struct sockaddr_in a;struct RES_RECORD answers[20], auth[20], addit[20]; //the replies from the DNS serverstruct sockaddr_in dest;struct DNS_HEADER *dns = NULL;struct QUESTION *qinfo = NULL;printf("Resolving %s", host);s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //UDP packet for DNS queriesdest.sin_family = AF_INET;dest.sin_port = htons(53);dest.sin_addr.s_addr = inet_addr(dns_servers[0]); //dns servers//Set the DNS structure to standard queriesdns = (struct DNS_HEADER *) &buf;dns->id = (unsigned short) htons(getpid());dns->qr = 0; //This is a querydns->opcode = 0; //This is a standard querydns->aa = 0; //Not Authoritativedns->tc = 0; //This message is not truncateddns->rd = 1; //Recursion Desireddns->ra = 0; //Recursion not available! hey we dont have it (lol)dns->z = 0;dns->ad = 0;dns->cd = 0;dns->rcode = 0;dns->q_count = htons(1); //we have only 1 questiondns->ans_count = 0;dns->auth_count = 0;dns->add_count = 0;//point to the query portionqname = (unsigned char*) &buf[sizeof(struct DNS_HEADER)];ChangetoDnsNameFormat(qname, host);qinfo = (struct QUESTION*) &buf[sizeof(struct DNS_HEADER)+ (strlen((const char*) qname) + 1)]; //fill itqinfo->qtype = htons(query_type); //type of the query , A , MX , CNAME , NS etcqinfo->qclass = htons(1); //its internet (lol)printf("\nSending Packet...");if (sendto(s, (char*) buf,sizeof(struct DNS_HEADER) + (strlen((const char*) qname) + 1)+ sizeof(struct QUESTION), 0, (struct sockaddr*) &dest,sizeof(dest)) < 0) {perror("sendto failed");}printf("Done");//Receive the answeri = sizeof dest;printf("\nReceiving answer...");if (recvfrom(s, (char*) buf, 65536, 0, (struct sockaddr*) &dest,(socklen_t*) &i) < 0) {perror("recvfrom failed");}printf("Done");dns = (struct DNS_HEADER*) buf;//move ahead of the dns header and the query fieldreader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*) qname) + 1)+ sizeof(struct QUESTION)];printf("\nThe response contains : ");printf("\n %d Questions.", ntohs(dns->q_count));printf("\n %d Answers.", ntohs(dns->ans_count));printf("\n %d Authoritative Servers.", ntohs(dns->auth_count));printf("\n %d Additional records.\n\n", ntohs(dns->add_count));//Start reading answersstop = 0;for (i = 0; i < ntohs(dns->ans_count); i++) {answers[i].name = ReadName(reader, buf, &stop);reader = reader + stop;answers[i].resource = (struct R_DATA*) (reader);reader = reader + sizeof(struct R_DATA);if (ntohs(answers[i].resource->type) == 1) //if its an ipv4 address{answers[i].rdata = (unsigned char*) malloc(ntohs(answers[i].resource->data_len));for (j = 0; j < ntohs(answers[i].resource->data_len); j++) {answers[i].rdata[j] = reader[j];}answers[i].rdata[ntohs(answers[i].resource->data_len)] = '\0';reader = reader + ntohs(answers[i].resource->data_len);} else {answers[i].rdata = ReadName(reader, buf, &stop);reader = reader + stop;}}//read authoritiesfor (i = 0; i < ntohs(dns->auth_count); i++) {auth[i].name = ReadName(reader, buf, &stop);reader += stop;auth[i].resource = (struct R_DATA*) (reader);reader += sizeof(struct R_DATA);auth[i].rdata = ReadName(reader, buf, &stop);reader += stop;}//read additionalfor (i = 0; i < ntohs(dns->add_count); i++) {addit[i].name = ReadName(reader, buf, &stop);reader += stop;addit[i].resource = (struct R_DATA*) (reader);reader += sizeof(struct R_DATA);if (ntohs(addit[i].resource->type) == 1) {addit[i].rdata = (unsigned char*) malloc(ntohs(addit[i].resource->data_len));for (j = 0; j < ntohs(addit[i].resource->data_len); j++)addit[i].rdata[j] = reader[j];addit[i].rdata[ntohs(addit[i].resource->data_len)] = '\0';reader += ntohs(addit[i].resource->data_len);} else {addit[i].rdata = ReadName(reader, buf, &stop);reader += stop;}}//print answersprintf("\nAnswer Records : %d \n", ntohs(dns->ans_count));for (i = 0; i < ntohs(dns->ans_count); i++) {printf("Name : %s ", answers[i].name);if (ntohs(answers[i].resource->type) == T_A) //IPv4 address{long *p;p = (long*) answers[i].rdata;a.sin_addr.s_addr = (*p); //working without ntohlprintf("has IPv4 address : %s", inet_ntoa(a.sin_addr));}if (ntohs(answers[i].resource->type) == 5) {//Canonical name for an aliasprintf("has alias name : %s", answers[i].rdata);}printf("\n");}//print authoritiesprintf("\nAuthoritive Records : %d \n", ntohs(dns->auth_count));for (i = 0; i < ntohs(dns->auth_count); i++) {printf("Name : %s ", auth[i].name);if (ntohs(auth[i].resource->type) == 2) {printf("has nameserver : %s", auth[i].rdata);}printf("\n");}//print additional resource recordsprintf("\nAdditional Records : %d \n", ntohs(dns->add_count));for (i = 0; i < ntohs(dns->add_count); i++) {printf("Name : %s ", addit[i].name);if (ntohs(addit[i].resource->type) == 1) {long *p;p = (long*) addit[i].rdata;a.sin_addr.s_addr = (*p);printf("has IPv4 address : %s", inet_ntoa(a.sin_addr));}printf("\n");}return;}/* * * */u_char* ReadName(unsigned char* reader, unsigned char* buffer, int* count) {unsigned char *name;unsigned int p = 0, jumped = 0, offset;int i, j;*count = 1;name = (unsigned char*) malloc(256);name[0] = '\0';//read the names in 3www6google3com formatwhile (*reader != 0) {if (*reader >= 192) {offset = (*reader) * 256 + *(reader + 1) - 49152; //49152 = 11000000 00000000 ;)reader = buffer + offset - 1;jumped = 1; //we have jumped to another location so counting wont go up!} else {name[p++] = *reader;}reader = reader + 1;if (jumped == 0) {*count = *count + 1; //if we havent jumped to another location then we can count up}}name[p] = '\0'; //string completeif (jumped == 1) {*count = *count + 1; //number of steps we actually moved forward in the packet}//now convert 3www6google3com0 to www.google.comfor (i = 0; i < (int) strlen((const char*) name); i++) {p = name[i];for (j = 0; j < (int) p; j++) {name[i] = name[i + 1];i = i + 1;}name[i] = '.';}name[i - 1] = '\0'; //remove the last dotreturn name;}/* * Get the DNS servers from /etc/resolv.conf file on Linux * */void get_dns_servers() {FILE *fp;char line[200], *p;if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) {printf("Failed opening /etc/resolv.conf file \n");}while (fgets(line, 200, fp)) {if (line[0] == '#') {continue;}if (strncmp(line, "nameserver", 10) == 0) {p = strtok(line, " ");p = strtok(NULL, " ");//p now is the dns ip :)//????}}strcpy(dns_servers[0], "208.67.222.222");strcpy(dns_servers[1], "208.67.220.220");}/* * This will convert www.google.com to 3www6google3com * got it :) * */void ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host) {int lock = 0, i;strcat((char*) host, ".");for (i = 0; i < strlen((char*) host); i++) {if (host[i] == '.') {*dns++ = i - lock;for (; lock < i; lock++) {*dns++ = host[lock];}lock++; //or lock=i+1;}}*dns++ = '\0';}

原文连接:http://www.binarytides.com/dns-query-code-in-c-with-linux-sockets/

0 0
原创粉丝点击