summaryrefslogtreecommitdiff
path: root/lib/addns
diff options
context:
space:
mode:
authorDavid Holder <david.holder@erion.co.uk>2015-05-13 15:10:47 +0100
committerJeremy Allison <jra@samba.org>2015-05-15 19:31:23 +0200
commitfff774eda3ed04d319232b108a94282af24cc6b0 (patch)
treed39c2a51d6b39a958f5cfc3cfb6b51aa43dbc1c7 /lib/addns
parent57568f1900152c4cb381e151049414086bada14b (diff)
downloadsamba-fff774eda3ed04d319232b108a94282af24cc6b0.tar.gz
s3: IPv6 enabled DNS connections for ADS client
This patch makes DNS client connections protocol independent. For example DNS updates. This makes IPv6-only clients possible. Signed-off-by: David Holder <david.holder@erion.co.uk> Reviewed-by: Jeremy Allison <jra@samba.org> Reviewed-by: Ralph Böhme <rb@sernet.de>
Diffstat (limited to 'lib/addns')
-rw-r--r--lib/addns/dns.h2
-rw-r--r--lib/addns/dnssock.c127
2 files changed, 86 insertions, 43 deletions
diff --git a/lib/addns/dns.h b/lib/addns/dns.h
index bf2ade387b9..de1897b6e87 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 13649b5dd4c..b1d794db456 100644
--- a/lib/addns/dnssock.c
+++ b/lib/addns/dnssock.c
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <unistd.h>
#include "system/select.h"
+#include "../lib/util/debug.h"
static int destroy_dns_connection(struct dns_connection *conn)
{
@@ -40,78 +41,118 @@ 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) {
+ ret = getaddrinfo(nameserver, service, &hints, &ai_result);
+ if (ret != 0) {
+ DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
TALLOC_FREE(conn);
- return ERROR_DNS_CONNECTION_FAILED;
+ 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);
- do {
- res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
- } while ((res == -1) && (errno == EINTR));
- if (res == -1) {
+ /* Failed to connect with any address */
+ if (rp == NULL) {
TALLOC_FREE(conn);
return ERROR_DNS_CONNECTION_FAILED;
}
- conn->hType = DNS_TCP;
+ talloc_set_destructor(conn, destroy_dns_connection);
+ conn->hType = DNS_TCP;
*result = conn;
return ERROR_DNS_SUCCESS;
}
/********************************************************************
-********************************************************************/
+ * ********************************************************************/
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;
+ }
+ ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
+ if (ret != -1) {
+ /* Successful connect */
+ break;
}
- memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
+ 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;
}
@@ -119,16 +160,18 @@ static DNS_ERROR dns_udp_open( const char *nameserver,
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;