LCOV - code coverage report
Current view: top level - lib/addns - dnssock.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 98 203 48.3 %
Date: 2024-02-28 12:06:22 Functions: 12 15 80.0 %

          Line data    Source code
       1             : /*
       2             :   Linux DNS client library implementation
       3             : 
       4             :   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
       5             :   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
       6             : 
       7             :      ** NOTE! The following LGPL license applies to the libaddns
       8             :      ** library. This does NOT imply that all of Samba is released
       9             :      ** under the LGPL
      10             : 
      11             :   This library is free software; you can redistribute it and/or
      12             :   modify it under the terms of the GNU Lesser General Public
      13             :   License as published by the Free Software Foundation; either
      14             :   version 2.1 of the License, or (at your option) any later version.
      15             : 
      16             :   This library is distributed in the hope that it will be useful,
      17             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      19             :   Lesser General Public License for more details.
      20             : 
      21             :   You should have received a copy of the GNU Lesser General Public
      22             :   License along with this library; if not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "replace.h"
      26             : #include "dns.h"
      27             : #include <sys/time.h>
      28             : #include <unistd.h>
      29             : #include "system/select.h"
      30             : #include "../lib/util/debug.h"
      31             : 
      32          86 : static int destroy_dns_connection(struct dns_connection *conn)
      33             : {
      34          86 :         return close(conn->s);
      35             : }
      36             : 
      37             : /********************************************************************
      38             : ********************************************************************/
      39             : 
      40          86 : static DNS_ERROR dns_open_helper(const char *nameserver,
      41             :                                  const char *service,
      42             :                                  struct addrinfo *hints,
      43             :                                  TALLOC_CTX *mem_ctx,
      44             :                                  struct dns_connection **ret_conn)
      45             : {
      46           0 :         int ret;
      47           0 :         struct addrinfo *rp;
      48          86 :         struct addrinfo *ai_result = NULL;
      49          86 :         struct dns_connection *conn = NULL;
      50             : 
      51          86 :         if (!(conn = talloc(mem_ctx, struct dns_connection))) {
      52           0 :                 return ERROR_DNS_NO_MEMORY;
      53             :         }
      54             : 
      55          86 :         ret = getaddrinfo(nameserver, service, hints, &ai_result);
      56          86 :         if (ret != 0) {
      57           0 :                 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
      58           0 :                 TALLOC_FREE(conn);
      59           0 :                 return ERROR_DNS_INVALID_NAME_SERVER;
      60             :         }
      61             : 
      62          86 :         for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
      63          86 :                 conn->s = socket(rp->ai_family,
      64             :                                 rp->ai_socktype,
      65             :                                 rp->ai_protocol);
      66          86 :                 if (conn->s == -1) {
      67           0 :                         continue;
      68             :                 }
      69           0 :                 do {
      70          86 :                         ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
      71          86 :                 } while ((ret == -1) && (errno == EINTR));
      72          86 :                 if (ret != -1) {
      73             :                         /* Successful connect */
      74          86 :                         break;
      75             :                 }
      76           0 :                 close(conn->s);
      77             :         }
      78             : 
      79          86 :         freeaddrinfo(ai_result);
      80             : 
      81          86 :         if (rp == NULL) {
      82           0 :                 TALLOC_FREE(conn);
      83           0 :                 return ERROR_DNS_CONNECTION_FAILED;
      84             :         }
      85             : 
      86          86 :         talloc_set_destructor(conn, destroy_dns_connection);
      87             : 
      88          86 :         *ret_conn = conn;
      89          86 :         return ERROR_DNS_SUCCESS;
      90             : }
      91             : 
      92          86 : static DNS_ERROR dns_tcp_open( const char *nameserver,
      93             :                                TALLOC_CTX *mem_ctx,
      94             :                                struct dns_connection **result )
      95             : {
      96           0 :         struct addrinfo hints;
      97           0 :         struct dns_connection *conn;
      98           0 :         DNS_ERROR dns_ret;
      99           0 :         char service[16];
     100             : 
     101          86 :         snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
     102             : 
     103          86 :         memset(&hints, 0, sizeof(struct addrinfo));
     104          86 :         hints.ai_family = AF_UNSPEC;
     105          86 :         hints.ai_socktype = SOCK_STREAM;
     106          86 :         hints.ai_flags = 0;
     107          86 :         hints.ai_protocol = IPPROTO_TCP;
     108             : 
     109          86 :         dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
     110          86 :         if (!ERR_DNS_IS_OK(dns_ret)) {
     111           0 :                 return dns_ret;
     112             :         }
     113             : 
     114          86 :         conn->hType = DNS_TCP;
     115          86 :         *result = conn;
     116          86 :         return ERROR_DNS_SUCCESS;
     117             : }
     118             : 
     119             : /********************************************************************
     120             :  * ********************************************************************/
     121             : 
     122           0 : static DNS_ERROR dns_udp_open( const char *nameserver,
     123             :                                TALLOC_CTX *mem_ctx,
     124             :                                struct dns_connection **result )
     125             : {
     126           0 :         struct addrinfo hints;
     127           0 :         struct sockaddr_storage RecvAddr;
     128           0 :         struct dns_connection *conn = NULL;
     129           0 :         DNS_ERROR dns_ret;
     130           0 :         socklen_t RecvAddrLen;
     131           0 :         char service[16];
     132             : 
     133           0 :         snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
     134             : 
     135           0 :         memset(&hints, 0, sizeof(struct addrinfo));
     136           0 :         hints.ai_family = AF_UNSPEC;
     137           0 :         hints.ai_socktype = SOCK_DGRAM;
     138           0 :         hints.ai_flags = 0;
     139           0 :         hints.ai_protocol = IPPROTO_UDP;
     140             : 
     141           0 :         dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
     142           0 :         if (!ERR_DNS_IS_OK(dns_ret)) {
     143           0 :                 TALLOC_FREE(conn);
     144           0 :                 return dns_ret;
     145             :         }
     146             : 
     147             :         /* Set up the RecvAddr structure with the IP address of
     148             :            the receiver and the specified port number. */
     149             : 
     150           0 :         RecvAddrLen = sizeof(RecvAddr);
     151           0 :         if (getpeername(conn->s,
     152             :                         (struct sockaddr *)&RecvAddr,
     153             :                         &RecvAddrLen) == -1) {
     154           0 :                 return ERROR_DNS_CONNECTION_FAILED;
     155             :         }
     156             : 
     157           0 :         conn->hType = DNS_UDP;
     158           0 :         memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
     159             : 
     160           0 :         *result = conn;
     161           0 :         return ERROR_DNS_SUCCESS;
     162             : }
     163             : 
     164             : /********************************************************************
     165             : ********************************************************************/
     166             : 
     167          86 : DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
     168             :                     TALLOC_CTX *mem_ctx,
     169             :                     struct dns_connection **conn )
     170             : {
     171          86 :         switch ( dwType ) {
     172          86 :         case DNS_TCP:
     173          86 :                 return dns_tcp_open( nameserver, mem_ctx, conn );
     174           0 :         case DNS_UDP:
     175           0 :                 return dns_udp_open( nameserver, mem_ctx, conn );
     176             :         }
     177             : 
     178           0 :         return ERROR_DNS_INVALID_PARAMETER;
     179             : }
     180             : 
     181         340 : static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
     182             : {
     183         340 :         size_t total = 0;
     184             : 
     185         722 :         while (total < len) {
     186             : 
     187           0 :                 ssize_t ret;
     188             : 
     189           0 :                 do {
     190         382 :                         ret = write(fd, data + total, len - total);
     191         382 :                 } while ((ret == -1) && (errno == EINTR));
     192             : 
     193         382 :                 if (ret <= 0) {
     194             :                         /*
     195             :                          * EOF or error
     196             :                          */
     197           0 :                         return ERROR_DNS_SOCKET_ERROR;
     198             :                 }
     199             : 
     200         382 :                 total += ret;
     201             :         }
     202             : 
     203         340 :         return ERROR_DNS_SUCCESS;
     204             : }
     205             : 
     206         170 : static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
     207             :                               const struct dns_buffer *buf)
     208             : {
     209         170 :         uint16_t len = htons(buf->offset);
     210           0 :         DNS_ERROR err;
     211             : 
     212         170 :         err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
     213         170 :         if (!ERR_DNS_IS_OK(err)) return err;
     214             : 
     215         170 :         return write_all(conn->s, buf->data, buf->offset);
     216             : }
     217             : 
     218           0 : static DNS_ERROR dns_send_udp(struct dns_connection *conn,
     219             :                               const struct dns_buffer *buf)
     220             : {
     221           0 :         ssize_t ret;
     222             : 
     223           0 :         do {
     224           0 :                 ret = send(conn->s, buf->data, buf->offset, 0);
     225           0 :         } while ((ret == -1) && (errno == EINTR));
     226             : 
     227           0 :         if (ret != buf->offset) {
     228           0 :                 return ERROR_DNS_SOCKET_ERROR;
     229             :         }
     230             : 
     231           0 :         return ERROR_DNS_SUCCESS;
     232             : }
     233             : 
     234         170 : DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
     235             : {
     236         170 :         if (conn->hType == DNS_TCP) {
     237         170 :                 return dns_send_tcp(conn, buf);
     238             :         }
     239             : 
     240           0 :         if (conn->hType == DNS_UDP) {
     241           0 :                 return dns_send_udp(conn, buf);
     242             :         }
     243             : 
     244           0 :         return ERROR_DNS_INVALID_PARAMETER;
     245             : }
     246             : 
     247         340 : static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
     248             : {
     249         340 :         size_t total = 0;
     250             : 
     251         680 :         while (total < len) {
     252           0 :                 struct pollfd pfd;
     253           0 :                 ssize_t ret;
     254           0 :                 int fd_ready;
     255             : 
     256         340 :                 ZERO_STRUCT(pfd);
     257         340 :                 pfd.fd = fd;
     258         340 :                 pfd.events = POLLIN|POLLHUP;
     259             : 
     260         340 :                 fd_ready = poll(&pfd, 1, 10000);
     261         340 :                 if (fd_ready == -1) {
     262           0 :                         if (errno == EINTR) {
     263           0 :                                 continue;
     264             :                         }
     265           0 :                         return ERROR_DNS_SOCKET_ERROR;
     266             :                 }
     267         340 :                 if ( fd_ready == 0 ) {
     268             :                         /* read timeout */
     269           0 :                         return ERROR_DNS_SOCKET_ERROR;
     270             :                 }
     271             : 
     272           0 :                 do {
     273         340 :                         ret = read(fd, data + total, len - total);
     274         340 :                 } while ((ret == -1) && (errno == EINTR));
     275             : 
     276         340 :                 if (ret <= 0) {
     277             :                         /* EOF or error */
     278           0 :                         return ERROR_DNS_SOCKET_ERROR;
     279             :                 }
     280             : 
     281         340 :                 total += ret;
     282             :         }
     283             : 
     284         340 :         return ERROR_DNS_SUCCESS;
     285             : }
     286             : 
     287         170 : static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
     288             :                                  struct dns_connection *conn,
     289             :                                  struct dns_buffer **presult)
     290             : {
     291           0 :         struct dns_buffer *buf;
     292           0 :         DNS_ERROR err;
     293           0 :         uint16_t len;
     294             : 
     295         170 :         if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
     296           0 :                 return ERROR_DNS_NO_MEMORY;
     297             :         }
     298             : 
     299         170 :         err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
     300         170 :         if (!ERR_DNS_IS_OK(err)) {
     301           0 :                 return err;
     302             :         }
     303             : 
     304         170 :         buf->size = ntohs(len);
     305             : 
     306         170 :         if (buf->size == 0) {
     307           0 :                 *presult = buf;
     308           0 :                 return ERROR_DNS_SUCCESS;
     309             :         }
     310             : 
     311         170 :         if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
     312           0 :                 TALLOC_FREE(buf);
     313           0 :                 return ERROR_DNS_NO_MEMORY;
     314             :         }
     315             : 
     316         170 :         err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
     317         170 :         if (!ERR_DNS_IS_OK(err)) {
     318           0 :                 TALLOC_FREE(buf);
     319           0 :                 return err;
     320             :         }
     321             : 
     322         170 :         *presult = buf;
     323         170 :         return ERROR_DNS_SUCCESS;
     324             : }
     325             : 
     326           0 : static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
     327             :                                  struct dns_connection *conn,
     328             :                                  struct dns_buffer **presult)
     329             : {
     330           0 :         struct dns_buffer *buf;
     331           0 :         ssize_t received;
     332             : 
     333           0 :         if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
     334           0 :                 return ERROR_DNS_NO_MEMORY;
     335             :         }
     336             : 
     337             :         /*
     338             :          * UDP based DNS can only be 512 bytes
     339             :          */
     340             : 
     341           0 :         if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
     342           0 :                 TALLOC_FREE(buf);
     343           0 :                 return ERROR_DNS_NO_MEMORY;
     344             :         }
     345             : 
     346           0 :         do {
     347           0 :                 received = recv(conn->s, (void *)buf->data, 512, 0);
     348           0 :         } while ((received == -1) && (errno == EINTR));
     349             : 
     350           0 :         if (received == -1) {
     351           0 :                 TALLOC_FREE(buf);
     352           0 :                 return ERROR_DNS_SOCKET_ERROR;
     353             :         }
     354             : 
     355           0 :         if (received > 512) {
     356           0 :                 TALLOC_FREE(buf);
     357           0 :                 return ERROR_DNS_BAD_RESPONSE;
     358             :         }
     359             : 
     360           0 :         buf->size = received;
     361           0 :         buf->offset = 0;
     362             : 
     363           0 :         *presult = buf;
     364           0 :         return ERROR_DNS_SUCCESS;
     365             : }
     366             : 
     367         170 : DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
     368             :                       struct dns_buffer **presult)
     369             : {
     370         170 :         if (conn->hType == DNS_TCP) {
     371         170 :                 return dns_receive_tcp(mem_ctx, conn, presult);
     372             :         }
     373             : 
     374           0 :         if (conn->hType == DNS_UDP) {
     375           0 :                 return dns_receive_udp(mem_ctx, conn, presult);
     376             :         }
     377             : 
     378           0 :         return ERROR_DNS_INVALID_PARAMETER;
     379             : }
     380             : 
     381         128 : DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
     382             :                           const struct dns_request *req,
     383             :                           struct dns_request **resp)
     384             : {
     385         128 :         struct dns_buffer *buf = NULL;
     386           0 :         DNS_ERROR err;
     387             : 
     388         128 :         err = dns_marshall_request(mem_ctx, req, &buf);
     389         128 :         if (!ERR_DNS_IS_OK(err)) goto error;
     390             : 
     391         128 :         err = dns_send(conn, buf);
     392         128 :         if (!ERR_DNS_IS_OK(err)) goto error;
     393         128 :         TALLOC_FREE(buf);
     394             : 
     395         128 :         err = dns_receive(mem_ctx, conn, &buf);
     396         128 :         if (!ERR_DNS_IS_OK(err)) goto error;
     397             : 
     398         128 :         err = dns_unmarshall_request(mem_ctx, buf, resp);
     399             : 
     400         128 :  error:
     401         128 :         TALLOC_FREE(buf);
     402         128 :         return err;
     403             : }
     404             : 
     405         127 : DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
     406             :                                  struct dns_connection *conn,
     407             :                                  struct dns_update_request *up_req,
     408             :                                  struct dns_update_request **up_resp)
     409             : {
     410           0 :         struct dns_request *resp;
     411           0 :         DNS_ERROR err;
     412             : 
     413         127 :         err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
     414             :                               &resp);
     415             : 
     416         127 :         if (!ERR_DNS_IS_OK(err)) return err;
     417             : 
     418         127 :         *up_resp = dns_request2update(resp);
     419         127 :         return ERROR_DNS_SUCCESS;
     420             : }

Generated by: LCOV version 1.14