root/source3/libaddns/dnsmarshall.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dns_create_buffer
  2. dns_marshall_buffer
  3. dns_marshall_uint16
  4. dns_marshall_uint32
  5. dns_unmarshall_buffer
  6. dns_unmarshall_uint16
  7. dns_unmarshall_uint32
  8. dns_marshall_domain_name
  9. dns_unmarshall_label
  10. dns_unmarshall_domain_name
  11. dns_marshall_question
  12. dns_unmarshall_question
  13. dns_marshall_rr
  14. dns_unmarshall_rr
  15. dns_marshall_request
  16. dns_unmarshall_request
  17. dns_update2request
  18. dns_request2update
  19. dns_marshall_update_request
  20. dns_unmarshall_update_request
  21. dns_response_code

   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)
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 528 {
 529         return flags & 0xF;
 530 }

/* [<][>][^][v][top][bottom][index][help] */