2005-07-11 01:16:55 +00:00
/*
* Copyright ( c ) 1995 - 2004 Kungliga Tekniska H <EFBFBD> gskolan
* ( Royal Institute of Technology , Stockholm , Sweden ) .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2006-11-07 06:59:56 +00:00
# include "roken.h"
2005-07-11 01:16:55 +00:00
# ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
# endif
# ifdef HAVE_RESOLV_H
# include <resolv.h>
# endif
# include "resolve.h"
# include <assert.h>
2006-04-24 09:36:24 +00:00
RCSID ( " $Id: resolve.c,v 1.55 2006/04/14 13:56:00 lha Exp $ " ) ;
2005-07-11 01:16:55 +00:00
# ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
# undef HAVE_RES_NSEARCH
# endif
# define DECL(X) {#X, rk_ns_t_##X}
static struct stot {
const char * name ;
int type ;
} stot [ ] = {
DECL ( a ) ,
DECL ( aaaa ) ,
DECL ( ns ) ,
DECL ( cname ) ,
DECL ( soa ) ,
DECL ( ptr ) ,
DECL ( mx ) ,
DECL ( txt ) ,
DECL ( afsdb ) ,
DECL ( sig ) ,
DECL ( key ) ,
DECL ( srv ) ,
DECL ( naptr ) ,
DECL ( sshfp ) ,
DECL ( ds ) ,
{ NULL , 0 }
} ;
int _resolve_debug = 0 ;
int ROKEN_LIB_FUNCTION
dns_string_to_type ( const char * name )
{
struct stot * p = stot ;
for ( p = stot ; p - > name ; p + + )
if ( strcasecmp ( name , p - > name ) = = 0 )
return p - > type ;
return - 1 ;
}
const char * ROKEN_LIB_FUNCTION
dns_type_to_string ( int type )
{
struct stot * p = stot ;
for ( p = stot ; p - > name ; p + + )
if ( type = = p - > type )
return p - > name ;
return NULL ;
}
# if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
2006-04-24 09:36:24 +00:00
static void
dns_free_rr ( struct resource_record * rr )
{
if ( rr - > domain )
free ( rr - > domain ) ;
if ( rr - > u . data )
free ( rr - > u . data ) ;
free ( rr ) ;
}
2005-07-11 01:16:55 +00:00
void ROKEN_LIB_FUNCTION
dns_free_data ( struct dns_reply * r )
{
struct resource_record * rr ;
if ( r - > q . domain )
free ( r - > q . domain ) ;
for ( rr = r - > head ; rr ; ) {
struct resource_record * tmp = rr ;
rr = rr - > next ;
2006-04-24 09:36:24 +00:00
dns_free_rr ( tmp ) ;
2005-07-11 01:16:55 +00:00
}
free ( r ) ;
}
static int
parse_record ( const unsigned char * data , const unsigned char * end_data ,
2006-04-24 09:36:24 +00:00
const unsigned char * * pp , struct resource_record * * ret_rr )
2005-07-11 01:16:55 +00:00
{
2006-04-24 09:36:24 +00:00
struct resource_record * rr ;
2005-07-11 01:16:55 +00:00
int type , class , ttl , size ;
int status ;
char host [ MAXDNAME ] ;
const unsigned char * p = * pp ;
2006-04-24 09:36:24 +00:00
* ret_rr = NULL ;
2005-07-11 01:16:55 +00:00
status = dn_expand ( data , end_data , p , host , sizeof ( host ) ) ;
if ( status < 0 )
return - 1 ;
if ( p + status + 10 > end_data )
return - 1 ;
2006-04-24 09:36:24 +00:00
2005-07-11 01:16:55 +00:00
p + = status ;
type = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
p + = 2 ;
class = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
p + = 2 ;
ttl = ( p [ 0 ] < < 24 ) | ( p [ 1 ] < < 16 ) | ( p [ 2 ] < < 8 ) | p [ 3 ] ;
p + = 4 ;
size = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
p + = 2 ;
if ( p + size > end_data )
return - 1 ;
2006-04-24 09:36:24 +00:00
rr = calloc ( 1 , sizeof ( * rr ) ) ;
if ( rr = = NULL )
2005-07-11 01:16:55 +00:00
return - 1 ;
2006-04-24 09:36:24 +00:00
rr - > domain = strdup ( host ) ;
if ( rr - > domain = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > type = type ;
rr - > class = class ;
rr - > ttl = ttl ;
rr - > size = size ;
2005-07-11 01:16:55 +00:00
switch ( type ) {
case rk_ns_t_ns :
case rk_ns_t_cname :
case rk_ns_t_ptr :
status = dn_expand ( data , end_data , p , host , sizeof ( host ) ) ;
if ( status < 0 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . txt = strdup ( host ) ;
if ( rr - > u . txt = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
break ;
case rk_ns_t_mx :
case rk_ns_t_afsdb : {
size_t hostlen ;
status = dn_expand ( data , end_data , p + 2 , host , sizeof ( host ) ) ;
if ( status < 0 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
if ( status + 2 > size ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
hostlen = strlen ( host ) ;
2006-04-24 09:36:24 +00:00
rr - > u . mx = ( struct mx_record * ) malloc ( sizeof ( struct mx_record ) +
2005-07-11 01:16:55 +00:00
hostlen ) ;
2006-04-24 09:36:24 +00:00
if ( rr - > u . mx = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . mx - > preference = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
strlcpy ( rr - > u . mx - > domain , host , hostlen + 1 ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_srv : {
size_t hostlen ;
status = dn_expand ( data , end_data , p + 6 , host , sizeof ( host ) ) ;
if ( status < 0 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
if ( status + 6 > size ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
hostlen = strlen ( host ) ;
2006-04-24 09:36:24 +00:00
rr - > u . srv =
2005-07-11 01:16:55 +00:00
( struct srv_record * ) malloc ( sizeof ( struct srv_record ) +
hostlen ) ;
2006-04-24 09:36:24 +00:00
if ( rr - > u . srv = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . srv - > priority = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
rr - > u . srv - > weight = ( p [ 2 ] < < 8 ) | p [ 3 ] ;
rr - > u . srv - > port = ( p [ 4 ] < < 8 ) | p [ 5 ] ;
strlcpy ( rr - > u . srv - > target , host , hostlen + 1 ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_txt : {
if ( size = = 0 | | size < * p + 1 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . txt = ( char * ) malloc ( * p + 1 ) ;
if ( rr - > u . txt = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
strncpy ( rr - > u . txt , ( const char * ) ( p + 1 ) , * p ) ;
rr - > u . txt [ * p ] = ' \0 ' ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_key : {
size_t key_len ;
if ( size < 4 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
key_len = size - 4 ;
2006-04-24 09:36:24 +00:00
rr - > u . key = malloc ( sizeof ( * rr - > u . key ) + key_len - 1 ) ;
if ( rr - > u . key = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . key - > flags = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
rr - > u . key - > protocol = p [ 2 ] ;
rr - > u . key - > algorithm = p [ 3 ] ;
rr - > u . key - > key_len = key_len ;
memcpy ( rr - > u . key - > key_data , p + 4 , key_len ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_sig : {
size_t sig_len , hostlen ;
if ( size < = 18 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
status = dn_expand ( data , end_data , p + 18 , host , sizeof ( host ) ) ;
if ( status < 0 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
if ( status + 18 > size ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
/* the signer name is placed after the sig_data, to make it
2006-03-11 04:03:12 +00:00
easy to free this structure ; the size calculation below
2005-07-11 01:16:55 +00:00
includes the zero - termination if the structure itself .
don ' t you just love C ?
*/
sig_len = size - 18 - status ;
hostlen = strlen ( host ) ;
2006-04-24 09:36:24 +00:00
rr - > u . sig = malloc ( sizeof ( * rr - > u . sig )
2005-07-11 01:16:55 +00:00
+ hostlen + sig_len ) ;
2006-04-24 09:36:24 +00:00
if ( rr - > u . sig = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . sig - > type = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
rr - > u . sig - > algorithm = p [ 2 ] ;
rr - > u . sig - > labels = p [ 3 ] ;
rr - > u . sig - > orig_ttl = ( p [ 4 ] < < 24 ) | ( p [ 5 ] < < 16 )
2005-07-11 01:16:55 +00:00
| ( p [ 6 ] < < 8 ) | p [ 7 ] ;
2006-04-24 09:36:24 +00:00
rr - > u . sig - > sig_expiration = ( p [ 8 ] < < 24 ) | ( p [ 9 ] < < 16 )
2005-07-11 01:16:55 +00:00
| ( p [ 10 ] < < 8 ) | p [ 11 ] ;
2006-04-24 09:36:24 +00:00
rr - > u . sig - > sig_inception = ( p [ 12 ] < < 24 ) | ( p [ 13 ] < < 16 )
2005-07-11 01:16:55 +00:00
| ( p [ 14 ] < < 8 ) | p [ 15 ] ;
2006-04-24 09:36:24 +00:00
rr - > u . sig - > key_tag = ( p [ 16 ] < < 8 ) | p [ 17 ] ;
rr - > u . sig - > sig_len = sig_len ;
memcpy ( rr - > u . sig - > sig_data , p + 18 + status , sig_len ) ;
rr - > u . sig - > signer = & rr - > u . sig - > sig_data [ sig_len ] ;
strlcpy ( rr - > u . sig - > signer , host , hostlen + 1 ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_cert : {
size_t cert_len ;
if ( size < 5 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
cert_len = size - 5 ;
2006-04-24 09:36:24 +00:00
rr - > u . cert = malloc ( sizeof ( * rr - > u . cert ) + cert_len - 1 ) ;
if ( rr - > u . cert = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . cert - > type = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
rr - > u . cert - > tag = ( p [ 2 ] < < 8 ) | p [ 3 ] ;
rr - > u . cert - > algorithm = p [ 4 ] ;
rr - > u . cert - > cert_len = cert_len ;
memcpy ( rr - > u . cert - > cert_data , p + 5 , cert_len ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_sshfp : {
size_t sshfp_len ;
if ( size < 2 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
sshfp_len = size - 2 ;
2006-04-24 09:36:24 +00:00
rr - > u . sshfp = malloc ( sizeof ( * rr - > u . sshfp ) + sshfp_len - 1 ) ;
if ( rr - > u . sshfp = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . sshfp - > algorithm = p [ 0 ] ;
rr - > u . sshfp - > type = p [ 1 ] ;
rr - > u . sshfp - > sshfp_len = sshfp_len ;
memcpy ( rr - > u . sshfp - > sshfp_data , p + 2 , sshfp_len ) ;
2005-07-11 01:16:55 +00:00
break ;
}
case rk_ns_t_ds : {
size_t digest_len ;
if ( size < 4 ) {
2006-04-24 09:36:24 +00:00
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
digest_len = size - 4 ;
2006-04-24 09:36:24 +00:00
rr - > u . ds = malloc ( sizeof ( * rr - > u . ds ) + digest_len - 1 ) ;
if ( rr - > u . ds = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
rr - > u . ds - > key_tag = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
rr - > u . ds - > algorithm = p [ 2 ] ;
rr - > u . ds - > digest_type = p [ 3 ] ;
rr - > u . ds - > digest_len = digest_len ;
memcpy ( rr - > u . ds - > digest_data , p + 4 , digest_len ) ;
2005-07-11 01:16:55 +00:00
break ;
}
default :
2006-04-24 09:36:24 +00:00
rr - > u . data = ( unsigned char * ) malloc ( size ) ;
if ( size ! = 0 & & rr - > u . data = = NULL ) {
dns_free_rr ( rr ) ;
2005-07-11 01:16:55 +00:00
return - 1 ;
}
2006-04-24 09:36:24 +00:00
if ( size )
memcpy ( rr - > u . data , p , size ) ;
2005-07-11 01:16:55 +00:00
}
* pp = p + size ;
2006-04-24 09:36:24 +00:00
* ret_rr = rr ;
2005-07-11 01:16:55 +00:00
return 0 ;
}
# ifndef TEST_RESOLVE
static
# endif
struct dns_reply *
parse_reply ( const unsigned char * data , size_t len )
{
const unsigned char * p ;
int status ;
int i ;
char host [ MAXDNAME ] ;
const unsigned char * end_data = data + len ;
struct dns_reply * r ;
struct resource_record * * rr ;
r = calloc ( 1 , sizeof ( * r ) ) ;
if ( r = = NULL )
return NULL ;
p = data ;
r - > h . id = ( p [ 0 ] < < 8 ) | p [ 1 ] ;
r - > h . flags = 0 ;
if ( p [ 2 ] & 0x01 )
r - > h . flags | = rk_DNS_HEADER_RESPONSE_FLAG ;
r - > h . opcode = ( p [ 2 ] > > 1 ) & 0xf ;
if ( p [ 2 ] & 0x20 )
r - > h . flags | = rk_DNS_HEADER_AUTHORITIVE_ANSWER ;
if ( p [ 2 ] & 0x40 )
r - > h . flags | = rk_DNS_HEADER_TRUNCATED_MESSAGE ;
if ( p [ 2 ] & 0x80 )
r - > h . flags | = rk_DNS_HEADER_RECURSION_DESIRED ;
if ( p [ 3 ] & 0x01 )
r - > h . flags | = rk_DNS_HEADER_RECURSION_AVAILABLE ;
if ( p [ 3 ] & 0x04 )
r - > h . flags | = rk_DNS_HEADER_AUTHORITIVE_ANSWER ;
if ( p [ 3 ] & 0x08 )
r - > h . flags | = rk_DNS_HEADER_CHECKING_DISABLED ;
r - > h . response_code = ( p [ 3 ] > > 4 ) & 0xf ;
r - > h . qdcount = ( p [ 4 ] < < 8 ) | p [ 5 ] ;
r - > h . ancount = ( p [ 6 ] < < 8 ) | p [ 7 ] ;
r - > h . nscount = ( p [ 8 ] < < 8 ) | p [ 9 ] ;
r - > h . arcount = ( p [ 10 ] < < 8 ) | p [ 11 ] ;
p + = 12 ;
if ( r - > h . qdcount ! = 1 ) {
free ( r ) ;
return NULL ;
}
status = dn_expand ( data , end_data , p , host , sizeof ( host ) ) ;
if ( status < 0 ) {
dns_free_data ( r ) ;
return NULL ;
}
r - > q . domain = strdup ( host ) ;
if ( r - > q . domain = = NULL ) {
dns_free_data ( r ) ;
return NULL ;
}
if ( p + status + 4 > end_data ) {
dns_free_data ( r ) ;
return NULL ;
}
p + = status ;
r - > q . type = ( p [ 0 ] < < 8 | p [ 1 ] ) ;
p + = 2 ;
r - > q . class = ( p [ 0 ] < < 8 | p [ 1 ] ) ;
p + = 2 ;
rr = & r - > head ;
for ( i = 0 ; i < r - > h . ancount ; i + + ) {
if ( parse_record ( data , end_data , & p , rr ) ! = 0 ) {
dns_free_data ( r ) ;
return NULL ;
}
rr = & ( * rr ) - > next ;
}
for ( i = 0 ; i < r - > h . nscount ; i + + ) {
if ( parse_record ( data , end_data , & p , rr ) ! = 0 ) {
dns_free_data ( r ) ;
return NULL ;
}
rr = & ( * rr ) - > next ;
}
for ( i = 0 ; i < r - > h . arcount ; i + + ) {
if ( parse_record ( data , end_data , & p , rr ) ! = 0 ) {
dns_free_data ( r ) ;
return NULL ;
}
rr = & ( * rr ) - > next ;
}
* rr = NULL ;
return r ;
}
static struct dns_reply *
dns_lookup_int ( const char * domain , int rr_class , int rr_type )
{
struct dns_reply * r ;
unsigned char * reply = NULL ;
int size ;
int len ;
# ifdef HAVE_RES_NSEARCH
struct __res_state state ;
memset ( & state , 0 , sizeof ( state ) ) ;
if ( res_ninit ( & state ) )
return NULL ; /* is this the best we can do? */
2007-01-10 01:57:32 +00:00
# elif defined(HAVE__RES)
2005-07-11 01:16:55 +00:00
u_long old_options = 0 ;
# endif
size = 0 ;
len = 1000 ;
do {
if ( reply ) {
free ( reply ) ;
reply = NULL ;
}
if ( size < = len )
size = len ;
if ( _resolve_debug ) {
# ifdef HAVE_RES_NSEARCH
state . options | = RES_DEBUG ;
2007-01-10 01:57:32 +00:00
# elif defined(HAVE__RES)
2005-07-11 01:16:55 +00:00
old_options = _res . options ;
_res . options | = RES_DEBUG ;
# endif
fprintf ( stderr , " dns_lookup(%s, %d, %s), buffer size %d \n " , domain ,
rr_class , dns_type_to_string ( rr_type ) , size ) ;
}
reply = malloc ( size ) ;
if ( reply = = NULL ) {
# ifdef HAVE_RES_NSEARCH
res_nclose ( & state ) ;
# endif
return NULL ;
}
# ifdef HAVE_RES_NSEARCH
len = res_nsearch ( & state , domain , rr_class , rr_type , reply , size ) ;
# else
len = res_search ( domain , rr_class , rr_type , reply , size ) ;
# endif
if ( _resolve_debug ) {
2007-01-10 01:57:32 +00:00
# if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
2005-07-11 01:16:55 +00:00
_res . options = old_options ;
# endif
fprintf ( stderr , " dns_lookup(%s, %d, %s) --> %d \n " ,
domain , rr_class , dns_type_to_string ( rr_type ) , len ) ;
}
if ( len < 0 ) {
# ifdef HAVE_RES_NSEARCH
2005-08-27 11:49:06 +00:00
# ifdef HAVE_RES_NDESTROY
res_ndestroy ( & state ) ;
# else
2005-07-11 01:16:55 +00:00
res_nclose ( & state ) ;
2005-08-27 11:49:06 +00:00
# endif
2005-07-11 01:16:55 +00:00
# endif
free ( reply ) ;
return NULL ;
}
} while ( size < len & & len < rk_DNS_MAX_PACKET_SIZE ) ;
# ifdef HAVE_RES_NSEARCH
res_nclose ( & state ) ;
# endif
len = min ( len , size ) ;
r = parse_reply ( reply , len ) ;
free ( reply ) ;
return r ;
}
struct dns_reply * ROKEN_LIB_FUNCTION
dns_lookup ( const char * domain , const char * type_name )
{
int type ;
type = dns_string_to_type ( type_name ) ;
if ( type = = - 1 ) {
if ( _resolve_debug )
fprintf ( stderr , " dns_lookup: unknown resource type: `%s' \n " ,
type_name ) ;
return NULL ;
}
return dns_lookup_int ( domain , C_IN , type ) ;
}
static int
compare_srv ( const void * a , const void * b )
{
const struct resource_record * const * aa = a , * const * bb = b ;
if ( ( * aa ) - > u . srv - > priority = = ( * bb ) - > u . srv - > priority )
return ( ( * aa ) - > u . srv - > weight - ( * bb ) - > u . srv - > weight ) ;
return ( ( * aa ) - > u . srv - > priority - ( * bb ) - > u . srv - > priority ) ;
}
# ifndef HAVE_RANDOM
# define random() rand()
# endif
/* try to rearrange the srv-records by the algorithm in RFC2782 */
void ROKEN_LIB_FUNCTION
dns_srv_order ( struct dns_reply * r )
{
struct resource_record * * srvs , * * ss , * * headp ;
struct resource_record * rr ;
int num_srv = 0 ;
# if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
int state [ 256 / sizeof ( int ) ] ;
char * oldstate ;
# endif
for ( rr = r - > head ; rr ; rr = rr - > next )
if ( rr - > type = = rk_ns_t_srv )
num_srv + + ;
if ( num_srv = = 0 )
return ;
srvs = malloc ( num_srv * sizeof ( * srvs ) ) ;
if ( srvs = = NULL )
return ; /* XXX not much to do here */
/* unlink all srv-records from the linked list and put them in
a vector */
for ( ss = srvs , headp = & r - > head ; * headp ; )
if ( ( * headp ) - > type = = rk_ns_t_srv ) {
* ss = * headp ;
* headp = ( * headp ) - > next ;
( * ss ) - > next = NULL ;
ss + + ;
} else
headp = & ( * headp ) - > next ;
/* sort them by priority and weight */
qsort ( srvs , num_srv , sizeof ( * srvs ) , compare_srv ) ;
# if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
oldstate = initstate ( time ( NULL ) , ( char * ) state , sizeof ( state ) ) ;
# endif
headp = & r - > head ;
for ( ss = srvs ; ss < srvs + num_srv ; ) {
int sum , rnd , count ;
struct resource_record * * ee , * * tt ;
/* find the last record with the same priority and count the
sum of all weights */
for ( sum = 0 , tt = ss ; tt < srvs + num_srv ; tt + + ) {
2006-04-24 09:36:24 +00:00
assert ( * tt ! = NULL ) ;
2005-07-11 01:16:55 +00:00
if ( ( * tt ) - > u . srv - > priority ! = ( * ss ) - > u . srv - > priority )
break ;
sum + = ( * tt ) - > u . srv - > weight ;
}
ee = tt ;
/* ss is now the first record of this priority and ee is the
first of the next */
while ( ss < ee ) {
rnd = random ( ) % ( sum + 1 ) ;
for ( count = 0 , tt = ss ; ; tt + + ) {
if ( * tt = = NULL )
continue ;
count + = ( * tt ) - > u . srv - > weight ;
if ( count > = rnd )
break ;
}
assert ( tt < ee ) ;
/* insert the selected record at the tail (of the head) of
the list */
( * tt ) - > next = * headp ;
* headp = * tt ;
headp = & ( * tt ) - > next ;
sum - = ( * tt ) - > u . srv - > weight ;
* tt = NULL ;
while ( ss < ee & & * ss = = NULL )
ss + + ;
}
}
# if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
setstate ( oldstate ) ;
# endif
free ( srvs ) ;
return ;
}
# else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
struct dns_reply * ROKEN_LIB_FUNCTION
dns_lookup ( const char * domain , const char * type_name )
{
return NULL ;
}
void ROKEN_LIB_FUNCTION
dns_free_data ( struct dns_reply * r )
{
}
void ROKEN_LIB_FUNCTION
dns_srv_order ( struct dns_reply * r )
{
}
# endif