2006-08-24 15:43:32 +00: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 03:52:17 +00:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-08-24 15:43:32 +00:00
*/
# include "dns.h"
2006-08-25 15:08:05 +00:00
# include <sys/time.h>
2006-11-17 21:46:26 +00:00
# include <unistd.h>
static int destroy_dns_connection ( struct dns_connection * conn )
{
return close ( conn - > s ) ;
}
2006-08-24 15:43:32 +00:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_tcp_open ( const char * nameserver ,
TALLOC_CTX * mem_ctx ,
struct dns_connection * * result )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
uint32_t ulAddress ;
2006-08-24 15:43:32 +00:00
struct hostent * pHost ;
struct sockaddr_in s_in ;
2006-11-17 21:46:26 +00:00
struct dns_connection * conn ;
int res ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ( conn = talloc ( mem_ctx , struct dns_connection ) ) ) {
2006-08-24 15:43:32 +00:00
return ERROR_DNS_NO_MEMORY ;
}
if ( ( ulAddress = inet_addr ( nameserver ) ) = = INADDR_NONE ) {
if ( ( pHost = gethostbyname ( nameserver ) ) = = NULL ) {
2006-11-17 21:46:26 +00:00
TALLOC_FREE ( conn ) ;
return ERROR_DNS_INVALID_NAME_SERVER ;
2006-08-24 15:43:32 +00:00
}
memcpy ( & ulAddress , pHost - > h_addr , pHost - > h_length ) ;
}
2006-11-17 21:46:26 +00:00
conn - > s = socket ( PF_INET , SOCK_STREAM , 0 ) ;
if ( conn - > s = = - 1 ) {
TALLOC_FREE ( conn ) ;
return ERROR_DNS_CONNECTION_FAILED ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
talloc_set_destructor ( conn , destroy_dns_connection ) ;
2006-08-24 15:43:32 +00:00
s_in . sin_family = AF_INET ;
s_in . sin_addr . s_addr = ulAddress ;
s_in . sin_port = htons ( DNS_TCP_PORT ) ;
2006-11-17 21:46:26 +00:00
res = connect ( conn - > s , ( struct sockaddr * ) & s_in , sizeof ( s_in ) ) ;
if ( res = = - 1 ) {
TALLOC_FREE ( conn ) ;
return ERROR_DNS_CONNECTION_FAILED ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
conn - > hType = DNS_TCP ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
* result = conn ;
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_udp_open ( const char * nameserver ,
TALLOC_CTX * mem_ctx ,
struct dns_connection * * result )
2006-08-24 15:43:32 +00:00
{
unsigned long ulAddress ;
struct hostent * pHost ;
struct sockaddr_in RecvAddr ;
2006-11-17 21:46:26 +00:00
struct dns_connection * conn ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ( conn = talloc ( NULL , struct dns_connection ) ) ) {
2006-08-24 15:43:32 +00:00
return ERROR_DNS_NO_MEMORY ;
}
if ( ( ulAddress = inet_addr ( nameserver ) ) = = INADDR_NONE ) {
if ( ( pHost = gethostbyname ( nameserver ) ) = = NULL ) {
2006-11-17 21:46:26 +00:00
TALLOC_FREE ( conn ) ;
return ERROR_DNS_INVALID_NAME_SERVER ;
2006-08-24 15:43:32 +00:00
}
memcpy ( & ulAddress , pHost - > h_addr , pHost - > h_length ) ;
}
/* Create a socket for sending data */
2006-11-17 21:46:26 +00:00
conn - > s = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
if ( conn - > s = = - 1 ) {
TALLOC_FREE ( conn ) ;
return ERROR_DNS_CONNECTION_FAILED ;
}
talloc_set_destructor ( conn , destroy_dns_connection ) ;
2006-08-24 15:43:32 +00:00
/* 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 . */
2008-03-06 11:42:48 +01:00
ZERO_STRUCT ( RecvAddr ) ;
2006-08-24 15:43:32 +00:00
RecvAddr . sin_family = AF_INET ;
RecvAddr . sin_port = htons ( DNS_UDP_PORT ) ;
RecvAddr . sin_addr . s_addr = ulAddress ;
2006-11-17 21:46:26 +00:00
conn - > hType = DNS_UDP ;
memcpy ( & conn - > RecvAddr , & RecvAddr , sizeof ( struct sockaddr_in ) ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
* result = conn ;
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-12-31 06:45:24 +00:00
DNS_ERROR dns_open_connection ( const char * nameserver , int32 dwType ,
2006-11-17 21:46:26 +00:00
TALLOC_CTX * mem_ctx ,
struct dns_connection * * conn )
2006-08-24 15:43:32 +00:00
{
switch ( dwType ) {
case DNS_TCP :
2006-11-17 21:46:26 +00:00
return dns_tcp_open ( nameserver , mem_ctx , conn ) ;
2006-08-24 15:43:32 +00:00
case DNS_UDP :
2006-11-17 21:46:26 +00:00
return dns_udp_open ( nameserver , mem_ctx , conn ) ;
2006-08-24 15:43:32 +00:00
}
return ERROR_DNS_INVALID_PARAMETER ;
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR write_all ( int fd , uint8 * data , size_t len )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
size_t total = 0 ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
while ( total < len ) {
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
ssize_t ret = write ( fd , data + total , len - total ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ret < = 0 ) {
/*
* EOF or error
*/
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
total + = ret ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_send_tcp ( struct dns_connection * conn ,
const struct dns_buffer * buf )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
uint16 len = htons ( buf - > offset ) ;
DNS_ERROR err ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = write_all ( conn - > s , ( uint8 * ) & len , sizeof ( len ) ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
return write_all ( conn - > s , buf - > data , buf - > offset ) ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_send_udp ( struct dns_connection * conn ,
const struct dns_buffer * buf )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
ssize_t ret ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
ret = sendto ( conn - > s , buf - > data , buf - > offset , 0 ,
( struct sockaddr * ) & conn - > RecvAddr ,
sizeof ( conn - > RecvAddr ) ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ret ! = buf - > offset ) {
return ERROR_DNS_SOCKET_ERROR ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
DNS_ERROR dns_send ( struct dns_connection * conn , const struct dns_buffer * buf )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
if ( conn - > hType = = DNS_TCP ) {
return dns_send_tcp ( conn , buf ) ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
if ( conn - > hType = = DNS_UDP ) {
return dns_send_udp ( conn , buf ) ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
return ERROR_DNS_INVALID_PARAMETER ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR read_all ( int fd , uint8 * data , size_t len )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
size_t total = 0 ;
2007-01-02 21:20:40 +00:00
fd_set rfds ;
struct timeval tv ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
while ( total < len ) {
2007-01-02 21:20:40 +00:00
ssize_t ret ;
int fd_ready ;
FD_ZERO ( & rfds ) ;
FD_SET ( fd , & rfds ) ;
/* 10 second timeout */
tv . tv_sec = 10 ;
tv . tv_usec = 0 ;
fd_ready = select ( fd + 1 , & rfds , NULL , NULL , & tv ) ;
if ( fd_ready = = 0 ) {
/* read timeout */
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 15:43:32 +00:00
2007-01-02 21:20:40 +00:00
ret = read ( fd , data + total , len - total ) ;
2006-11-17 21:46:26 +00:00
if ( ret < = 0 ) {
2007-01-02 21:20:40 +00:00
/* EOF or error */
2006-11-17 21:46:26 +00:00
return ERROR_DNS_SOCKET_ERROR ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
total + = ret ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_receive_tcp ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
struct dns_buffer * buf ;
DNS_ERROR err ;
uint16 len ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ( buf = TALLOC_ZERO_P ( mem_ctx , struct dns_buffer ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = read_all ( conn - > s , ( uint8 * ) & len , sizeof ( len ) ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) {
return err ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
buf - > size = ntohs ( len ) ;
2006-08-24 15:43:32 +00:00
2007-04-30 02:39:34 +00:00
if ( buf - > size ) {
if ( ! ( buf - > data = TALLOC_ARRAY ( buf , uint8 , buf - > size ) ) ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_NO_MEMORY ;
}
} else {
buf - > data = NULL ;
2006-11-17 21:46:26 +00:00
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = read_all ( conn - > s , buf - > data , buf - > size ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) {
TALLOC_FREE ( buf ) ;
return err ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
* presult = buf ;
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
static DNS_ERROR dns_receive_udp ( TALLOC_CTX * mem_ctx ,
struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
struct dns_buffer * buf ;
ssize_t received ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ( buf = TALLOC_ZERO_P ( mem_ctx , struct dns_buffer ) ) ) {
return ERROR_DNS_NO_MEMORY ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
/*
* UDP based DNS can only be 512 bytes
*/
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ( buf - > data = TALLOC_ARRAY ( buf , uint8 , 512 ) ) ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_NO_MEMORY ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
received = recv ( conn - > s , ( void * ) buf - > data , 512 , 0 ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( received = = - 1 ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_SOCKET_ERROR ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
if ( received > 512 ) {
TALLOC_FREE ( buf ) ;
return ERROR_DNS_BAD_RESPONSE ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
buf - > size = received ;
buf - > offset = 0 ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
* presult = buf ;
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
DNS_ERROR dns_receive ( TALLOC_CTX * mem_ctx , struct dns_connection * conn ,
struct dns_buffer * * presult )
2006-08-24 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
if ( conn - > hType = = DNS_TCP ) {
return dns_receive_tcp ( mem_ctx , conn , presult ) ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00:00
if ( conn - > hType = = DNS_UDP ) {
return dns_receive_udp ( mem_ctx , conn , presult ) ;
}
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
return ERROR_DNS_INVALID_PARAMETER ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00: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 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
struct dns_buffer * buf = NULL ;
DNS_ERROR err ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = dns_marshall_request ( conn , req , & buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = dns_send ( conn , buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
TALLOC_FREE ( buf ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = dns_receive ( mem_ctx , conn , & buf ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = dns_unmarshall_request ( mem_ctx , buf , resp ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
error :
TALLOC_FREE ( buf ) ;
return err ;
2006-08-24 15:43:32 +00:00
}
2006-11-17 21:46:26 +00: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 15:43:32 +00:00
{
2006-11-17 21:46:26 +00:00
struct dns_request * resp ;
DNS_ERROR err ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
err = dns_transaction ( mem_ctx , conn , dns_update2request ( up_req ) ,
& resp ) ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2006-08-24 15:43:32 +00:00
2006-11-17 21:46:26 +00:00
* up_resp = dns_request2update ( resp ) ;
return ERROR_DNS_SUCCESS ;
2006-08-24 15:43:32 +00:00
}