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 29static int destroy_dns_connection(struct dns_connection *conn) 30{ 31 return close(conn->s); 32} 33 34/******************************************************************** 35********************************************************************/ 36 37static DNS_ERROR dns_tcp_open( const char *nameserver, 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 86static DNS_ERROR dns_udp_open( const char *nameserver, 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 136DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType, 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 150static DNS_ERROR write_all(int fd, uint8 *data, size_t len) 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 171static DNS_ERROR dns_send_tcp(struct dns_connection *conn, 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 183static DNS_ERROR dns_send_udp(struct dns_connection *conn, 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 199DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf) 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 212static DNS_ERROR read_all(int fd, uint8 *data, size_t len) 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 if (fd < 0 || fd >= FD_SETSIZE) { 223 /* read timeout */ 224 return ERROR_DNS_SOCKET_ERROR; 225 } 226 227 FD_ZERO( &rfds ); 228 FD_SET( fd, &rfds ); 229 230 /* 10 second timeout */ 231 tv.tv_sec = 10; 232 tv.tv_usec = 0; 233 234 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv ); 235 if ( fd_ready == 0 ) { 236 /* read timeout */ 237 return ERROR_DNS_SOCKET_ERROR; 238 } 239 240 ret = read(fd, data + total, len - total); 241 if (ret <= 0) { 242 /* EOF or error */ 243 return ERROR_DNS_SOCKET_ERROR; 244 } 245 246 total += ret; 247 } 248 249 return ERROR_DNS_SUCCESS; 250} 251 252static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx, 253 struct dns_connection *conn, 254 struct dns_buffer **presult) 255{ 256 struct dns_buffer *buf; 257 DNS_ERROR err; 258 uint16 len; 259 260 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) { 261 return ERROR_DNS_NO_MEMORY; 262 } 263 264 err = read_all(conn->s, (uint8 *)&len, sizeof(len)); 265 if (!ERR_DNS_IS_OK(err)) { 266 return err; 267 } 268 269 buf->size = ntohs(len); 270 271 if (buf->size) { 272 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) { 273 TALLOC_FREE(buf); 274 return ERROR_DNS_NO_MEMORY; 275 } 276 } else { 277 buf->data = NULL; 278 } 279 280 err = read_all(conn->s, buf->data, buf->size); 281 if (!ERR_DNS_IS_OK(err)) { 282 TALLOC_FREE(buf); 283 return err; 284 } 285 286 *presult = buf; 287 return ERROR_DNS_SUCCESS; 288} 289 290static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx, 291 struct dns_connection *conn, 292 struct dns_buffer **presult) 293{ 294 struct dns_buffer *buf; 295 ssize_t received; 296 297 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) { 298 return ERROR_DNS_NO_MEMORY; 299 } 300 301 /* 302 * UDP based DNS can only be 512 bytes 303 */ 304 305 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) { 306 TALLOC_FREE(buf); 307 return ERROR_DNS_NO_MEMORY; 308 } 309 310 received = recv(conn->s, (void *)buf->data, 512, 0); 311 312 if (received == -1) { 313 TALLOC_FREE(buf); 314 return ERROR_DNS_SOCKET_ERROR; 315 } 316 317 if (received > 512) { 318 TALLOC_FREE(buf); 319 return ERROR_DNS_BAD_RESPONSE; 320 } 321 322 buf->size = received; 323 buf->offset = 0; 324 325 *presult = buf; 326 return ERROR_DNS_SUCCESS; 327} 328 329DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn, 330 struct dns_buffer **presult) 331{ 332 if (conn->hType == DNS_TCP) { 333 return dns_receive_tcp(mem_ctx, conn, presult); 334 } 335 336 if (conn->hType == DNS_UDP) { 337 return dns_receive_udp(mem_ctx, conn, presult); 338 } 339 340 return ERROR_DNS_INVALID_PARAMETER; 341} 342 343DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn, 344 const struct dns_request *req, 345 struct dns_request **resp) 346{ 347 struct dns_buffer *buf = NULL; 348 DNS_ERROR err; 349 350 err = dns_marshall_request(conn, req, &buf); 351 if (!ERR_DNS_IS_OK(err)) goto error; 352 353 err = dns_send(conn, buf); 354 if (!ERR_DNS_IS_OK(err)) goto error; 355 TALLOC_FREE(buf); 356 357 err = dns_receive(mem_ctx, conn, &buf); 358 if (!ERR_DNS_IS_OK(err)) goto error; 359 360 err = dns_unmarshall_request(mem_ctx, buf, resp); 361 362 error: 363 TALLOC_FREE(buf); 364 return err; 365} 366 367DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx, 368 struct dns_connection *conn, 369 struct dns_update_request *up_req, 370 struct dns_update_request **up_resp) 371{ 372 struct dns_request *resp; 373 DNS_ERROR err; 374 375 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req), 376 &resp); 377 378 if (!ERR_DNS_IS_OK(err)) return err; 379 380 *up_resp = dns_request2update(resp); 381 return ERROR_DNS_SUCCESS; 382} 383