LCOV - code coverage report
Current view: top level - lib/addns - dnsrecord.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 179 223 80.3 %
Date: 2024-06-13 04:01:37 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /*
       2             :   Linux DNS client library implementation
       3             :   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
       4             :   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
       5             : 
       6             :      ** NOTE! The following LGPL license applies to the libaddns
       7             :      ** library. This does NOT imply that all of Samba is released
       8             :      ** under the LGPL
       9             : 
      10             :   This library is free software; you can redistribute it and/or
      11             :   modify it under the terms of the GNU Lesser General Public
      12             :   License as published by the Free Software Foundation; either
      13             :   version 2.1 of the License, or (at your option) any later version.
      14             : 
      15             :   This library is distributed in the hope that it will be useful,
      16             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :   Lesser General Public License for more details.
      19             : 
      20             :   You should have received a copy of the GNU Lesser General Public
      21             :   License along with this library; if not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "dns.h"
      25             : #include "lib/util/genrand.h"
      26             : 
      27          35 : DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
      28             :                             uint16_t q_type, uint16_t q_class,
      29             :                             struct dns_request **preq )
      30             : {
      31          35 :         struct dns_request *req = NULL;
      32          35 :         struct dns_question *q = NULL;
      33             :         DNS_ERROR err;
      34             : 
      35          53 :         if (!(req = talloc_zero(mem_ctx, struct dns_request)) ||
      36          53 :             !(req->questions = talloc_array(req, struct dns_question *, 1)) ||
      37          35 :             !(req->questions[0] = talloc(req->questions,
      38             :                                          struct dns_question))) {
      39           0 :                 TALLOC_FREE(req);
      40           0 :                 return ERROR_DNS_NO_MEMORY;
      41             :         }
      42             : 
      43          35 :         generate_random_buffer((uint8_t *)&req->id, sizeof(req->id));
      44             : 
      45          35 :         req->num_questions = 1;
      46          35 :         q = req->questions[0];
      47             : 
      48          35 :         err = dns_domain_name_from_string(q, name, &q->name);
      49          35 :         if (!ERR_DNS_IS_OK(err)) {
      50           0 :                 TALLOC_FREE(req);
      51           0 :                 return err;
      52             :         }
      53             : 
      54          35 :         q->q_type = q_type;
      55          35 :         q->q_class = q_class;
      56             : 
      57          35 :         *preq = req;
      58          35 :         return ERROR_DNS_SUCCESS;
      59             : }
      60             : 
      61         103 : DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
      62             :                              struct dns_update_request **preq )
      63             : {
      64         103 :         struct dns_update_request *req = NULL;
      65         103 :         struct dns_zone *z = NULL;
      66             :         DNS_ERROR err;
      67             : 
      68         155 :         if (!(req = talloc_zero(mem_ctx, struct dns_update_request)) ||
      69         155 :             !(req->zones = talloc_array(req, struct dns_zone *, 1)) ||
      70         103 :             !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
      71           0 :                 TALLOC_FREE(req);
      72           0 :                 return ERROR_DNS_NO_MEMORY;
      73             :         }
      74             : 
      75         103 :         req->id = random();
      76         103 :         req->flags = 0x2800; /* Dynamic update */
      77             : 
      78         103 :         req->num_zones = 1;
      79         103 :         z = req->zones[0];
      80             : 
      81         103 :         err = dns_domain_name_from_string(z, name, &z->name);
      82         103 :         if (!ERR_DNS_IS_OK(err)) {
      83           0 :                 TALLOC_FREE(req);
      84           0 :                 return err;
      85             :         }
      86             : 
      87         103 :         z->z_type = QTYPE_SOA;
      88         103 :         z->z_class = DNS_CLASS_IN;
      89             : 
      90         103 :         *preq = req;
      91         103 :         return ERROR_DNS_SUCCESS;
      92             : }
      93             : 
      94         401 : DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
      95             :                           uint16_t type, uint16_t r_class, uint32_t ttl,
      96             :                           uint16_t data_length, uint8_t *data,
      97             :                           struct dns_rrec **prec)
      98             : {
      99         401 :         struct dns_rrec *rec = NULL;
     100             :         DNS_ERROR err;
     101             : 
     102         401 :         if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
     103           0 :                 return ERROR_DNS_NO_MEMORY;
     104             :         }
     105             : 
     106         401 :         err = dns_domain_name_from_string(rec, name, &rec->name);
     107         401 :         if (!(ERR_DNS_IS_OK(err))) {
     108           0 :                 TALLOC_FREE(rec);
     109           0 :                 return err;
     110             :         }
     111             : 
     112         401 :         rec->type = type;
     113         401 :         rec->r_class = r_class;
     114         401 :         rec->ttl = ttl;
     115         401 :         rec->data_length = data_length;
     116         401 :         rec->data = talloc_move(rec, &data);
     117             : 
     118         401 :         *prec = rec;
     119         401 :         return ERROR_DNS_SUCCESS;
     120             : }
     121             : 
     122          91 : DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
     123             :                               uint32_t ttl, const struct sockaddr_storage *pss,
     124             :                               struct dns_rrec **prec)
     125             : {
     126             :         uint8_t *data;
     127             :         DNS_ERROR err;
     128             :         struct in_addr ip;
     129             : 
     130          91 :         if (pss->ss_family != AF_INET) {
     131           0 :                 return ERROR_DNS_INVALID_PARAMETER;
     132             :         }
     133             : 
     134          91 :         ip = ((const struct sockaddr_in *)pss)->sin_addr;
     135          91 :         if (!(data = (uint8_t *)talloc_memdup(mem_ctx, (const void *)&ip.s_addr,
     136             :                                             sizeof(ip.s_addr)))) {
     137           0 :                 return ERROR_DNS_NO_MEMORY;
     138             :         }
     139             : 
     140          91 :         err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
     141             :                               sizeof(ip.s_addr), data, prec);
     142             : 
     143          91 :         if (!ERR_DNS_IS_OK(err)) {
     144           0 :                 TALLOC_FREE(data);
     145             :         }
     146             : 
     147          91 :         return err;
     148             : }
     149             : 
     150          72 : DNS_ERROR dns_create_aaaa_record(TALLOC_CTX *mem_ctx, const char *host,
     151             :                                  uint32_t ttl, const struct sockaddr_storage *pss,
     152             :                                  struct dns_rrec **prec)
     153             : {
     154             : #ifdef HAVE_IPV6
     155             :         uint8_t *data;
     156             :         DNS_ERROR err;
     157             :         struct in6_addr ip6;
     158             : 
     159          72 :         if (pss->ss_family != AF_INET6) {
     160           0 :                 return ERROR_DNS_INVALID_PARAMETER;
     161             :         }
     162             : 
     163          72 :         ip6 = ((const struct sockaddr_in6 *)pss)->sin6_addr;
     164          72 :         if (!(data = (uint8_t *)talloc_memdup(mem_ctx, (const void *)&ip6.s6_addr,
     165             :                                             sizeof(ip6.s6_addr)))) {
     166           0 :                 return ERROR_DNS_NO_MEMORY;
     167             :         }
     168             : 
     169          72 :         err = dns_create_rrec(mem_ctx, host, QTYPE_AAAA, DNS_CLASS_IN, ttl,
     170             :                               sizeof(ip6.s6_addr), data, prec);
     171             : 
     172          72 :         if (!ERR_DNS_IS_OK(err)) {
     173           0 :                 TALLOC_FREE(data);
     174             :         }
     175             : 
     176          72 :         return err;
     177             : #else
     178             :         return ERROR_DNS_INVALID_PARAMETER;
     179             : #endif
     180             : }
     181             : 
     182          54 : DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
     183             :                                         const char *name,
     184             :                                         const struct sockaddr_storage *ss,
     185             :                                         struct dns_rrec **prec)
     186             : {
     187          54 :         if (ss != NULL) {
     188          54 :                 switch (ss->ss_family) {
     189          30 :                 case AF_INET:
     190          30 :                         return dns_create_a_record(mem_ctx, name, 0, ss, prec);
     191             : #ifdef HAVE_IPV6
     192          24 :                 case AF_INET6:
     193          24 :                         return dns_create_aaaa_record(mem_ctx, name, 0, ss, prec);
     194             : #endif
     195           0 :                 default:
     196           0 :                         return ERROR_DNS_INVALID_PARAMETER;
     197             :                 }
     198             :         }
     199             : 
     200           0 :         return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
     201             :                                NULL, prec);
     202             : }
     203             : 
     204          34 : DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
     205             :                                             const char *name, uint32_t type,
     206             :                                             struct dns_rrec **prec)
     207             : {
     208          34 :         return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
     209             :                                0, NULL, prec);
     210             : }
     211             : 
     212          68 : DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
     213             :                                    uint16_t type, uint16_t r_class,
     214             :                                    struct dns_rrec **prec)
     215             : {
     216          68 :         return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
     217             : }
     218             : 
     219          34 : DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
     220             :                                  const char *algorithm_name, time_t inception,
     221             :                                  time_t expiration, uint16_t mode, uint16_t error,
     222             :                                  uint16_t key_length, const uint8_t *key,
     223             :                                  struct dns_rrec **prec)
     224             : {
     225          34 :         struct dns_buffer *buf = NULL;
     226          34 :         struct dns_domain_name *algorithm = NULL;
     227             :         DNS_ERROR err;
     228             : 
     229          34 :         if (!(buf = dns_create_buffer(mem_ctx))) {
     230           0 :                 return ERROR_DNS_NO_MEMORY;
     231             :         }
     232             : 
     233          34 :         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
     234          34 :         if (!ERR_DNS_IS_OK(err)) goto error;
     235             : 
     236          34 :         dns_marshall_domain_name(buf, algorithm);
     237          34 :         dns_marshall_uint32(buf, inception);
     238          34 :         dns_marshall_uint32(buf, expiration);
     239          34 :         dns_marshall_uint16(buf, mode);
     240          34 :         dns_marshall_uint16(buf, error);
     241          34 :         dns_marshall_uint16(buf, key_length);
     242          34 :         dns_marshall_buffer(buf, key, key_length);
     243          34 :         dns_marshall_uint16(buf, 0); /* Other Size */
     244             : 
     245          34 :         if (!ERR_DNS_IS_OK(buf->error)) {
     246           0 :                 err = buf->error;
     247           0 :                 goto error;
     248             :         }
     249             : 
     250          51 :         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
     251          34 :                               buf->offset, buf->data, prec);
     252             : 
     253          34 :  error:
     254          34 :         TALLOC_FREE(buf);
     255          34 :         return err;
     256             : }
     257             : 
     258          34 : DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
     259             :                                      struct dns_tkey_record **ptkey)
     260             : {
     261             :         struct dns_tkey_record *tkey;
     262             :         struct dns_buffer buf;
     263             :         uint32_t tmp_inception, tmp_expiration;
     264             :         
     265          34 :         if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
     266           0 :                 return ERROR_DNS_NO_MEMORY;
     267             :         }
     268             : 
     269          34 :         buf.data = rec->data;
     270          34 :         buf.size = rec->data_length;
     271          34 :         buf.offset = 0;
     272          34 :         buf.error = ERROR_DNS_SUCCESS;
     273             : 
     274          34 :         dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
     275          34 :         dns_unmarshall_uint32(&buf, &tmp_inception);
     276          34 :         dns_unmarshall_uint32(&buf, &tmp_expiration);
     277          34 :         dns_unmarshall_uint16(&buf, &tkey->mode);
     278          34 :         dns_unmarshall_uint16(&buf, &tkey->error);
     279          34 :         dns_unmarshall_uint16(&buf, &tkey->key_length);
     280             : 
     281          34 :         if (!ERR_DNS_IS_OK(buf.error)) goto error;
     282             : 
     283          34 :         if (tkey->key_length) {
     284          34 :                 if (!(tkey->key = talloc_array(tkey, uint8_t, tkey->key_length))) {
     285           0 :                         buf.error = ERROR_DNS_NO_MEMORY;
     286           0 :                         goto error;
     287             :                 }
     288             :         } else {
     289           0 :                 tkey->key = NULL;
     290             :         }
     291             : 
     292          34 :         dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
     293          34 :         if (!ERR_DNS_IS_OK(buf.error)) goto error;
     294             : 
     295          34 :         tkey->inception = (time_t)tmp_inception;
     296          34 :         tkey->expiration = (time_t)tmp_expiration;
     297             : 
     298          34 :         *ptkey = tkey;
     299          34 :         return ERROR_DNS_SUCCESS;
     300             : 
     301           0 :  error:
     302           0 :         TALLOC_FREE(tkey);
     303           0 :         return buf.error;
     304             : }
     305             : 
     306          34 : DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
     307             :                                  const char *algorithm_name,
     308             :                                  time_t time_signed, uint16_t fudge,
     309             :                                  uint16_t mac_length, const uint8_t *mac,
     310             :                                  uint16_t original_id, uint16_t error,
     311             :                                  struct dns_rrec **prec)
     312             : {
     313          34 :         struct dns_buffer *buf = NULL;
     314          34 :         struct dns_domain_name *algorithm = NULL;
     315             :         DNS_ERROR err;
     316             : 
     317          34 :         if (!(buf = dns_create_buffer(mem_ctx))) {
     318           0 :                 return ERROR_DNS_NO_MEMORY;
     319             :         }
     320             : 
     321          34 :         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
     322          34 :         if (!ERR_DNS_IS_OK(err)) goto error;
     323             : 
     324          34 :         dns_marshall_domain_name(buf, algorithm);
     325          34 :         dns_marshall_uint16(buf, 0); /* time prefix */
     326          34 :         dns_marshall_uint32(buf, time_signed);
     327          34 :         dns_marshall_uint16(buf, fudge);
     328          34 :         dns_marshall_uint16(buf, mac_length);
     329          34 :         dns_marshall_buffer(buf, mac, mac_length);
     330          34 :         dns_marshall_uint16(buf, original_id);
     331          34 :         dns_marshall_uint16(buf, error);
     332          34 :         dns_marshall_uint16(buf, 0); /* Other Size */
     333             : 
     334          34 :         if (!ERR_DNS_IS_OK(buf->error)) {
     335           0 :                 err = buf->error;
     336           0 :                 goto error;
     337             :         }
     338             : 
     339          51 :         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
     340          34 :                               buf->offset, buf->data, prec);
     341             : 
     342          34 :  error:
     343          34 :         TALLOC_FREE(buf);
     344          34 :         return err;
     345             : }
     346             : 
     347         401 : DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
     348             :                        uint16_t *num_records, struct dns_rrec ***records)
     349             : {
     350             :         struct dns_rrec **new_records;
     351             : 
     352         401 :         if (!(new_records = talloc_realloc(mem_ctx, *records,
     353             :                                                  struct dns_rrec *,
     354             :                                                  (*num_records)+1))) {
     355           0 :                 return ERROR_DNS_NO_MEMORY;
     356             :         }
     357             : 
     358         401 :         new_records[*num_records] = talloc_move(new_records, &rec);
     359             : 
     360         401 :         *num_records += 1;
     361         401 :         *records = new_records;
     362         401 :         return ERROR_DNS_SUCCESS;
     363             : }
     364             : 
     365             : /*
     366             :  * Create a request that probes a server whether the list of IP addresses
     367             :  * provides meets our expectations
     368             :  */
     369             : 
     370          34 : DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
     371             :                            const char *host, int num_ips,
     372             :                            const struct sockaddr_storage *sslist,
     373             :                            struct dns_update_request **preq)
     374             : {
     375          34 :         struct dns_update_request *req = NULL;
     376          34 :         struct dns_rrec *rec = NULL;
     377             :         DNS_ERROR err;
     378             :         uint16_t i;
     379             : 
     380          34 :         err = dns_create_update(mem_ctx, zone, &req);
     381          34 :         if (!ERR_DNS_IS_OK(err)) return err;
     382             : 
     383          34 :         err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
     384          34 :         if (!ERR_DNS_IS_OK(err)) goto error;
     385             : 
     386          34 :         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     387          34 :         if (!ERR_DNS_IS_OK(err)) goto error;
     388             : 
     389          88 :         for (i=0; i<num_ips; i++) {
     390          54 :                 err = dns_create_name_in_use_record(req, host,
     391          54 :                                                     &sslist[i], &rec);
     392          54 :                 if (!ERR_DNS_IS_OK(err)) goto error;
     393             : 
     394          54 :                 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     395          54 :                 if (!ERR_DNS_IS_OK(err)) goto error;
     396             :         }
     397             : 
     398          34 :         *preq = req;
     399          34 :         return ERROR_DNS_SUCCESS;
     400             : 
     401           0 :  error:
     402           0 :         TALLOC_FREE(req);
     403           0 :         return err;
     404             : }
     405             :                            
     406          68 : DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
     407             :                                     const char *domainname,
     408             :                                     const char *hostname,
     409             :                                     const struct sockaddr_storage *ss_addrs,
     410             :                                     size_t num_addrs,
     411             :                                     struct dns_update_request **preq)
     412             : {
     413          68 :         struct dns_update_request *req = NULL;
     414          68 :         struct dns_rrec *rec = NULL;
     415             :         DNS_ERROR err;
     416             :         size_t i;
     417             : 
     418          68 :         err = dns_create_update(mem_ctx, domainname, &req);
     419          68 :         if (!ERR_DNS_IS_OK(err)) return err;
     420             : 
     421             :         /*
     422             :          * Use the same prereq as WinXP -- No CNAME records for this host.
     423             :          */
     424             : 
     425          68 :         err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
     426             :                               0, 0, NULL, &rec);
     427          68 :         if (!ERR_DNS_IS_OK(err)) goto error;
     428             : 
     429          68 :         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     430          68 :         if (!ERR_DNS_IS_OK(err)) goto error;
     431             : 
     432             :         /*
     433             :          * Delete all existing RRsets from our name
     434             :          */
     435             : 
     436          68 :         err = dns_create_delete_record(req, hostname, QTYPE_ANY, DNS_CLASS_ANY,
     437             :                                        &rec);
     438          68 :         if (!ERR_DNS_IS_OK(err)) goto error;
     439             : 
     440          68 :         err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
     441          68 :         if (!ERR_DNS_IS_OK(err)) goto error;
     442             : 
     443             :         /*
     444             :          * .. and add our IPs
     445             :          */
     446             : 
     447         176 :         for ( i=0; i<num_addrs; i++ ) {
     448             : 
     449         108 :                 switch(ss_addrs[i].ss_family) {
     450          60 :                 case AF_INET:
     451          60 :                         err = dns_create_a_record(req, hostname, 3600, &ss_addrs[i], &rec);
     452          60 :                         break;
     453             : #ifdef HAVE_IPV6
     454          48 :                 case AF_INET6:
     455          48 :                         err = dns_create_aaaa_record(req, hostname, 3600, &ss_addrs[i], &rec);
     456          48 :                         break;
     457             : #endif
     458           0 :                 default:
     459           0 :                         continue;
     460             :                 }
     461         108 :                 if (!ERR_DNS_IS_OK(err))
     462           0 :                         goto error;
     463             : 
     464         108 :                 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
     465         108 :                 if (!ERR_DNS_IS_OK(err))
     466           0 :                         goto error;
     467             :         }
     468             : 
     469          68 :         *preq = req;
     470          68 :         return ERROR_DNS_SUCCESS;
     471             : 
     472           0 :  error:
     473           0 :         TALLOC_FREE(req);
     474           0 :         return err;
     475             : }

Generated by: LCOV version 1.13