LCOV - code coverage report
Current view: top level - lib/addns - dnsmarshall.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 186 252 73.8 %
Date: 2024-02-28 12:06:22 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         296 : struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
      27             : {
      28           0 :         struct dns_buffer *result;
      29             : 
      30         296 :         if (!(result = talloc_zero(mem_ctx, struct dns_buffer))) {
      31           0 :                 return NULL;
      32             :         }
      33             : 
      34         296 :         result->offset = 0;
      35         296 :         result->error = ERROR_DNS_SUCCESS;
      36             :         
      37             :         /*
      38             :          * Small initial size to exercise the realloc code
      39             :          */
      40         296 :         result->size = 2;
      41             : 
      42         296 :         if (!(result->data = talloc_zero_array(result, uint8_t, result->size))) {
      43           0 :                 TALLOC_FREE(result);
      44           0 :                 return NULL;
      45             :         }
      46             : 
      47         296 :         return result;
      48             : }
      49             : 
      50       14402 : void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
      51             :                          size_t len)
      52             : {
      53       14402 :         if (!ERR_DNS_IS_OK(buf->error)) return;
      54             : 
      55       14402 :         if (buf->offset + len < buf->offset) {
      56             :                 /*
      57             :                  * Wraparound!
      58             :                  */
      59           0 :                 buf->error = ERROR_DNS_INVALID_PARAMETER;
      60           0 :                 return;
      61             :         }
      62             : 
      63       14402 :         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       14402 :         if (buf->offset + len > buf->size) {
      72        1004 :                 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        1004 :                 new_size += (64 - (new_size % 64));
      80             : 
      81        1004 :                 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        1004 :                 buf->size = new_size;
      88        1004 :                 buf->data = new_data;
      89             :         }
      90             : 
      91       14402 :         if (data != NULL) {
      92       14108 :                 memcpy(buf->data + buf->offset, data, len);
      93             :         }
      94       14402 :         buf->offset += len;
      95       14402 :         return;
      96             : }
      97             : 
      98        4159 : void dns_marshall_uint16(struct dns_buffer *buf, uint16_t val)
      99             : {
     100        4159 :         uint16_t n_val = htons(val);
     101        4159 :         dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
     102        4159 : }
     103             : 
     104         821 : void dns_marshall_uint32(struct dns_buffer *buf, uint32_t val)
     105             : {
     106         821 :         uint32_t n_val = htonl(val);
     107         821 :         dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
     108         821 : }
     109             : 
     110       10618 : void dns_unmarshall_buffer(struct dns_buffer *buf, uint8_t *data,
     111             :                            size_t len)
     112             : {
     113       10618 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     114             : 
     115       10618 :         if ((len > buf->size) || (buf->offset + len > buf->size)) {
     116           0 :                 buf->error = ERROR_DNS_INVALID_MESSAGE;
     117           0 :                 return;
     118             :         }
     119             : 
     120       10618 :         memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
     121       10618 :         buf->offset += len;
     122             : 
     123       10618 :         return;
     124             : }
     125             : 
     126        3025 : void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val)
     127             : {
     128           0 :         uint16_t n_val;
     129             : 
     130        3025 :         dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
     131        3025 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     132             : 
     133        3025 :         *val = ntohs(n_val);
     134             : }
     135             : 
     136         597 : void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val)
     137             : {
     138           0 :         uint32_t n_val;
     139             : 
     140         597 :         dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
     141         597 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     142             : 
     143         597 :         *val = ntohl(n_val);
     144             : }
     145             : 
     146         991 : 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         991 :         char end_char = '\0';
     151             : 
     152             :         /*
     153             :          * TODO: Implement DNS compression
     154             :          */
     155             : 
     156        4859 :         for (label = name->pLabelList; label != NULL; label = label->next) {
     157        3868 :                 uint8_t len = label->len;
     158             : 
     159        3868 :                 dns_marshall_buffer(buf, (uint8_t *)&len, sizeof(len));
     160        3868 :                 if (!ERR_DNS_IS_OK(buf->error)) return;
     161             : 
     162        3868 :                 dns_marshall_buffer(buf, (uint8_t *)label->label, len);
     163        3868 :                 if (!ERR_DNS_IS_OK(buf->error)) return;
     164             :         }
     165             : 
     166         991 :         dns_marshall_buffer(buf, (uint8_t *)&end_char, 1);
     167             : }
     168             : 
     169        3688 : 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        3688 :         if (!ERR_DNS_IS_OK(buf->error)) return;
     178             : 
     179        3688 :         if (level > 128) {
     180             :                 /*
     181             :                  * Protect against recursion
     182             :                  */
     183           0 :                 buf->error = ERROR_DNS_INVALID_MESSAGE;
     184           0 :                 return;
     185             :         }
     186             : 
     187        3688 :         dns_unmarshall_buffer(buf, &len, sizeof(len));
     188        3688 :         if (!ERR_DNS_IS_OK(buf->error)) return;
     189             : 
     190        3688 :         if (len == 0) {
     191         725 :                 *plabel = NULL;
     192         725 :                 return;
     193             :         }
     194             : 
     195        2963 :         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         220 :                 dns_unmarshall_buffer(buf, &low, sizeof(low));
     204         220 :                 if (!ERR_DNS_IS_OK(buf->error)) return;
     205             : 
     206         220 :                 new_buf = *buf;
     207         220 :                 new_buf.offset = len & 0x3f;
     208         220 :                 new_buf.offset <<= 8;
     209         220 :                 new_buf.offset |= low;
     210             : 
     211         220 :                 dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
     212         220 :                 buf->error = new_buf.error;
     213         220 :                 return;
     214             :         }
     215             : 
     216        2743 :         if ((len & 0xc0) != 0) {
     217           0 :                 buf->error = ERROR_DNS_INVALID_NAME;
     218           0 :                 return;
     219             :         }
     220             : 
     221        2743 :         if (!(label = talloc_zero(mem_ctx, struct dns_domain_label))) {
     222           0 :                 buf->error = ERROR_DNS_NO_MEMORY;
     223           0 :                 return;
     224             :         }
     225             : 
     226        2743 :         label->len = len;
     227             : 
     228        2743 :         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        2743 :         dns_unmarshall_buffer(buf, (uint8_t *)label->label, len);
     234        2743 :         if (!ERR_DNS_IS_OK(buf->error)) goto error;
     235             : 
     236        2743 :         dns_unmarshall_label(label, level+1, buf, &label->next);
     237        2743 :         if (!ERR_DNS_IS_OK(buf->error)) goto error;
     238             : 
     239        2743 :         *plabel = label;
     240        2743 :         return;
     241             : 
     242           0 :  error:
     243           0 :         TALLOC_FREE(label);
     244           0 :         return;
     245             : }
     246             : 
     247         725 : 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         725 :         if (!ERR_DNS_IS_OK(buf->error)) return;
     254             : 
     255         725 :         if (!(name = talloc_zero(mem_ctx, struct dns_domain_name))) {
     256           0 :                 buf->error = ERROR_DNS_NO_MEMORY;
     257           0 :                 return;
     258             :         }
     259             : 
     260         725 :         dns_unmarshall_label(name, 0, buf, &name->pLabelList);
     261             : 
     262         725 :         if (!ERR_DNS_IS_OK(buf->error)) {
     263           0 :                 return;
     264             :         }
     265             : 
     266         725 :         *pname = name;
     267         725 :         return;
     268             : }
     269             : 
     270         212 : static void dns_marshall_question(struct dns_buffer *buf,
     271             :                                   const struct dns_question *q)
     272             : {
     273         212 :         dns_marshall_domain_name(buf, q->name);
     274         212 :         dns_marshall_uint16(buf, q->q_type);
     275         212 :         dns_marshall_uint16(buf, q->q_class);
     276         212 : }
     277             : 
     278         170 : 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         170 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     285             : 
     286         170 :         if (!(q = talloc_zero(mem_ctx, struct dns_question))) {
     287           0 :                 buf->error = ERROR_DNS_NO_MEMORY;
     288           0 :                 return;
     289             :         }
     290             : 
     291         170 :         dns_unmarshall_domain_name(q, buf, &q->name);
     292         170 :         dns_unmarshall_uint16(buf, &q->q_type);
     293         170 :         dns_unmarshall_uint16(buf, &q->q_class);
     294             : 
     295         170 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     296             : 
     297         170 :         *pq = q;
     298             : }
     299             : 
     300         611 : static void dns_marshall_rr(struct dns_buffer *buf,
     301             :                             const struct dns_rrec *r)
     302             : {
     303         611 :         dns_marshall_domain_name(buf, r->name);
     304         611 :         dns_marshall_uint16(buf, r->type);
     305         611 :         dns_marshall_uint16(buf, r->r_class);
     306         611 :         dns_marshall_uint32(buf, r->ttl);
     307         611 :         dns_marshall_uint16(buf, r->data_length);
     308         611 :         dns_marshall_buffer(buf, r->data, r->data_length);
     309         611 : }
     310             : 
     311         513 : 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         513 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     318             : 
     319         513 :         if (!(r = talloc_zero(mem_ctx, struct dns_rrec))) {
     320           0 :                 buf->error = ERROR_DNS_NO_MEMORY;
     321           0 :                 return;
     322             :         }
     323             : 
     324         513 :         dns_unmarshall_domain_name(r, buf, &r->name);
     325         513 :         dns_unmarshall_uint16(buf, &r->type);
     326         513 :         dns_unmarshall_uint16(buf, &r->r_class);
     327         513 :         dns_unmarshall_uint32(buf, &r->ttl);
     328         513 :         dns_unmarshall_uint16(buf, &r->data_length);
     329         513 :         r->data = NULL;
     330             : 
     331         513 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     332             : 
     333         513 :         if (r->data_length != 0) {
     334         303 :                 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         303 :                 dns_unmarshall_buffer(buf, r->data, r->data_length);
     339             :         }
     340             : 
     341         513 :         if (!(ERR_DNS_IS_OK(buf->error))) return;
     342             : 
     343         513 :         *pr = r;
     344             : }
     345             : 
     346         212 : 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         212 :         if (!(buf = dns_create_buffer(mem_ctx))) {
     354           0 :                 return ERROR_DNS_NO_MEMORY;
     355             :         }
     356             : 
     357         212 :         dns_marshall_uint16(buf, req->id);
     358         212 :         dns_marshall_uint16(buf, req->flags);
     359         212 :         dns_marshall_uint16(buf, req->num_questions);
     360         212 :         dns_marshall_uint16(buf, req->num_answers);
     361         212 :         dns_marshall_uint16(buf, req->num_auths);
     362         212 :         dns_marshall_uint16(buf, req->num_additionals);
     363             : 
     364         424 :         for (i=0; i<req->num_questions; i++) {
     365         212 :                 dns_marshall_question(buf, req->questions[i]);
     366             :         }
     367         438 :         for (i=0; i<req->num_answers; i++) {
     368         226 :                 dns_marshall_rr(buf, req->answers[i]);
     369             :         }
     370         513 :         for (i=0; i<req->num_auths; i++) {
     371         301 :                 dns_marshall_rr(buf, req->auths[i]);
     372             :         }
     373         296 :         for (i=0; i<req->num_additionals; i++) {
     374          84 :                 dns_marshall_rr(buf, req->additional[i]);
     375             :         }
     376             : 
     377         212 :         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         212 :         *pbuf = buf;
     384         212 :         return ERROR_DNS_SUCCESS;
     385             : }
     386             : 
     387         170 : 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         170 :         DNS_ERROR err = ERROR_DNS_NO_MEMORY;
     394             : 
     395         170 :         if (!(req = talloc_zero(mem_ctx, struct dns_request))) {
     396           0 :                 return err;
     397             :         }
     398             : 
     399         170 :         dns_unmarshall_uint16(buf, &req->id);
     400         170 :         dns_unmarshall_uint16(buf, &req->flags);
     401         170 :         dns_unmarshall_uint16(buf, &req->num_questions);
     402         170 :         dns_unmarshall_uint16(buf, &req->num_answers);
     403         170 :         dns_unmarshall_uint16(buf, &req->num_auths);
     404         170 :         dns_unmarshall_uint16(buf, &req->num_additionals);
     405             : 
     406         170 :         if (!ERR_DNS_IS_OK(buf->error)){
     407           0 :                 err = buf->error;
     408           0 :                 goto error;
     409             :         }
     410             : 
     411         170 :         err = ERROR_DNS_NO_MEMORY;
     412             : 
     413         170 :         if ((req->num_questions != 0) &&
     414         170 :             !(req->questions = talloc_zero_array(req, struct dns_question *,
     415             :                                             req->num_questions))) {
     416           0 :                 goto error;
     417             :         }
     418         170 :         if ((req->num_answers != 0) &&
     419         169 :             !(req->answers = talloc_zero_array(req, struct dns_rrec *,
     420             :                                           req->num_answers))) {
     421           0 :                 goto error;
     422             :         }
     423         170 :         if ((req->num_auths != 0) &&
     424          86 :             !(req->auths = talloc_zero_array(req, struct dns_rrec *,
     425             :                                         req->num_auths))) {
     426           0 :                 goto error;
     427             :         }
     428         170 :         if ((req->num_additionals != 0) &&
     429          84 :             !(req->additional = talloc_zero_array(req, struct dns_rrec *,
     430             :                                               req->num_additionals))) {
     431           0 :                 goto error;
     432             :         }
     433             : 
     434         340 :         for (i=0; i<req->num_questions; i++) {
     435         170 :                 dns_unmarshall_question(req->questions, buf,
     436         170 :                                         &req->questions[i]);
     437             :         }
     438         397 :         for (i=0; i<req->num_answers; i++) {
     439         227 :                 dns_unmarshall_rr(req->answers, buf,
     440         227 :                                   &req->answers[i]);
     441             :         }
     442         372 :         for (i=0; i<req->num_auths; i++) {
     443         202 :                 dns_unmarshall_rr(req->auths, buf,
     444         202 :                                   &req->auths[i]);
     445             :         }
     446         254 :         for (i=0; i<req->num_additionals; i++) {
     447          84 :                 dns_unmarshall_rr(req->additional, buf,
     448          84 :                                   &req->additional[i]);
     449             :         }
     450             : 
     451         170 :         if (!ERR_DNS_IS_OK(buf->error)) {
     452           0 :                 err = buf->error;
     453           0 :                 goto error;
     454             :         }
     455             : 
     456         170 :         *preq = req;
     457         170 :         return ERROR_DNS_SUCCESS;
     458             : 
     459           0 :  error:
     460           0 :         TALLOC_FREE(req);
     461           0 :         return err;
     462             : }
     463             : 
     464         169 : 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         169 :         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         169 :         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         169 :         return req;
     501             : }
     502             : 
     503         127 : struct dns_update_request *dns_request2update(struct dns_request *request)
     504             : {
     505             :         /*
     506             :          * For portability concerns see dns_update2request;
     507             :          */
     508         127 :         return (struct dns_update_request *)(void *)request;
     509             : }
     510             : 
     511          42 : DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
     512             :                                       struct dns_update_request *update,
     513             :                                       struct dns_buffer **pbuf)
     514             : {
     515          42 :         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         128 : uint16_t dns_response_code(uint16_t flags)
     532             : {
     533         128 :         return flags & 0xF;
     534             : }

Generated by: LCOV version 1.14