root/source3/libaddns/dnssock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. destroy_dns_connection
  2. dns_tcp_open
  3. dns_udp_open
  4. dns_open_connection
  5. write_all
  6. dns_send_tcp
  7. dns_send_udp
  8. dns_send
  9. read_all
  10. dns_receive_tcp
  11. dns_receive_udp
  12. dns_receive
  13. dns_transaction
  14. dns_update_transaction

   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 "dns.h"
  26 #include <sys/time.h>
  27 #include <unistd.h>
  28 
  29 static int destroy_dns_connection(struct dns_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
  30 {
  31         return close(conn->s);
  32 }
  33 
  34 /********************************************************************
  35 ********************************************************************/
  36 
  37 static DNS_ERROR dns_tcp_open( const char *nameserver,
     /* [<][>][^][v][top][bottom][index][help] */
  38                                TALLOC_CTX *mem_ctx,
  39                                struct dns_connection **result )
  40 {
  41         uint32_t ulAddress;
  42         struct hostent *pHost;
  43         struct sockaddr_in s_in;
  44         struct dns_connection *conn;
  45         int res;
  46 
  47         if (!(conn = talloc(mem_ctx, struct dns_connection))) {
  48                 return ERROR_DNS_NO_MEMORY;
  49         }
  50 
  51         if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
  52                 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
  53                         TALLOC_FREE(conn);
  54                         return ERROR_DNS_INVALID_NAME_SERVER;
  55                 }
  56                 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
  57         }
  58 
  59         conn->s = socket( PF_INET, SOCK_STREAM, 0 );
  60         if (conn->s == -1) {
  61                 TALLOC_FREE(conn);
  62                 return ERROR_DNS_CONNECTION_FAILED;
  63         }
  64 
  65         talloc_set_destructor(conn, destroy_dns_connection);
  66 
  67         s_in.sin_family = AF_INET;
  68         s_in.sin_addr.s_addr = ulAddress;
  69         s_in.sin_port = htons( DNS_TCP_PORT );
  70 
  71         res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
  72         if (res == -1) {
  73                 TALLOC_FREE(conn);
  74                 return ERROR_DNS_CONNECTION_FAILED;
  75         }
  76 
  77         conn->hType = DNS_TCP;
  78 
  79         *result = conn;
  80         return ERROR_DNS_SUCCESS;
  81 }
  82 
  83 /********************************************************************
  84 ********************************************************************/
  85 
  86 static DNS_ERROR dns_udp_open( const char *nameserver,
     /* [<][>][^][v][top][bottom][index][help] */
  87                                TALLOC_CTX *mem_ctx,
  88                                struct dns_connection **result )
  89 {
  90         unsigned long ulAddress;
  91         struct hostent *pHost;
  92         struct sockaddr_in RecvAddr;
  93         struct dns_connection *conn;
  94 
  95         if (!(conn = talloc(NULL, struct dns_connection))) {
  96                 return ERROR_DNS_NO_MEMORY;
  97         }
  98 
  99         if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
 100                 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
 101                         TALLOC_FREE(conn);
 102                         return ERROR_DNS_INVALID_NAME_SERVER;
 103                 }
 104                 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
 105         }
 106         
 107         /* Create a socket for sending data */
 108 
 109         conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
 110         if (conn->s == -1) {
 111                 TALLOC_FREE(conn);
 112                 return ERROR_DNS_CONNECTION_FAILED;
 113         }
 114 
 115         talloc_set_destructor(conn, destroy_dns_connection);
 116 
 117         /* Set up the RecvAddr structure with the IP address of
 118            the receiver (in this example case "123.456.789.1")
 119            and the specified port number. */
 120 
 121         ZERO_STRUCT(RecvAddr);
 122         RecvAddr.sin_family = AF_INET;
 123         RecvAddr.sin_port = htons( DNS_UDP_PORT );
 124         RecvAddr.sin_addr.s_addr = ulAddress;
 125 
 126         conn->hType = DNS_UDP;
 127         memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
 128 
 129         *result = conn;
 130         return ERROR_DNS_SUCCESS;
 131 }
 132 
 133 /********************************************************************
 134 ********************************************************************/
 135 
 136 DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
     /* [<][>][^][v][top][bottom][index][help] */
 137                     TALLOC_CTX *mem_ctx,
 138                     struct dns_connection **conn )
 139 {
 140         switch ( dwType ) {
 141         case DNS_TCP:
 142                 return dns_tcp_open( nameserver, mem_ctx, conn );
 143         case DNS_UDP:
 144                 return dns_udp_open( nameserver, mem_ctx, conn );
 145         }
 146         
 147         return ERROR_DNS_INVALID_PARAMETER;
 148 }
 149 
 150 static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
     /* [<][>][^][v][top][bottom][index][help] */
 151 {
 152         size_t total = 0;
 153 
 154         while (total < len) {
 155 
 156                 ssize_t ret = write(fd, data + total, len - total);
 157 
 158                 if (ret <= 0) {
 159                         /*
 160                          * EOF or error
 161                          */
 162                         return ERROR_DNS_SOCKET_ERROR;
 163                 }
 164 
 165                 total += ret;
 166         }
 167 
 168         return ERROR_DNS_SUCCESS;
 169 }
 170 
 171 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 172                               const struct dns_buffer *buf)
 173 {
 174         uint16 len = htons(buf->offset);
 175         DNS_ERROR err;
 176 
 177         err = write_all(conn->s, (uint8 *)&len, sizeof(len));
 178         if (!ERR_DNS_IS_OK(err)) return err;
 179 
 180         return write_all(conn->s, buf->data, buf->offset);
 181 }
 182 
 183 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 184                               const struct dns_buffer *buf)
 185 {
 186         ssize_t ret;
 187 
 188         ret = sendto(conn->s, buf->data, buf->offset, 0,
 189                      (struct sockaddr *)&conn->RecvAddr,
 190                      sizeof(conn->RecvAddr));
 191 
 192         if (ret != buf->offset) {
 193                 return ERROR_DNS_SOCKET_ERROR;
 194         }
 195 
 196         return ERROR_DNS_SUCCESS;
 197 }
 198 
 199 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
     /* [<][>][^][v][top][bottom][index][help] */
 200 {
 201         if (conn->hType == DNS_TCP) {
 202                 return dns_send_tcp(conn, buf);
 203         }
 204 
 205         if (conn->hType == DNS_UDP) {
 206                 return dns_send_udp(conn, buf);
 207         }
 208 
 209         return ERROR_DNS_INVALID_PARAMETER;
 210 }
 211 
 212 static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
     /* [<][>][^][v][top][bottom][index][help] */
 213 {
 214         size_t total = 0;
 215         fd_set rfds;
 216         struct timeval tv;
 217 
 218         while (total < len) {
 219                 ssize_t ret;
 220                 int fd_ready;
 221                 
 222                 FD_ZERO( &rfds );
 223                 FD_SET( fd, &rfds );
 224 
 225                 /* 10 second timeout */
 226                 tv.tv_sec = 10;
 227                 tv.tv_usec = 0;
 228                 
 229                 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
 230                 if ( fd_ready == 0 ) {
 231                         /* read timeout */
 232                         return ERROR_DNS_SOCKET_ERROR;
 233                 }
 234 
 235                 ret = read(fd, data + total, len - total);
 236                 if (ret <= 0) {
 237                         /* EOF or error */
 238                         return ERROR_DNS_SOCKET_ERROR;
 239                 }
 240 
 241                 total += ret;
 242         }
 243 
 244         return ERROR_DNS_SUCCESS;
 245 }
 246 
 247 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 248                                  struct dns_connection *conn,
 249                                  struct dns_buffer **presult)
 250 {
 251         struct dns_buffer *buf;
 252         DNS_ERROR err;
 253         uint16 len;
 254 
 255         if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
 256                 return ERROR_DNS_NO_MEMORY;
 257         }
 258 
 259         err = read_all(conn->s, (uint8 *)&len, sizeof(len));
 260         if (!ERR_DNS_IS_OK(err)) {
 261                 return err;
 262         }
 263 
 264         buf->size = ntohs(len);
 265 
 266         if (buf->size) {
 267                 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
 268                         TALLOC_FREE(buf);
 269                         return ERROR_DNS_NO_MEMORY;
 270                 }
 271         } else {
 272                 buf->data = NULL;
 273         }
 274 
 275         err = read_all(conn->s, buf->data, buf->size);
 276         if (!ERR_DNS_IS_OK(err)) {
 277                 TALLOC_FREE(buf);
 278                 return err;
 279         }
 280 
 281         *presult = buf;
 282         return ERROR_DNS_SUCCESS;
 283 }
 284 
 285 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 286                                  struct dns_connection *conn,
 287                                  struct dns_buffer **presult)
 288 {
 289         struct dns_buffer *buf;
 290         ssize_t received;
 291 
 292         if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
 293                 return ERROR_DNS_NO_MEMORY;
 294         }
 295 
 296         /*
 297          * UDP based DNS can only be 512 bytes
 298          */
 299 
 300         if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
 301                 TALLOC_FREE(buf);
 302                 return ERROR_DNS_NO_MEMORY;
 303         }
 304 
 305         received = recv(conn->s, (void *)buf->data, 512, 0);
 306 
 307         if (received == -1) {
 308                 TALLOC_FREE(buf);
 309                 return ERROR_DNS_SOCKET_ERROR;
 310         }
 311 
 312         if (received > 512) {
 313                 TALLOC_FREE(buf);
 314                 return ERROR_DNS_BAD_RESPONSE;
 315         }
 316 
 317         buf->size = received;
 318         buf->offset = 0;
 319 
 320         *presult = buf;
 321         return ERROR_DNS_SUCCESS;
 322 }
 323 
 324 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 325                       struct dns_buffer **presult)
 326 {
 327         if (conn->hType == DNS_TCP) {
 328                 return dns_receive_tcp(mem_ctx, conn, presult);
 329         }
 330 
 331         if (conn->hType == DNS_UDP) {
 332                 return dns_receive_udp(mem_ctx, conn, presult);
 333         }
 334 
 335         return ERROR_DNS_INVALID_PARAMETER;
 336 }
 337 
 338 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 339                           const struct dns_request *req,
 340                           struct dns_request **resp)
 341 {
 342         struct dns_buffer *buf = NULL;
 343         DNS_ERROR err;
 344 
 345         err = dns_marshall_request(conn, req, &buf);
 346         if (!ERR_DNS_IS_OK(err)) goto error;
 347 
 348         err = dns_send(conn, buf);
 349         if (!ERR_DNS_IS_OK(err)) goto error;
 350         TALLOC_FREE(buf);
 351 
 352         err = dns_receive(mem_ctx, conn, &buf);
 353         if (!ERR_DNS_IS_OK(err)) goto error;
 354 
 355         err = dns_unmarshall_request(mem_ctx, buf, resp);
 356 
 357  error:
 358         TALLOC_FREE(buf);
 359         return err;
 360 }
 361 
 362 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 363                                  struct dns_connection *conn,
 364                                  struct dns_update_request *up_req,
 365                                  struct dns_update_request **up_resp)
 366 {
 367         struct dns_request *resp;
 368         DNS_ERROR err;
 369 
 370         err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
 371                               &resp);
 372 
 373         if (!ERR_DNS_IS_OK(err)) return err;
 374 
 375         *up_resp = dns_request2update(resp);
 376         return ERROR_DNS_SUCCESS;
 377 }

/* [<][>][^][v][top][bottom][index][help] */