void* run_server(void* data) {
    timeout_thread_data* tdata = (timeout_thread_data*)data;
    int fd;
    struct sockaddr_in serv_addr;
    uint8_t mesg[65536];
    fd_set read_fds;
    ldns_rdf* answerfrom;
    ldns_resolver* resolver;
    int num_received = 0;
    queued_response responses[10];

    ldns_resolver_new_frm_file(&resolver, NULL);


    fd=socket(AF_INET,SOCK_DGRAM,0);

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    serv_addr.sin_port=htons(tdata->port);
    bind(fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));

    /* signal that it's listening */
    /* dirty timing hack to yield */
    sleep(1);
    tdata->running = 1;
    /* queue up query responses to send out, and delay sending them
     * for a second */
    while (tdata->running) {
        struct sockaddr_in client_addr;
        FD_ZERO(&read_fds);
        FD_SET(fd, &read_fds);
        struct timeval tv;
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        int r = select(fd + 1, &read_fds, NULL, NULL, &tv);
        if (r > 0 && num_received < 10) {
            ldns_pkt* query;
            socklen_t len = sizeof(client_addr);
            int n = recvfrom(fd,mesg,65536,0,(struct sockaddr *)&(responses[num_received].client_addr),&len);
            ldns_wire2pkt(&query, mesg, n);
            ldns_resolver_send_pkt(&(responses[num_received].pkt), resolver, query);
            ldns_str2rdf_a(&answerfrom, "127.0.0.1");
            ldns_pkt_set_answerfrom(responses[num_received].pkt, answerfrom);
            ldns_pkt_free(query);
            ++num_received;
        } else if (r == 0 && num_received > 0) {
            int i = 0;
            /* timeout - see if we have anything to send */
            for (i = 0; i < num_received; ++i) {
                uint8_t* pkt_data;
                size_t pkt_len;
                ldns_pkt* answer = responses[i].pkt;
                ldns_pkt2wire(&pkt_data, answer, &pkt_len);
                sendto(fd,pkt_data,pkt_len,0,(struct sockaddr *)&(responses[i].client_addr),sizeof(client_addr));
                free(pkt_data);
                ldns_pkt_free(answer);
            }
            num_received = 0;
        }
    }
    ldns_resolver_deep_free(resolver);

    return NULL;

}
Пример #2
0
ldns_status
ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac)
{
	uint8_t i;

	struct sockaddr_storage *src = NULL;
	size_t src_len;
	struct sockaddr_storage *ns;
	size_t ns_len;
	struct timeval tv_s;
	struct timeval tv_e;

	ldns_rdf **ns_array;
	size_t *rtt;
	ldns_pkt *reply;
	bool all_servers_rtt_inf;
	uint8_t retries;

	uint8_t *reply_bytes = NULL;
	size_t reply_size = 0;
	ldns_status status, send_status;

	assert(r != NULL);

	status = LDNS_STATUS_OK;
	rtt = ldns_resolver_rtt(r);
	ns_array = ldns_resolver_nameservers(r);
	reply = NULL; 
	ns_len = 0;

	all_servers_rtt_inf = true;

	if (ldns_resolver_random(r)) {
		ldns_resolver_nameservers_randomize(r);
	}

	if(ldns_resolver_source(r)) {
		src = ldns_rdf2native_sockaddr_storage_port(
				ldns_resolver_source(r), 0, &src_len);
	}

	/* loop through all defined nameservers */
	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
		if (rtt[i] == LDNS_RESOLV_RTT_INF) {
			/* not reachable nameserver! */
			continue;
		}

		/* maybe verbosity setting?
		printf("Sending to ");
		ldns_rdf_print(stdout, ns_array[i]);
		printf("\n");
		*/
		ns = ldns_rdf2native_sockaddr_storage(ns_array[i],
				ldns_resolver_port(r), &ns_len);


#ifndef S_SPLINT_S
		if ((ns->ss_family == AF_INET) &&
				(ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) {
			/* not reachable */
			LDNS_FREE(ns);
			continue;
		}

		if ((ns->ss_family == AF_INET6) &&
				 (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) {
			/* not reachable */
			LDNS_FREE(ns);
			continue;
		}
#endif

		all_servers_rtt_inf = false;

		gettimeofday(&tv_s, NULL);

		send_status = LDNS_STATUS_ERR;

		/* reply_bytes implicitly handles our error */
		if (ldns_resolver_usevc(r)) {
			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
				send_status = 
					ldns_tcp_send_from(&reply_bytes, qb, 
						ns, (socklen_t)ns_len,
						src, (socklen_t)src_len,
						ldns_resolver_timeout(r),
						&reply_size);
				if (send_status == LDNS_STATUS_OK) {
					break;
				}
			}
		} else {
			for (retries = ldns_resolver_retry(r); retries > 0; retries--) {
				/* ldns_rdf_print(stdout, ns_array[i]); */
				send_status = 
					ldns_udp_send_from(&reply_bytes, qb,
						ns,  (socklen_t)ns_len,
						src, (socklen_t)src_len,
						ldns_resolver_timeout(r),
						&reply_size);
				if (send_status == LDNS_STATUS_OK) {
					break;
				}
			}
		}

		if (send_status != LDNS_STATUS_OK) {
			ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
			status = send_status;
		}
		
		/* obey the fail directive */
		if (!reply_bytes) {
			/* the current nameserver seems to have a problem, blacklist it */
			if (ldns_resolver_fail(r)) {
				LDNS_FREE(ns);
				return LDNS_STATUS_ERR;
			} else {
				LDNS_FREE(ns);
				continue;
			}
		} 
		
		status = ldns_wire2pkt(&reply, reply_bytes, reply_size);
		if (status != LDNS_STATUS_OK) {
			LDNS_FREE(reply_bytes);
			LDNS_FREE(ns);
			return status;
		}
		
		LDNS_FREE(ns);
		gettimeofday(&tv_e, NULL);

		if (reply) {
			ldns_pkt_set_querytime(reply, (uint32_t)
				((tv_e.tv_sec - tv_s.tv_sec) * 1000) +
				(tv_e.tv_usec - tv_s.tv_usec) / 1000);
			ldns_pkt_set_answerfrom(reply,
					ldns_rdf_clone(ns_array[i]));
			ldns_pkt_set_timestamp(reply, tv_s);
			ldns_pkt_set_size(reply, reply_size);
			break;
		} else {
			if (ldns_resolver_fail(r)) {
				/* if fail is set bail out, after the first
				 * one */
				break;
			}
		}

		/* wait retrans seconds... */
		sleep((unsigned int) ldns_resolver_retrans(r));
	}

	if(src) {
		LDNS_FREE(src);
	}
	if (all_servers_rtt_inf) {
		LDNS_FREE(reply_bytes);
		return LDNS_STATUS_RES_NO_NS;
	}
#ifdef HAVE_SSL
	if (tsig_mac && reply && reply_bytes) {
		if (!ldns_pkt_tsig_verify(reply,
		                          reply_bytes,
					  reply_size,
		                          ldns_resolver_tsig_keyname(r),
		                          ldns_resolver_tsig_keydata(r), tsig_mac)) {
			status = LDNS_STATUS_CRYPTO_TSIG_BOGUS;
		}
	}
#else
	(void)tsig_mac;
#endif /* HAVE_SSL */

	LDNS_FREE(reply_bytes);
	if (result) {
		*result = reply;
	}

	return status;
}