2012-03-11 10:13:51 +01:00
/*
Unix SMB / CIFS implementation .
Small async DNS library for Samba with socketwrapper support
Copyright ( C ) 2010 Kai Blin < kai @ samba . org >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/network.h"
# include <tevent.h>
# include "lib/tsocket/tsocket.h"
# include "libcli/util/werror.h"
# include "libcli/dns/libdns.h"
# include "lib/util/tevent_werror.h"
# include "lib/util/samba_util.h"
# include "libcli/util/error.h"
# include "librpc/gen_ndr/dns.h"
struct dns_udp_request_state {
struct tevent_context * ev ;
struct tdgram_context * dgram ;
size_t query_len ;
uint8_t * reply ;
size_t reply_len ;
} ;
2012-10-13 02:09:57 +02:00
# define DNS_REQUEST_TIMEOUT 2
2012-03-11 10:13:51 +01:00
/* Declare callback functions used below. */
2012-05-29 23:05:14 +02:00
static void dns_udp_request_get_reply ( struct tevent_req * subreq ) ;
static void dns_udp_request_done ( struct tevent_req * subreq ) ;
2012-03-11 10:13:51 +01:00
struct tevent_req * dns_udp_request_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
const char * server_addr_string ,
const uint8_t * query ,
size_t query_len )
{
struct tevent_req * req , * subreq ;
struct dns_udp_request_state * state ;
struct tsocket_address * local_addr , * server_addr ;
struct tdgram_context * dgram ;
int ret ;
req = tevent_req_create ( mem_ctx , & state , struct dns_udp_request_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
/* Use connected UDP sockets */
ret = tsocket_address_inet_from_strings ( state , " ip " , NULL , 0 ,
& local_addr ) ;
if ( ret ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( ret ) ) ;
return tevent_req_post ( req , ev ) ;
}
ret = tsocket_address_inet_from_strings ( state , " ip " , server_addr_string ,
DNS_SERVICE_PORT , & server_addr ) ;
if ( ret ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( ret ) ) ;
return tevent_req_post ( req , ev ) ;
}
ret = tdgram_inet_udp_socket ( local_addr , server_addr , state , & dgram ) ;
if ( ret ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( ret ) ) ;
return tevent_req_post ( req , ev ) ;
}
state - > dgram = dgram ;
state - > query_len = query_len ;
dump_data ( 10 , query , query_len ) ;
subreq = tdgram_sendto_send ( state , ev , dgram , query , query_len , NULL ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2012-10-13 02:09:57 +02:00
if ( ! tevent_req_set_endtime ( req , ev ,
timeval_current_ofs ( DNS_REQUEST_TIMEOUT , 0 ) ) ) {
return tevent_req_post ( req , ev ) ;
}
2012-05-29 23:05:14 +02:00
tevent_req_set_callback ( subreq , dns_udp_request_get_reply , req ) ;
2012-03-11 10:13:51 +01:00
return req ;
}
2012-05-29 23:05:14 +02:00
static void dns_udp_request_get_reply ( struct tevent_req * subreq )
2012-03-11 10:13:51 +01:00
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct dns_udp_request_state * state = tevent_req_data ( req ,
struct dns_udp_request_state ) ;
ssize_t len ;
int err = 0 ;
len = tdgram_sendto_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( len = = - 1 & & err ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( err ) ) ;
return ;
}
if ( len ! = state - > query_len ) {
tevent_req_werror ( req , WERR_NET_WRITE_FAULT ) ;
return ;
}
subreq = tdgram_recvfrom_send ( state , state - > ev , state - > dgram ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2012-05-29 23:05:14 +02:00
tevent_req_set_callback ( subreq , dns_udp_request_done , req ) ;
2012-03-11 10:13:51 +01:00
return ;
}
2012-05-29 23:05:14 +02:00
static void dns_udp_request_done ( struct tevent_req * subreq )
2012-03-11 10:13:51 +01:00
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct dns_udp_request_state * state = tevent_req_data ( req ,
struct dns_udp_request_state ) ;
ssize_t len ;
int err = 0 ;
len = tdgram_recvfrom_recv ( subreq , & err , state , & state - > reply , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( len = = - 1 & & err ! = 0 ) {
tevent_req_werror ( req , unix_to_werror ( err ) ) ;
return ;
}
state - > reply_len = len ;
dump_data ( 10 , state - > reply , state - > reply_len ) ;
tevent_req_done ( req ) ;
}
WERROR dns_udp_request_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
uint8_t * * reply ,
size_t * reply_len )
{
struct dns_udp_request_state * state = tevent_req_data ( req ,
struct dns_udp_request_state ) ;
WERROR w_error ;
if ( tevent_req_is_werror ( req , & w_error ) ) {
tevent_req_received ( req ) ;
return w_error ;
}
* reply = talloc_move ( mem_ctx , & state - > reply ) ;
* reply_len = state - > reply_len ;
tevent_req_received ( req ) ;
return WERR_OK ;
}