示例#1
0
char* resolve(char* potentials, char* current, char* querying) {
	if(!current) { // if there's no current server for some reason, pick one randomly
		int i = randStart(potentials);
		int j = 0;
		char server[256];
		memset(&server, 0, sizeof(server));
		while(potentials[i] != '\n') {
			server[j] = potentials[i];
			i++, j++;
		} server[j] = '\0'; 	// null terminate the server string
		current = server;
	}

	/* Initial debug statement */
	if(debug) {
		printf("How about nameserver %s?\n", current);
		int count = ncounter(potentials);
		printf("\nResolving %s using server %s out of %d.\n", querying, current, count);
	}

	// Create a socket
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if(sock < 0) {
		perror("Creating socket failed: "); 
		exit(1);
	}
	//int optval = 1; // set socket to time out on recv
	//setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&optval, sizeof optval);
	struct timeval timeout;
	timeout.tv_sec = 1;
	timeout.tv_usec = 0;
	setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));


	/* Send the query */
	in_addr_t nameserver_addr  = inet_addr(current); 
	// construct the query message
	uint8_t query[1500];
	int query_len=construct_query(query,1500,querying);	

	struct sockaddr_in addr; 	// internet socket address data structure
	addr.sin_family = AF_INET;
	addr.sin_port = htons(53); // port 53 for DNS
	addr.sin_addr.s_addr = nameserver_addr; // destination address (any local for now)
	
	int send_count = sendto(sock, query, query_len, 0,
													(struct sockaddr*)&addr,sizeof(addr));
	if(send_count<0) { perror("Send failed");	exit(1); }	

	// await the response 
	uint8_t answerbuf[1500];
	int rec_count = recv(sock,answerbuf,1500,0);
	if (rec_count < 1) {			// this is not properly resolving a time out; just blocks forever
		if((errno == EAGAIN) || (errno == EWOULDBLOCK)) 
			return resolve(root_servers, NULL, querying); // if we timed out, call the function again w/ a NULL server, pick random.
	}
	
	// parse the response to get our answer
	struct dns_hdr *ans_hdr=(struct dns_hdr*)answerbuf;
	uint8_t *answer_ptr = answerbuf + sizeof(struct dns_hdr);
	
	// now answer_ptr points at the first question. 
	int question_count = ntohs(ans_hdr->q_count);
	int answer_count = ntohs(ans_hdr->a_count);
	int auth_count = ntohs(ans_hdr->auth_count);
	int other_count = ntohs(ans_hdr->other_count);

	int total = answer_count + auth_count + other_count;

	if(debug) {
		printf("Got %d+%d+%d=%d resource records total.\n", answer_count, auth_count, other_count, total);
	}

	// skip past all questions
	int q;
	for(q=0;q<question_count;q++) {
		char string_name[255];
		memset(string_name,0,255);
		int size=from_dns_style(answerbuf,answer_ptr,string_name);
		answer_ptr+=size;
		answer_ptr+=4; //2 for type, 2 for class
	}

	// ANSWER AND AUTHORITY SECTIONS
	int a;
	char *nsrecords[512];
	int nsCount = 0;
	for(a=0;a<answer_count+auth_count;a++) {
		// first the name this answer is referring to 
		char string_name[255];
		int dnsnamelen=from_dns_style(answerbuf,answer_ptr,string_name);
		answer_ptr += dnsnamelen;

		// then fixed part of the RR record
		struct dns_rr* rr = (struct dns_rr*)answer_ptr;
		answer_ptr+=sizeof(struct dns_rr);

		// A record in answer section - we're done, return the name
		if(htons(rr->type)==RECTYPE_A) {
			if(debug)
				printf("The name %s resolves to IP addr: %s\n",
						 	string_name,
							 inet_ntoa(*((struct in_addr *)answer_ptr)));
			return inet_ntoa(*((struct in_addr *)answer_ptr));
		}
		// CNAME record
		else if(htons(rr->type)==RECTYPE_CNAME) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The name %s is also known as %s.\n",
							 string_name, ns_string);
			querying = ns_string;

			/* If we just queried with the basic nameserver, populate the list w/ root servers
				and reset the nameserver_flag so we don't do this again */
			if(nameserver_flag) {
				potentials = root_servers;
				nameserver_flag = 0;
			}
			// pick a random server to query next, from the list
			int i = randStart(potentials);
			int j = 0;
			char server[256];
			memset(&server, 0, sizeof(server));
			while(potentials[i] != '\n') {
				server[j] = potentials[i];
				i++, j++;
			} server[j] = '\0'; 
			return resolve(potentials, server, querying);		 // recursively continue to query!					
		}
		// NS record
		else if(htons(rr->type)==RECTYPE_NS) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The name %s can be resolved by NS: %s\n",
							 string_name, ns_string);
			// Put these in an array to use if there's nothing else.
			nsrecords[nsCount] = malloc(25*sizeof(char));
			nsrecords[nsCount] = strdup(ns_string);
			nsCount++;
		}
		// PTR record (reverse lookup, ip to domain name -- if we were looking for this, also done)
		else if(htons(rr->type)==RECTYPE_PTR) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The host at %s is also known as %s.\n",
						 	string_name, ns_string);	
			if(reverse_flag)
				return strdup(ns_string);			// if this was a reverse lookup, we're done! otherwise whatever							
		}
		// SOA record (ignore)
		else if(htons(rr->type)==RECTYPE_SOA) {
			if(debug)
				printf("Ignoring SOA record\n");
		}
		// AAAA record (ignore)
		else if(htons(rr->type)==RECTYPE_AAAA)  {
			if(debug)
				printf("Ignoring IPv6 record\n");
		}
		else {
			if(debug)
				printf("got unknown record type %hu\n",htons(rr->type));
			return NULL;
		} 

		answer_ptr+=htons(rr->datalen);
	}

	// if nothing in additional section, preemptively check the NS records
	if(other_count == 0) {
		char *nsips = malloc(BUFLEN);
		int counter = 0;
		int k;
		if(nsCount==0)
			return NULL;
		for(k=0; k<nsCount; k++) {
			char *tempStr = resolve(root_servers, NULL, nsrecords[k]);
			int i=0;
			while(tempStr[i] != '\0') {
				nsips[counter] = tempStr[i];
				counter++, i++;
			} nsips[counter] = '\n'; // newline termination
			counter++;
		}
		return resolve(nsips, NULL, querying); // now try to resolve the query using these IPs
	}	

	// ADDITIONAL SECTION (if there wasn't an answer or a PTR)
	char *returnArray = malloc(BUFLEN);
	for(a=answer_count+auth_count;a<answer_count+auth_count+other_count;a++){
		char string_name[255];
		int dnsnamelen=from_dns_style(answerbuf,answer_ptr,string_name);
		answer_ptr += dnsnamelen;

		// then fixed part of the RR record
		struct dns_rr* rr = (struct dns_rr*)answer_ptr;
		answer_ptr+=sizeof(struct dns_rr);

		// take these and query these next create an array of ptrs to push into the resolve query
		if(htons(rr->type)==RECTYPE_A) {
			char ipaddr[256];
			memset(&ipaddr, 0, sizeof(ipaddr));
			char *temp = inet_ntoa(*((struct in_addr *)answer_ptr));
			int i = 0;
			while(temp[i] != '\0') {
				ipaddr[i] = temp [i];
				i++;
			} ipaddr[i] = '\n';
			strcat(returnArray, ipaddr);
			if(debug)
				printf("The name %s resolves to IP addr: %s\n",
						 string_name,
						 inet_ntoa(*((struct in_addr *)answer_ptr)));
		}
		// NS record
		else if(htons(rr->type)==RECTYPE_NS) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The name %s can be resolved by NS: %s\n",
							 string_name, ns_string);					
		}
		// CNAME record
		else if(htons(rr->type)==RECTYPE_CNAME) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The name %s is also known as %s.\n",
							 string_name, ns_string);								
		}
		// PTR record (reverse lookup, ip to domain name -- if we were looking for this, also done)
		else if(htons(rr->type)==RECTYPE_PTR) {
			char ns_string[255];
			int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
			if(debug)
				printf("The host at %s is also known as %s.\n",
						 string_name, ns_string);								
		}
		// SOA record (ignore)
		else if(htons(rr->type)==RECTYPE_SOA) {
			if(debug)
				printf("Ignoring SOA record\n");
		}
		// AAAA record (ignore)
		else if(htons(rr->type)==RECTYPE_AAAA)  {
			if(debug)
				printf("Ignoring IPv6 record\n");
		}
		else {
			if(debug)
				printf("got unknown record type %hu\n",htons(rr->type));
		} 

		answer_ptr+=htons(rr->datalen);
	}

	// Iterate through all possible servers.
	int k;
	int i = 0;
	for(k=0; k < ncounter(potentials); k++) {
		int j = 0;
		char server[256];
		memset(&server, 0, sizeof(server));
		while(potentials[i] != '\n') {
			server[j] = potentials[i];
			i++, j++;
		} server[j] = '\0';
		i++; // so it starts at the next character
		char *retStr;
		if((retStr = resolve(returnArray, server, querying)) != NULL) // if we got a response, give it!
			return retStr;
	}

	shutdown(sock,SHUT_RDWR);
	close(sock);
	return NULL; 		// if nothing else worked
}
示例#2
0
文件: hw3.c 项目: llovett/mini-dns
char *resolve_address(char *hostname, nameserver **nameservers, int ns_count) {
    // The hostname we'll be looking up in any recursive call
    char *newhostname = hostname;

    // Stuff we'll use after getting ahold of a nameserver
    uint8_t answerbuf[1500];

    // Build a socket with a timeout
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock < 0) {
	perror("Creating socket failed: ");
	exit(1);
    }
    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

    // Loop to contact a nameserver
    int chosen_server = rand()%ns_count;
    // The nameserver we'll be using to do the query
    nameserver *active_ns;
    // Number of times left to try contacting a nameserver
    int attempts_left = MAX_ATTEMPTS * ns_count;
    while ( attempts_left-- > 0 ) {
	// Try a nameserver
	active_ns = nameservers[chosen_server];
	in_addr_t nameserver_addr=inet_addr(active_ns->server_addr);

	// construct the query message
	uint8_t query[1500];
	int query_len=construct_query(query,1500,hostname);

	struct sockaddr_in addr;	// internet socket address data structure
	addr.sin_family = AF_INET;
	addr.sin_port = htons(53);	// port 53 for DNS
	addr.sin_addr.s_addr = nameserver_addr; // destination address (any local for now)

	if (debug) {
	    printf("How about nameserver %s?\n", active_ns->server_addr);
	}

	int send_count = sendto(sock, query, query_len, 0,
				(struct sockaddr*)&addr,sizeof(addr));
	if(send_count<0) {
	    perror("Send failed");
	    exit(1);
	}

	// Await the response
	int rec_count = recv(sock,answerbuf,1500,0);

	// Check for errors while receiving
	if ((rec_count < 1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
	    if (debug) {
		printf("Timed out while waiting for nameserver %s.\n", active_ns->server_addr);
	    }
	    // Try choosing another nameserver randomly
	    chosen_server = rand()%ns_count;
	} else {
	    break;
	}
    }
    if ( attempts_left <= 0 ) {
	fprintf(stderr, "Could not contact any nameservers.\n");
	exit(1);
    }

    if (debug) {
	printf("Resolving %s using server %s out of %d\n",
	       hostname, active_ns->server_addr, ns_count);
    }

    // parse the response to get our answer
    struct dns_hdr *ans_hdr=(struct dns_hdr*)answerbuf;
    uint8_t *answer_ptr = answerbuf + sizeof(struct dns_hdr);

    // now answer_ptr points at the first question.
    int question_count = ntohs(ans_hdr->q_count);
    int answer_count = ntohs(ans_hdr->a_count);
    int auth_count = ntohs(ans_hdr->auth_count);
    int other_count = ntohs(ans_hdr->other_count);

    if (debug) {
	int resource_count = question_count + answer_count + auth_count + other_count;
	printf("%d questions, %d answers, %d authoritative records, and %d others = %d resource records total\n",
	       question_count, answer_count, auth_count, other_count, resource_count);
    }

    // skip past all questions
    int q;
    for(q=0;q<question_count;q++) {
	char string_name[255];
	memset(string_name,0,255);
	int size=from_dns_style(answerbuf,answer_ptr,string_name);
	answer_ptr+=size;
	answer_ptr+=4; //2 for type, 2 for class
    }

    int a;
    int got_answer=0;

    // now answer_ptr points at the first answer. loop through
    // all answers in all sections
    nameserver *new_nameservers[100];
    int ns_index = 0;
    for(a=0;a<answer_count+auth_count+other_count;a++) {
	// first the name this answer is referring to
	char string_name[255];
	int dnsnamelen=from_dns_style(answerbuf,answer_ptr,string_name);
	answer_ptr += dnsnamelen;

	// then fixed part of the RR record
	struct dns_rr* rr = (struct dns_rr*)answer_ptr;
	answer_ptr+=sizeof(struct dns_rr);

	const uint8_t RECTYPE_A=1;
	const uint8_t RECTYPE_NS=2;
	const uint8_t RECTYPE_CNAME=5;
	const uint8_t RECTYPE_SOA=6;
	const uint8_t RECTYPE_PTR=12;
	const uint8_t RECTYPE_AAAA=28;

	if(htons(rr->type)==RECTYPE_A) {
	    char *ip_addr = inet_ntoa(*((struct in_addr *)answer_ptr));

	    if (debug)
		printf("The name %s resolves to IP addr: %s\n",
		       string_name,
		       ip_addr);

	    got_answer=1;

	    // Are we done?
	    if ( !strcasecmp(string_name, newhostname) ) {
		delete_nameservers(new_nameservers, ns_index);
		if (newhostname != hostname)
		    free(newhostname);
		return strdup(ip_addr);
	    }

	    // Try to match some IPs up with symbolic hostnames for nameservers
	    int i;
	    for ( i=0; i<ns_index; i++ ) {
		nameserver *new_ns = new_nameservers[i];
		if ( !strcasecmp(string_name,new_ns->server) ) {
		    new_ns->server_addr = strdup(ip_addr);
		    break;
		}
	    }
	}
	// NS record
	else if(htons(rr->type)==RECTYPE_NS) {
	    char ns_string[255];
	    int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);
	    if(debug)
		printf("The name %s can be resolved by NS: %s\n",
		       string_name, ns_string);

	    // Keep maximum number of nameservers
	    if ( ns_index < MAX_NAMESERVERS ) {
		nameserver *new_ns = nameserver_create(ns_string, NULL);
		new_nameservers[ns_index++] = new_ns;
	    }

	    got_answer=1;
	}
	// CNAME record
	else if(htons(rr->type)==RECTYPE_CNAME) {
	    char ns_string[255];
	    int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);

	    if(debug) {
		printf("The name %s is also known as %s.\n",
		       string_name, ns_string);
	    }

	    if ( !strcasecmp(string_name,newhostname) ) {
		if ( newhostname != hostname )
		    free(newhostname);
		newhostname = strdup(ns_string);
	    }

	    got_answer=1;
	}
	// PTR record
	else if(htons(rr->type)==RECTYPE_PTR) {
	    char ns_string[255];
	    int ns_len=from_dns_style(answerbuf,answer_ptr,ns_string);

	    if (debug) {
		printf("The host at %s is also known as %s.\n",
		       string_name, ns_string);
	    }

	    got_answer=1;

	    delete_nameservers(new_nameservers, ns_index);
	    if (newhostname != hostname)
		free(newhostname);
	    return strdup(ns_string);
	}
	// SOA record
	else if(htons(rr->type)==RECTYPE_SOA) {
	    if(debug) {
		printf("Ignoring SOA record\n");
	    }
	}
	// AAAA record
	else if(htons(rr->type)==RECTYPE_AAAA)  {
	    if(debug) {
		printf("Ignoring IPv6 record\n");
	    }
	}
	else {
	    if(debug) {
		printf("got unknown record type %hu\n",htons(rr->type));
	    }
	}

	answer_ptr+=htons(rr->datalen);
    }

    shutdown(sock,SHUT_RDWR);
    close(sock);

    if ( ns_index > 0 ) {
	int i;
	for ( i=0; i<ns_index; i++ ) {
	    nameserver *ns = new_nameservers[i];
	    // Make sure we have the IP address of this nameserver
	    if ( !ns->server_addr ) {
		if (debug) {
		    printf("Need to resolve IP address of nameserver %s\n", ns->server);
		}

		ns->server_addr = resolve_address(ns->server, root_servers, num_root_servers);

		if ( !ns->server_addr && debug ) {
		    printf("Failed to retrieve IP address for %s.\n", ns->server);
		}
	    }
	}

	if (debug) {
	    printf("now resolving the hostname %s...\n", newhostname);
	}

	// Free old nameservers array
	char *result = resolve_address(newhostname, new_nameservers, ns_index);
	if (newhostname != hostname)
	    free(newhostname);
	delete_nameservers(new_nameservers, ns_index);
	return result;
    }

    if (newhostname != hostname)
	free(newhostname);
    delete_nameservers(new_nameservers, ns_index);

    return NULL;
}