From: Jelte Jansen Date: Thu, 24 Feb 2005 14:33:57 +0000 (+0000) Subject: added rr_clone X-Git-Tag: release-0.50~374 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52daeb902562dd9414c02c00ae43cdb174b6d69b;p=thirdparty%2Fldns.git added rr_clone added axfr_start() and axfr_next() --- diff --git a/host2str.c b/host2str.c index 8b492495..88dff489 100644 --- a/host2str.c +++ b/host2str.c @@ -819,7 +819,7 @@ ldns_rr_list2buffer_str(ldns_buffer *output, ldns_rr_list *list) uint16_t i; for(i = 0; i < ldns_rr_list_rr_count(list); i++) { - ldns_rr2buffer_str(output, ldns_rr_list_rr(list, i)); + (void) ldns_rr2buffer_str(output, ldns_rr_list_rr(list, i)); ldns_buffer_printf(output, "\n"); } return ldns_buffer_status(output); diff --git a/ldns/error.h b/ldns/error.h index 20d45abc..07d0fefd 100644 --- a/ldns/error.h +++ b/ldns/error.h @@ -31,7 +31,9 @@ enum ldns_enum_status LDNS_STATUS_INVALID_IP6, LDNS_STATUS_INVALID_STR, LDNS_STATUS_INVALID_B64, - LDNS_STATUS_INVALID_HEX + LDNS_STATUS_INVALID_HEX, + LDNS_STATUS_NETWORK_ERROR, + LDNS_STATUS_ADDRESS_ERROR }; typedef enum ldns_enum_status ldns_status; diff --git a/ldns/resolver.h b/ldns/resolver.h index b5139575..8f86a415 100644 --- a/ldns/resolver.h +++ b/ldns/resolver.h @@ -60,6 +60,15 @@ struct ldns_struct_resolver bool _defnames; /** \brief if true apply the search list */ bool _dnsrch; + + /** keep some things for axfr */ + int _socket; + int _axfr_soa_count; + /* when axfring we get complete packets from the server + but we want to give the caller 1 rr at a time, so + keep the current pkt */ + ldns_pkt *_cur_axfr_pkt; + uint16_t _axfr_i; }; typedef struct ldns_struct_resolver ldns_resolver; @@ -97,4 +106,11 @@ void ldns_resolver_set_defnames(ldns_resolver *, bool); void ldns_resolver_set_usevc(ldns_resolver *, bool); void ldns_resolver_set_dnsrch(ldns_resolver *, bool); +/** + * Prepares the resolver for an axfr query + * The query is sent and the answers can be read with ldns_axfr_next + */ +ldns_status ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class); +ldns_rr *ldns_axfr_next(ldns_resolver *resolver); + #endif /* !_LDNS_RESOLVER_H */ diff --git a/ldns/rr.h b/ldns/rr.h index d4df551d..c892d90b 100644 --- a/ldns/rr.h +++ b/ldns/rr.h @@ -269,6 +269,7 @@ size_t ldns_rr_uncompressed_size(const ldns_rr *); int ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2); void ldns_rr_list_sort(ldns_rr_list *); +ldns_rr *ldns_rr_clone(ldns_rr *rr); #endif /* _LDNS_RR_H */ diff --git a/resolver.c b/resolver.c index e48986cb..63553fb2 100644 --- a/resolver.c +++ b/resolver.c @@ -247,6 +247,11 @@ ldns_resolver_new(void) ldns_resolver_set_port(r, LDNS_PORT); ldns_resolver_set_domain(r, NULL); ldns_resolver_set_defnames(r, false); + + r->_socket = 0; + r->_axfr_soa_count = 0; + r->_axfr_i = 0; + r->_cur_axfr_pkt = NULL; return r; } @@ -373,3 +378,142 @@ ldns_resolver_bgsend() { return NULL; } + +/* + * Start an axfr, send the query and keep the connection open + */ +ldns_status +ldns_axfr_start(ldns_resolver *resolver, + ldns_rdf *domain, + ldns_rr_class class) +{ + ldns_pkt *query; + ldns_buffer *query_wire; + + struct sockaddr_storage *ns; + struct sockaddr_in *ns4; + struct sockaddr_in6 *ns6; + socklen_t ns_len = 0; + ldns_status status; + + if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) { + return LDNS_STATUS_ERR; + } + + /* Create the query */ + query = ldns_pkt_query_new(ldns_rdf_clone(domain), + LDNS_RR_TYPE_AXFR, + class, + 0); + + + if (!query) { + return LDNS_STATUS_ADDRESS_ERROR; + } + /* For AXFR, we have to make the connection ourselves */ + ns = ldns_rdf2native_sockaddr_storage(resolver->_nameservers[0]); + + /* Determine the address size. + * This is a nice one for a convenience funtion + */ + switch(ns->ss_family) { + case AF_INET: + ns4 = (struct sockaddr_in*) ns; + ns4->sin_port = htons(53); + ns_len = (socklen_t)sizeof(struct sockaddr_in); + break; + case AF_INET6: + ns6 = (struct sockaddr_in6*) ns; + ns6->sin6_port = htons(53); + ns_len = (socklen_t)sizeof(struct sockaddr_in6); + break; + default: + printf("unkown inet family\n"); + return -1; + } + + resolver->_socket = ldns_tcp_connect(ns, ns_len); + if (resolver->_socket == 0) { + ldns_pkt_free(query); + return LDNS_STATUS_NETWORK_ERROR; + } + + /* Convert the query to a buffer + * Is this necessary? + */ + query_wire = ldns_buffer_new(MAX_PACKETLEN); + status = ldns_pkt2buffer_wire(query_wire, query); + if (status != LDNS_STATUS_OK) { + ldns_pkt_free(query); + return status; + } + + /* Send the query */ + if (ldns_tcp_send_query(query_wire, resolver->_socket, ns, ns_len) == 0) { + ldns_pkt_free(query); + ldns_buffer_free(query_wire); + return LDNS_STATUS_NETWORK_ERROR; + } + + ldns_pkt_free(query); + ldns_buffer_free(query_wire); + + /* + * The AXFR is done once the second SOA record is sent + */ + resolver->_axfr_soa_count = 0; + + return LDNS_STATUS_OK; +} + +ldns_rr * +ldns_axfr_next(ldns_resolver *resolver) +{ + ldns_rr *cur_rr; + + /* check if start() has been called */ + if (!resolver || resolver->_socket == 0) { + return NULL; + } + + if (resolver->_cur_axfr_pkt) { + if (resolver->_axfr_i == ldns_pkt_ancount(resolver->_cur_axfr_pkt)) { + ldns_pkt_free(resolver->_cur_axfr_pkt); + resolver->_cur_axfr_pkt = NULL; + return ldns_axfr_next(resolver); + } + cur_rr = ldns_rr_clone(ldns_rr_list_rr(ldns_pkt_answer(resolver->_cur_axfr_pkt), resolver->_axfr_i)); + resolver->_axfr_i++; + if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) { + resolver->_axfr_soa_count++; + if (resolver->_axfr_soa_count >= 2) { + close(resolver->_socket); + resolver->_socket = 0; + ldns_pkt_free(resolver->_cur_axfr_pkt); + } + } + return cur_rr; + } else { + resolver->_cur_axfr_pkt = ldns_tcp_read_packet(resolver->_socket); + + resolver->_axfr_i = 0; + return ldns_axfr_next(resolver); + + if (!resolver->_cur_axfr_pkt) { + fprintf(stderr, "[ldns_axfr_next] error reading packet\n"); + return NULL; + } + + if (ldns_pkt_rcode(resolver->_cur_axfr_pkt) != 0) { + fprintf(stderr, "Got error code\n"); + close(resolver->_socket); + resolver->_socket = 0; + ldns_pkt_free(resolver->_cur_axfr_pkt); + resolver->_cur_axfr_pkt = NULL; + return NULL; + } + + } + +} + diff --git a/rr.c b/rr.c index 3ec8b013..21eeb048 100644 --- a/rr.c +++ b/rr.c @@ -614,6 +614,24 @@ ldns_get_class_by_name(const char *name) return 0; } +ldns_rr * +ldns_rr_clone(ldns_rr *rr) +{ + uint16_t i; + + ldns_rr *new_rr = ldns_rr_new(); + ldns_rr_set_owner(new_rr, ldns_rdf_clone(ldns_rr_owner(rr))); + ldns_rr_set_ttl(new_rr, ldns_rr_ttl(rr)); + ldns_rr_set_type(new_rr, ldns_rr_get_type(rr)); + ldns_rr_set_class(new_rr, ldns_rr_get_class(rr)); + + for (i = 0; i < ldns_rr_rd_count(rr); i++) { + ldns_rr_push_rdf(new_rr, ldns_rdf_clone(ldns_rr_rdf(rr, i))); + } + + return new_rr; +} + static int qsort_rr_compare(const void *a, const void *b) { diff --git a/run-test11.c b/run-test11.c index 06bbbe8b..fb96306a 100644 --- a/run-test11.c +++ b/run-test11.c @@ -23,26 +23,14 @@ int main(int argc, char **argv) { ldns_rdf *nameserver; - - ldns_pkt *query; - ldns_buffer *query_wire; + ldns_rdf *domain; - ldns_pkt *pkt; - int soa_count; - int connection; - - struct sockaddr_storage *ns; - struct sockaddr_in *ns4; - struct sockaddr_in6 *ns6; - int ns_len = 0; + ldns_resolver *resolver; + ldns_rr *rr = NULL; char *server_ip = NULL; char *name = NULL; - - ldns_rr_list *rr_list; - ldns_rr *cur_rr; char *rr_str; - uint16_t i; /* Get the domain and the nameserver from the command line */ if (argc < 3) { @@ -57,86 +45,29 @@ main(int argc, char **argv) printf("Bad server ip\n"); return -1; } - - /* Create the query */ - query = ldns_pkt_query_new_frm_str(name, - LDNS_RR_TYPE_AXFR, - LDNS_RR_CLASS_IN, - 0); - - /* For AXFR, we have to make the connection ourselves */ - ns = ldns_rdf2native_sockaddr_storage(nameserver); - - ldns_rdf_free(nameserver); - - /* Determine the address size. - * This is a nice one for a convenience funtion - */ - switch(ns->ss_family) { - case AF_INET: - ns4 = (struct sockaddr_in*) ns; - ns4->sin_port = htons(53); - ns_len = (socklen_t)sizeof(struct sockaddr_in); - break; - case AF_INET6: - ns6 = (struct sockaddr_in6*) ns; - ns6->sin6_port = htons(53); - ns_len = (socklen_t)sizeof(struct sockaddr_in6); - break; - default: - printf("unkown inet family\n"); - return -1; - } - - connection = ldns_tcp_connect(ns, ns_len); - if (connection == 0) { - return -1; - } - /* Convert the query to a buffer - * Is this necessary? - */ - query_wire = ldns_buffer_new(MAX_PACKETLEN); - if (ldns_pkt2buffer_wire(query_wire, query) != LDNS_STATUS_OK) { - printf("Unable to create wire data for query\n"); - return -1; + resolver = ldns_resolver_new(); + ldns_resolver_set_usevc(resolver, true); + ldns_resolver_push_nameserver(resolver, nameserver); + + domain = ldns_rdf_new_frm_str(name, LDNS_RDF_TYPE_DNAME); + if (!domain) { + printf("Bad domain\n"); } - /* Send the query */ - ldns_tcp_send_query(query_wire, connection, ns, ns_len); + ldns_axfr_start(resolver, domain, LDNS_RR_CLASS_IN); - ldns_pkt_free(query); - ldns_buffer_free(query_wire); - - /* Print all the resource records we receive. - * The AXFR is done once the second SOA record is sent - */ - soa_count = 0; - while (soa_count < 2) { - pkt = ldns_tcp_read_packet(connection); - - if (!pkt) { - printf("error reading packet\n"); - } else { - rr_list = ldns_pkt_answer(pkt); - - /* Counting the number of certain types of rrs might - * be another good convenience function */ - for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { - cur_rr = ldns_rr_list_rr(rr_list, i); - if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) { - soa_count++; - } - rr_str = ldns_rr2str(cur_rr); - printf("%s\n", rr_str); - FREE(rr_str); - } - ldns_pkt_free(pkt); - } + while ((rr = ldns_axfr_next(resolver))) { + rr_str = ldns_rr2str(rr); + printf("%s\n", rr_str); + ldns_rr_free(rr); + FREE(rr_str); } - /* Don't forget to close the connection */ - close(connection); - + + ldns_rdf_free(nameserver); + ldns_rdf_free(domain); + ldns_resolver_free(resolver); + return 0; }