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
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
02110 - 1301 USA
*/
# include "dns.h"
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_query ( TALLOC_CTX * mem_ctx , const char * name ,
uint16 q_type , uint16 q_class ,
struct dns_request * * preq )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_request * req ;
struct dns_question * q ;
DNS_ERROR err ;
if ( ! ( req = TALLOC_ZERO_P ( mem_ctx , struct dns_request ) ) | |
! ( req - > questions = TALLOC_ARRAY ( req , struct dns_question * , 1 ) ) | |
! ( req - > questions [ 0 ] = talloc ( req - > questions ,
struct dns_question ) ) ) {
TALLOC_FREE ( req ) ;
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
req - > id = random ( ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
req - > num_questions = 1 ;
q = req - > questions [ 0 ] ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_domain_name_from_string ( q , name , & q - > name ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) {
TALLOC_FREE ( req ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
q - > q_type = q_type ;
q - > q_class = q_class ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* preq = req ;
return ERROR_DNS_SUCCESS ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_update ( TALLOC_CTX * mem_ctx , const char * name ,
struct dns_update_request * * preq )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_update_request * req ;
struct dns_zone * z ;
DNS_ERROR err ;
if ( ! ( req = TALLOC_ZERO_P ( mem_ctx , struct dns_update_request ) ) | |
! ( req - > zones = TALLOC_ARRAY ( req , struct dns_zone * , 1 ) ) | |
! ( req - > zones [ 0 ] = talloc ( req - > zones , struct dns_zone ) ) ) {
TALLOC_FREE ( req ) ;
return ERROR_DNS_NO_MEMORY ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
req - > id = random ( ) ;
req - > flags = 0x2800 ; /* Dynamic update */
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
req - > num_zones = 1 ;
z = req - > zones [ 0 ] ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_domain_name_from_string ( z , name , & z - > name ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) {
TALLOC_FREE ( req ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
z - > z_type = QTYPE_SOA ;
z - > z_class = DNS_CLASS_IN ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* preq = req ;
return ERROR_DNS_SUCCESS ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_rrec ( TALLOC_CTX * mem_ctx , const char * name ,
uint16 type , uint16 r_class , uint32 ttl ,
uint16 data_length , uint8 * data ,
struct dns_rrec * * prec )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_rrec * rec ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( rec = talloc ( mem_ctx , struct dns_rrec ) ) ) {
return ERROR_DNS_NO_MEMORY ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
err = dns_domain_name_from_string ( rec , name , & rec - > name ) ;
if ( ! ( ERR_DNS_IS_OK ( err ) ) ) {
TALLOC_FREE ( rec ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
rec - > type = type ;
rec - > r_class = r_class ;
rec - > ttl = ttl ;
rec - > data_length = data_length ;
rec - > data = talloc_move ( rec , & data ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* prec = rec ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_a_record ( TALLOC_CTX * mem_ctx , const char * host ,
uint32 ttl , in_addr_t ip ,
struct dns_rrec * * prec )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
uint8 * data ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( data = ( uint8 * ) TALLOC_MEMDUP ( mem_ctx , ( const void * ) & ip ,
sizeof ( ip ) ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_rrec ( mem_ctx , host , QTYPE_A , DNS_CLASS_IN , ttl ,
sizeof ( ip ) , data , prec ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( err ) ) {
TALLOC_FREE ( data ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return err ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_name_in_use_record ( TALLOC_CTX * mem_ctx ,
const char * name ,
const in_addr_t * ip ,
struct dns_rrec * * prec )
{
if ( ip ! = NULL ) {
return dns_create_a_record ( mem_ctx , name , 0 , * ip , prec ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
return dns_create_rrec ( mem_ctx , name , QTYPE_ANY , DNS_CLASS_IN , 0 , 0 ,
NULL , prec ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_name_not_in_use_record ( TALLOC_CTX * mem_ctx ,
const char * name , uint32 type ,
struct dns_rrec * * prec )
{
return dns_create_rrec ( mem_ctx , name , type , DNS_CLASS_NONE , 0 ,
0 , NULL , prec ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_delete_record ( TALLOC_CTX * mem_ctx , const char * name ,
uint16 type , uint16 r_class ,
struct dns_rrec * * prec )
{
return dns_create_rrec ( mem_ctx , name , type , r_class , 0 , 0 , NULL , prec ) ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_tkey_record ( TALLOC_CTX * mem_ctx , const char * keyname ,
const char * algorithm_name , time_t inception ,
time_t expiration , uint16 mode , uint16 error ,
uint16 key_length , const uint8 * key ,
struct dns_rrec * * prec )
{
struct dns_buffer * buf ;
struct dns_domain_name * algorithm ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( buf = dns_create_buffer ( mem_ctx ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_domain_name_from_string ( buf , algorithm_name , & algorithm ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
dns_marshall_domain_name ( buf , algorithm ) ;
dns_marshall_uint32 ( buf , inception ) ;
dns_marshall_uint32 ( buf , expiration ) ;
dns_marshall_uint16 ( buf , mode ) ;
dns_marshall_uint16 ( buf , error ) ;
dns_marshall_uint16 ( buf , key_length ) ;
dns_marshall_buffer ( buf , key , key_length ) ;
dns_marshall_uint16 ( buf , 0 ) ; /* Other Size */
if ( ! ERR_DNS_IS_OK ( buf - > error ) ) {
err = buf - > error ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_rrec ( mem_ctx , keyname , QTYPE_TKEY , DNS_CLASS_ANY , 0 ,
buf - > offset , buf - > data , prec ) ;
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_unmarshall_tkey_record ( TALLOC_CTX * mem_ctx , struct dns_rrec * rec ,
struct dns_tkey_record * * ptkey )
{
struct dns_tkey_record * tkey ;
struct dns_buffer buf ;
uint32 tmp_inception , tmp_expiration ;
if ( ! ( tkey = talloc ( mem_ctx , struct dns_tkey_record ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
buf . data = rec - > data ;
buf . size = rec - > data_length ;
buf . offset = 0 ;
buf . error = ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
dns_unmarshall_domain_name ( tkey , & buf , & tkey - > algorithm ) ;
dns_unmarshall_uint32 ( & buf , & tmp_inception ) ;
dns_unmarshall_uint32 ( & buf , & tmp_expiration ) ;
dns_unmarshall_uint16 ( & buf , & tkey - > mode ) ;
dns_unmarshall_uint16 ( & buf , & tkey - > error ) ;
dns_unmarshall_uint16 ( & buf , & tkey - > key_length ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ERR_DNS_IS_OK ( buf . error ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( tkey - > key = TALLOC_ARRAY ( tkey , uint8 , tkey - > key_length ) ) ) {
buf . error = ERROR_DNS_NO_MEMORY ;
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
dns_unmarshall_buffer ( & buf , tkey - > key , tkey - > key_length ) ;
if ( ! ERR_DNS_IS_OK ( buf . error ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
tkey - > inception = ( time_t ) tmp_inception ;
tkey - > expiration = ( time_t ) tmp_expiration ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* ptkey = tkey ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
error :
TALLOC_FREE ( tkey ) ;
return buf . error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_tsig_record ( TALLOC_CTX * mem_ctx , const char * keyname ,
const char * algorithm_name ,
time_t time_signed , uint16 fudge ,
uint16 mac_length , const uint8 * mac ,
uint16 original_id , uint16 error ,
struct dns_rrec * * prec )
{
struct dns_buffer * buf ;
struct dns_domain_name * algorithm ;
DNS_ERROR err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( buf = dns_create_buffer ( mem_ctx ) ) ) {
return ERROR_DNS_NO_MEMORY ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
err = dns_domain_name_from_string ( buf , algorithm_name , & algorithm ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
dns_marshall_domain_name ( buf , algorithm ) ;
dns_marshall_uint16 ( buf , 0 ) ; /* time prefix */
dns_marshall_uint32 ( buf , time_signed ) ;
dns_marshall_uint16 ( buf , fudge ) ;
dns_marshall_uint16 ( buf , mac_length ) ;
dns_marshall_buffer ( buf , mac , mac_length ) ;
dns_marshall_uint16 ( buf , original_id ) ;
dns_marshall_uint16 ( buf , error ) ;
dns_marshall_uint16 ( buf , 0 ) ; /* Other Size */
if ( ! ERR_DNS_IS_OK ( buf - > error ) ) {
err = buf - > error ;
goto error ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
err = dns_create_rrec ( mem_ctx , keyname , QTYPE_TSIG , DNS_CLASS_ANY , 0 ,
buf - > offset , buf - > data , prec ) ;
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_add_rrec ( TALLOC_CTX * mem_ctx , struct dns_rrec * rec ,
uint16 * num_records , struct dns_rrec * * * records )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_rrec * * new_records ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
if ( ! ( new_records = TALLOC_REALLOC_ARRAY ( mem_ctx , * records ,
struct dns_rrec * ,
( * num_records ) + 1 ) ) ) {
return ERROR_DNS_NO_MEMORY ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
new_records [ * num_records ] = talloc_move ( new_records , & rec ) ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* num_records + = 1 ;
* records = new_records ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
/*
* Create a request that probes a server whether the list of IP addresses
* provides meets our expectations
*/
DNS_ERROR dns_create_probe ( TALLOC_CTX * mem_ctx , const char * zone ,
const char * host , int num_ips ,
const struct in_addr * iplist ,
struct dns_update_request * * preq )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_update_request * req ;
struct dns_rrec * rec ;
DNS_ERROR err ;
uint16 i ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_update ( mem_ctx , zone , & req ) ;
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_create_name_not_in_use_record ( req , host , QTYPE_CNAME , & rec ) ;
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_add_rrec ( req , rec , & req - > num_preqs , & req - > preqs ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
for ( i = 0 ; i < num_ips ; i + + ) {
err = dns_create_name_in_use_record ( req , host ,
& iplist [ i ] . s_addr , & rec ) ;
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_add_rrec ( req , rec , & req - > num_preqs , & req - > preqs ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
* preq = req ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
error :
TALLOC_FREE ( req ) ;
return err ;
2006-08-24 19:43:32 +04:00
}
2006-11-18 00:46:26 +03:00
DNS_ERROR dns_create_update_request ( TALLOC_CTX * mem_ctx ,
const char * domainname ,
const char * hostname ,
2006-12-14 20:00:10 +03:00
const struct in_addr * ip_addrs ,
2006-12-14 19:27:45 +03:00
size_t num_addrs ,
2006-11-18 00:46:26 +03:00
struct dns_update_request * * preq )
2006-08-24 19:43:32 +04:00
{
2006-11-18 00:46:26 +03:00
struct dns_update_request * req ;
struct dns_rrec * rec ;
DNS_ERROR err ;
2006-12-14 19:27:45 +03:00
size_t i ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_update ( mem_ctx , domainname , & req ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) return err ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
/*
* The zone must be used at all
*/
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_rrec ( req , domainname , QTYPE_ANY , DNS_CLASS_ANY ,
0 , 0 , NULL , & rec ) ;
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_add_rrec ( req , rec , & req - > num_preqs , & req - > preqs ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
/*
* Delete any existing A records
*/
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
err = dns_create_delete_record ( req , hostname , QTYPE_A , DNS_CLASS_ANY ,
& rec ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
err = dns_add_rrec ( req , rec , & req - > num_updates , & req - > updates ) ;
if ( ! ERR_DNS_IS_OK ( err ) ) goto error ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
/*
2006-12-14 19:27:45 +03:00
* . . and add our IPs
2006-11-18 00:46:26 +03:00
*/
2006-08-24 19:43:32 +04:00
2006-12-14 19:27:45 +03:00
for ( i = 0 ; i < num_addrs ; i + + ) {
2006-12-14 20:00:10 +03:00
err = dns_create_a_record ( req , hostname , 3600 , ip_addrs [ i ] . s_addr , & rec ) ;
2006-12-14 19:27:45 +03:00
if ( ! ERR_DNS_IS_OK ( err ) )
goto error ;
2006-08-24 19:43:32 +04:00
2006-12-14 19:27:45 +03:00
err = dns_add_rrec ( req , rec , & req - > num_updates , & req - > updates ) ;
if ( ! ERR_DNS_IS_OK ( err ) )
goto error ;
}
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
* preq = req ;
return ERROR_DNS_SUCCESS ;
2006-08-24 19:43:32 +04:00
2006-11-18 00:46:26 +03:00
error :
TALLOC_FREE ( req ) ;
return err ;
2006-08-24 19:43:32 +04:00
}