1b528cefcSMark Murray /* 2*8373020dSJacques Vidrine * Copyright (c) 1995 - 2002 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #ifdef HAVE_CONFIG_H 35b528cefcSMark Murray #include <config.h> 36b528cefcSMark Murray #endif 37b528cefcSMark Murray #include "roken.h" 38b528cefcSMark Murray #ifdef HAVE_ARPA_NAMESER_H 39b528cefcSMark Murray #include <arpa/nameser.h> 40b528cefcSMark Murray #endif 41b528cefcSMark Murray #ifdef HAVE_RESOLV_H 42b528cefcSMark Murray #include <resolv.h> 43b528cefcSMark Murray #endif 44b528cefcSMark Murray #include "resolve.h" 45b528cefcSMark Murray 464137ff4cSJacques Vidrine #include <assert.h> 474137ff4cSJacques Vidrine 48*8373020dSJacques Vidrine RCSID("$Id: resolve.c,v 1.33 2002/08/28 20:07:24 joda Exp $"); 49b528cefcSMark Murray 50b528cefcSMark Murray #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) 51b528cefcSMark Murray 52b528cefcSMark Murray #define DECL(X) {#X, T_##X} 53b528cefcSMark Murray 54b528cefcSMark Murray static struct stot{ 55b528cefcSMark Murray const char *name; 56b528cefcSMark Murray int type; 57b528cefcSMark Murray }stot[] = { 58b528cefcSMark Murray DECL(A), 59b528cefcSMark Murray DECL(NS), 60b528cefcSMark Murray DECL(CNAME), 615e9cd1aeSAssar Westerlund DECL(SOA), 62b528cefcSMark Murray DECL(PTR), 63b528cefcSMark Murray DECL(MX), 64b528cefcSMark Murray DECL(TXT), 65b528cefcSMark Murray DECL(AFSDB), 665e9cd1aeSAssar Westerlund DECL(SIG), 675e9cd1aeSAssar Westerlund DECL(KEY), 68b528cefcSMark Murray DECL(SRV), 695e9cd1aeSAssar Westerlund DECL(NAPTR), 70b528cefcSMark Murray {NULL, 0} 71b528cefcSMark Murray }; 72b528cefcSMark Murray 735e9cd1aeSAssar Westerlund int _resolve_debug = 0; 74b528cefcSMark Murray 755e9cd1aeSAssar Westerlund int 765e9cd1aeSAssar Westerlund dns_string_to_type(const char *name) 77b528cefcSMark Murray { 78b528cefcSMark Murray struct stot *p = stot; 79b528cefcSMark Murray for(p = stot; p->name; p++) 80b528cefcSMark Murray if(strcasecmp(name, p->name) == 0) 81b528cefcSMark Murray return p->type; 82b528cefcSMark Murray return -1; 83b528cefcSMark Murray } 84b528cefcSMark Murray 855e9cd1aeSAssar Westerlund const char * 865e9cd1aeSAssar Westerlund dns_type_to_string(int type) 87b528cefcSMark Murray { 88b528cefcSMark Murray struct stot *p = stot; 89b528cefcSMark Murray for(p = stot; p->name; p++) 90b528cefcSMark Murray if(type == p->type) 91b528cefcSMark Murray return p->name; 92b528cefcSMark Murray return NULL; 93b528cefcSMark Murray } 94b528cefcSMark Murray 95b528cefcSMark Murray void 96b528cefcSMark Murray dns_free_data(struct dns_reply *r) 97b528cefcSMark Murray { 98b528cefcSMark Murray struct resource_record *rr; 99b528cefcSMark Murray if(r->q.domain) 100b528cefcSMark Murray free(r->q.domain); 101b528cefcSMark Murray for(rr = r->head; rr;){ 102b528cefcSMark Murray struct resource_record *tmp = rr; 103b528cefcSMark Murray if(rr->domain) 104b528cefcSMark Murray free(rr->domain); 105b528cefcSMark Murray if(rr->u.data) 106b528cefcSMark Murray free(rr->u.data); 107b528cefcSMark Murray rr = rr->next; 108b528cefcSMark Murray free(tmp); 109b528cefcSMark Murray } 110b528cefcSMark Murray free (r); 111b528cefcSMark Murray } 112b528cefcSMark Murray 113b528cefcSMark Murray static struct dns_reply* 114b528cefcSMark Murray parse_reply(unsigned char *data, int len) 115b528cefcSMark Murray { 116*8373020dSJacques Vidrine const unsigned char *p; 117b528cefcSMark Murray char host[128]; 118b528cefcSMark Murray int status; 119*8373020dSJacques Vidrine const unsigned char *end_data = data + len; 120b528cefcSMark Murray struct dns_reply *r; 121b528cefcSMark Murray struct resource_record **rr; 122b528cefcSMark Murray 123b528cefcSMark Murray r = calloc(1, sizeof(*r)); 124b528cefcSMark Murray if (r == NULL) 125b528cefcSMark Murray return NULL; 126b528cefcSMark Murray 127b528cefcSMark Murray p = data; 128b528cefcSMark Murray #if 0 129b528cefcSMark Murray /* doesn't work on Crays */ 130b528cefcSMark Murray memcpy(&r->h, p, sizeof(HEADER)); 131b528cefcSMark Murray p += sizeof(HEADER); 132b528cefcSMark Murray #else 133b528cefcSMark Murray memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */ 134b528cefcSMark Murray p += 12; 135b528cefcSMark Murray #endif 136*8373020dSJacques Vidrine status = dn_expand(data, end_data, p, host, sizeof(host)); 137b528cefcSMark Murray if(status < 0){ 138b528cefcSMark Murray dns_free_data(r); 139b528cefcSMark Murray return NULL; 140b528cefcSMark Murray } 141b528cefcSMark Murray r->q.domain = strdup(host); 142b528cefcSMark Murray if(r->q.domain == NULL) { 143b528cefcSMark Murray dns_free_data(r); 144b528cefcSMark Murray return NULL; 145b528cefcSMark Murray } 146*8373020dSJacques Vidrine if (p + status + 4 > end_data) { 147*8373020dSJacques Vidrine dns_free_data(r); 148*8373020dSJacques Vidrine return NULL; 149*8373020dSJacques Vidrine } 150b528cefcSMark Murray p += status; 151b528cefcSMark Murray r->q.type = (p[0] << 8 | p[1]); 152b528cefcSMark Murray p += 2; 153b528cefcSMark Murray r->q.class = (p[0] << 8 | p[1]); 154b528cefcSMark Murray p += 2; 155b528cefcSMark Murray rr = &r->head; 156*8373020dSJacques Vidrine while(p < end_data){ 157b528cefcSMark Murray int type, class, ttl, size; 158*8373020dSJacques Vidrine status = dn_expand(data, end_data, p, host, sizeof(host)); 159b528cefcSMark Murray if(status < 0){ 160b528cefcSMark Murray dns_free_data(r); 161b528cefcSMark Murray return NULL; 162b528cefcSMark Murray } 163*8373020dSJacques Vidrine if (p + status + 10 > end_data) { 164*8373020dSJacques Vidrine dns_free_data(r); 165*8373020dSJacques Vidrine return NULL; 166*8373020dSJacques Vidrine } 167b528cefcSMark Murray p += status; 168b528cefcSMark Murray type = (p[0] << 8) | p[1]; 169b528cefcSMark Murray p += 2; 170b528cefcSMark Murray class = (p[0] << 8) | p[1]; 171b528cefcSMark Murray p += 2; 172b528cefcSMark Murray ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 173b528cefcSMark Murray p += 4; 174b528cefcSMark Murray size = (p[0] << 8) | p[1]; 175b528cefcSMark Murray p += 2; 176*8373020dSJacques Vidrine 177*8373020dSJacques Vidrine if (p + size > end_data) { 178*8373020dSJacques Vidrine dns_free_data(r); 179*8373020dSJacques Vidrine return NULL; 180*8373020dSJacques Vidrine } 181*8373020dSJacques Vidrine 182b528cefcSMark Murray *rr = (struct resource_record*)calloc(1, 183b528cefcSMark Murray sizeof(struct resource_record)); 184b528cefcSMark Murray if(*rr == NULL) { 185b528cefcSMark Murray dns_free_data(r); 186b528cefcSMark Murray return NULL; 187b528cefcSMark Murray } 188b528cefcSMark Murray (*rr)->domain = strdup(host); 189b528cefcSMark Murray if((*rr)->domain == NULL) { 190b528cefcSMark Murray dns_free_data(r); 191b528cefcSMark Murray return NULL; 192b528cefcSMark Murray } 193b528cefcSMark Murray (*rr)->type = type; 194b528cefcSMark Murray (*rr)->class = class; 195b528cefcSMark Murray (*rr)->ttl = ttl; 196b528cefcSMark Murray (*rr)->size = size; 197b528cefcSMark Murray switch(type){ 198b528cefcSMark Murray case T_NS: 199b528cefcSMark Murray case T_CNAME: 200b528cefcSMark Murray case T_PTR: 201*8373020dSJacques Vidrine status = dn_expand(data, end_data, p, host, sizeof(host)); 202b528cefcSMark Murray if(status < 0){ 203b528cefcSMark Murray dns_free_data(r); 204b528cefcSMark Murray return NULL; 205b528cefcSMark Murray } 206b528cefcSMark Murray (*rr)->u.txt = strdup(host); 207b528cefcSMark Murray if((*rr)->u.txt == NULL) { 208b528cefcSMark Murray dns_free_data(r); 209b528cefcSMark Murray return NULL; 210b528cefcSMark Murray } 211b528cefcSMark Murray break; 212b528cefcSMark Murray case T_MX: 213b528cefcSMark Murray case T_AFSDB:{ 214*8373020dSJacques Vidrine status = dn_expand(data, end_data, p + 2, host, sizeof(host)); 215b528cefcSMark Murray if(status < 0){ 216b528cefcSMark Murray dns_free_data(r); 217b528cefcSMark Murray return NULL; 218b528cefcSMark Murray } 219*8373020dSJacques Vidrine if (status + 2 > size) { 220*8373020dSJacques Vidrine dns_free_data(r); 221*8373020dSJacques Vidrine return NULL; 222*8373020dSJacques Vidrine } 223*8373020dSJacques Vidrine 224b528cefcSMark Murray (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 225b528cefcSMark Murray strlen(host)); 226b528cefcSMark Murray if((*rr)->u.mx == NULL) { 227b528cefcSMark Murray dns_free_data(r); 228b528cefcSMark Murray return NULL; 229b528cefcSMark Murray } 230b528cefcSMark Murray (*rr)->u.mx->preference = (p[0] << 8) | p[1]; 231b528cefcSMark Murray strcpy((*rr)->u.mx->domain, host); 232b528cefcSMark Murray break; 233b528cefcSMark Murray } 234b528cefcSMark Murray case T_SRV:{ 235*8373020dSJacques Vidrine status = dn_expand(data, end_data, p + 6, host, sizeof(host)); 236b528cefcSMark Murray if(status < 0){ 237b528cefcSMark Murray dns_free_data(r); 238b528cefcSMark Murray return NULL; 239b528cefcSMark Murray } 240*8373020dSJacques Vidrine if (status + 6 > size) { 241*8373020dSJacques Vidrine dns_free_data(r); 242*8373020dSJacques Vidrine return NULL; 243*8373020dSJacques Vidrine } 244*8373020dSJacques Vidrine 245b528cefcSMark Murray (*rr)->u.srv = 246b528cefcSMark Murray (struct srv_record*)malloc(sizeof(struct srv_record) + 247b528cefcSMark Murray strlen(host)); 248b528cefcSMark Murray if((*rr)->u.srv == NULL) { 249b528cefcSMark Murray dns_free_data(r); 250b528cefcSMark Murray return NULL; 251b528cefcSMark Murray } 252b528cefcSMark Murray (*rr)->u.srv->priority = (p[0] << 8) | p[1]; 253b528cefcSMark Murray (*rr)->u.srv->weight = (p[2] << 8) | p[3]; 254b528cefcSMark Murray (*rr)->u.srv->port = (p[4] << 8) | p[5]; 255b528cefcSMark Murray strcpy((*rr)->u.srv->target, host); 256b528cefcSMark Murray break; 257b528cefcSMark Murray } 258b528cefcSMark Murray case T_TXT:{ 259b528cefcSMark Murray (*rr)->u.txt = (char*)malloc(size + 1); 260b528cefcSMark Murray if((*rr)->u.txt == NULL) { 261b528cefcSMark Murray dns_free_data(r); 262b528cefcSMark Murray return NULL; 263b528cefcSMark Murray } 264b528cefcSMark Murray strncpy((*rr)->u.txt, (char*)p + 1, *p); 265b528cefcSMark Murray (*rr)->u.txt[*p] = 0; 266b528cefcSMark Murray break; 267b528cefcSMark Murray } 2685e9cd1aeSAssar Westerlund case T_KEY : { 2695e9cd1aeSAssar Westerlund size_t key_len; 270b528cefcSMark Murray 271*8373020dSJacques Vidrine if (size < 4) { 272*8373020dSJacques Vidrine dns_free_data (r); 273*8373020dSJacques Vidrine return NULL; 274*8373020dSJacques Vidrine } 275*8373020dSJacques Vidrine 2765e9cd1aeSAssar Westerlund key_len = size - 4; 2775e9cd1aeSAssar Westerlund (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1); 2785e9cd1aeSAssar Westerlund if ((*rr)->u.key == NULL) { 2795e9cd1aeSAssar Westerlund dns_free_data (r); 2805e9cd1aeSAssar Westerlund return NULL; 2815e9cd1aeSAssar Westerlund } 2825e9cd1aeSAssar Westerlund 2835e9cd1aeSAssar Westerlund (*rr)->u.key->flags = (p[0] << 8) | p[1]; 2845e9cd1aeSAssar Westerlund (*rr)->u.key->protocol = p[2]; 2855e9cd1aeSAssar Westerlund (*rr)->u.key->algorithm = p[3]; 2865e9cd1aeSAssar Westerlund (*rr)->u.key->key_len = key_len; 2875e9cd1aeSAssar Westerlund memcpy ((*rr)->u.key->key_data, p + 4, key_len); 2885e9cd1aeSAssar Westerlund break; 2895e9cd1aeSAssar Westerlund } 2905e9cd1aeSAssar Westerlund case T_SIG : { 2915e9cd1aeSAssar Westerlund size_t sig_len; 2925e9cd1aeSAssar Westerlund 293*8373020dSJacques Vidrine status = dn_expand (data, end_data, p + 18, host, sizeof(host)); 2945e9cd1aeSAssar Westerlund if (status < 0) { 2955e9cd1aeSAssar Westerlund dns_free_data (r); 2965e9cd1aeSAssar Westerlund return NULL; 2975e9cd1aeSAssar Westerlund } 298*8373020dSJacques Vidrine if (status + 18 > size) { 299*8373020dSJacques Vidrine dns_free_data(r); 300*8373020dSJacques Vidrine return NULL; 301*8373020dSJacques Vidrine } 302*8373020dSJacques Vidrine 3035e9cd1aeSAssar Westerlund sig_len = len - 18 - status; 3045e9cd1aeSAssar Westerlund (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig) 3055e9cd1aeSAssar Westerlund + strlen(host) + sig_len); 3065e9cd1aeSAssar Westerlund if ((*rr)->u.sig == NULL) { 3075e9cd1aeSAssar Westerlund dns_free_data (r); 3085e9cd1aeSAssar Westerlund return NULL; 3095e9cd1aeSAssar Westerlund } 3105e9cd1aeSAssar Westerlund (*rr)->u.sig->type = (p[0] << 8) | p[1]; 3115e9cd1aeSAssar Westerlund (*rr)->u.sig->algorithm = p[2]; 3125e9cd1aeSAssar Westerlund (*rr)->u.sig->labels = p[3]; 3135e9cd1aeSAssar Westerlund (*rr)->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16) 3145e9cd1aeSAssar Westerlund | (p[6] << 8) | p[7]; 3155e9cd1aeSAssar Westerlund (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16) 3165e9cd1aeSAssar Westerlund | (p[10] << 8) | p[11]; 3175e9cd1aeSAssar Westerlund (*rr)->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16) 3185e9cd1aeSAssar Westerlund | (p[14] << 8) | p[15]; 3195e9cd1aeSAssar Westerlund (*rr)->u.sig->key_tag = (p[16] << 8) | p[17]; 3205e9cd1aeSAssar Westerlund (*rr)->u.sig->sig_len = sig_len; 3215e9cd1aeSAssar Westerlund memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len); 3225e9cd1aeSAssar Westerlund (*rr)->u.sig->signer = &(*rr)->u.sig->sig_data[sig_len]; 3235e9cd1aeSAssar Westerlund strcpy((*rr)->u.sig->signer, host); 3245e9cd1aeSAssar Westerlund break; 3255e9cd1aeSAssar Westerlund } 3265e9cd1aeSAssar Westerlund 3275e9cd1aeSAssar Westerlund case T_CERT : { 3285e9cd1aeSAssar Westerlund size_t cert_len; 3295e9cd1aeSAssar Westerlund 330*8373020dSJacques Vidrine if (size < 5) { 331*8373020dSJacques Vidrine dns_free_data(r); 332*8373020dSJacques Vidrine return NULL; 333*8373020dSJacques Vidrine } 334*8373020dSJacques Vidrine 3355e9cd1aeSAssar Westerlund cert_len = size - 5; 3365e9cd1aeSAssar Westerlund (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1); 3375e9cd1aeSAssar Westerlund if ((*rr)->u.cert == NULL) { 3385e9cd1aeSAssar Westerlund dns_free_data (r); 3395e9cd1aeSAssar Westerlund return NULL; 3405e9cd1aeSAssar Westerlund } 3415e9cd1aeSAssar Westerlund 3425e9cd1aeSAssar Westerlund (*rr)->u.cert->type = (p[0] << 8) | p[1]; 3435e9cd1aeSAssar Westerlund (*rr)->u.cert->tag = (p[2] << 8) | p[3]; 3445e9cd1aeSAssar Westerlund (*rr)->u.cert->algorithm = p[4]; 3455e9cd1aeSAssar Westerlund (*rr)->u.cert->cert_len = cert_len; 3465e9cd1aeSAssar Westerlund memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len); 3475e9cd1aeSAssar Westerlund break; 3485e9cd1aeSAssar Westerlund } 349b528cefcSMark Murray default: 350b528cefcSMark Murray (*rr)->u.data = (unsigned char*)malloc(size); 351b528cefcSMark Murray if(size != 0 && (*rr)->u.data == NULL) { 352b528cefcSMark Murray dns_free_data(r); 353b528cefcSMark Murray return NULL; 354b528cefcSMark Murray } 355b528cefcSMark Murray memcpy((*rr)->u.data, p, size); 356b528cefcSMark Murray } 357b528cefcSMark Murray p += size; 358b528cefcSMark Murray rr = &(*rr)->next; 359b528cefcSMark Murray } 360b528cefcSMark Murray *rr = NULL; 361b528cefcSMark Murray return r; 362b528cefcSMark Murray } 363b528cefcSMark Murray 364b528cefcSMark Murray static struct dns_reply * 365b528cefcSMark Murray dns_lookup_int(const char *domain, int rr_class, int rr_type) 366b528cefcSMark Murray { 367b528cefcSMark Murray unsigned char reply[1024]; 368b528cefcSMark Murray int len; 369*8373020dSJacques Vidrine #ifdef HAVE__RES 370b528cefcSMark Murray u_long old_options = 0; 371*8373020dSJacques Vidrine #endif 372b528cefcSMark Murray 373b528cefcSMark Murray if (_resolve_debug) { 374*8373020dSJacques Vidrine #ifdef HAVE__RES 375b528cefcSMark Murray old_options = _res.options; 376b528cefcSMark Murray _res.options |= RES_DEBUG; 377*8373020dSJacques Vidrine #endif 378b528cefcSMark Murray fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain, 3795e9cd1aeSAssar Westerlund rr_class, dns_type_to_string(rr_type)); 380b528cefcSMark Murray } 381b528cefcSMark Murray len = res_search(domain, rr_class, rr_type, reply, sizeof(reply)); 382b528cefcSMark Murray if (_resolve_debug) { 383*8373020dSJacques Vidrine #ifdef HAVE__RES 384b528cefcSMark Murray _res.options = old_options; 385*8373020dSJacques Vidrine #endif 386b528cefcSMark Murray fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 3875e9cd1aeSAssar Westerlund domain, rr_class, dns_type_to_string(rr_type), len); 388b528cefcSMark Murray } 389*8373020dSJacques Vidrine if(len < 0) { 390*8373020dSJacques Vidrine return NULL; 391*8373020dSJacques Vidrine } else { 392*8373020dSJacques Vidrine len = min(len, sizeof(reply)); 393*8373020dSJacques Vidrine return parse_reply(reply, len); 394*8373020dSJacques Vidrine } 395b528cefcSMark Murray } 396b528cefcSMark Murray 397b528cefcSMark Murray struct dns_reply * 398b528cefcSMark Murray dns_lookup(const char *domain, const char *type_name) 399b528cefcSMark Murray { 400b528cefcSMark Murray int type; 401b528cefcSMark Murray 4025e9cd1aeSAssar Westerlund type = dns_string_to_type(type_name); 403b528cefcSMark Murray if(type == -1) { 404b528cefcSMark Murray if(_resolve_debug) 405b528cefcSMark Murray fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 406b528cefcSMark Murray type_name); 407b528cefcSMark Murray return NULL; 408b528cefcSMark Murray } 409b528cefcSMark Murray return dns_lookup_int(domain, C_IN, type); 410b528cefcSMark Murray } 411b528cefcSMark Murray 4124137ff4cSJacques Vidrine static int 4134137ff4cSJacques Vidrine compare_srv(const void *a, const void *b) 4144137ff4cSJacques Vidrine { 4154137ff4cSJacques Vidrine const struct resource_record *const* aa = a, *const* bb = b; 4164137ff4cSJacques Vidrine 4174137ff4cSJacques Vidrine if((*aa)->u.srv->priority == (*bb)->u.srv->priority) 4184137ff4cSJacques Vidrine return ((*aa)->u.srv->weight - (*bb)->u.srv->weight); 4194137ff4cSJacques Vidrine return ((*aa)->u.srv->priority - (*bb)->u.srv->priority); 4204137ff4cSJacques Vidrine } 4214137ff4cSJacques Vidrine 4224137ff4cSJacques Vidrine #ifndef HAVE_RANDOM 4234137ff4cSJacques Vidrine #define random() rand() 4244137ff4cSJacques Vidrine #endif 4254137ff4cSJacques Vidrine 4264137ff4cSJacques Vidrine /* try to rearrange the srv-records by the algorithm in RFC2782 */ 4274137ff4cSJacques Vidrine void 4284137ff4cSJacques Vidrine dns_srv_order(struct dns_reply *r) 4294137ff4cSJacques Vidrine { 4304137ff4cSJacques Vidrine struct resource_record **srvs, **ss, **headp; 4314137ff4cSJacques Vidrine struct resource_record *rr; 4324137ff4cSJacques Vidrine int num_srv = 0; 4334137ff4cSJacques Vidrine 4344137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 435*8373020dSJacques Vidrine int state[256 / sizeof(int)]; 436*8373020dSJacques Vidrine char *oldstate; 4374137ff4cSJacques Vidrine #endif 4384137ff4cSJacques Vidrine 4394137ff4cSJacques Vidrine for(rr = r->head; rr; rr = rr->next) 4404137ff4cSJacques Vidrine if(rr->type == T_SRV) 4414137ff4cSJacques Vidrine num_srv++; 4424137ff4cSJacques Vidrine 4434137ff4cSJacques Vidrine if(num_srv == 0) 4444137ff4cSJacques Vidrine return; 4454137ff4cSJacques Vidrine 4464137ff4cSJacques Vidrine srvs = malloc(num_srv * sizeof(*srvs)); 4474137ff4cSJacques Vidrine if(srvs == NULL) 4484137ff4cSJacques Vidrine return; /* XXX not much to do here */ 4494137ff4cSJacques Vidrine 4504137ff4cSJacques Vidrine /* unlink all srv-records from the linked list and put them in 4514137ff4cSJacques Vidrine a vector */ 4524137ff4cSJacques Vidrine for(ss = srvs, headp = &r->head; *headp; ) 4534137ff4cSJacques Vidrine if((*headp)->type == T_SRV) { 4544137ff4cSJacques Vidrine *ss = *headp; 4554137ff4cSJacques Vidrine *headp = (*headp)->next; 4564137ff4cSJacques Vidrine (*ss)->next = NULL; 4574137ff4cSJacques Vidrine ss++; 4584137ff4cSJacques Vidrine } else 4594137ff4cSJacques Vidrine headp = &(*headp)->next; 4604137ff4cSJacques Vidrine 4614137ff4cSJacques Vidrine /* sort them by priority and weight */ 4624137ff4cSJacques Vidrine qsort(srvs, num_srv, sizeof(*srvs), compare_srv); 4634137ff4cSJacques Vidrine 4644137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 465*8373020dSJacques Vidrine oldstate = initstate(time(NULL), (char*)state, sizeof(state)); 4664137ff4cSJacques Vidrine #endif 4674137ff4cSJacques Vidrine 4684137ff4cSJacques Vidrine headp = &r->head; 4694137ff4cSJacques Vidrine 4704137ff4cSJacques Vidrine for(ss = srvs; ss < srvs + num_srv; ) { 4714137ff4cSJacques Vidrine int sum, rnd, count; 4724137ff4cSJacques Vidrine struct resource_record **ee, **tt; 4734137ff4cSJacques Vidrine /* find the last record with the same priority and count the 4744137ff4cSJacques Vidrine sum of all weights */ 4754137ff4cSJacques Vidrine for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) { 4764137ff4cSJacques Vidrine if(*tt == NULL) 4774137ff4cSJacques Vidrine continue; 4784137ff4cSJacques Vidrine if((*tt)->u.srv->priority != (*ss)->u.srv->priority) 4794137ff4cSJacques Vidrine break; 4804137ff4cSJacques Vidrine sum += (*tt)->u.srv->weight; 4814137ff4cSJacques Vidrine } 4824137ff4cSJacques Vidrine ee = tt; 4834137ff4cSJacques Vidrine /* ss is now the first record of this priority and ee is the 4844137ff4cSJacques Vidrine first of the next */ 4854137ff4cSJacques Vidrine while(ss < ee) { 4864137ff4cSJacques Vidrine rnd = random() % (sum + 1); 4874137ff4cSJacques Vidrine for(count = 0, tt = ss; ; tt++) { 4884137ff4cSJacques Vidrine if(*tt == NULL) 4894137ff4cSJacques Vidrine continue; 4904137ff4cSJacques Vidrine count += (*tt)->u.srv->weight; 4914137ff4cSJacques Vidrine if(count >= rnd) 4924137ff4cSJacques Vidrine break; 4934137ff4cSJacques Vidrine } 4944137ff4cSJacques Vidrine 4954137ff4cSJacques Vidrine assert(tt < ee); 4964137ff4cSJacques Vidrine 4974137ff4cSJacques Vidrine /* insert the selected record at the tail (of the head) of 4984137ff4cSJacques Vidrine the list */ 4994137ff4cSJacques Vidrine (*tt)->next = *headp; 5004137ff4cSJacques Vidrine *headp = *tt; 5014137ff4cSJacques Vidrine headp = &(*tt)->next; 5024137ff4cSJacques Vidrine sum -= (*tt)->u.srv->weight; 5034137ff4cSJacques Vidrine *tt = NULL; 5044137ff4cSJacques Vidrine while(ss < ee && *ss == NULL) 5054137ff4cSJacques Vidrine ss++; 5064137ff4cSJacques Vidrine } 5074137ff4cSJacques Vidrine } 5084137ff4cSJacques Vidrine 5094137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE) 5104137ff4cSJacques Vidrine setstate(oldstate); 5114137ff4cSJacques Vidrine #endif 5124137ff4cSJacques Vidrine free(srvs); 5134137ff4cSJacques Vidrine return; 5144137ff4cSJacques Vidrine } 5154137ff4cSJacques Vidrine 516b528cefcSMark Murray #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 517b528cefcSMark Murray 518b528cefcSMark Murray struct dns_reply * 519b528cefcSMark Murray dns_lookup(const char *domain, const char *type_name) 520b528cefcSMark Murray { 521b528cefcSMark Murray return NULL; 522b528cefcSMark Murray } 523b528cefcSMark Murray 524b528cefcSMark Murray void 525b528cefcSMark Murray dns_free_data(struct dns_reply *r) 526b528cefcSMark Murray { 527b528cefcSMark Murray } 528b528cefcSMark Murray 5294137ff4cSJacques Vidrine void 5304137ff4cSJacques Vidrine dns_srv_order(struct dns_reply *r) 5314137ff4cSJacques Vidrine { 5324137ff4cSJacques Vidrine } 5334137ff4cSJacques Vidrine 534b528cefcSMark Murray #endif 535b528cefcSMark Murray 536b528cefcSMark Murray #ifdef TEST 537b528cefcSMark Murray int 538b528cefcSMark Murray main(int argc, char **argv) 539b528cefcSMark Murray { 540b528cefcSMark Murray struct dns_reply *r; 541b528cefcSMark Murray struct resource_record *rr; 542b528cefcSMark Murray r = dns_lookup(argv[1], argv[2]); 543b528cefcSMark Murray if(r == NULL){ 544b528cefcSMark Murray printf("No reply.\n"); 545b528cefcSMark Murray return 1; 546b528cefcSMark Murray } 5474137ff4cSJacques Vidrine if(r->q.type == T_SRV) 5484137ff4cSJacques Vidrine dns_srv_order(r); 5494137ff4cSJacques Vidrine 550b528cefcSMark Murray for(rr = r->head; rr;rr=rr->next){ 5515e9cd1aeSAssar Westerlund printf("%s %s %d ", rr->domain, dns_type_to_string(rr->type), rr->ttl); 552b528cefcSMark Murray switch(rr->type){ 553b528cefcSMark Murray case T_NS: 5545e9cd1aeSAssar Westerlund case T_CNAME: 5555e9cd1aeSAssar Westerlund case T_PTR: 556b528cefcSMark Murray printf("%s\n", (char*)rr->u.data); 557b528cefcSMark Murray break; 558b528cefcSMark Murray case T_A: 5595e9cd1aeSAssar Westerlund printf("%s\n", inet_ntoa(*rr->u.a)); 560b528cefcSMark Murray break; 561b528cefcSMark Murray case T_MX: 562b528cefcSMark Murray case T_AFSDB:{ 5635e9cd1aeSAssar Westerlund printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain); 564b528cefcSMark Murray break; 565b528cefcSMark Murray } 566b528cefcSMark Murray case T_SRV:{ 5675e9cd1aeSAssar Westerlund struct srv_record *srv = rr->u.srv; 568b528cefcSMark Murray printf("%d %d %d %s\n", srv->priority, srv->weight, 569b528cefcSMark Murray srv->port, srv->target); 570b528cefcSMark Murray break; 571b528cefcSMark Murray } 5725e9cd1aeSAssar Westerlund case T_TXT: { 5735e9cd1aeSAssar Westerlund printf("%s\n", rr->u.txt); 5745e9cd1aeSAssar Westerlund break; 5755e9cd1aeSAssar Westerlund } 5765e9cd1aeSAssar Westerlund case T_SIG : { 5775e9cd1aeSAssar Westerlund struct sig_record *sig = rr->u.sig; 5785e9cd1aeSAssar Westerlund const char *type_string = dns_type_to_string (sig->type); 5795e9cd1aeSAssar Westerlund 5805e9cd1aeSAssar Westerlund printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n", 5815e9cd1aeSAssar Westerlund sig->type, type_string ? type_string : "", 5825e9cd1aeSAssar Westerlund sig->algorithm, sig->labels, sig->orig_ttl, 5835e9cd1aeSAssar Westerlund sig->sig_expiration, sig->sig_inception, sig->key_tag, 5845e9cd1aeSAssar Westerlund sig->signer); 5855e9cd1aeSAssar Westerlund break; 5865e9cd1aeSAssar Westerlund } 5875e9cd1aeSAssar Westerlund case T_KEY : { 5885e9cd1aeSAssar Westerlund struct key_record *key = rr->u.key; 5895e9cd1aeSAssar Westerlund 5905e9cd1aeSAssar Westerlund printf ("flags %u, protocol %u, algorithm %u\n", 5915e9cd1aeSAssar Westerlund key->flags, key->protocol, key->algorithm); 5925e9cd1aeSAssar Westerlund break; 5935e9cd1aeSAssar Westerlund } 594b528cefcSMark Murray default: 595b528cefcSMark Murray printf("\n"); 596b528cefcSMark Murray break; 597b528cefcSMark Murray } 598b528cefcSMark Murray } 599b528cefcSMark Murray 600b528cefcSMark Murray return 0; 601b528cefcSMark Murray } 602b528cefcSMark Murray #endif 603