LCOV - code coverage report
Current view: top level - lib/addns - dnsrecord.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 181 244 74.2 %
Date: 2024-01-11 09:59:51 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          43 : 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          43 :         struct dns_request *req = NULL;
      32          43 :         struct dns_question *q = NULL;
      33           0 :         DNS_ERROR err;
      34             : 
      35          43 :         if (!(req = talloc_zero(mem_ctx, struct dns_request)) ||
      36          43 :             !(req->questions = talloc_array(req, struct dns_question *, 1)) ||
      37          43 :             !(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          43 :         generate_random_buffer((uint8_t *)&req->id, sizeof(req->id));
      44             : 
      45          43 :         req->num_questions = 1;
      46          43 :         q = req->questions[0];
      47             : 
      48          43 :         err = dns_domain_name_from_string(q, name, &q->name);
      49          43 :         if (!ERR_DNS_IS_OK(err)) {
      50           0 :                 TALLOC_FREE(req);
      51           0 :                 return err;
      52             :         }
      53             : 
      54          43 :         q->q_type = q_type;
      55          43 :         q->q_class = q_class;
      56             : 
      57          43 :         *preq = req;
      58          43 :         return ERROR_DNS_SUCCESS;
      59             : }
      60             : 
      61         127 : DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
      62             :                              struct dns_update_request **preq )
      63             : {
      64         127 :         struct dns_update_request *req = NULL;
      65         127 :         struct dns_zone *z = NULL;
      66           0 :         DNS_ERROR err;
      67             : 
      68         127 :         if (!(req = talloc_zero(mem_ctx, struct dns_update_request)) ||
      69         127 :             !(req->zones = talloc_array(req, struct dns_zone *, 1)) ||
      70         127 :             !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
      71           0 :                 TALLOC_FREE(req);
      72           0 :                 return ERROR_DNS_NO_MEMORY;
      73             :         }
      74             : 
      75         127 :         req->id = random();
      76         127 :         req->flags = 0x2800; /* Dynamic update */
      77             : 
      78         127 :         req->num_zones = 1;
      79         127 :         z = req->zones[0];
      80             : 
      81         127 :         err = dns_domain_name_from_string(z, name, &z->name);
      82         127 :         if (!ERR_DNS_IS_OK(err)) {
      83           0 :                 TALLOC_FREE(req);
      84           0 :                 return err;
      85             :         }
      86             : 
      87         127 :         z->z_type = QTYPE_SOA;
      88         127 :         z->z_class = DNS_CLASS_IN;
      89             : 
      90         127 :         *preq = req;
      91         127 :         return ERROR_DNS_SUCCESS;
      92             : }
      93             : 
      94         469 : 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         469 :         struct dns_rrec *rec = NULL;
     100           0 :         DNS_ERROR err;
     101             : 
     102         469 :         if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
     103           0 :                 return ERROR_DNS_NO_MEMORY;
     104             :         }
     105             : 
     106         469 :         err = dns_domain_name_from_string(rec, name, &rec->name);
     107         469 :         if (!(ERR_DNS_IS_OK(err))) {
     108           0 :                 TALLOC_FREE(rec);
     109           0 :                 return err;
     110             :         }
     111             : 
     112         469 :         rec->type = type;
     113         469 :         rec->r_class = r_class;
     114         469 :         rec->ttl = ttl;
     115         469 :         rec->data_length = data_length;
     116         469 :         rec->data = talloc_move(rec, &data);
     117             : 
     118         469 :         *prec = rec;
     119         469 :         return ERROR_DNS_SUCCESS;
     120             : }
     121             : 
     122         103 : 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           0 :         uint8_t *data;
     127           0 :         DNS_ERROR err;
     128           0 :         struct in_addr ip;
     129             : 
     130         103 :         if (pss->ss_family != AF_INET) {
     131           0 :                 return ERROR_DNS_INVALID_PARAMETER;
     132             :         }
     133             : 
     134         103 :         ip = ((const struct sockaddr_in *)pss)->sin_addr;
     135         103 :         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         103 :         err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
     141             :                               sizeof(ip.s_addr), data, prec);
     142             : 
     143         103 :         if (!ERR_DNS_IS_OK(err)) {
     144           0 :                 TALLOC_FREE(data);
     145             :         }
     146             : 
     147         103 :         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           0 :         uint8_t *data;
     156           0 :         DNS_ERROR err;
     157           0 :         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          58 : 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          58 :         if (ss != NULL) {
     188          58 :                 switch (ss->ss_family) {
     189          34 :                 case AF_INET:
     190          34 :                         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          42 : 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          42 :         return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
     209             :                                0, NULL, prec);
     210             : }
     211             : 
     212          84 : 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          84 :         return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
     217             : }
     218             : 
     219          42 : 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          42 :         struct dns_buffer *buf = NULL;
     226          42 :         struct dns_domain_name *algorithm = NULL;
     227           0 :         DNS_ERROR err;
     228             : 
     229          42 :         if (!(buf = dns_create_buffer(mem_ctx))) {
     230           0 :                 return ERROR_DNS_NO_MEMORY;
     231             :         }
     232             : 
     233          42 :         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
     234          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     235             : 
     236          42 :         dns_marshall_domain_name(buf, algorithm);
     237          42 :         dns_marshall_uint32(buf, inception);
     238          42 :         dns_marshall_uint32(buf, expiration);
     239          42 :         dns_marshall_uint16(buf, mode);
     240          42 :         dns_marshall_uint16(buf, error);
     241          42 :         dns_marshall_uint16(buf, key_length);
     242          42 :         dns_marshall_buffer(buf, key, key_length);
     243          42 :         dns_marshall_uint16(buf, 0); /* Other Size */
     244             : 
     245          42 :         if (!ERR_DNS_IS_OK(buf->error)) {
     246           0 :                 err = buf->error;
     247           0 :                 goto error;
     248             :         }
     249             : 
     250          42 :         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
     251          42 :                               buf->offset, buf->data, prec);
     252             : 
     253          42 :  error:
     254          42 :         TALLOC_FREE(buf);
     255          42 :         return err;
     256             : }
     257             : 
     258          42 : DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
     259             :                                      struct dns_tkey_record **ptkey)
     260             : {
     261           0 :         struct dns_tkey_record *tkey;
     262           0 :         struct dns_buffer buf;
     263           0 :         uint32_t tmp_inception, tmp_expiration;
     264             :         
     265          42 :         if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
     266           0 :                 return ERROR_DNS_NO_MEMORY;
     267             :         }
     268             : 
     269          42 :         buf.data = rec->data;
     270          42 :         buf.size = rec->data_length;
     271          42 :         buf.offset = 0;
     272          42 :         buf.error = ERROR_DNS_SUCCESS;
     273             : 
     274          42 :         dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
     275          42 :         dns_unmarshall_uint32(&buf, &tmp_inception);
     276          42 :         dns_unmarshall_uint32(&buf, &tmp_expiration);
     277          42 :         dns_unmarshall_uint16(&buf, &tkey->mode);
     278          42 :         dns_unmarshall_uint16(&buf, &tkey->error);
     279          42 :         dns_unmarshall_uint16(&buf, &tkey->key_length);
     280             : 
     281          42 :         if (!ERR_DNS_IS_OK(buf.error)) goto error;
     282             : 
     283          42 :         if (tkey->key_length) {
     284          42 :                 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          42 :         dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
     293          42 :         if (!ERR_DNS_IS_OK(buf.error)) goto error;
     294             : 
     295          42 :         tkey->inception = (time_t)tmp_inception;
     296          42 :         tkey->expiration = (time_t)tmp_expiration;
     297             : 
     298          42 :         *ptkey = tkey;
     299          42 :         return ERROR_DNS_SUCCESS;
     300             : 
     301           0 :  error:
     302           0 :         TALLOC_FREE(tkey);
     303           0 :         return buf.error;
     304             : }
     305             : 
     306          42 : 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          42 :         struct dns_buffer *buf = NULL;
     314          42 :         struct dns_domain_name *algorithm = NULL;
     315           0 :         DNS_ERROR err;
     316             : 
     317          42 :         if (!(buf = dns_create_buffer(mem_ctx))) {
     318           0 :                 return ERROR_DNS_NO_MEMORY;
     319             :         }
     320             : 
     321          42 :         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
     322          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     323             : 
     324          42 :         dns_marshall_domain_name(buf, algorithm);
     325          42 :         dns_marshall_uint16(buf, 0); /* time prefix */
     326          42 :         dns_marshall_uint32(buf, time_signed);
     327          42 :         dns_marshall_uint16(buf, fudge);
     328          42 :         dns_marshall_uint16(buf, mac_length);
     329          42 :         dns_marshall_buffer(buf, mac, mac_length);
     330          42 :         dns_marshall_uint16(buf, original_id);
     331          42 :         dns_marshall_uint16(buf, error);
     332          42 :         dns_marshall_uint16(buf, 0); /* Other Size */
     333             : 
     334          42 :         if (!ERR_DNS_IS_OK(buf->error)) {
     335           0 :                 err = buf->error;
     336           0 :                 goto error;
     337             :         }
     338             : 
     339          42 :         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
     340          42 :                               buf->offset, buf->data, prec);
     341             : 
     342          42 :  error:
     343          42 :         TALLOC_FREE(buf);
     344          42 :         return err;
     345             : }
     346             : 
     347         469 : DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
     348             :                        uint16_t *num_records, struct dns_rrec ***records)
     349             : {
     350           0 :         struct dns_rrec **new_records;
     351             : 
     352         469 :         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         469 :         new_records[*num_records] = talloc_move(new_records, &rec);
     359             : 
     360         469 :         *num_records += 1;
     361         469 :         *records = new_records;
     362         469 :         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          42 : 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          42 :         struct dns_update_request *req = NULL;
     376          42 :         struct dns_rrec *rec = NULL;
     377           0 :         DNS_ERROR err;
     378           0 :         uint16_t i;
     379             : 
     380          42 :         err = dns_create_update(mem_ctx, zone, &req);
     381          42 :         if (!ERR_DNS_IS_OK(err)) return err;
     382             : 
     383          42 :         err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
     384          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     385             : 
     386          42 :         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     387          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     388             : 
     389         100 :         for (i=0; i<num_ips; i++) {
     390          58 :                 err = dns_create_name_in_use_record(req, host,
     391          58 :                                                     &sslist[i], &rec);
     392          58 :                 if (!ERR_DNS_IS_OK(err)) goto error;
     393             : 
     394          58 :                 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     395          58 :                 if (!ERR_DNS_IS_OK(err)) goto error;
     396             :         }
     397             : 
     398          42 :         *preq = req;
     399          42 :         return ERROR_DNS_SUCCESS;
     400             : 
     401           0 :  error:
     402           0 :         TALLOC_FREE(req);
     403           0 :         return err;
     404             : }
     405             :                            
     406          84 : 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             :                                     uint32_t ttl,
     412             :                                     struct dns_update_request **preq)
     413             : {
     414          84 :         struct dns_update_request *req = NULL;
     415          84 :         struct dns_rrec *rec = NULL;
     416           0 :         DNS_ERROR err;
     417           0 :         size_t i;
     418             : 
     419          84 :         err = dns_create_update(mem_ctx, domainname, &req);
     420          84 :         if (!ERR_DNS_IS_OK(err)) return err;
     421             : 
     422             :         /*
     423             :          * Use the same prereq as WinXP -- No CNAME records for this host.
     424             :          */
     425             : 
     426          84 :         err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
     427             :                               0, 0, NULL, &rec);
     428          84 :         if (!ERR_DNS_IS_OK(err)) goto error;
     429             : 
     430          84 :         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
     431          84 :         if (!ERR_DNS_IS_OK(err)) goto error;
     432             : 
     433             :         /*
     434             :          * Delete all existing RRsets from our name
     435             :          */
     436             : 
     437          84 :         err = dns_create_delete_record(req, hostname, QTYPE_ANY, DNS_CLASS_ANY,
     438             :                                        &rec);
     439          84 :         if (!ERR_DNS_IS_OK(err)) goto error;
     440             : 
     441          84 :         err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
     442          84 :         if (!ERR_DNS_IS_OK(err)) goto error;
     443             : 
     444             :         /*
     445             :          * .. and add our IPs
     446             :          */
     447             : 
     448         200 :         for ( i=0; i<num_addrs; i++ ) {
     449             : 
     450         116 :                 switch(ss_addrs[i].ss_family) {
     451          68 :                 case AF_INET:
     452          68 :                         err = dns_create_a_record(req,
     453             :                                                   hostname,
     454             :                                                   ttl,
     455          68 :                                                   &ss_addrs[i],
     456             :                                                   &rec);
     457          68 :                         break;
     458             : #ifdef HAVE_IPV6
     459          48 :                 case AF_INET6:
     460          48 :                         err = dns_create_aaaa_record(req,
     461             :                                                      hostname,
     462             :                                                      ttl,
     463          48 :                                                      &ss_addrs[i],
     464             :                                                      &rec);
     465          48 :                         break;
     466             : #endif
     467           0 :                 default:
     468           0 :                         continue;
     469             :                 }
     470         116 :                 if (!ERR_DNS_IS_OK(err))
     471           0 :                         goto error;
     472             : 
     473         116 :                 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
     474         116 :                 if (!ERR_DNS_IS_OK(err))
     475           0 :                         goto error;
     476             :         }
     477             : 
     478          84 :         *preq = req;
     479          84 :         return ERROR_DNS_SUCCESS;
     480             : 
     481           0 :  error:
     482           0 :         TALLOC_FREE(req);
     483           0 :         return err;
     484             : }

Generated by: LCOV version 1.14