1 /* 2 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> 36 #endif 37 #include "roken.h" 38 #ifdef HAVE_ARPA_NAMESER_H 39 #include <arpa/nameser.h> 40 #endif 41 #ifdef HAVE_RESOLV_H 42 #include <resolv.h> 43 #endif 44 #include "resolve.h" 45 46 RCSID("$Id: resolve.c,v 1.22 1999/12/02 16:58:52 joda Exp $"); 47 48 #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) 49 50 #define DECL(X) {#X, T_##X} 51 52 static struct stot{ 53 const char *name; 54 int type; 55 }stot[] = { 56 DECL(A), 57 DECL(NS), 58 DECL(CNAME), 59 DECL(PTR), 60 DECL(MX), 61 DECL(TXT), 62 DECL(AFSDB), 63 DECL(SRV), 64 {NULL, 0} 65 }; 66 67 int _resolve_debug; 68 69 static int 70 string_to_type(const char *name) 71 { 72 struct stot *p = stot; 73 for(p = stot; p->name; p++) 74 if(strcasecmp(name, p->name) == 0) 75 return p->type; 76 return -1; 77 } 78 79 static const char * 80 type_to_string(int type) 81 { 82 struct stot *p = stot; 83 for(p = stot; p->name; p++) 84 if(type == p->type) 85 return p->name; 86 return NULL; 87 } 88 89 void 90 dns_free_data(struct dns_reply *r) 91 { 92 struct resource_record *rr; 93 if(r->q.domain) 94 free(r->q.domain); 95 for(rr = r->head; rr;){ 96 struct resource_record *tmp = rr; 97 if(rr->domain) 98 free(rr->domain); 99 if(rr->u.data) 100 free(rr->u.data); 101 rr = rr->next; 102 free(tmp); 103 } 104 free (r); 105 } 106 107 static struct dns_reply* 108 parse_reply(unsigned char *data, int len) 109 { 110 unsigned char *p; 111 char host[128]; 112 int status; 113 114 struct dns_reply *r; 115 struct resource_record **rr; 116 117 r = calloc(1, sizeof(*r)); 118 if (r == NULL) 119 return NULL; 120 121 p = data; 122 #if 0 123 /* doesn't work on Crays */ 124 memcpy(&r->h, p, sizeof(HEADER)); 125 p += sizeof(HEADER); 126 #else 127 memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */ 128 p += 12; 129 #endif 130 status = dn_expand(data, data + len, p, host, sizeof(host)); 131 if(status < 0){ 132 dns_free_data(r); 133 return NULL; 134 } 135 r->q.domain = strdup(host); 136 if(r->q.domain == NULL) { 137 dns_free_data(r); 138 return NULL; 139 } 140 p += status; 141 r->q.type = (p[0] << 8 | p[1]); 142 p += 2; 143 r->q.class = (p[0] << 8 | p[1]); 144 p += 2; 145 rr = &r->head; 146 while(p < data + len){ 147 int type, class, ttl, size; 148 status = dn_expand(data, data + len, p, host, sizeof(host)); 149 if(status < 0){ 150 dns_free_data(r); 151 return NULL; 152 } 153 p += status; 154 type = (p[0] << 8) | p[1]; 155 p += 2; 156 class = (p[0] << 8) | p[1]; 157 p += 2; 158 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 159 p += 4; 160 size = (p[0] << 8) | p[1]; 161 p += 2; 162 *rr = (struct resource_record*)calloc(1, 163 sizeof(struct resource_record)); 164 if(*rr == NULL) { 165 dns_free_data(r); 166 return NULL; 167 } 168 (*rr)->domain = strdup(host); 169 if((*rr)->domain == NULL) { 170 dns_free_data(r); 171 return NULL; 172 } 173 (*rr)->type = type; 174 (*rr)->class = class; 175 (*rr)->ttl = ttl; 176 (*rr)->size = size; 177 switch(type){ 178 case T_NS: 179 case T_CNAME: 180 case T_PTR: 181 status = dn_expand(data, data + len, p, host, sizeof(host)); 182 if(status < 0){ 183 dns_free_data(r); 184 return NULL; 185 } 186 (*rr)->u.txt = strdup(host); 187 if((*rr)->u.txt == NULL) { 188 dns_free_data(r); 189 return NULL; 190 } 191 break; 192 case T_MX: 193 case T_AFSDB:{ 194 status = dn_expand(data, data + len, p + 2, host, sizeof(host)); 195 if(status < 0){ 196 dns_free_data(r); 197 return NULL; 198 } 199 (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) + 200 strlen(host)); 201 if((*rr)->u.mx == NULL) { 202 dns_free_data(r); 203 return NULL; 204 } 205 (*rr)->u.mx->preference = (p[0] << 8) | p[1]; 206 strcpy((*rr)->u.mx->domain, host); 207 break; 208 } 209 case T_SRV:{ 210 status = dn_expand(data, data + len, p + 6, host, sizeof(host)); 211 if(status < 0){ 212 dns_free_data(r); 213 return NULL; 214 } 215 (*rr)->u.srv = 216 (struct srv_record*)malloc(sizeof(struct srv_record) + 217 strlen(host)); 218 if((*rr)->u.srv == NULL) { 219 dns_free_data(r); 220 return NULL; 221 } 222 (*rr)->u.srv->priority = (p[0] << 8) | p[1]; 223 (*rr)->u.srv->weight = (p[2] << 8) | p[3]; 224 (*rr)->u.srv->port = (p[4] << 8) | p[5]; 225 strcpy((*rr)->u.srv->target, host); 226 break; 227 } 228 case T_TXT:{ 229 (*rr)->u.txt = (char*)malloc(size + 1); 230 if((*rr)->u.txt == NULL) { 231 dns_free_data(r); 232 return NULL; 233 } 234 strncpy((*rr)->u.txt, (char*)p + 1, *p); 235 (*rr)->u.txt[*p] = 0; 236 break; 237 } 238 239 default: 240 (*rr)->u.data = (unsigned char*)malloc(size); 241 if(size != 0 && (*rr)->u.data == NULL) { 242 dns_free_data(r); 243 return NULL; 244 } 245 memcpy((*rr)->u.data, p, size); 246 } 247 p += size; 248 rr = &(*rr)->next; 249 } 250 *rr = NULL; 251 return r; 252 } 253 254 static struct dns_reply * 255 dns_lookup_int(const char *domain, int rr_class, int rr_type) 256 { 257 unsigned char reply[1024]; 258 int len; 259 struct dns_reply *r = NULL; 260 u_long old_options = 0; 261 262 if (_resolve_debug) { 263 old_options = _res.options; 264 _res.options |= RES_DEBUG; 265 fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain, 266 rr_class, type_to_string(rr_type)); 267 } 268 len = res_search(domain, rr_class, rr_type, reply, sizeof(reply)); 269 if (_resolve_debug) { 270 _res.options = old_options; 271 fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n", 272 domain, rr_class, type_to_string(rr_type), len); 273 } 274 if (len >= 0) 275 r = parse_reply(reply, len); 276 return r; 277 } 278 279 struct dns_reply * 280 dns_lookup(const char *domain, const char *type_name) 281 { 282 int type; 283 284 type = string_to_type(type_name); 285 if(type == -1) { 286 if(_resolve_debug) 287 fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n", 288 type_name); 289 return NULL; 290 } 291 return dns_lookup_int(domain, C_IN, type); 292 } 293 294 #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */ 295 296 struct dns_reply * 297 dns_lookup(const char *domain, const char *type_name) 298 { 299 return NULL; 300 } 301 302 void 303 dns_free_data(struct dns_reply *r) 304 { 305 } 306 307 #endif 308 309 #ifdef TEST 310 int 311 main(int argc, char **argv) 312 { 313 struct dns_reply *r; 314 struct resource_record *rr; 315 r = dns_lookup(argv[1], argv[2]); 316 if(r == NULL){ 317 printf("No reply.\n"); 318 return 1; 319 } 320 for(rr = r->head; rr;rr=rr->next){ 321 printf("%s %s %d ", rr->domain, type_to_string(rr->type), rr->ttl); 322 switch(rr->type){ 323 case T_NS: 324 printf("%s\n", (char*)rr->u.data); 325 break; 326 case T_A: 327 printf("%d.%d.%d.%d\n", 328 ((unsigned char*)rr->u.data)[0], 329 ((unsigned char*)rr->u.data)[1], 330 ((unsigned char*)rr->u.data)[2], 331 ((unsigned char*)rr->u.data)[3]); 332 break; 333 case T_MX: 334 case T_AFSDB:{ 335 struct mx_record *mx = (struct mx_record*)rr->u.data; 336 printf("%d %s\n", mx->preference, mx->domain); 337 break; 338 } 339 case T_SRV:{ 340 struct srv_record *srv = (struct srv_record*)rr->u.data; 341 printf("%d %d %d %s\n", srv->priority, srv->weight, 342 srv->port, srv->target); 343 break; 344 } 345 default: 346 printf("\n"); 347 break; 348 } 349 } 350 351 return 0; 352 } 353 #endif 354