2006-08-24 19:43:32 +04:00
/*
Linux DNS client library implementation
Copyright ( C ) 2006 Krishna Ganugapati < krishnag @ centeris . com >
Copyright ( C ) 2006 Gerald Carter < jerry @ samba . org >
* * NOTE ! The following LGPL license applies to the libaddns
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 2.1 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 07:52:17 +04:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-08-24 19:43:32 +04:00
*/
2011-02-10 13:01:54 +03:00
# include "replace.h"
2006-08-24 19:43:32 +04:00
# include "dns.h"
2006-08-25 19:08:05 +04:00
# include <sys/time.h>
2006-11-18 00:46:26 +03:00
# include <unistd.h>
2011-02-10 13:01:54 +03:00
# include "system/select.h"
2015-05-13 17:10:47 +03:00
# include "../lib/util/debug.h"
2006-11-18 00:46:26 +03:00
static int destroy_dns_connection ( struct dns_connection * conn )
{
return close ( conn - > s ) ;
}
2006-08-24 19:43:32 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-04-23 04:48:58 +03:00
static DNS_ERROR dns_open_helper ( const char * nameserver ,
const char * service ,
struct addrinfo * hints ,
TALLOC_CTX * mem_ctx ,
struct dns_connection * * ret_conn )
2006-08-24 19:43:32 +04:00
{
2015-05-13 17:10:47 +03:00
int ret ;
2016-04-23 04:48:58 +03:00
struct addrinfo * rp ;
struct addrinfo * ai_result = NULL ;
struct dns_connection * conn = NULL ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( conn = talloc ( mem_ctx , struct dns_connection ) ) ) {
2006-08-24 19:43:32 +04:00
return ERROR_DNS_NO_MEMORY ;
}
2016-04-23 04:48:58 +03:00
ret = getaddrinfo ( nameserver , service , hints , & ai_result ) ;
2015-05-13 17:10:47 +03:00
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " dns_tcp_open: getaddrinfo: %s \n " , gai_strerror ( ret ) ) ) ;
2006-11-18 00:46:26 +03:00
TALLOC_FREE ( conn ) ;
2015-05-13 17:10:47 +03:00
return ERROR_DNS_INVALID_NAME_SERVER ;
2006-08-24 19:43:32 +04:00
}
2015-05-13 17:10:47 +03:00
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 ) ;
}
2006-11-18 00:46:26 +03:00
2015-05-13 17:10:47 +03:00
freeaddrinfo ( ai_result ) ;
2006-08-24 19:43:32 +04:00
2015-05-13 17:10:47 +03:00
if ( rp = = NULL ) {
2006-11-18 00:46:26 +03:00
TALLOC_FREE ( conn ) ;
return ERROR_DNS_CONNECTION_FAILED ;
2006-08-24 19:43:32 +04:00
}
2015-05-13 17:10:47 +03:00
talloc_set_destructor ( conn , destroy_dns_connection ) ;
2006-08-24 19:43:32 +04:00
2016-04-23 04:48:58 +03:00
* ret_conn = conn ;
return ERROR_DNS_SUCCESS ;
}
static DNS_ERROR dns_tcp_open ( const char * nameserver ,
TALLOC_CTX * mem_ctx ,
struct dns_connection * * result )
{
struct addrinfo hints ;
struct dns_connection * conn ;
DNS_ERROR dns_ret ;
char service [ 16 ] ;
snprintf ( service , sizeof ( service ) , " %d " , DNS_TCP_PORT ) ;
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 ;
dns_ret = dns_open_helper ( nameserver , service , & hints , mem_ctx , & conn ) ;
if ( ! ERR_DNS_IS_OK ( dns_ret ) ) {
return dns_ret ;
}
2015-05-13 17:10:47 +03:00
conn - > hType = DNS_TCP ;
2006-11-18 00:46:26 +03:00
* result = conn ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
/********************************************************************
2015-05-13 17:10:47 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_udp_open ( const char * nameserver ,
TALLOC_CTX * mem_ctx ,
struct dns_connection * * result )
2006-08-24 19:43:32 +04:00
{
2015-05-13 17:10:47 +03:00
struct addrinfo hints ;
struct sockaddr_storage RecvAddr ;
2019-07-09 17:08:49 +03:00
struct dns_connection * conn = NULL ;
2016-04-23 04:48:58 +03:00
DNS_ERROR dns_ret ;
2015-05-13 17:10:47 +03:00
socklen_t RecvAddrLen ;
char service [ 16 ] ;
snprintf ( service , sizeof ( service ) , " %d " , DNS_UDP_PORT ) ;
2006-08-24 19:43:32 +04:00
2015-05-13 17:10:47 +03:00
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 ;
2016-04-23 04:48:58 +03:00
dns_ret = dns_open_helper ( nameserver , service , & hints , mem_ctx , & conn ) ;
if ( ! ERR_DNS_IS_OK ( dns_ret ) ) {
2015-05-13 17:10:47 +03:00
TALLOC_FREE ( conn ) ;
2016-04-23 04:48:58 +03:00
return dns_ret ;
2015-05-13 17:10:47 +03:00
}
2006-08-24 19:43:32 +04:00
/* Set up the RecvAddr structure with the IP address of
2015-05-13 17:10:47 +03:00
the receiver and the specified port number . */
2006-08-24 19:43:32 +04:00
2015-05-13 17:10:47 +03:00
RecvAddrLen = sizeof ( RecvAddr ) ;
if ( getpeername ( conn - > s ,
( struct sockaddr * ) & RecvAddr ,
& RecvAddrLen ) = = - 1 ) {
return ERROR_DNS_CONNECTION_FAILED ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
conn - > hType = DNS_UDP ;
2015-05-13 17:10:47 +03:00
memcpy ( & conn - > RecvAddr , & RecvAddr , sizeof ( struct sockaddr_storage ) ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* result = conn ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-05 22:47:58 +04:00
DNS_ERROR dns_open_connection ( const char * nameserver , int32_t dwType ,
2006-11-18 00:46:26 +03:00
TALLOC_CTX * mem_ctx ,
struct dns_connection * * conn )
2006-08-24 19:43:32 +04:00
{
switch ( dwType ) {
case DNS_TCP :
2006-11-18 00:46:26 +03:00
return dns_tcp_open ( nameserver , mem_ctx , conn ) ;
2006-08-24 19:43:32 +04:00
case DNS_UDP :
2006-11-18 00:46:26 +03:00
return dns_udp_open ( nameserver , mem_ctx , conn ) ;
2006-08-24 19:43:32 +04:00
}
2011-02-10 13:01:54 +03:00
2006-08-24 19:43:32 +04:00
return ERROR_DNS_INVALID_PARAMETER ;
}
2012-07-05 22:47:58 +04:00
static DNS_ERROR write_all ( int fd , uint8_t * data , size_t len )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
size_t total = 0 ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
while ( total < len ) {
2006-08-24 19:43:32 +04:00
2014-04-10 02:27:45 +04:00
ssize_t ret ;
do {
ret = write ( fd , data + total , len - total ) ;
} while ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ret < = 0 ) {
/*
* EOF or error
*/
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
total + = ret ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_send_tcp ( struct dns_connection * conn ,
const struct dns_buffer * buf )
2006-08-24 19:43:32 +04:00
{
2012-07-05 22:47:58 +04:00
uint16_t len = htons ( buf - > offset ) ;
2006-11-18 00:46:26 +03:00
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2012-07-05 22:47:58 +04:00
err = write_all ( conn - > s , ( uint8_t * ) & len , sizeof ( len ) ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return write_all ( conn - > s , buf - > data , buf - > offset ) ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_send_udp ( struct dns_connection * conn ,
const struct dns_buffer * buf )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
ssize_t ret ;
2006-08-24 19:43:32 +04:00
2014-04-10 02:27:45 +04:00
do {
2018-06-11 23:38:00 +03:00
ret = send ( conn - > s , buf - > data , buf - > offset , 0 ) ;
2014-04-10 02:27:45 +04:00
} while ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ret ! = buf - > offset ) {
return ERROR_DNS_SOCKET_ERROR ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_send ( struct dns_connection * conn , const struct dns_buffer * buf )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
if ( conn - > hType = = DNS_TCP ) {
return dns_send_tcp ( conn , buf ) ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
if ( conn - > hType = = DNS_UDP ) {
return dns_send_udp ( conn , buf ) ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
return ERROR_DNS_INVALID_PARAMETER ;
2006-08-24 19:43:32 +04:00
}
2012-07-05 22:47:58 +04:00
static DNS_ERROR read_all ( int fd , uint8_t * data , size_t len )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
size_t total = 0 ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
while ( total < len ) {
2011-02-10 13:01:54 +03:00
struct pollfd pfd ;
2007-01-03 00:20:40 +03:00
ssize_t ret ;
int fd_ready ;
2011-02-10 13:01:54 +03:00
ZERO_STRUCT ( pfd ) ;
pfd . fd = fd ;
pfd . events = POLLIN | POLLHUP ;
fd_ready = poll ( & pfd , 1 , 10000 ) ;
2014-04-10 02:27:45 +04:00
if ( fd_ready = = - 1 ) {
if ( errno = = EINTR ) {
continue ;
}
return ERROR_DNS_SOCKET_ERROR ;
}
2007-01-03 00:20:40 +03:00
if ( fd_ready = = 0 ) {
/* read timeout */
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 19:43:32 +04:00
2014-04-10 02:27:45 +04:00
do {
ret = read ( fd , data + total , len - total ) ;
} while ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) ;
2006-11-18 00:46:26 +03:00
if ( ret < = 0 ) {
2007-01-03 00:20:40 +03:00
/* EOF or error */
2006-11-18 00:46:26 +03:00
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
total + = ret ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_receive_tcp ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_buffer * buf ;
DNS_ERROR err ;
2012-07-05 22:47:58 +04:00
uint16_t len ;
2006-08-24 19:43:32 +04:00
2011-06-07 05:44:43 +04:00
if ( ! ( buf = talloc_zero ( mem_ctx , struct dns_buffer ) ) ) {
2006-11-18 00:46:26 +03:00
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2012-07-05 22:47:58 +04:00
err = read_all ( conn - > s , ( uint8_t * ) & len , sizeof ( len ) ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) {
return err ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
buf - > size = ntohs ( len ) ;
2006-08-24 19:43:32 +04:00
2015-06-23 11:10:19 +03:00
if ( buf - > size = = 0 ) {
* presult = buf ;
return ERROR_DNS_SUCCESS ;
}
if ( ! ( buf - > data = talloc_array ( buf , uint8_t , buf - > size ) ) ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_NO_MEMORY ;
2006-11-18 00:46:26 +03:00
}
2006-08-24 19:43:32 +04:00
2015-06-23 11:12:15 +03:00
err = read_all ( conn - > s , buf - > data , talloc_get_size ( buf - > data ) ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) {
TALLOC_FREE ( buf ) ;
return err ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* presult = buf ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
static DNS_ERROR dns_receive_udp ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_buffer * buf ;
ssize_t received ;
2006-08-24 19:43:32 +04:00
2011-06-07 05:44:43 +04:00
if ( ! ( buf = talloc_zero ( mem_ctx , struct dns_buffer ) ) ) {
2006-11-18 00:46:26 +03:00
return ERROR_DNS_NO_MEMORY ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
/*
* UDP based DNS can only be 512 bytes
*/
2006-08-24 19:43:32 +04:00
2012-07-05 22:47:58 +04:00
if ( ! ( buf - > data = talloc_array ( buf , uint8_t , 512 ) ) ) {
2006-11-18 00:46:26 +03:00
TALLOC_FREE ( buf ) ;
return ERROR_DNS_NO_MEMORY ;
2006-08-24 19:43:32 +04:00
}
2014-04-10 02:27:45 +04:00
do {
received = recv ( conn - > s , ( void * ) buf - > data , 512 , 0 ) ;
} while ( ( received = = - 1 ) & & ( errno = = EINTR ) ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( received = = - 1 ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_SOCKET_ERROR ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
if ( received > 512 ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_BAD_RESPONSE ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
buf - > size = received ;
buf - > offset = 0 ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* presult = buf ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_receive ( TALLOC_CTX * mem_ctx , struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
if ( conn - > hType = = DNS_TCP ) {
return dns_receive_tcp ( mem_ctx , conn , presult ) ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
if ( conn - > hType = = DNS_UDP ) {
return dns_receive_udp ( mem_ctx , conn , presult ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return ERROR_DNS_INVALID_PARAMETER ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_transaction ( TALLOC_CTX * mem_ctx , struct dns_connection * conn ,
const struct dns_request * req ,
struct dns_request * * resp )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_buffer * buf = NULL ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2012-05-08 00:14:07 +04:00
err = dns_marshall_request ( mem_ctx , req , & buf ) ;
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_send ( conn , buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
TALLOC_FREE ( buf ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_receive ( mem_ctx , conn , & buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_unmarshall_request ( mem_ctx , buf , resp ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
error :
TALLOC_FREE ( buf ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_update_transaction ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
struct dns_update_request * up_req ,
struct dns_update_request * * up_resp )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_request * resp ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_transaction ( mem_ctx , conn , dns_update2request ( up_req ) ,
& resp ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* up_resp = dns_request2update ( resp ) ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}