17b5038d7SDag-Erling Smørgrav /* 27b5038d7SDag-Erling Smørgrav * net.c 37b5038d7SDag-Erling Smørgrav * 47b5038d7SDag-Erling Smørgrav * Network implementation 57b5038d7SDag-Erling Smørgrav * All network related functions are grouped here 67b5038d7SDag-Erling Smørgrav * 77b5038d7SDag-Erling Smørgrav * a Net::DNS like library for C 87b5038d7SDag-Erling Smørgrav * 97b5038d7SDag-Erling Smørgrav * (c) NLnet Labs, 2004-2006 107b5038d7SDag-Erling Smørgrav * 117b5038d7SDag-Erling Smørgrav * See the file LICENSE for the license 127b5038d7SDag-Erling Smørgrav */ 137b5038d7SDag-Erling Smørgrav 147b5038d7SDag-Erling Smørgrav #include <ldns/config.h> 157b5038d7SDag-Erling Smørgrav 167b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h> 177b5038d7SDag-Erling Smørgrav 187b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETINET_IN_H 197b5038d7SDag-Erling Smørgrav #include <netinet/in.h> 207b5038d7SDag-Erling Smørgrav #endif 217b5038d7SDag-Erling Smørgrav #ifdef HAVE_SYS_SOCKET_H 227b5038d7SDag-Erling Smørgrav #include <sys/socket.h> 237b5038d7SDag-Erling Smørgrav #endif 247b5038d7SDag-Erling Smørgrav #ifdef HAVE_NETDB_H 257b5038d7SDag-Erling Smørgrav #include <netdb.h> 267b5038d7SDag-Erling Smørgrav #endif 277b5038d7SDag-Erling Smørgrav #ifdef HAVE_ARPA_INET_H 287b5038d7SDag-Erling Smørgrav #include <arpa/inet.h> 297b5038d7SDag-Erling Smørgrav #endif 307b5038d7SDag-Erling Smørgrav #include <sys/time.h> 317b5038d7SDag-Erling Smørgrav #include <errno.h> 327b5038d7SDag-Erling Smørgrav #include <fcntl.h> 337b5038d7SDag-Erling Smørgrav 347b5038d7SDag-Erling Smørgrav ldns_status 357b5038d7SDag-Erling Smørgrav ldns_send(ldns_pkt **result_packet, ldns_resolver *r, const ldns_pkt *query_pkt) 367b5038d7SDag-Erling Smørgrav { 377b5038d7SDag-Erling Smørgrav ldns_buffer *qb; 387b5038d7SDag-Erling Smørgrav ldns_status result; 397b5038d7SDag-Erling Smørgrav ldns_rdf *tsig_mac = NULL; 407b5038d7SDag-Erling Smørgrav 417b5038d7SDag-Erling Smørgrav qb = ldns_buffer_new(LDNS_MIN_BUFLEN); 427b5038d7SDag-Erling Smørgrav 437b5038d7SDag-Erling Smørgrav if (query_pkt && ldns_pkt_tsig(query_pkt)) { 447b5038d7SDag-Erling Smørgrav tsig_mac = ldns_rr_rdf(ldns_pkt_tsig(query_pkt), 3); 457b5038d7SDag-Erling Smørgrav } 467b5038d7SDag-Erling Smørgrav 477b5038d7SDag-Erling Smørgrav if (!query_pkt || 487b5038d7SDag-Erling Smørgrav ldns_pkt2buffer_wire(qb, query_pkt) != LDNS_STATUS_OK) { 497b5038d7SDag-Erling Smørgrav result = LDNS_STATUS_ERR; 507b5038d7SDag-Erling Smørgrav } else { 517b5038d7SDag-Erling Smørgrav result = ldns_send_buffer(result_packet, r, qb, tsig_mac); 527b5038d7SDag-Erling Smørgrav } 537b5038d7SDag-Erling Smørgrav 547b5038d7SDag-Erling Smørgrav ldns_buffer_free(qb); 557b5038d7SDag-Erling Smørgrav 567b5038d7SDag-Erling Smørgrav return result; 577b5038d7SDag-Erling Smørgrav } 587b5038d7SDag-Erling Smørgrav 597b5038d7SDag-Erling Smørgrav ldns_status 607b5038d7SDag-Erling Smørgrav ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf *tsig_mac) 617b5038d7SDag-Erling Smørgrav { 627b5038d7SDag-Erling Smørgrav uint8_t i; 637b5038d7SDag-Erling Smørgrav 647b5038d7SDag-Erling Smørgrav struct sockaddr_storage *ns; 657b5038d7SDag-Erling Smørgrav size_t ns_len; 667b5038d7SDag-Erling Smørgrav struct timeval tv_s; 677b5038d7SDag-Erling Smørgrav struct timeval tv_e; 687b5038d7SDag-Erling Smørgrav 697b5038d7SDag-Erling Smørgrav ldns_rdf **ns_array; 707b5038d7SDag-Erling Smørgrav size_t *rtt; 717b5038d7SDag-Erling Smørgrav ldns_pkt *reply; 727b5038d7SDag-Erling Smørgrav bool all_servers_rtt_inf; 737b5038d7SDag-Erling Smørgrav uint8_t retries; 747b5038d7SDag-Erling Smørgrav 757b5038d7SDag-Erling Smørgrav uint8_t *reply_bytes = NULL; 767b5038d7SDag-Erling Smørgrav size_t reply_size = 0; 777b5038d7SDag-Erling Smørgrav ldns_status status, send_status; 787b5038d7SDag-Erling Smørgrav 797b5038d7SDag-Erling Smørgrav assert(r != NULL); 807b5038d7SDag-Erling Smørgrav 817b5038d7SDag-Erling Smørgrav status = LDNS_STATUS_OK; 827b5038d7SDag-Erling Smørgrav rtt = ldns_resolver_rtt(r); 837b5038d7SDag-Erling Smørgrav ns_array = ldns_resolver_nameservers(r); 847b5038d7SDag-Erling Smørgrav reply = NULL; 857b5038d7SDag-Erling Smørgrav ns_len = 0; 867b5038d7SDag-Erling Smørgrav 877b5038d7SDag-Erling Smørgrav all_servers_rtt_inf = true; 887b5038d7SDag-Erling Smørgrav 897b5038d7SDag-Erling Smørgrav if (ldns_resolver_random(r)) { 907b5038d7SDag-Erling Smørgrav ldns_resolver_nameservers_randomize(r); 917b5038d7SDag-Erling Smørgrav } 927b5038d7SDag-Erling Smørgrav 937b5038d7SDag-Erling Smørgrav /* loop through all defined nameservers */ 947b5038d7SDag-Erling Smørgrav for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { 957b5038d7SDag-Erling Smørgrav if (rtt[i] == LDNS_RESOLV_RTT_INF) { 967b5038d7SDag-Erling Smørgrav /* not reachable nameserver! */ 977b5038d7SDag-Erling Smørgrav continue; 987b5038d7SDag-Erling Smørgrav } 997b5038d7SDag-Erling Smørgrav 1007b5038d7SDag-Erling Smørgrav /* maybe verbosity setting? 1017b5038d7SDag-Erling Smørgrav printf("Sending to "); 1027b5038d7SDag-Erling Smørgrav ldns_rdf_print(stdout, ns_array[i]); 1037b5038d7SDag-Erling Smørgrav printf("\n"); 1047b5038d7SDag-Erling Smørgrav */ 1057b5038d7SDag-Erling Smørgrav ns = ldns_rdf2native_sockaddr_storage(ns_array[i], 1067b5038d7SDag-Erling Smørgrav ldns_resolver_port(r), &ns_len); 1077b5038d7SDag-Erling Smørgrav 1087b5038d7SDag-Erling Smørgrav 1097b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 1107b5038d7SDag-Erling Smørgrav if ((ns->ss_family == AF_INET) && 1117b5038d7SDag-Erling Smørgrav (ldns_resolver_ip6(r) == LDNS_RESOLV_INET6)) { 1127b5038d7SDag-Erling Smørgrav /* not reachable */ 113*2787e39aSDag-Erling Smørgrav LDNS_FREE(ns); 1147b5038d7SDag-Erling Smørgrav continue; 1157b5038d7SDag-Erling Smørgrav } 1167b5038d7SDag-Erling Smørgrav 1177b5038d7SDag-Erling Smørgrav if ((ns->ss_family == AF_INET6) && 1187b5038d7SDag-Erling Smørgrav (ldns_resolver_ip6(r) == LDNS_RESOLV_INET)) { 1197b5038d7SDag-Erling Smørgrav /* not reachable */ 120*2787e39aSDag-Erling Smørgrav LDNS_FREE(ns); 1217b5038d7SDag-Erling Smørgrav continue; 1227b5038d7SDag-Erling Smørgrav } 1237b5038d7SDag-Erling Smørgrav #endif 1247b5038d7SDag-Erling Smørgrav 1257b5038d7SDag-Erling Smørgrav all_servers_rtt_inf = false; 1267b5038d7SDag-Erling Smørgrav 1277b5038d7SDag-Erling Smørgrav gettimeofday(&tv_s, NULL); 1287b5038d7SDag-Erling Smørgrav 1297b5038d7SDag-Erling Smørgrav send_status = LDNS_STATUS_ERR; 1307b5038d7SDag-Erling Smørgrav 1317b5038d7SDag-Erling Smørgrav /* reply_bytes implicitly handles our error */ 1327b5038d7SDag-Erling Smørgrav if (1 == ldns_resolver_usevc(r)) { 1337b5038d7SDag-Erling Smørgrav for (retries = ldns_resolver_retry(r); retries > 0; retries--) { 1347b5038d7SDag-Erling Smørgrav send_status = 1357b5038d7SDag-Erling Smørgrav ldns_tcp_send(&reply_bytes, qb, ns, 1367b5038d7SDag-Erling Smørgrav (socklen_t)ns_len, ldns_resolver_timeout(r), 1377b5038d7SDag-Erling Smørgrav &reply_size); 1387b5038d7SDag-Erling Smørgrav if (send_status == LDNS_STATUS_OK) { 1397b5038d7SDag-Erling Smørgrav break; 1407b5038d7SDag-Erling Smørgrav } 1417b5038d7SDag-Erling Smørgrav } 1427b5038d7SDag-Erling Smørgrav } else { 1437b5038d7SDag-Erling Smørgrav for (retries = ldns_resolver_retry(r); retries > 0; retries--) { 1447b5038d7SDag-Erling Smørgrav /* ldns_rdf_print(stdout, ns_array[i]); */ 1457b5038d7SDag-Erling Smørgrav send_status = 1467b5038d7SDag-Erling Smørgrav ldns_udp_send(&reply_bytes, qb, ns, 1477b5038d7SDag-Erling Smørgrav (socklen_t)ns_len, ldns_resolver_timeout(r), 1487b5038d7SDag-Erling Smørgrav &reply_size); 1497b5038d7SDag-Erling Smørgrav 1507b5038d7SDag-Erling Smørgrav if (send_status == LDNS_STATUS_OK) { 1517b5038d7SDag-Erling Smørgrav break; 1527b5038d7SDag-Erling Smørgrav } 1537b5038d7SDag-Erling Smørgrav } 1547b5038d7SDag-Erling Smørgrav } 1557b5038d7SDag-Erling Smørgrav 1567b5038d7SDag-Erling Smørgrav if (send_status != LDNS_STATUS_OK) { 1577b5038d7SDag-Erling Smørgrav ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF); 1587b5038d7SDag-Erling Smørgrav status = send_status; 1597b5038d7SDag-Erling Smørgrav } 1607b5038d7SDag-Erling Smørgrav 1617b5038d7SDag-Erling Smørgrav /* obey the fail directive */ 1627b5038d7SDag-Erling Smørgrav if (!reply_bytes) { 1637b5038d7SDag-Erling Smørgrav /* the current nameserver seems to have a problem, blacklist it */ 1647b5038d7SDag-Erling Smørgrav if (ldns_resolver_fail(r)) { 1657b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 1667b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ERR; 1677b5038d7SDag-Erling Smørgrav } else { 1687b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 1697b5038d7SDag-Erling Smørgrav continue; 1707b5038d7SDag-Erling Smørgrav } 1717b5038d7SDag-Erling Smørgrav } 1727b5038d7SDag-Erling Smørgrav 1737b5038d7SDag-Erling Smørgrav status = ldns_wire2pkt(&reply, reply_bytes, reply_size); 1747b5038d7SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) { 1757b5038d7SDag-Erling Smørgrav LDNS_FREE(reply_bytes); 1767b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 1777b5038d7SDag-Erling Smørgrav return status; 1787b5038d7SDag-Erling Smørgrav } 1797b5038d7SDag-Erling Smørgrav 1807b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 1817b5038d7SDag-Erling Smørgrav gettimeofday(&tv_e, NULL); 1827b5038d7SDag-Erling Smørgrav 1837b5038d7SDag-Erling Smørgrav if (reply) { 1847b5038d7SDag-Erling Smørgrav ldns_pkt_set_querytime(reply, (uint32_t) 1857b5038d7SDag-Erling Smørgrav ((tv_e.tv_sec - tv_s.tv_sec) * 1000) + 1867b5038d7SDag-Erling Smørgrav (tv_e.tv_usec - tv_s.tv_usec) / 1000); 187*2787e39aSDag-Erling Smørgrav ldns_pkt_set_answerfrom(reply, 188*2787e39aSDag-Erling Smørgrav ldns_rdf_clone(ns_array[i])); 1897b5038d7SDag-Erling Smørgrav ldns_pkt_set_timestamp(reply, tv_s); 1907b5038d7SDag-Erling Smørgrav ldns_pkt_set_size(reply, reply_size); 1917b5038d7SDag-Erling Smørgrav break; 1927b5038d7SDag-Erling Smørgrav } else { 1937b5038d7SDag-Erling Smørgrav if (ldns_resolver_fail(r)) { 1947b5038d7SDag-Erling Smørgrav /* if fail is set bail out, after the first 1957b5038d7SDag-Erling Smørgrav * one */ 1967b5038d7SDag-Erling Smørgrav break; 1977b5038d7SDag-Erling Smørgrav } 1987b5038d7SDag-Erling Smørgrav } 1997b5038d7SDag-Erling Smørgrav 2007b5038d7SDag-Erling Smørgrav /* wait retrans seconds... */ 2017b5038d7SDag-Erling Smørgrav sleep((unsigned int) ldns_resolver_retrans(r)); 2027b5038d7SDag-Erling Smørgrav } 2037b5038d7SDag-Erling Smørgrav 2047b5038d7SDag-Erling Smørgrav if (all_servers_rtt_inf) { 2057b5038d7SDag-Erling Smørgrav LDNS_FREE(reply_bytes); 2067b5038d7SDag-Erling Smørgrav return LDNS_STATUS_RES_NO_NS; 2077b5038d7SDag-Erling Smørgrav } 2087b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL 209*2787e39aSDag-Erling Smørgrav if (tsig_mac && reply && reply_bytes) { 2107b5038d7SDag-Erling Smørgrav if (!ldns_pkt_tsig_verify(reply, 2117b5038d7SDag-Erling Smørgrav reply_bytes, 2127b5038d7SDag-Erling Smørgrav reply_size, 2137b5038d7SDag-Erling Smørgrav ldns_resolver_tsig_keyname(r), 2147b5038d7SDag-Erling Smørgrav ldns_resolver_tsig_keydata(r), tsig_mac)) { 2157b5038d7SDag-Erling Smørgrav status = LDNS_STATUS_CRYPTO_TSIG_BOGUS; 2167b5038d7SDag-Erling Smørgrav } 2177b5038d7SDag-Erling Smørgrav } 2187b5038d7SDag-Erling Smørgrav #else 2197b5038d7SDag-Erling Smørgrav (void)tsig_mac; 2207b5038d7SDag-Erling Smørgrav #endif /* HAVE_SSL */ 2217b5038d7SDag-Erling Smørgrav 2227b5038d7SDag-Erling Smørgrav LDNS_FREE(reply_bytes); 2237b5038d7SDag-Erling Smørgrav if (result) { 2247b5038d7SDag-Erling Smørgrav *result = reply; 2257b5038d7SDag-Erling Smørgrav } 2267b5038d7SDag-Erling Smørgrav 2277b5038d7SDag-Erling Smørgrav return status; 2287b5038d7SDag-Erling Smørgrav } 2297b5038d7SDag-Erling Smørgrav 2307b5038d7SDag-Erling Smørgrav /** best effort to set nonblocking */ 2317b5038d7SDag-Erling Smørgrav static void 2327b5038d7SDag-Erling Smørgrav ldns_sock_nonblock(int sockfd) 2337b5038d7SDag-Erling Smørgrav { 2347b5038d7SDag-Erling Smørgrav #ifdef HAVE_FCNTL 2357b5038d7SDag-Erling Smørgrav int flag; 2367b5038d7SDag-Erling Smørgrav if((flag = fcntl(sockfd, F_GETFL)) != -1) { 2377b5038d7SDag-Erling Smørgrav flag |= O_NONBLOCK; 2387b5038d7SDag-Erling Smørgrav if(fcntl(sockfd, F_SETFL, flag) == -1) { 2397b5038d7SDag-Erling Smørgrav /* ignore error, continue blockingly */ 2407b5038d7SDag-Erling Smørgrav } 2417b5038d7SDag-Erling Smørgrav } 2427b5038d7SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET) 2437b5038d7SDag-Erling Smørgrav unsigned long on = 1; 2447b5038d7SDag-Erling Smørgrav if(ioctlsocket(sockfd, FIONBIO, &on) != 0) { 2457b5038d7SDag-Erling Smørgrav /* ignore error, continue blockingly */ 2467b5038d7SDag-Erling Smørgrav } 2477b5038d7SDag-Erling Smørgrav #endif 2487b5038d7SDag-Erling Smørgrav } 2497b5038d7SDag-Erling Smørgrav 2507b5038d7SDag-Erling Smørgrav /** best effort to set blocking */ 2517b5038d7SDag-Erling Smørgrav static void 2527b5038d7SDag-Erling Smørgrav ldns_sock_block(int sockfd) 2537b5038d7SDag-Erling Smørgrav { 2547b5038d7SDag-Erling Smørgrav #ifdef HAVE_FCNTL 2557b5038d7SDag-Erling Smørgrav int flag; 2567b5038d7SDag-Erling Smørgrav if((flag = fcntl(sockfd, F_GETFL)) != -1) { 2577b5038d7SDag-Erling Smørgrav flag &= ~O_NONBLOCK; 2587b5038d7SDag-Erling Smørgrav if(fcntl(sockfd, F_SETFL, flag) == -1) { 2597b5038d7SDag-Erling Smørgrav /* ignore error, continue */ 2607b5038d7SDag-Erling Smørgrav } 2617b5038d7SDag-Erling Smørgrav } 2627b5038d7SDag-Erling Smørgrav #elif defined(HAVE_IOCTLSOCKET) 2637b5038d7SDag-Erling Smørgrav unsigned long off = 0; 2647b5038d7SDag-Erling Smørgrav if(ioctlsocket(sockfd, FIONBIO, &off) != 0) { 2657b5038d7SDag-Erling Smørgrav /* ignore error, continue */ 2667b5038d7SDag-Erling Smørgrav } 2677b5038d7SDag-Erling Smørgrav #endif 2687b5038d7SDag-Erling Smørgrav } 2697b5038d7SDag-Erling Smørgrav 2707b5038d7SDag-Erling Smørgrav /** wait for a socket to become ready */ 2717b5038d7SDag-Erling Smørgrav static int 2727b5038d7SDag-Erling Smørgrav ldns_sock_wait(int sockfd, struct timeval timeout, int write) 2737b5038d7SDag-Erling Smørgrav { 2747b5038d7SDag-Erling Smørgrav int ret; 2757b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 2767b5038d7SDag-Erling Smørgrav fd_set fds; 2777b5038d7SDag-Erling Smørgrav FD_ZERO(&fds); 2787b5038d7SDag-Erling Smørgrav FD_SET(FD_SET_T sockfd, &fds); 2797b5038d7SDag-Erling Smørgrav if(write) 2807b5038d7SDag-Erling Smørgrav ret = select(sockfd+1, NULL, &fds, NULL, &timeout); 2817b5038d7SDag-Erling Smørgrav else 2827b5038d7SDag-Erling Smørgrav ret = select(sockfd+1, &fds, NULL, NULL, &timeout); 2837b5038d7SDag-Erling Smørgrav #endif 2847b5038d7SDag-Erling Smørgrav if(ret == 0) 2857b5038d7SDag-Erling Smørgrav /* timeout expired */ 2867b5038d7SDag-Erling Smørgrav return 0; 2877b5038d7SDag-Erling Smørgrav else if(ret == -1) 2887b5038d7SDag-Erling Smørgrav /* error */ 2897b5038d7SDag-Erling Smørgrav return 0; 2907b5038d7SDag-Erling Smørgrav return 1; 2917b5038d7SDag-Erling Smørgrav } 2927b5038d7SDag-Erling Smørgrav 2937b5038d7SDag-Erling Smørgrav ldns_status 2947b5038d7SDag-Erling Smørgrav ldns_udp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, 2957b5038d7SDag-Erling Smørgrav socklen_t tolen, struct timeval timeout, size_t *answer_size) 2967b5038d7SDag-Erling Smørgrav { 2977b5038d7SDag-Erling Smørgrav int sockfd; 2987b5038d7SDag-Erling Smørgrav uint8_t *answer; 2997b5038d7SDag-Erling Smørgrav 3007b5038d7SDag-Erling Smørgrav sockfd = ldns_udp_bgsend(qbin, to, tolen, timeout); 3017b5038d7SDag-Erling Smørgrav 3027b5038d7SDag-Erling Smørgrav if (sockfd == 0) { 3037b5038d7SDag-Erling Smørgrav return LDNS_STATUS_SOCKET_ERROR; 3047b5038d7SDag-Erling Smørgrav } 3057b5038d7SDag-Erling Smørgrav 3067b5038d7SDag-Erling Smørgrav /* wait for an response*/ 3077b5038d7SDag-Erling Smørgrav if(!ldns_sock_wait(sockfd, timeout, 0)) { 3087b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 3097b5038d7SDag-Erling Smørgrav close(sockfd); 3107b5038d7SDag-Erling Smørgrav #else 3117b5038d7SDag-Erling Smørgrav closesocket(sockfd); 3127b5038d7SDag-Erling Smørgrav #endif 3137b5038d7SDag-Erling Smørgrav return LDNS_STATUS_NETWORK_ERR; 3147b5038d7SDag-Erling Smørgrav } 3157b5038d7SDag-Erling Smørgrav 3167b5038d7SDag-Erling Smørgrav /* set to nonblocking, so if the checksum is bad, it becomes 3177b5038d7SDag-Erling Smørgrav * an EGAIN error and the ldns_udp_send function does not block, 3187b5038d7SDag-Erling Smørgrav * but returns a 'NETWORK_ERROR' much like a timeout. */ 3197b5038d7SDag-Erling Smørgrav ldns_sock_nonblock(sockfd); 3207b5038d7SDag-Erling Smørgrav 3217b5038d7SDag-Erling Smørgrav answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL); 3227b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 3237b5038d7SDag-Erling Smørgrav close(sockfd); 3247b5038d7SDag-Erling Smørgrav #else 3257b5038d7SDag-Erling Smørgrav closesocket(sockfd); 3267b5038d7SDag-Erling Smørgrav #endif 3277b5038d7SDag-Erling Smørgrav 3287b5038d7SDag-Erling Smørgrav if (*answer_size == 0) { 3297b5038d7SDag-Erling Smørgrav /* oops */ 3307b5038d7SDag-Erling Smørgrav return LDNS_STATUS_NETWORK_ERR; 3317b5038d7SDag-Erling Smørgrav } 3327b5038d7SDag-Erling Smørgrav 3337b5038d7SDag-Erling Smørgrav *result = answer; 3347b5038d7SDag-Erling Smørgrav return LDNS_STATUS_OK; 3357b5038d7SDag-Erling Smørgrav } 3367b5038d7SDag-Erling Smørgrav 3377b5038d7SDag-Erling Smørgrav int 3387b5038d7SDag-Erling Smørgrav ldns_udp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, 3397b5038d7SDag-Erling Smørgrav struct timeval timeout) 3407b5038d7SDag-Erling Smørgrav { 3417b5038d7SDag-Erling Smørgrav int sockfd; 3427b5038d7SDag-Erling Smørgrav 3437b5038d7SDag-Erling Smørgrav sockfd = ldns_udp_connect(to, timeout); 3447b5038d7SDag-Erling Smørgrav 3457b5038d7SDag-Erling Smørgrav if (sockfd == 0) { 3467b5038d7SDag-Erling Smørgrav return 0; 3477b5038d7SDag-Erling Smørgrav } 3487b5038d7SDag-Erling Smørgrav 3497b5038d7SDag-Erling Smørgrav if (ldns_udp_send_query(qbin, sockfd, to, tolen) == 0) { 3507b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 3517b5038d7SDag-Erling Smørgrav close(sockfd); 3527b5038d7SDag-Erling Smørgrav #else 3537b5038d7SDag-Erling Smørgrav closesocket(sockfd); 3547b5038d7SDag-Erling Smørgrav #endif 3557b5038d7SDag-Erling Smørgrav return 0; 3567b5038d7SDag-Erling Smørgrav } 3577b5038d7SDag-Erling Smørgrav return sockfd; 3587b5038d7SDag-Erling Smørgrav } 3597b5038d7SDag-Erling Smørgrav 3607b5038d7SDag-Erling Smørgrav int 3617b5038d7SDag-Erling Smørgrav ldns_udp_connect(const struct sockaddr_storage *to, struct timeval ATTR_UNUSED(timeout)) 3627b5038d7SDag-Erling Smørgrav { 3637b5038d7SDag-Erling Smørgrav int sockfd; 3647b5038d7SDag-Erling Smørgrav 3657b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 3667b5038d7SDag-Erling Smørgrav if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_DGRAM, 3677b5038d7SDag-Erling Smørgrav IPPROTO_UDP)) 3687b5038d7SDag-Erling Smørgrav == -1) { 3697b5038d7SDag-Erling Smørgrav return 0; 3707b5038d7SDag-Erling Smørgrav } 3717b5038d7SDag-Erling Smørgrav #endif 3727b5038d7SDag-Erling Smørgrav return sockfd; 3737b5038d7SDag-Erling Smørgrav } 3747b5038d7SDag-Erling Smørgrav 3757b5038d7SDag-Erling Smørgrav int 3767b5038d7SDag-Erling Smørgrav ldns_tcp_connect(const struct sockaddr_storage *to, socklen_t tolen, 3777b5038d7SDag-Erling Smørgrav struct timeval timeout) 3787b5038d7SDag-Erling Smørgrav { 3797b5038d7SDag-Erling Smørgrav int sockfd; 3807b5038d7SDag-Erling Smørgrav 3817b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 3827b5038d7SDag-Erling Smørgrav if ((sockfd = socket((int)((struct sockaddr*)to)->sa_family, SOCK_STREAM, 3837b5038d7SDag-Erling Smørgrav IPPROTO_TCP)) == -1) { 3847b5038d7SDag-Erling Smørgrav return 0; 3857b5038d7SDag-Erling Smørgrav } 3867b5038d7SDag-Erling Smørgrav #endif 3877b5038d7SDag-Erling Smørgrav 3887b5038d7SDag-Erling Smørgrav /* perform nonblocking connect, to be able to wait with select() */ 3897b5038d7SDag-Erling Smørgrav ldns_sock_nonblock(sockfd); 3907b5038d7SDag-Erling Smørgrav if (connect(sockfd, (struct sockaddr*)to, tolen) == -1) { 3917b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 3927b5038d7SDag-Erling Smørgrav #ifdef EINPROGRESS 3937b5038d7SDag-Erling Smørgrav if(errno != EINPROGRESS) { 3947b5038d7SDag-Erling Smørgrav #else 3957b5038d7SDag-Erling Smørgrav if(1) { 3967b5038d7SDag-Erling Smørgrav #endif 3977b5038d7SDag-Erling Smørgrav close(sockfd); 3987b5038d7SDag-Erling Smørgrav return 0; 3997b5038d7SDag-Erling Smørgrav } 4007b5038d7SDag-Erling Smørgrav #else /* USE_WINSOCK */ 4017b5038d7SDag-Erling Smørgrav if(WSAGetLastError() != WSAEINPROGRESS && 4027b5038d7SDag-Erling Smørgrav WSAGetLastError() != WSAEWOULDBLOCK) { 4037b5038d7SDag-Erling Smørgrav closesocket(sockfd); 4047b5038d7SDag-Erling Smørgrav return 0; 4057b5038d7SDag-Erling Smørgrav } 4067b5038d7SDag-Erling Smørgrav #endif 4077b5038d7SDag-Erling Smørgrav /* error was only telling us that it would block */ 4087b5038d7SDag-Erling Smørgrav } 4097b5038d7SDag-Erling Smørgrav 4107b5038d7SDag-Erling Smørgrav /* wait(write) until connected or error */ 4117b5038d7SDag-Erling Smørgrav while(1) { 4127b5038d7SDag-Erling Smørgrav int error = 0; 4137b5038d7SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(error); 4147b5038d7SDag-Erling Smørgrav 4157b5038d7SDag-Erling Smørgrav if(!ldns_sock_wait(sockfd, timeout, 1)) { 4167b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 4177b5038d7SDag-Erling Smørgrav close(sockfd); 4187b5038d7SDag-Erling Smørgrav #else 4197b5038d7SDag-Erling Smørgrav closesocket(sockfd); 4207b5038d7SDag-Erling Smørgrav #endif 4217b5038d7SDag-Erling Smørgrav return 0; 4227b5038d7SDag-Erling Smørgrav } 4237b5038d7SDag-Erling Smørgrav 4247b5038d7SDag-Erling Smørgrav /* check if there is a pending error for nonblocking connect */ 4257b5038d7SDag-Erling Smørgrav if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, 4267b5038d7SDag-Erling Smørgrav &len) < 0) { 4277b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 4287b5038d7SDag-Erling Smørgrav error = errno; /* on solaris errno is error */ 4297b5038d7SDag-Erling Smørgrav #else 4307b5038d7SDag-Erling Smørgrav error = WSAGetLastError(); 4317b5038d7SDag-Erling Smørgrav #endif 4327b5038d7SDag-Erling Smørgrav } 4337b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 4347b5038d7SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK) 4357b5038d7SDag-Erling Smørgrav if(error == EINPROGRESS || error == EWOULDBLOCK) 4367b5038d7SDag-Erling Smørgrav continue; /* try again */ 4377b5038d7SDag-Erling Smørgrav #endif 4387b5038d7SDag-Erling Smørgrav else if(error != 0) { 4397b5038d7SDag-Erling Smørgrav close(sockfd); 4407b5038d7SDag-Erling Smørgrav /* error in errno for our user */ 4417b5038d7SDag-Erling Smørgrav errno = error; 4427b5038d7SDag-Erling Smørgrav return 0; 4437b5038d7SDag-Erling Smørgrav } 4447b5038d7SDag-Erling Smørgrav #else /* USE_WINSOCK */ 4457b5038d7SDag-Erling Smørgrav if(error == WSAEINPROGRESS) 4467b5038d7SDag-Erling Smørgrav continue; 4477b5038d7SDag-Erling Smørgrav else if(error == WSAEWOULDBLOCK) 4487b5038d7SDag-Erling Smørgrav continue; 4497b5038d7SDag-Erling Smørgrav else if(error != 0) { 4507b5038d7SDag-Erling Smørgrav closesocket(sockfd); 4517b5038d7SDag-Erling Smørgrav errno = error; 4527b5038d7SDag-Erling Smørgrav return 0; 4537b5038d7SDag-Erling Smørgrav } 4547b5038d7SDag-Erling Smørgrav #endif /* USE_WINSOCK */ 4557b5038d7SDag-Erling Smørgrav /* connected */ 4567b5038d7SDag-Erling Smørgrav break; 4577b5038d7SDag-Erling Smørgrav } 4587b5038d7SDag-Erling Smørgrav 4597b5038d7SDag-Erling Smørgrav /* set the socket blocking again */ 4607b5038d7SDag-Erling Smørgrav ldns_sock_block(sockfd); 4617b5038d7SDag-Erling Smørgrav 4627b5038d7SDag-Erling Smørgrav return sockfd; 4637b5038d7SDag-Erling Smørgrav } 4647b5038d7SDag-Erling Smørgrav 4657b5038d7SDag-Erling Smørgrav ssize_t 4667b5038d7SDag-Erling Smørgrav ldns_tcp_send_query(ldns_buffer *qbin, int sockfd, 4677b5038d7SDag-Erling Smørgrav const struct sockaddr_storage *to, socklen_t tolen) 4687b5038d7SDag-Erling Smørgrav { 4697b5038d7SDag-Erling Smørgrav uint8_t *sendbuf; 4707b5038d7SDag-Erling Smørgrav ssize_t bytes; 4717b5038d7SDag-Erling Smørgrav 4727b5038d7SDag-Erling Smørgrav /* add length of packet */ 4737b5038d7SDag-Erling Smørgrav sendbuf = LDNS_XMALLOC(uint8_t, ldns_buffer_position(qbin) + 2); 4747b5038d7SDag-Erling Smørgrav if(!sendbuf) return 0; 4757b5038d7SDag-Erling Smørgrav ldns_write_uint16(sendbuf, ldns_buffer_position(qbin)); 476*2787e39aSDag-Erling Smørgrav memcpy(sendbuf + 2, ldns_buffer_begin(qbin), ldns_buffer_position(qbin)); 4777b5038d7SDag-Erling Smørgrav 4787b5038d7SDag-Erling Smørgrav bytes = sendto(sockfd, (void*)sendbuf, 4797b5038d7SDag-Erling Smørgrav ldns_buffer_position(qbin) + 2, 0, (struct sockaddr *)to, tolen); 4807b5038d7SDag-Erling Smørgrav 4817b5038d7SDag-Erling Smørgrav LDNS_FREE(sendbuf); 4827b5038d7SDag-Erling Smørgrav 4837b5038d7SDag-Erling Smørgrav if (bytes == -1 || (size_t) bytes != ldns_buffer_position(qbin) + 2 ) { 4847b5038d7SDag-Erling Smørgrav return 0; 4857b5038d7SDag-Erling Smørgrav } 4867b5038d7SDag-Erling Smørgrav return bytes; 4877b5038d7SDag-Erling Smørgrav } 4887b5038d7SDag-Erling Smørgrav 4897b5038d7SDag-Erling Smørgrav /* don't wait for an answer */ 4907b5038d7SDag-Erling Smørgrav ssize_t 4917b5038d7SDag-Erling Smørgrav ldns_udp_send_query(ldns_buffer *qbin, int sockfd, const struct sockaddr_storage *to, 4927b5038d7SDag-Erling Smørgrav socklen_t tolen) 4937b5038d7SDag-Erling Smørgrav { 4947b5038d7SDag-Erling Smørgrav ssize_t bytes; 4957b5038d7SDag-Erling Smørgrav 4967b5038d7SDag-Erling Smørgrav bytes = sendto(sockfd, (void*)ldns_buffer_begin(qbin), 4977b5038d7SDag-Erling Smørgrav ldns_buffer_position(qbin), 0, (struct sockaddr *)to, tolen); 4987b5038d7SDag-Erling Smørgrav 4997b5038d7SDag-Erling Smørgrav if (bytes == -1 || (size_t)bytes != ldns_buffer_position(qbin)) { 5007b5038d7SDag-Erling Smørgrav return 0; 5017b5038d7SDag-Erling Smørgrav } 5027b5038d7SDag-Erling Smørgrav if ((size_t) bytes != ldns_buffer_position(qbin)) { 5037b5038d7SDag-Erling Smørgrav return 0; 5047b5038d7SDag-Erling Smørgrav } 5057b5038d7SDag-Erling Smørgrav return bytes; 5067b5038d7SDag-Erling Smørgrav } 5077b5038d7SDag-Erling Smørgrav 5087b5038d7SDag-Erling Smørgrav uint8_t * 5097b5038d7SDag-Erling Smørgrav ldns_udp_read_wire(int sockfd, size_t *size, struct sockaddr_storage *from, 5107b5038d7SDag-Erling Smørgrav socklen_t *fromlen) 5117b5038d7SDag-Erling Smørgrav { 5127b5038d7SDag-Erling Smørgrav uint8_t *wire, *wireout; 5137b5038d7SDag-Erling Smørgrav ssize_t wire_size; 5147b5038d7SDag-Erling Smørgrav 5157b5038d7SDag-Erling Smørgrav wire = LDNS_XMALLOC(uint8_t, LDNS_MAX_PACKETLEN); 5167b5038d7SDag-Erling Smørgrav if (!wire) { 5177b5038d7SDag-Erling Smørgrav *size = 0; 5187b5038d7SDag-Erling Smørgrav return NULL; 5197b5038d7SDag-Erling Smørgrav } 5207b5038d7SDag-Erling Smørgrav 5217b5038d7SDag-Erling Smørgrav wire_size = recvfrom(sockfd, (void*)wire, LDNS_MAX_PACKETLEN, 0, 5227b5038d7SDag-Erling Smørgrav (struct sockaddr *)from, fromlen); 5237b5038d7SDag-Erling Smørgrav 5247b5038d7SDag-Erling Smørgrav /* recvfrom can also return 0 */ 5257b5038d7SDag-Erling Smørgrav if (wire_size == -1 || wire_size == 0) { 5267b5038d7SDag-Erling Smørgrav *size = 0; 5277b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5287b5038d7SDag-Erling Smørgrav return NULL; 5297b5038d7SDag-Erling Smørgrav } 5307b5038d7SDag-Erling Smørgrav 5317b5038d7SDag-Erling Smørgrav *size = (size_t)wire_size; 5327b5038d7SDag-Erling Smørgrav wireout = LDNS_XREALLOC(wire, uint8_t, (size_t)wire_size); 5337b5038d7SDag-Erling Smørgrav if(!wireout) LDNS_FREE(wire); 5347b5038d7SDag-Erling Smørgrav 5357b5038d7SDag-Erling Smørgrav return wireout; 5367b5038d7SDag-Erling Smørgrav } 5377b5038d7SDag-Erling Smørgrav 5387b5038d7SDag-Erling Smørgrav uint8_t * 5397b5038d7SDag-Erling Smørgrav ldns_tcp_read_wire_timeout(int sockfd, size_t *size, struct timeval timeout) 5407b5038d7SDag-Erling Smørgrav { 5417b5038d7SDag-Erling Smørgrav uint8_t *wire; 5427b5038d7SDag-Erling Smørgrav uint16_t wire_size; 5437b5038d7SDag-Erling Smørgrav ssize_t bytes = 0, rc = 0; 5447b5038d7SDag-Erling Smørgrav 5457b5038d7SDag-Erling Smørgrav wire = LDNS_XMALLOC(uint8_t, 2); 5467b5038d7SDag-Erling Smørgrav if (!wire) { 5477b5038d7SDag-Erling Smørgrav *size = 0; 5487b5038d7SDag-Erling Smørgrav return NULL; 5497b5038d7SDag-Erling Smørgrav } 5507b5038d7SDag-Erling Smørgrav 5517b5038d7SDag-Erling Smørgrav while (bytes < 2) { 5527b5038d7SDag-Erling Smørgrav if(!ldns_sock_wait(sockfd, timeout, 0)) { 5537b5038d7SDag-Erling Smørgrav *size = 0; 5547b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5557b5038d7SDag-Erling Smørgrav return NULL; 5567b5038d7SDag-Erling Smørgrav } 5577b5038d7SDag-Erling Smørgrav rc = recv(sockfd, (void*) (wire + bytes), 5587b5038d7SDag-Erling Smørgrav (size_t) (2 - bytes), 0); 5597b5038d7SDag-Erling Smørgrav if (rc == -1 || rc == 0) { 5607b5038d7SDag-Erling Smørgrav *size = 0; 5617b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5627b5038d7SDag-Erling Smørgrav return NULL; 5637b5038d7SDag-Erling Smørgrav } 5647b5038d7SDag-Erling Smørgrav bytes += rc; 5657b5038d7SDag-Erling Smørgrav } 5667b5038d7SDag-Erling Smørgrav 5677b5038d7SDag-Erling Smørgrav wire_size = ldns_read_uint16(wire); 5687b5038d7SDag-Erling Smørgrav 5697b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5707b5038d7SDag-Erling Smørgrav wire = LDNS_XMALLOC(uint8_t, wire_size); 5717b5038d7SDag-Erling Smørgrav if (!wire) { 5727b5038d7SDag-Erling Smørgrav *size = 0; 5737b5038d7SDag-Erling Smørgrav return NULL; 5747b5038d7SDag-Erling Smørgrav } 5757b5038d7SDag-Erling Smørgrav bytes = 0; 5767b5038d7SDag-Erling Smørgrav 5777b5038d7SDag-Erling Smørgrav while (bytes < (ssize_t) wire_size) { 5787b5038d7SDag-Erling Smørgrav if(!ldns_sock_wait(sockfd, timeout, 0)) { 5797b5038d7SDag-Erling Smørgrav *size = 0; 5807b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5817b5038d7SDag-Erling Smørgrav return NULL; 5827b5038d7SDag-Erling Smørgrav } 5837b5038d7SDag-Erling Smørgrav rc = recv(sockfd, (void*) (wire + bytes), 5847b5038d7SDag-Erling Smørgrav (size_t) (wire_size - bytes), 0); 5857b5038d7SDag-Erling Smørgrav if (rc == -1 || rc == 0) { 5867b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 5877b5038d7SDag-Erling Smørgrav *size = 0; 5887b5038d7SDag-Erling Smørgrav return NULL; 5897b5038d7SDag-Erling Smørgrav } 5907b5038d7SDag-Erling Smørgrav bytes += rc; 5917b5038d7SDag-Erling Smørgrav } 5927b5038d7SDag-Erling Smørgrav 5937b5038d7SDag-Erling Smørgrav *size = (size_t) bytes; 5947b5038d7SDag-Erling Smørgrav return wire; 5957b5038d7SDag-Erling Smørgrav } 5967b5038d7SDag-Erling Smørgrav 5977b5038d7SDag-Erling Smørgrav uint8_t * 5987b5038d7SDag-Erling Smørgrav ldns_tcp_read_wire(int sockfd, size_t *size) 5997b5038d7SDag-Erling Smørgrav { 6007b5038d7SDag-Erling Smørgrav uint8_t *wire; 6017b5038d7SDag-Erling Smørgrav uint16_t wire_size; 6027b5038d7SDag-Erling Smørgrav ssize_t bytes = 0, rc = 0; 6037b5038d7SDag-Erling Smørgrav 6047b5038d7SDag-Erling Smørgrav wire = LDNS_XMALLOC(uint8_t, 2); 6057b5038d7SDag-Erling Smørgrav if (!wire) { 6067b5038d7SDag-Erling Smørgrav *size = 0; 6077b5038d7SDag-Erling Smørgrav return NULL; 6087b5038d7SDag-Erling Smørgrav } 6097b5038d7SDag-Erling Smørgrav 6107b5038d7SDag-Erling Smørgrav while (bytes < 2) { 6117b5038d7SDag-Erling Smørgrav rc = recv(sockfd, (void*) (wire + bytes), 6127b5038d7SDag-Erling Smørgrav (size_t) (2 - bytes), 0); 6137b5038d7SDag-Erling Smørgrav if (rc == -1 || rc == 0) { 6147b5038d7SDag-Erling Smørgrav *size = 0; 6157b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 6167b5038d7SDag-Erling Smørgrav return NULL; 6177b5038d7SDag-Erling Smørgrav } 6187b5038d7SDag-Erling Smørgrav bytes += rc; 6197b5038d7SDag-Erling Smørgrav } 6207b5038d7SDag-Erling Smørgrav 6217b5038d7SDag-Erling Smørgrav wire_size = ldns_read_uint16(wire); 6227b5038d7SDag-Erling Smørgrav 6237b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 6247b5038d7SDag-Erling Smørgrav wire = LDNS_XMALLOC(uint8_t, wire_size); 6257b5038d7SDag-Erling Smørgrav if (!wire) { 6267b5038d7SDag-Erling Smørgrav *size = 0; 6277b5038d7SDag-Erling Smørgrav return NULL; 6287b5038d7SDag-Erling Smørgrav } 6297b5038d7SDag-Erling Smørgrav bytes = 0; 6307b5038d7SDag-Erling Smørgrav 6317b5038d7SDag-Erling Smørgrav while (bytes < (ssize_t) wire_size) { 6327b5038d7SDag-Erling Smørgrav rc = recv(sockfd, (void*) (wire + bytes), 6337b5038d7SDag-Erling Smørgrav (size_t) (wire_size - bytes), 0); 6347b5038d7SDag-Erling Smørgrav if (rc == -1 || rc == 0) { 6357b5038d7SDag-Erling Smørgrav LDNS_FREE(wire); 6367b5038d7SDag-Erling Smørgrav *size = 0; 6377b5038d7SDag-Erling Smørgrav return NULL; 6387b5038d7SDag-Erling Smørgrav } 6397b5038d7SDag-Erling Smørgrav bytes += rc; 6407b5038d7SDag-Erling Smørgrav } 6417b5038d7SDag-Erling Smørgrav 6427b5038d7SDag-Erling Smørgrav *size = (size_t) bytes; 6437b5038d7SDag-Erling Smørgrav return wire; 6447b5038d7SDag-Erling Smørgrav } 6457b5038d7SDag-Erling Smørgrav 6467b5038d7SDag-Erling Smørgrav /* keep in mind that in DNS tcp messages the first 2 bytes signal the 6477b5038d7SDag-Erling Smørgrav * amount data to expect 6487b5038d7SDag-Erling Smørgrav */ 6497b5038d7SDag-Erling Smørgrav ldns_status 6507b5038d7SDag-Erling Smørgrav ldns_tcp_send(uint8_t **result, ldns_buffer *qbin, const struct sockaddr_storage *to, 6517b5038d7SDag-Erling Smørgrav socklen_t tolen, struct timeval timeout, size_t *answer_size) 6527b5038d7SDag-Erling Smørgrav { 6537b5038d7SDag-Erling Smørgrav int sockfd; 6547b5038d7SDag-Erling Smørgrav uint8_t *answer; 6557b5038d7SDag-Erling Smørgrav 6567b5038d7SDag-Erling Smørgrav sockfd = ldns_tcp_bgsend(qbin, to, tolen, timeout); 6577b5038d7SDag-Erling Smørgrav 6587b5038d7SDag-Erling Smørgrav if (sockfd == 0) { 6597b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ERR; 6607b5038d7SDag-Erling Smørgrav } 6617b5038d7SDag-Erling Smørgrav 6627b5038d7SDag-Erling Smørgrav answer = ldns_tcp_read_wire_timeout(sockfd, answer_size, timeout); 6637b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 6647b5038d7SDag-Erling Smørgrav close(sockfd); 6657b5038d7SDag-Erling Smørgrav #else 6667b5038d7SDag-Erling Smørgrav closesocket(sockfd); 6677b5038d7SDag-Erling Smørgrav #endif 6687b5038d7SDag-Erling Smørgrav 6697b5038d7SDag-Erling Smørgrav if (*answer_size == 0) { 6707b5038d7SDag-Erling Smørgrav /* oops */ 6717b5038d7SDag-Erling Smørgrav return LDNS_STATUS_NETWORK_ERR; 6727b5038d7SDag-Erling Smørgrav } 6737b5038d7SDag-Erling Smørgrav 6747b5038d7SDag-Erling Smørgrav /* resize accordingly */ 675*2787e39aSDag-Erling Smørgrav *result = LDNS_XREALLOC(answer, uint8_t, (size_t)*answer_size); 6767b5038d7SDag-Erling Smørgrav if(!*result) { 6777b5038d7SDag-Erling Smørgrav LDNS_FREE(answer); 6787b5038d7SDag-Erling Smørgrav return LDNS_STATUS_MEM_ERR; 6797b5038d7SDag-Erling Smørgrav } 6807b5038d7SDag-Erling Smørgrav return LDNS_STATUS_OK; 6817b5038d7SDag-Erling Smørgrav } 6827b5038d7SDag-Erling Smørgrav 6837b5038d7SDag-Erling Smørgrav int 6847b5038d7SDag-Erling Smørgrav ldns_tcp_bgsend(ldns_buffer *qbin, const struct sockaddr_storage *to, socklen_t tolen, 6857b5038d7SDag-Erling Smørgrav struct timeval timeout) 6867b5038d7SDag-Erling Smørgrav { 6877b5038d7SDag-Erling Smørgrav int sockfd; 6887b5038d7SDag-Erling Smørgrav 6897b5038d7SDag-Erling Smørgrav sockfd = ldns_tcp_connect(to, tolen, timeout); 6907b5038d7SDag-Erling Smørgrav 6917b5038d7SDag-Erling Smørgrav if (sockfd == 0) { 6927b5038d7SDag-Erling Smørgrav return 0; 6937b5038d7SDag-Erling Smørgrav } 6947b5038d7SDag-Erling Smørgrav 6957b5038d7SDag-Erling Smørgrav if (ldns_tcp_send_query(qbin, sockfd, to, tolen) == 0) { 6967b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 6977b5038d7SDag-Erling Smørgrav close(sockfd); 6987b5038d7SDag-Erling Smørgrav #else 6997b5038d7SDag-Erling Smørgrav closesocket(sockfd); 7007b5038d7SDag-Erling Smørgrav #endif 7017b5038d7SDag-Erling Smørgrav return 0; 7027b5038d7SDag-Erling Smørgrav } 7037b5038d7SDag-Erling Smørgrav 7047b5038d7SDag-Erling Smørgrav return sockfd; 7057b5038d7SDag-Erling Smørgrav } 7067b5038d7SDag-Erling Smørgrav 7077b5038d7SDag-Erling Smørgrav /* code from rdata.c */ 7087b5038d7SDag-Erling Smørgrav struct sockaddr_storage * 7097b5038d7SDag-Erling Smørgrav ldns_rdf2native_sockaddr_storage(const ldns_rdf *rd, uint16_t port, size_t *size) 7107b5038d7SDag-Erling Smørgrav { 7117b5038d7SDag-Erling Smørgrav struct sockaddr_storage *data; 7127b5038d7SDag-Erling Smørgrav struct sockaddr_in *data_in; 7137b5038d7SDag-Erling Smørgrav struct sockaddr_in6 *data_in6; 7147b5038d7SDag-Erling Smørgrav 7157b5038d7SDag-Erling Smørgrav data = LDNS_MALLOC(struct sockaddr_storage); 7167b5038d7SDag-Erling Smørgrav if (!data) { 7177b5038d7SDag-Erling Smørgrav return NULL; 7187b5038d7SDag-Erling Smørgrav } 7197b5038d7SDag-Erling Smørgrav /* zero the structure for portability */ 7207b5038d7SDag-Erling Smørgrav memset(data, 0, sizeof(struct sockaddr_storage)); 7217b5038d7SDag-Erling Smørgrav if (port == 0) { 7227b5038d7SDag-Erling Smørgrav port = LDNS_PORT; 7237b5038d7SDag-Erling Smørgrav } 7247b5038d7SDag-Erling Smørgrav 7257b5038d7SDag-Erling Smørgrav switch(ldns_rdf_get_type(rd)) { 7267b5038d7SDag-Erling Smørgrav case LDNS_RDF_TYPE_A: 7277b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 7287b5038d7SDag-Erling Smørgrav data->ss_family = AF_INET; 7297b5038d7SDag-Erling Smørgrav #endif 7307b5038d7SDag-Erling Smørgrav data_in = (struct sockaddr_in*) data; 7317b5038d7SDag-Erling Smørgrav data_in->sin_port = (in_port_t)htons(port); 7327b5038d7SDag-Erling Smørgrav memcpy(&(data_in->sin_addr), ldns_rdf_data(rd), ldns_rdf_size(rd)); 7337b5038d7SDag-Erling Smørgrav *size = sizeof(struct sockaddr_in); 7347b5038d7SDag-Erling Smørgrav return data; 7357b5038d7SDag-Erling Smørgrav case LDNS_RDF_TYPE_AAAA: 7367b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 7377b5038d7SDag-Erling Smørgrav data->ss_family = AF_INET6; 7387b5038d7SDag-Erling Smørgrav #endif 7397b5038d7SDag-Erling Smørgrav data_in6 = (struct sockaddr_in6*) data; 7407b5038d7SDag-Erling Smørgrav data_in6->sin6_port = (in_port_t)htons(port); 7417b5038d7SDag-Erling Smørgrav memcpy(&data_in6->sin6_addr, ldns_rdf_data(rd), ldns_rdf_size(rd)); 7427b5038d7SDag-Erling Smørgrav *size = sizeof(struct sockaddr_in6); 7437b5038d7SDag-Erling Smørgrav return data; 7447b5038d7SDag-Erling Smørgrav default: 7457b5038d7SDag-Erling Smørgrav LDNS_FREE(data); 7467b5038d7SDag-Erling Smørgrav return NULL; 7477b5038d7SDag-Erling Smørgrav } 7487b5038d7SDag-Erling Smørgrav } 7497b5038d7SDag-Erling Smørgrav 7507b5038d7SDag-Erling Smørgrav #ifndef S_SPLINT_S 7517b5038d7SDag-Erling Smørgrav ldns_rdf * 7527b5038d7SDag-Erling Smørgrav ldns_sockaddr_storage2rdf(struct sockaddr_storage *sock, uint16_t *port) 7537b5038d7SDag-Erling Smørgrav { 7547b5038d7SDag-Erling Smørgrav ldns_rdf *addr; 7557b5038d7SDag-Erling Smørgrav struct sockaddr_in *data_in; 7567b5038d7SDag-Erling Smørgrav struct sockaddr_in6 *data_in6; 7577b5038d7SDag-Erling Smørgrav 7587b5038d7SDag-Erling Smørgrav switch(sock->ss_family) { 7597b5038d7SDag-Erling Smørgrav case AF_INET: 7607b5038d7SDag-Erling Smørgrav data_in = (struct sockaddr_in*)sock; 7617b5038d7SDag-Erling Smørgrav if (port) { 7627b5038d7SDag-Erling Smørgrav *port = ntohs((uint16_t)data_in->sin_port); 7637b5038d7SDag-Erling Smørgrav } 7647b5038d7SDag-Erling Smørgrav addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A, 7657b5038d7SDag-Erling Smørgrav LDNS_IP4ADDRLEN, &data_in->sin_addr); 7667b5038d7SDag-Erling Smørgrav break; 7677b5038d7SDag-Erling Smørgrav case AF_INET6: 7687b5038d7SDag-Erling Smørgrav data_in6 = (struct sockaddr_in6*)sock; 7697b5038d7SDag-Erling Smørgrav if (port) { 7707b5038d7SDag-Erling Smørgrav *port = ntohs((uint16_t)data_in6->sin6_port); 7717b5038d7SDag-Erling Smørgrav } 7727b5038d7SDag-Erling Smørgrav addr = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA, 7737b5038d7SDag-Erling Smørgrav LDNS_IP6ADDRLEN, &data_in6->sin6_addr); 7747b5038d7SDag-Erling Smørgrav break; 7757b5038d7SDag-Erling Smørgrav default: 7767b5038d7SDag-Erling Smørgrav if (port) { 7777b5038d7SDag-Erling Smørgrav *port = 0; 7787b5038d7SDag-Erling Smørgrav } 7797b5038d7SDag-Erling Smørgrav return NULL; 7807b5038d7SDag-Erling Smørgrav } 7817b5038d7SDag-Erling Smørgrav return addr; 7827b5038d7SDag-Erling Smørgrav } 7837b5038d7SDag-Erling Smørgrav #endif 7847b5038d7SDag-Erling Smørgrav 7857b5038d7SDag-Erling Smørgrav /* code from resolver.c */ 7867b5038d7SDag-Erling Smørgrav ldns_status 7877b5038d7SDag-Erling Smørgrav ldns_axfr_start(ldns_resolver *resolver, ldns_rdf *domain, ldns_rr_class class) 7887b5038d7SDag-Erling Smørgrav { 7897b5038d7SDag-Erling Smørgrav ldns_pkt *query; 7907b5038d7SDag-Erling Smørgrav ldns_buffer *query_wire; 7917b5038d7SDag-Erling Smørgrav 7927b5038d7SDag-Erling Smørgrav struct sockaddr_storage *ns = NULL; 7937b5038d7SDag-Erling Smørgrav size_t ns_len = 0; 7947b5038d7SDag-Erling Smørgrav size_t ns_i; 7957b5038d7SDag-Erling Smørgrav ldns_status status; 7967b5038d7SDag-Erling Smørgrav 7977b5038d7SDag-Erling Smørgrav if (!resolver || ldns_resolver_nameserver_count(resolver) < 1) { 7987b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ERR; 7997b5038d7SDag-Erling Smørgrav } 8007b5038d7SDag-Erling Smørgrav 8017b5038d7SDag-Erling Smørgrav query = ldns_pkt_query_new(ldns_rdf_clone(domain), LDNS_RR_TYPE_AXFR, class, 0); 8027b5038d7SDag-Erling Smørgrav 8037b5038d7SDag-Erling Smørgrav if (!query) { 8047b5038d7SDag-Erling Smørgrav return LDNS_STATUS_ADDRESS_ERR; 8057b5038d7SDag-Erling Smørgrav } 8067b5038d7SDag-Erling Smørgrav /* For AXFR, we have to make the connection ourselves */ 8077b5038d7SDag-Erling Smørgrav /* try all nameservers (which usually would mean v4 fallback if 8087b5038d7SDag-Erling Smørgrav * @hostname is used */ 8097b5038d7SDag-Erling Smørgrav for (ns_i = 0; 8107b5038d7SDag-Erling Smørgrav ns_i < ldns_resolver_nameserver_count(resolver) && 8117b5038d7SDag-Erling Smørgrav resolver->_socket == 0; 8127b5038d7SDag-Erling Smørgrav ns_i++) { 813*2787e39aSDag-Erling Smørgrav if (ns != NULL) { 814*2787e39aSDag-Erling Smørgrav LDNS_FREE(ns); 815*2787e39aSDag-Erling Smørgrav } 8167b5038d7SDag-Erling Smørgrav ns = ldns_rdf2native_sockaddr_storage( 8177b5038d7SDag-Erling Smørgrav resolver->_nameservers[ns_i], 8187b5038d7SDag-Erling Smørgrav ldns_resolver_port(resolver), &ns_len); 8197b5038d7SDag-Erling Smørgrav 8207b5038d7SDag-Erling Smørgrav resolver->_socket = ldns_tcp_connect(ns, (socklen_t)ns_len, 8217b5038d7SDag-Erling Smørgrav ldns_resolver_timeout(resolver)); 8227b5038d7SDag-Erling Smørgrav } 8237b5038d7SDag-Erling Smørgrav 8247b5038d7SDag-Erling Smørgrav if (resolver->_socket == 0) { 8257b5038d7SDag-Erling Smørgrav ldns_pkt_free(query); 8267b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 8277b5038d7SDag-Erling Smørgrav return LDNS_STATUS_NETWORK_ERR; 8287b5038d7SDag-Erling Smørgrav } 8297b5038d7SDag-Erling Smørgrav 8307b5038d7SDag-Erling Smørgrav #ifdef HAVE_SSL 8317b5038d7SDag-Erling Smørgrav if (ldns_resolver_tsig_keyname(resolver) && ldns_resolver_tsig_keydata(resolver)) { 8327b5038d7SDag-Erling Smørgrav status = ldns_pkt_tsig_sign(query, 8337b5038d7SDag-Erling Smørgrav ldns_resolver_tsig_keyname(resolver), 8347b5038d7SDag-Erling Smørgrav ldns_resolver_tsig_keydata(resolver), 8357b5038d7SDag-Erling Smørgrav 300, ldns_resolver_tsig_algorithm(resolver), NULL); 8367b5038d7SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) { 8377b5038d7SDag-Erling Smørgrav /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start 8387b5038d7SDag-Erling Smørgrav we have to close the socket here! */ 8397b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 8407b5038d7SDag-Erling Smørgrav close(resolver->_socket); 8417b5038d7SDag-Erling Smørgrav #else 8427b5038d7SDag-Erling Smørgrav closesocket(resolver->_socket); 8437b5038d7SDag-Erling Smørgrav #endif 8447b5038d7SDag-Erling Smørgrav resolver->_socket = 0; 8457b5038d7SDag-Erling Smørgrav 846*2787e39aSDag-Erling Smørgrav ldns_pkt_free(query); 847*2787e39aSDag-Erling Smørgrav LDNS_FREE(ns); 848*2787e39aSDag-Erling Smørgrav 8497b5038d7SDag-Erling Smørgrav return LDNS_STATUS_CRYPTO_TSIG_ERR; 8507b5038d7SDag-Erling Smørgrav } 8517b5038d7SDag-Erling Smørgrav } 8527b5038d7SDag-Erling Smørgrav #endif /* HAVE_SSL */ 8537b5038d7SDag-Erling Smørgrav 8547b5038d7SDag-Erling Smørgrav /* Convert the query to a buffer 8557b5038d7SDag-Erling Smørgrav * Is this necessary? 8567b5038d7SDag-Erling Smørgrav */ 8577b5038d7SDag-Erling Smørgrav query_wire = ldns_buffer_new(LDNS_MAX_PACKETLEN); 8587b5038d7SDag-Erling Smørgrav if(!query_wire) { 8597b5038d7SDag-Erling Smørgrav ldns_pkt_free(query); 8607b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 8617b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 8627b5038d7SDag-Erling Smørgrav close(resolver->_socket); 8637b5038d7SDag-Erling Smørgrav #else 8647b5038d7SDag-Erling Smørgrav closesocket(resolver->_socket); 8657b5038d7SDag-Erling Smørgrav #endif 8667b5038d7SDag-Erling Smørgrav resolver->_socket = 0; 8677b5038d7SDag-Erling Smørgrav 8687b5038d7SDag-Erling Smørgrav return LDNS_STATUS_MEM_ERR; 8697b5038d7SDag-Erling Smørgrav } 8707b5038d7SDag-Erling Smørgrav status = ldns_pkt2buffer_wire(query_wire, query); 8717b5038d7SDag-Erling Smørgrav if (status != LDNS_STATUS_OK) { 8727b5038d7SDag-Erling Smørgrav ldns_pkt_free(query); 8737b5038d7SDag-Erling Smørgrav ldns_buffer_free(query_wire); 8747b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 8757b5038d7SDag-Erling Smørgrav 8767b5038d7SDag-Erling Smørgrav /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start 8777b5038d7SDag-Erling Smørgrav we have to close the socket here! */ 8787b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 8797b5038d7SDag-Erling Smørgrav close(resolver->_socket); 8807b5038d7SDag-Erling Smørgrav #else 8817b5038d7SDag-Erling Smørgrav closesocket(resolver->_socket); 8827b5038d7SDag-Erling Smørgrav #endif 8837b5038d7SDag-Erling Smørgrav resolver->_socket = 0; 8847b5038d7SDag-Erling Smørgrav 8857b5038d7SDag-Erling Smørgrav return status; 8867b5038d7SDag-Erling Smørgrav } 8877b5038d7SDag-Erling Smørgrav /* Send the query */ 8887b5038d7SDag-Erling Smørgrav if (ldns_tcp_send_query(query_wire, resolver->_socket, ns, 8897b5038d7SDag-Erling Smørgrav (socklen_t)ns_len) == 0) { 8907b5038d7SDag-Erling Smørgrav ldns_pkt_free(query); 8917b5038d7SDag-Erling Smørgrav ldns_buffer_free(query_wire); 8927b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 8937b5038d7SDag-Erling Smørgrav 8947b5038d7SDag-Erling Smørgrav /* RoRi: to prevent problems on subsequent calls to ldns_axfr_start 8957b5038d7SDag-Erling Smørgrav we have to close the socket here! */ 8967b5038d7SDag-Erling Smørgrav 8977b5038d7SDag-Erling Smørgrav #ifndef USE_WINSOCK 8987b5038d7SDag-Erling Smørgrav close(resolver->_socket); 8997b5038d7SDag-Erling Smørgrav #else 9007b5038d7SDag-Erling Smørgrav closesocket(resolver->_socket); 9017b5038d7SDag-Erling Smørgrav #endif 9027b5038d7SDag-Erling Smørgrav resolver->_socket = 0; 9037b5038d7SDag-Erling Smørgrav 9047b5038d7SDag-Erling Smørgrav return LDNS_STATUS_NETWORK_ERR; 9057b5038d7SDag-Erling Smørgrav } 9067b5038d7SDag-Erling Smørgrav 9077b5038d7SDag-Erling Smørgrav ldns_pkt_free(query); 9087b5038d7SDag-Erling Smørgrav ldns_buffer_free(query_wire); 9097b5038d7SDag-Erling Smørgrav LDNS_FREE(ns); 9107b5038d7SDag-Erling Smørgrav 9117b5038d7SDag-Erling Smørgrav /* 9127b5038d7SDag-Erling Smørgrav * The AXFR is done once the second SOA record is sent 9137b5038d7SDag-Erling Smørgrav */ 9147b5038d7SDag-Erling Smørgrav resolver->_axfr_soa_count = 0; 9157b5038d7SDag-Erling Smørgrav return LDNS_STATUS_OK; 9167b5038d7SDag-Erling Smørgrav } 917