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

Generated by: LCOV version 1.13