| 1 | /*
 | 
|---|
| 2 |   Linux DNS client library implementation
 | 
|---|
| 3 |   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
 | 
|---|
| 4 | 
 | 
|---|
| 5 |      ** NOTE! The following LGPL license applies to the libaddns
 | 
|---|
| 6 |      ** library. This does NOT imply that all of Samba is released
 | 
|---|
| 7 |      ** under the LGPL
 | 
|---|
| 8 | 
 | 
|---|
| 9 |   This library is free software; you can redistribute it and/or
 | 
|---|
| 10 |   modify it under the terms of the GNU Lesser General Public
 | 
|---|
| 11 |   License as published by the Free Software Foundation; either
 | 
|---|
| 12 |   version 2.1 of the License, or (at your option) any later version.
 | 
|---|
| 13 | 
 | 
|---|
| 14 |   This library is distributed in the hope that it will be useful,
 | 
|---|
| 15 |   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 16 |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
|---|
| 17 |   Lesser General Public License for more details.
 | 
|---|
| 18 | 
 | 
|---|
| 19 |   You should have received a copy of the GNU Lesser General Public
 | 
|---|
| 20 |   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 21 | */
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #include "dns.h"
 | 
|---|
| 24 | #include "assert.h"
 | 
|---|
| 25 | 
 | 
|---|
| 26 | struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
 | 
|---|
| 27 | {
 | 
|---|
| 28 |         struct dns_buffer *result;
 | 
|---|
| 29 | 
 | 
|---|
| 30 |         if (!(result = talloc(mem_ctx, struct dns_buffer))) {
 | 
|---|
| 31 |                 return NULL;
 | 
|---|
| 32 |         }
 | 
|---|
| 33 | 
 | 
|---|
| 34 |         result->offset = 0;
 | 
|---|
| 35 |         result->error = ERROR_DNS_SUCCESS;
 | 
|---|
| 36 |         
 | 
|---|
| 37 |         /*
 | 
|---|
| 38 |          * Small inital size to excercise the realloc code
 | 
|---|
| 39 |          */
 | 
|---|
| 40 |         result->size = 2;
 | 
|---|
| 41 | 
 | 
|---|
| 42 |         if (!(result->data = TALLOC_ARRAY(result, uint8, result->size))) {
 | 
|---|
| 43 |                 TALLOC_FREE(result);
 | 
|---|
| 44 |                 return NULL;
 | 
|---|
| 45 |         }
 | 
|---|
| 46 | 
 | 
|---|
| 47 |         return result;
 | 
|---|
| 48 | }
 | 
|---|
| 49 | 
 | 
|---|
| 50 | void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
 | 
|---|
| 51 |                          size_t len)
 | 
|---|
| 52 | {
 | 
|---|
| 53 |         if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 54 | 
 | 
|---|
| 55 |         if (buf->offset + len < buf->offset) {
 | 
|---|
| 56 |                 /*
 | 
|---|
| 57 |                  * Wraparound!
 | 
|---|
| 58 |                  */
 | 
|---|
| 59 |                 buf->error = ERROR_DNS_INVALID_PARAMETER;
 | 
|---|
| 60 |                 return;
 | 
|---|
| 61 |         }
 | 
|---|
| 62 | 
 | 
|---|
| 63 |         if ((buf->offset + len) > 0xffff) {
 | 
|---|
| 64 |                 /*
 | 
|---|
| 65 |                  * Only 64k possible
 | 
|---|
| 66 |                  */
 | 
|---|
| 67 |                 buf->error = ERROR_DNS_INVALID_PARAMETER;
 | 
|---|
| 68 |                 return;
 | 
|---|
| 69 |         }
 | 
|---|
| 70 |                 
 | 
|---|
| 71 |         if (buf->offset + len > buf->size) {
 | 
|---|
| 72 |                 size_t new_size = buf->offset + len;
 | 
|---|
| 73 |                 uint8 *new_data;
 | 
|---|
| 74 | 
 | 
|---|
| 75 |                 /*
 | 
|---|
| 76 |                  * Don't do too many reallocs, round up to some multiple
 | 
|---|
| 77 |                  */
 | 
|---|
| 78 | 
 | 
|---|
| 79 |                 new_size += (64 - (new_size % 64));
 | 
|---|
| 80 | 
 | 
|---|
| 81 |                 if (!(new_data = TALLOC_REALLOC_ARRAY(buf, buf->data, uint8,
 | 
|---|
| 82 |                                                       new_size))) {
 | 
|---|
| 83 |                         buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 84 |                         return;
 | 
|---|
| 85 |                 }
 | 
|---|
| 86 | 
 | 
|---|
| 87 |                 buf->size = new_size;
 | 
|---|
| 88 |                 buf->data = new_data;
 | 
|---|
| 89 |         }
 | 
|---|
| 90 | 
 | 
|---|
| 91 |         memcpy(buf->data + buf->offset, data, len);
 | 
|---|
| 92 |         buf->offset += len;
 | 
|---|
| 93 |         return;
 | 
|---|
| 94 | }
 | 
|---|
| 95 | 
 | 
|---|
| 96 | void dns_marshall_uint16(struct dns_buffer *buf, uint16 val)
 | 
|---|
| 97 | {
 | 
|---|
| 98 |         uint16 n_val = htons(val);
 | 
|---|
| 99 |         dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
 | 
|---|
| 100 | }
 | 
|---|
| 101 | 
 | 
|---|
| 102 | void dns_marshall_uint32(struct dns_buffer *buf, uint32 val)
 | 
|---|
| 103 | {
 | 
|---|
| 104 |         uint32 n_val = htonl(val);
 | 
|---|
| 105 |         dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
 | 
|---|
| 106 | }
 | 
|---|
| 107 | 
 | 
|---|
| 108 | void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
 | 
|---|
| 109 |                            size_t len)
 | 
|---|
| 110 | {
 | 
|---|
| 111 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 112 | 
 | 
|---|
| 113 |         if ((len > buf->size) || (buf->offset + len > buf->size)) {
 | 
|---|
| 114 |                 buf->error = ERROR_DNS_INVALID_MESSAGE;
 | 
|---|
| 115 |                 return;
 | 
|---|
| 116 |         }
 | 
|---|
| 117 | 
 | 
|---|
| 118 |         memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
 | 
|---|
| 119 |         buf->offset += len;
 | 
|---|
| 120 | 
 | 
|---|
| 121 |         return;
 | 
|---|
| 122 | }
 | 
|---|
| 123 | 
 | 
|---|
| 124 | void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val)
 | 
|---|
| 125 | {
 | 
|---|
| 126 |         uint16 n_val;
 | 
|---|
| 127 | 
 | 
|---|
| 128 |         dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
 | 
|---|
| 129 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 130 | 
 | 
|---|
| 131 |         *val = ntohs(n_val);
 | 
|---|
| 132 | }
 | 
|---|
| 133 | 
 | 
|---|
| 134 | void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val)
 | 
|---|
| 135 | {
 | 
|---|
| 136 |         uint32 n_val;
 | 
|---|
| 137 | 
 | 
|---|
| 138 |         dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
 | 
|---|
| 139 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 140 | 
 | 
|---|
| 141 |         *val = ntohl(n_val);
 | 
|---|
| 142 | }
 | 
|---|
| 143 | 
 | 
|---|
| 144 | void dns_marshall_domain_name(struct dns_buffer *buf,
 | 
|---|
| 145 |                               const struct dns_domain_name *name)
 | 
|---|
| 146 | {
 | 
|---|
| 147 |         struct dns_domain_label *label;
 | 
|---|
| 148 |         char end_char = '\0';
 | 
|---|
| 149 | 
 | 
|---|
| 150 |         /*
 | 
|---|
| 151 |          * TODO: Implement DNS compression
 | 
|---|
| 152 |          */
 | 
|---|
| 153 | 
 | 
|---|
| 154 |         for (label = name->pLabelList; label != NULL; label = label->next) {
 | 
|---|
| 155 |                 uint8 len = label->len;
 | 
|---|
| 156 | 
 | 
|---|
| 157 |                 dns_marshall_buffer(buf, (uint8 *)&len, sizeof(len));
 | 
|---|
| 158 |                 if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 159 | 
 | 
|---|
| 160 |                 dns_marshall_buffer(buf, (uint8 *)label->label, len);
 | 
|---|
| 161 |                 if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 162 |         }
 | 
|---|
| 163 | 
 | 
|---|
| 164 |         dns_marshall_buffer(buf, (uint8 *)&end_char, 1);
 | 
|---|
| 165 | }
 | 
|---|
| 166 | 
 | 
|---|
| 167 | static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
 | 
|---|
| 168 |                                  int level,
 | 
|---|
| 169 |                                  struct dns_buffer *buf,
 | 
|---|
| 170 |                                  struct dns_domain_label **plabel)
 | 
|---|
| 171 | {
 | 
|---|
| 172 |         struct dns_domain_label *label;
 | 
|---|
| 173 |         uint8 len;
 | 
|---|
| 174 | 
 | 
|---|
| 175 |         if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 176 | 
 | 
|---|
| 177 |         if (level > 128) {
 | 
|---|
| 178 |                 /*
 | 
|---|
| 179 |                  * Protect against recursion
 | 
|---|
| 180 |                  */
 | 
|---|
| 181 |                 buf->error = ERROR_DNS_INVALID_MESSAGE;
 | 
|---|
| 182 |                 return;
 | 
|---|
| 183 |         }
 | 
|---|
| 184 | 
 | 
|---|
| 185 |         dns_unmarshall_buffer(buf, &len, sizeof(len));
 | 
|---|
| 186 |         if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 187 | 
 | 
|---|
| 188 |         if (len == 0) {
 | 
|---|
| 189 |                 *plabel = NULL;
 | 
|---|
| 190 |                 return;
 | 
|---|
| 191 |         }
 | 
|---|
| 192 | 
 | 
|---|
| 193 |         if ((len & 0xc0) == 0xc0) {
 | 
|---|
| 194 |                 /*
 | 
|---|
| 195 |                  * We've got a compressed name. Build up a new "fake" buffer
 | 
|---|
| 196 |                  * and using the calculated offset.
 | 
|---|
| 197 |                  */
 | 
|---|
| 198 |                 struct dns_buffer new_buf;
 | 
|---|
| 199 |                 uint8 low;
 | 
|---|
| 200 | 
 | 
|---|
| 201 |                 dns_unmarshall_buffer(buf, &low, sizeof(low));
 | 
|---|
| 202 |                 if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 203 | 
 | 
|---|
| 204 |                 new_buf = *buf;
 | 
|---|
| 205 |                 new_buf.offset = len & 0x3f;
 | 
|---|
| 206 |                 new_buf.offset <<= 8;
 | 
|---|
| 207 |                 new_buf.offset |= low;
 | 
|---|
| 208 | 
 | 
|---|
| 209 |                 dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
 | 
|---|
| 210 |                 buf->error = new_buf.error;
 | 
|---|
| 211 |                 return;
 | 
|---|
| 212 |         }
 | 
|---|
| 213 | 
 | 
|---|
| 214 |         if ((len & 0xc0) != 0) {
 | 
|---|
| 215 |                 buf->error = ERROR_DNS_INVALID_NAME;
 | 
|---|
| 216 |                 return;
 | 
|---|
| 217 |         }
 | 
|---|
| 218 | 
 | 
|---|
| 219 |         if (!(label = talloc(mem_ctx, struct dns_domain_label))) {
 | 
|---|
| 220 |                 buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 221 |                 return;
 | 
|---|
| 222 |         }
 | 
|---|
| 223 | 
 | 
|---|
| 224 |         label->len = len;
 | 
|---|
| 225 | 
 | 
|---|
| 226 |         if (!(label->label = TALLOC_ARRAY(label, char, len+1))) {
 | 
|---|
| 227 |                 buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 228 |                 goto error;
 | 
|---|
| 229 |         }
 | 
|---|
| 230 | 
 | 
|---|
| 231 |         dns_unmarshall_buffer(buf, (uint8 *)label->label, len);
 | 
|---|
| 232 |         if (!ERR_DNS_IS_OK(buf->error)) goto error;
 | 
|---|
| 233 | 
 | 
|---|
| 234 |         dns_unmarshall_label(label, level+1, buf, &label->next);
 | 
|---|
| 235 |         if (!ERR_DNS_IS_OK(buf->error)) goto error;
 | 
|---|
| 236 | 
 | 
|---|
| 237 |         *plabel = label;
 | 
|---|
| 238 |         return;
 | 
|---|
| 239 | 
 | 
|---|
| 240 |  error:
 | 
|---|
| 241 |         TALLOC_FREE(label);
 | 
|---|
| 242 |         return;
 | 
|---|
| 243 | }
 | 
|---|
| 244 | 
 | 
|---|
| 245 | void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
 | 
|---|
| 246 |                                 struct dns_buffer *buf,
 | 
|---|
| 247 |                                 struct dns_domain_name **pname)
 | 
|---|
| 248 | {
 | 
|---|
| 249 |         struct dns_domain_name *name;
 | 
|---|
| 250 | 
 | 
|---|
| 251 |         if (!ERR_DNS_IS_OK(buf->error)) return;
 | 
|---|
| 252 | 
 | 
|---|
| 253 |         if (!(name = talloc(mem_ctx, struct dns_domain_name))) {
 | 
|---|
| 254 |                 buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 255 |                 return;
 | 
|---|
| 256 |         }
 | 
|---|
| 257 | 
 | 
|---|
| 258 |         dns_unmarshall_label(name, 0, buf, &name->pLabelList);
 | 
|---|
| 259 | 
 | 
|---|
| 260 |         if (!ERR_DNS_IS_OK(buf->error)) {
 | 
|---|
| 261 |                 return;
 | 
|---|
| 262 |         }
 | 
|---|
| 263 | 
 | 
|---|
| 264 |         *pname = name;
 | 
|---|
| 265 |         return;
 | 
|---|
| 266 | }
 | 
|---|
| 267 | 
 | 
|---|
| 268 | static void dns_marshall_question(struct dns_buffer *buf,
 | 
|---|
| 269 |                                   const struct dns_question *q)
 | 
|---|
| 270 | {
 | 
|---|
| 271 |         dns_marshall_domain_name(buf, q->name);
 | 
|---|
| 272 |         dns_marshall_uint16(buf, q->q_type);
 | 
|---|
| 273 |         dns_marshall_uint16(buf, q->q_class);
 | 
|---|
| 274 | }
 | 
|---|
| 275 | 
 | 
|---|
| 276 | static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
 | 
|---|
| 277 |                                     struct dns_buffer *buf,
 | 
|---|
| 278 |                                     struct dns_question **pq)
 | 
|---|
| 279 | {
 | 
|---|
| 280 |         struct dns_question *q;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 283 | 
 | 
|---|
| 284 |         if (!(q = talloc(mem_ctx, struct dns_question))) {
 | 
|---|
| 285 |                 buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 286 |                 return;
 | 
|---|
| 287 |         }
 | 
|---|
| 288 | 
 | 
|---|
| 289 |         dns_unmarshall_domain_name(q, buf, &q->name);
 | 
|---|
| 290 |         dns_unmarshall_uint16(buf, &q->q_type);
 | 
|---|
| 291 |         dns_unmarshall_uint16(buf, &q->q_class);
 | 
|---|
| 292 | 
 | 
|---|
| 293 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 294 | 
 | 
|---|
| 295 |         *pq = q;
 | 
|---|
| 296 | }
 | 
|---|
| 297 | 
 | 
|---|
| 298 | static void dns_marshall_rr(struct dns_buffer *buf,
 | 
|---|
| 299 |                             const struct dns_rrec *r)
 | 
|---|
| 300 | {
 | 
|---|
| 301 |         dns_marshall_domain_name(buf, r->name);
 | 
|---|
| 302 |         dns_marshall_uint16(buf, r->type);
 | 
|---|
| 303 |         dns_marshall_uint16(buf, r->r_class);
 | 
|---|
| 304 |         dns_marshall_uint32(buf, r->ttl);
 | 
|---|
| 305 |         dns_marshall_uint16(buf, r->data_length);
 | 
|---|
| 306 |         dns_marshall_buffer(buf, r->data, r->data_length);
 | 
|---|
| 307 | }
 | 
|---|
| 308 | 
 | 
|---|
| 309 | static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
 | 
|---|
| 310 |                               struct dns_buffer *buf,
 | 
|---|
| 311 |                               struct dns_rrec **pr)
 | 
|---|
| 312 | {
 | 
|---|
| 313 |         struct dns_rrec *r;
 | 
|---|
| 314 | 
 | 
|---|
| 315 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 316 | 
 | 
|---|
| 317 |         if (!(r = talloc(mem_ctx, struct dns_rrec))) {
 | 
|---|
| 318 |                 buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 319 |                 return;
 | 
|---|
| 320 |         }
 | 
|---|
| 321 | 
 | 
|---|
| 322 |         dns_unmarshall_domain_name(r, buf, &r->name);
 | 
|---|
| 323 |         dns_unmarshall_uint16(buf, &r->type);
 | 
|---|
| 324 |         dns_unmarshall_uint16(buf, &r->r_class);
 | 
|---|
| 325 |         dns_unmarshall_uint32(buf, &r->ttl);
 | 
|---|
| 326 |         dns_unmarshall_uint16(buf, &r->data_length);
 | 
|---|
| 327 |         r->data = NULL;
 | 
|---|
| 328 | 
 | 
|---|
| 329 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 330 | 
 | 
|---|
| 331 |         if (r->data_length != 0) {
 | 
|---|
| 332 |                 if (!(r->data = TALLOC_ARRAY(r, uint8, r->data_length))) {
 | 
|---|
| 333 |                         buf->error = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 334 |                         return;
 | 
|---|
| 335 |                 }
 | 
|---|
| 336 |                 dns_unmarshall_buffer(buf, r->data, r->data_length);
 | 
|---|
| 337 |         }
 | 
|---|
| 338 | 
 | 
|---|
| 339 |         if (!(ERR_DNS_IS_OK(buf->error))) return;
 | 
|---|
| 340 | 
 | 
|---|
| 341 |         *pr = r;
 | 
|---|
| 342 | }
 | 
|---|
| 343 | 
 | 
|---|
| 344 | DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
 | 
|---|
| 345 |                                const struct dns_request *req,
 | 
|---|
| 346 |                                struct dns_buffer **pbuf)
 | 
|---|
| 347 | {
 | 
|---|
| 348 |         struct dns_buffer *buf;
 | 
|---|
| 349 |         uint16 i;
 | 
|---|
| 350 | 
 | 
|---|
| 351 |         if (!(buf = dns_create_buffer(mem_ctx))) {
 | 
|---|
| 352 |                 return ERROR_DNS_NO_MEMORY;
 | 
|---|
| 353 |         }
 | 
|---|
| 354 | 
 | 
|---|
| 355 |         dns_marshall_uint16(buf, req->id);
 | 
|---|
| 356 |         dns_marshall_uint16(buf, req->flags);
 | 
|---|
| 357 |         dns_marshall_uint16(buf, req->num_questions);
 | 
|---|
| 358 |         dns_marshall_uint16(buf, req->num_answers);
 | 
|---|
| 359 |         dns_marshall_uint16(buf, req->num_auths);
 | 
|---|
| 360 |         dns_marshall_uint16(buf, req->num_additionals);
 | 
|---|
| 361 | 
 | 
|---|
| 362 |         for (i=0; i<req->num_questions; i++) {
 | 
|---|
| 363 |                 dns_marshall_question(buf, req->questions[i]);
 | 
|---|
| 364 |         }
 | 
|---|
| 365 |         for (i=0; i<req->num_answers; i++) {
 | 
|---|
| 366 |                 dns_marshall_rr(buf, req->answers[i]);
 | 
|---|
| 367 |         }
 | 
|---|
| 368 |         for (i=0; i<req->num_auths; i++) {
 | 
|---|
| 369 |                 dns_marshall_rr(buf, req->auths[i]);
 | 
|---|
| 370 |         }
 | 
|---|
| 371 |         for (i=0; i<req->num_additionals; i++) {
 | 
|---|
| 372 |                 dns_marshall_rr(buf, req->additionals[i]);
 | 
|---|
| 373 |         }
 | 
|---|
| 374 | 
 | 
|---|
| 375 |         if (!ERR_DNS_IS_OK(buf->error)) {
 | 
|---|
| 376 |                 DNS_ERROR err = buf->error;
 | 
|---|
| 377 |                 TALLOC_FREE(buf);
 | 
|---|
| 378 |                 return err;
 | 
|---|
| 379 |         }
 | 
|---|
| 380 | 
 | 
|---|
| 381 |         *pbuf = buf;
 | 
|---|
| 382 |         return ERROR_DNS_SUCCESS;
 | 
|---|
| 383 | }
 | 
|---|
| 384 | 
 | 
|---|
| 385 | DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
 | 
|---|
| 386 |                                  struct dns_buffer *buf,
 | 
|---|
| 387 |                                  struct dns_request **preq)
 | 
|---|
| 388 | {
 | 
|---|
| 389 |         struct dns_request *req;
 | 
|---|
| 390 |         uint16 i;
 | 
|---|
| 391 |         DNS_ERROR err;
 | 
|---|
| 392 | 
 | 
|---|
| 393 |         if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request))) {
 | 
|---|
| 394 |                 return ERROR_DNS_NO_MEMORY;
 | 
|---|
| 395 |         }
 | 
|---|
| 396 | 
 | 
|---|
| 397 |         dns_unmarshall_uint16(buf, &req->id);
 | 
|---|
| 398 |         dns_unmarshall_uint16(buf, &req->flags);
 | 
|---|
| 399 |         dns_unmarshall_uint16(buf, &req->num_questions);
 | 
|---|
| 400 |         dns_unmarshall_uint16(buf, &req->num_answers);
 | 
|---|
| 401 |         dns_unmarshall_uint16(buf, &req->num_auths);
 | 
|---|
| 402 |         dns_unmarshall_uint16(buf, &req->num_additionals);
 | 
|---|
| 403 | 
 | 
|---|
| 404 |         if (!ERR_DNS_IS_OK(buf->error)) goto error;
 | 
|---|
| 405 | 
 | 
|---|
| 406 |         err = ERROR_DNS_NO_MEMORY;
 | 
|---|
| 407 | 
 | 
|---|
| 408 |         if ((req->num_questions != 0) &&
 | 
|---|
| 409 |             !(req->questions = TALLOC_ARRAY(req, struct dns_question *,
 | 
|---|
| 410 |                                             req->num_questions))) {
 | 
|---|
| 411 |                 goto error;
 | 
|---|
| 412 |         }
 | 
|---|
| 413 |         if ((req->num_answers != 0) &&
 | 
|---|
| 414 |             !(req->answers = TALLOC_ARRAY(req, struct dns_rrec *,
 | 
|---|
| 415 |                                           req->num_answers))) {
 | 
|---|
| 416 |                 goto error;
 | 
|---|
| 417 |         }
 | 
|---|
| 418 |         if ((req->num_auths != 0) &&
 | 
|---|
| 419 |             !(req->auths = TALLOC_ARRAY(req, struct dns_rrec *,
 | 
|---|
| 420 |                                         req->num_auths))) {
 | 
|---|
| 421 |                 goto error;
 | 
|---|
| 422 |         }
 | 
|---|
| 423 |         if ((req->num_additionals != 0) &&
 | 
|---|
| 424 |             !(req->additionals = TALLOC_ARRAY(req, struct dns_rrec *,
 | 
|---|
| 425 |                                               req->num_additionals))) {
 | 
|---|
| 426 |                 goto error;
 | 
|---|
| 427 |         }
 | 
|---|
| 428 | 
 | 
|---|
| 429 |         for (i=0; i<req->num_questions; i++) {
 | 
|---|
| 430 |                 dns_unmarshall_question(req->questions, buf,
 | 
|---|
| 431 |                                         &req->questions[i]);
 | 
|---|
| 432 |         }
 | 
|---|
| 433 |         for (i=0; i<req->num_answers; i++) {
 | 
|---|
| 434 |                 dns_unmarshall_rr(req->answers, buf,
 | 
|---|
| 435 |                                   &req->answers[i]);
 | 
|---|
| 436 |         }
 | 
|---|
| 437 |         for (i=0; i<req->num_auths; i++) {
 | 
|---|
| 438 |                 dns_unmarshall_rr(req->auths, buf,
 | 
|---|
| 439 |                                   &req->auths[i]);
 | 
|---|
| 440 |         }
 | 
|---|
| 441 |         for (i=0; i<req->num_additionals; i++) {
 | 
|---|
| 442 |                 dns_unmarshall_rr(req->additionals, buf,
 | 
|---|
| 443 |                                   &req->additionals[i]);
 | 
|---|
| 444 |         }
 | 
|---|
| 445 | 
 | 
|---|
| 446 |         if (!ERR_DNS_IS_OK(buf->error)) {
 | 
|---|
| 447 |                 err = buf->error;
 | 
|---|
| 448 |                 goto error;
 | 
|---|
| 449 |         }
 | 
|---|
| 450 | 
 | 
|---|
| 451 |         *preq = req;
 | 
|---|
| 452 |         return ERROR_DNS_SUCCESS;
 | 
|---|
| 453 | 
 | 
|---|
| 454 |  error:
 | 
|---|
| 455 |         err = buf->error;
 | 
|---|
| 456 |         TALLOC_FREE(req);
 | 
|---|
| 457 |         return err;
 | 
|---|
| 458 | }
 | 
|---|
| 459 | 
 | 
|---|
| 460 | struct dns_request *dns_update2request(struct dns_update_request *update)
 | 
|---|
| 461 | {
 | 
|---|
| 462 |         struct dns_request *req;
 | 
|---|
| 463 | 
 | 
|---|
| 464 |         /*
 | 
|---|
| 465 |          * This is a non-specified construct that happens to work on Linux/gcc
 | 
|---|
| 466 |          * and I would expect it to work everywhere else. dns_request and
 | 
|---|
| 467 |          * dns_update_request are essentially the same structures with
 | 
|---|
| 468 |          * different names, so any difference would mean that the compiler
 | 
|---|
| 469 |          * applied two different variations of padding given the same types in
 | 
|---|
| 470 |          * the structures.
 | 
|---|
| 471 |          */
 | 
|---|
| 472 | 
 | 
|---|
| 473 |         req = (struct dns_request *)(void *)update;
 | 
|---|
| 474 | 
 | 
|---|
| 475 |         /*
 | 
|---|
| 476 |          * The assert statement here looks like we could do the equivalent
 | 
|---|
| 477 |          * assignments to get portable, but it would mean that we have to
 | 
|---|
| 478 |          * allocate the dns_question record for the dns_zone records. We
 | 
|---|
| 479 |          * assume that if this assert works then the same holds true for
 | 
|---|
| 480 |          * dns_zone<>dns_question as well.
 | 
|---|
| 481 |          */
 | 
|---|
| 482 | 
 | 
|---|
| 483 | #ifdef DEVELOPER
 | 
|---|
| 484 |         assert((req->id == update->id) && (req->flags == update->flags) &&
 | 
|---|
| 485 |                (req->num_questions == update->num_zones) &&
 | 
|---|
| 486 |                (req->num_answers == update->num_preqs) &&
 | 
|---|
| 487 |                (req->num_auths == update->num_updates) &&
 | 
|---|
| 488 |                (req->num_additionals == update->num_additionals) &&
 | 
|---|
| 489 |                (req->questions ==
 | 
|---|
| 490 |                 (struct dns_question **)(void *)update->zones) &&
 | 
|---|
| 491 |                (req->answers == update->preqs) &&
 | 
|---|
| 492 |                (req->auths == update->updates) &&
 | 
|---|
| 493 |                (req->additionals == update->additionals));
 | 
|---|
| 494 | #endif
 | 
|---|
| 495 | 
 | 
|---|
| 496 |         return req;
 | 
|---|
| 497 | }
 | 
|---|
| 498 | 
 | 
|---|
| 499 | struct dns_update_request *dns_request2update(struct dns_request *request)
 | 
|---|
| 500 | {
 | 
|---|
| 501 |         /*
 | 
|---|
| 502 |          * For portability concerns see dns_update2request;
 | 
|---|
| 503 |          */
 | 
|---|
| 504 |         return (struct dns_update_request *)(void *)request;
 | 
|---|
| 505 | }
 | 
|---|
| 506 | 
 | 
|---|
| 507 | DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
 | 
|---|
| 508 |                                       struct dns_update_request *update,
 | 
|---|
| 509 |                                       struct dns_buffer **pbuf)
 | 
|---|
| 510 | {
 | 
|---|
| 511 |         return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
 | 
|---|
| 512 | }
 | 
|---|
| 513 | 
 | 
|---|
| 514 | DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
 | 
|---|
| 515 |                                         struct dns_buffer *buf,
 | 
|---|
| 516 |                                         struct dns_update_request **pupreq)
 | 
|---|
| 517 | {
 | 
|---|
| 518 |         /*
 | 
|---|
| 519 |          * See comments above about portability. If the above works, this will
 | 
|---|
| 520 |          * as well.
 | 
|---|
| 521 |          */
 | 
|---|
| 522 | 
 | 
|---|
| 523 |         return dns_unmarshall_request(mem_ctx, buf,
 | 
|---|
| 524 |                                       (struct dns_request **)(void *)pupreq);
 | 
|---|
| 525 | }
 | 
|---|
| 526 | 
 | 
|---|
| 527 | uint16 dns_response_code(uint16 flags)
 | 
|---|
| 528 | {
 | 
|---|
| 529 |         return flags & 0xF;
 | 
|---|
| 530 | }
 | 
|---|