From d3f3fd8c052ddba23c95b47fa60beb8e8771753a Mon Sep 17 00:00:00 2001 From: David Holder Date: Wed, 27 May 2015 09:15:51 -0700 Subject: [PATCH] s3: IPv6 enabled DNS connections for ADS client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes DNS client connections protocol independent. For example DNS updates. This makes IPv6-only clients possible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11283 Back-port from fff774eda3ed04d319232b108a94282af24cc6b0 Signed-off-by: David Holder Reviewed-by: Jeremy Allison Reviewed-by: Ralph Böhme --- lib/addns/dns.h | 2 +- lib/addns/dnssock.c | 125 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 41 deletions(-) diff --git a/lib/addns/dns.h b/lib/addns/dns.h index bf2ade3..de1897b 100644 --- a/lib/addns/dns.h +++ b/lib/addns/dns.h @@ -222,7 +222,7 @@ struct dns_update_request { struct dns_connection { int32_t hType; int s; - struct sockaddr RecvAddr; + struct sockaddr_storage RecvAddr; }; struct dns_buffer { diff --git a/lib/addns/dnssock.c b/lib/addns/dnssock.c index 5f99519..bab20a4 100644 --- a/lib/addns/dnssock.c +++ b/lib/addns/dnssock.c @@ -27,6 +27,7 @@ #include #include #include "system/select.h" +#include "../lib/util/debug.h" static int destroy_dns_connection(struct dns_connection *conn) { @@ -40,42 +41,58 @@ static DNS_ERROR dns_tcp_open( const char *nameserver, TALLOC_CTX *mem_ctx, struct dns_connection **result ) { - uint32_t ulAddress; - struct hostent *pHost; - struct sockaddr_in s_in; + struct addrinfo hints; + struct addrinfo *ai_result = NULL; + struct addrinfo *rp; struct dns_connection *conn; - int res; + int ret; + char service[16]; + + snprintf(service, sizeof(service), "%d", DNS_TCP_PORT); if (!(conn = talloc(mem_ctx, struct dns_connection))) { return ERROR_DNS_NO_MEMORY; } - if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) { - if ( (pHost = gethostbyname( nameserver )) == NULL ) { - TALLOC_FREE(conn); - return ERROR_DNS_INVALID_NAME_SERVER; - } - memcpy( &ulAddress, pHost->h_addr, pHost->h_length ); - } + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = IPPROTO_TCP; - conn->s = socket( PF_INET, SOCK_STREAM, 0 ); - if (conn->s == -1) { - TALLOC_FREE(conn); - return ERROR_DNS_CONNECTION_FAILED; + ret = getaddrinfo(nameserver, service, &hints, &ai_result); + if (ret != 0) { + DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret))); + return ERROR_DNS_INVALID_NAME_SERVER; } - talloc_set_destructor(conn, destroy_dns_connection); + for (rp = ai_result; rp != NULL; rp = rp->ai_next) { + conn->s = socket(rp->ai_family, + rp->ai_socktype, + rp->ai_protocol); + if (conn->s == -1) { + continue; + } + do { + ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen); + } while ((ret == -1) && (errno == EINTR)); + if (ret != -1) { + /* Successful connect */ + break; + } + close(conn->s); + } - s_in.sin_family = AF_INET; - s_in.sin_addr.s_addr = ulAddress; - s_in.sin_port = htons( DNS_TCP_PORT ); + freeaddrinfo(ai_result); - res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in )); - if (res == -1) { + /* Failed to connect with any address */ + if (rp == NULL) { TALLOC_FREE(conn); return ERROR_DNS_CONNECTION_FAILED; } + talloc_set_destructor(conn, destroy_dns_connection); + conn->hType = DNS_TCP; *result = conn; @@ -89,44 +106,72 @@ static DNS_ERROR dns_udp_open( const char *nameserver, TALLOC_CTX *mem_ctx, struct dns_connection **result ) { - unsigned long ulAddress; - struct hostent *pHost; - struct sockaddr_in RecvAddr; + struct addrinfo hints; + struct addrinfo *ai_result = NULL; + struct addrinfo *rp; + struct sockaddr_storage RecvAddr; struct dns_connection *conn; + int ret; + socklen_t RecvAddrLen; + char service[16]; + + snprintf(service, sizeof(service), "%d", DNS_UDP_PORT); if (!(conn = talloc(NULL, struct dns_connection))) { return ERROR_DNS_NO_MEMORY; } - if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) { - if ( (pHost = gethostbyname( nameserver )) == NULL ) { - TALLOC_FREE(conn); - return ERROR_DNS_INVALID_NAME_SERVER; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = IPPROTO_UDP; + + ret = getaddrinfo(nameserver, service, &hints, &ai_result); + if (ret != 0) { + DEBUG(1,("dns_ucp_open:getaddrinfo: %s\n", gai_strerror(ret))); + TALLOC_FREE(conn); + return ERROR_DNS_INVALID_NAME_SERVER; + } + + for (rp = ai_result; rp != NULL; rp = rp->ai_next) { + conn->s = socket(rp->ai_family, + rp->ai_socktype, + rp->ai_protocol); + if (conn->s == -1) { + continue; } - memcpy( &ulAddress, pHost->h_addr, pHost->h_length ); + ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen); + if (ret != -1) { + /* Successful connect */ + break; + } + close(conn->s); } - /* Create a socket for sending data */ + freeaddrinfo(ai_result); - conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); - if (conn->s == -1) { + /* Failed to connect with any address */ + if (rp == NULL) { TALLOC_FREE(conn); - return ERROR_DNS_CONNECTION_FAILED; + return ERROR_DNS_CONNECTION_FAILED; } talloc_set_destructor(conn, destroy_dns_connection); /* Set up the RecvAddr structure with the IP address of - the receiver (in this example case "123.456.789.1") - and the specified port number. */ + the receiver and the specified port number. */ - ZERO_STRUCT(RecvAddr); - RecvAddr.sin_family = AF_INET; - RecvAddr.sin_port = htons( DNS_UDP_PORT ); - RecvAddr.sin_addr.s_addr = ulAddress; + RecvAddrLen = sizeof(RecvAddr); + if (getpeername(conn->s, + (struct sockaddr *)&RecvAddr, + &RecvAddrLen) == -1) { + TALLOC_FREE(conn); + return ERROR_DNS_CONNECTION_FAILED; + } conn->hType = DNS_UDP; - memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) ); + memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage)); *result = conn; return ERROR_DNS_SUCCESS; -- 2.2.0.rc0.207.ga3a616c