LCOV - code coverage report
Current view: top level - lib/addns - dnsmarshall.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 186 252 73.8 %
Date: 2024-05-31 13:13:24 Functions: 20 21 95.2 %

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

Generated by: LCOV version 1.14