1 /* $NetBSD: dns_rr.c,v 1.1.1.1 2009/06/23 10:08:43 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dns_rr 3 6 /* SUMMARY 7 /* resource record memory and list management 8 /* SYNOPSIS 9 /* #include <dns.h> 10 /* 11 /* DNS_RR *dns_rr_create(qname, rname, type, class, ttl, preference, 12 /* data, data_len) 13 /* const char *qname; 14 /* const char *rname; 15 /* unsigned short type; 16 /* unsigned short class; 17 /* unsigned int ttl; 18 /* unsigned preference; 19 /* const char *data; 20 /* size_t data_len; 21 /* 22 /* void dns_rr_free(list) 23 /* DNS_RR *list; 24 /* 25 /* DNS_RR *dns_rr_copy(record) 26 /* DNS_RR *record; 27 /* 28 /* DNS_RR *dns_rr_append(list, record) 29 /* DNS_RR *list; 30 /* DNS_RR *record; 31 /* 32 /* DNS_RR *dns_rr_sort(list, compar) 33 /* DNS_RR *list 34 /* int (*compar)(DNS_RR *, DNS_RR *); 35 /* 36 /* int dns_rr_compare_pref(DNS_RR *a, DNS_RR *b) 37 /* DNS_RR *list 38 /* DNS_RR *list 39 /* 40 /* DNS_RR *dns_rr_shuffle(list) 41 /* DNS_RR *list; 42 /* 43 /* DNS_RR *dns_rr_remove(list, record) 44 /* DNS_RR *list; 45 /* DNS_RR *record; 46 /* DESCRIPTION 47 /* The routines in this module maintain memory for DNS resource record 48 /* information, and maintain lists of DNS resource records. 49 /* 50 /* dns_rr_create() creates and initializes one resource record. 51 /* The \fIqname\fR field specifies the query name. 52 /* The \fIrname\fR field specifies the reply name. 53 /* \fIpreference\fR is used for MX records; \fIdata\fR is a null 54 /* pointer or specifies optional resource-specific data; 55 /* \fIdata_len\fR is the amount of resource-specific data. 56 /* 57 /* dns_rr_free() releases the resource used by of zero or more 58 /* resource records. 59 /* 60 /* dns_rr_copy() makes a copy of a resource record. 61 /* 62 /* dns_rr_append() appends a resource record to a (list of) resource 63 /* record(s). 64 /* A null input list is explicitly allowed. 65 /* 66 /* dns_rr_sort() sorts a list of resource records into ascending 67 /* order according to a user-specified criterion. The result is the 68 /* sorted list. 69 /* 70 /* dns_rr_compare_pref() is a dns_rr_sort() helper to sort records 71 /* by their MX preference. 72 /* 73 /* dns_rr_shuffle() randomly permutes a list of resource records. 74 /* 75 /* dns_rr_remove() removes the specified record from the specified list. 76 /* The updated list is the result value. 77 /* The record MUST be a list member. 78 /* LICENSE 79 /* .ad 80 /* .fi 81 /* The Secure Mailer license must be distributed with this software. 82 /* AUTHOR(S) 83 /* Wietse Venema 84 /* IBM T.J. Watson Research 85 /* P.O. Box 704 86 /* Yorktown Heights, NY 10598, USA 87 /*--*/ 88 89 /* System library. */ 90 91 #include <sys_defs.h> 92 #include <string.h> 93 #include <stdlib.h> 94 95 /* Utility library. */ 96 97 #include <msg.h> 98 #include <mymalloc.h> 99 #include <myrand.h> 100 101 /* DNS library. */ 102 103 #include "dns.h" 104 105 /* dns_rr_create - fill in resource record structure */ 106 107 DNS_RR *dns_rr_create(const char *qname, const char *rname, 108 ushort type, ushort class, 109 unsigned int ttl, unsigned pref, 110 const char *data, size_t data_len) 111 { 112 DNS_RR *rr; 113 114 rr = (DNS_RR *) mymalloc(sizeof(*rr) + data_len - 1); 115 rr->qname = mystrdup(qname); 116 rr->rname = mystrdup(rname); 117 rr->type = type; 118 rr->class = class; 119 rr->ttl = ttl; 120 rr->pref = pref; 121 if (data && data_len > 0) 122 memcpy(rr->data, data, data_len); 123 rr->data_len = data_len; 124 rr->next = 0; 125 return (rr); 126 } 127 128 /* dns_rr_free - destroy resource record structure */ 129 130 void dns_rr_free(DNS_RR *rr) 131 { 132 if (rr) { 133 if (rr->next) 134 dns_rr_free(rr->next); 135 myfree(rr->qname); 136 myfree(rr->rname); 137 myfree((char *) rr); 138 } 139 } 140 141 /* dns_rr_copy - copy resource record */ 142 143 DNS_RR *dns_rr_copy(DNS_RR *src) 144 { 145 ssize_t len = sizeof(*src) + src->data_len - 1; 146 DNS_RR *dst; 147 148 /* 149 * Combine struct assignment and data copy in one block copy operation. 150 */ 151 dst = (DNS_RR *) mymalloc(len); 152 memcpy((char *) dst, (char *) src, len); 153 dst->qname = mystrdup(src->qname); 154 dst->rname = mystrdup(src->rname); 155 dst->next = 0; 156 return (dst); 157 } 158 159 /* dns_rr_append - append resource record to list */ 160 161 DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr) 162 { 163 if (list == 0) { 164 list = rr; 165 } else { 166 list->next = dns_rr_append(list->next, rr); 167 } 168 return (list); 169 } 170 171 /* dns_rr_compare_pref - compare resource records by preference */ 172 173 int dns_rr_compare_pref(DNS_RR *a, DNS_RR *b) 174 { 175 if (a->pref != b->pref) 176 return (a->pref - b->pref); 177 #ifdef HAS_IPV6 178 if (a->type == b->type) /* 200412 */ 179 return 0; 180 if (a->type == T_AAAA) 181 return (-1); 182 if (b->type == T_AAAA) 183 return (+1); 184 #endif 185 return 0; 186 } 187 188 /* dns_rr_sort_callback - glue function */ 189 190 static int (*dns_rr_sort_user) (DNS_RR *, DNS_RR *); 191 192 static int dns_rr_sort_callback(const void *a, const void *b) 193 { 194 DNS_RR *aa = *(DNS_RR **) a; 195 DNS_RR *bb = *(DNS_RR **) b; 196 197 return (dns_rr_sort_user(aa, bb)); 198 } 199 200 /* dns_rr_sort - sort resource record list */ 201 202 DNS_RR *dns_rr_sort(DNS_RR *list, int (*compar) (DNS_RR *, DNS_RR *)) 203 { 204 int (*saved_user) (DNS_RR *, DNS_RR *); 205 DNS_RR **rr_array; 206 DNS_RR *rr; 207 int len; 208 int i; 209 210 /* 211 * Save state and initialize. 212 */ 213 saved_user = dns_rr_sort_user; 214 dns_rr_sort_user = compar; 215 216 /* 217 * Build linear array with pointers to each list element. 218 */ 219 for (len = 0, rr = list; rr != 0; len++, rr = rr->next) 220 /* void */ ; 221 rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array)); 222 for (len = 0, rr = list; rr != 0; len++, rr = rr->next) 223 rr_array[len] = rr; 224 225 /* 226 * Sort by user-specified criterion. 227 */ 228 qsort((char *) rr_array, len, sizeof(*rr_array), dns_rr_sort_callback); 229 230 /* 231 * Fix the links. 232 */ 233 for (i = 0; i < len - 1; i++) 234 rr_array[i]->next = rr_array[i + 1]; 235 rr_array[i]->next = 0; 236 list = rr_array[0]; 237 238 /* 239 * Cleanup. 240 */ 241 myfree((char *) rr_array); 242 dns_rr_sort_user = saved_user; 243 return (list); 244 } 245 246 /* dns_rr_shuffle - shuffle resource record list */ 247 248 DNS_RR *dns_rr_shuffle(DNS_RR *list) 249 { 250 DNS_RR **rr_array; 251 DNS_RR *rr; 252 int len; 253 int i; 254 int r; 255 256 /* 257 * Build linear array with pointers to each list element. 258 */ 259 for (len = 0, rr = list; rr != 0; len++, rr = rr->next) 260 /* void */ ; 261 rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array)); 262 for (len = 0, rr = list; rr != 0; len++, rr = rr->next) 263 rr_array[len] = rr; 264 265 /* 266 * Shuffle resource records. 267 */ 268 for (i = 0; i < len; i++) { 269 r = myrand() % len; 270 rr = rr_array[i]; 271 rr_array[i] = rr_array[r]; 272 rr_array[r] = rr; 273 } 274 275 /* 276 * Fix the links. 277 */ 278 for (i = 0; i < len - 1; i++) 279 rr_array[i]->next = rr_array[i + 1]; 280 rr_array[i]->next = 0; 281 list = rr_array[0]; 282 283 /* 284 * Cleanup. 285 */ 286 myfree((char *) rr_array); 287 return (list); 288 } 289 290 /* dns_rr_remove - remove record from list, return new list */ 291 292 DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record) 293 { 294 if (list == 0) 295 msg_panic("dns_rr_remove: record not found"); 296 297 if (list == record) { 298 list = record->next; 299 record->next = 0; 300 dns_rr_free(record); 301 } else { 302 list->next = dns_rr_remove(list->next, record); 303 } 304 return (list); 305 } 306