r22731: - Fix bug #4594.
[Samba/bb.git] / source3 / libaddns / dnssock.c
blob6ceefb4e32d4ffea13360be022e9834a0f7be0d0
1 /*
2 Linux DNS client library implementation
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
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
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.
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.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
27 #include "dns.h"
28 #include <sys/time.h>
29 #include <unistd.h>
31 static int destroy_dns_connection(struct dns_connection *conn)
33 return close(conn->s);
36 /********************************************************************
37 ********************************************************************/
39 static DNS_ERROR dns_tcp_open( const char *nameserver,
40 TALLOC_CTX *mem_ctx,
41 struct dns_connection **result )
43 uint32_t ulAddress;
44 struct hostent *pHost;
45 struct sockaddr_in s_in;
46 struct dns_connection *conn;
47 int res;
49 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
50 return ERROR_DNS_NO_MEMORY;
53 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
54 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
55 TALLOC_FREE(conn);
56 return ERROR_DNS_INVALID_NAME_SERVER;
58 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
61 conn->s = socket( PF_INET, SOCK_STREAM, 0 );
62 if (conn->s == -1) {
63 TALLOC_FREE(conn);
64 return ERROR_DNS_CONNECTION_FAILED;
67 talloc_set_destructor(conn, destroy_dns_connection);
69 s_in.sin_family = AF_INET;
70 s_in.sin_addr.s_addr = ulAddress;
71 s_in.sin_port = htons( DNS_TCP_PORT );
73 res = connect(conn->s, (struct sockaddr*)&s_in, sizeof( s_in ));
74 if (res == -1) {
75 TALLOC_FREE(conn);
76 return ERROR_DNS_CONNECTION_FAILED;
79 conn->hType = DNS_TCP;
81 *result = conn;
82 return ERROR_DNS_SUCCESS;
85 /********************************************************************
86 ********************************************************************/
88 static DNS_ERROR dns_udp_open( const char *nameserver,
89 TALLOC_CTX *mem_ctx,
90 struct dns_connection **result )
92 unsigned long ulAddress;
93 struct hostent *pHost;
94 struct sockaddr_in RecvAddr;
95 struct dns_connection *conn;
97 if (!(conn = talloc(NULL, struct dns_connection))) {
98 return ERROR_DNS_NO_MEMORY;
101 if ( (ulAddress = inet_addr( nameserver )) == INADDR_NONE ) {
102 if ( (pHost = gethostbyname( nameserver )) == NULL ) {
103 TALLOC_FREE(conn);
104 return ERROR_DNS_INVALID_NAME_SERVER;
106 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
109 /* Create a socket for sending data */
111 conn->s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
112 if (conn->s == -1) {
113 TALLOC_FREE(conn);
114 return ERROR_DNS_CONNECTION_FAILED;
117 talloc_set_destructor(conn, destroy_dns_connection);
119 /* Set up the RecvAddr structure with the IP address of
120 the receiver (in this example case "123.456.789.1")
121 and the specified port number. */
123 RecvAddr.sin_family = AF_INET;
124 RecvAddr.sin_port = htons( DNS_UDP_PORT );
125 RecvAddr.sin_addr.s_addr = ulAddress;
127 conn->hType = DNS_UDP;
128 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
130 *result = conn;
131 return ERROR_DNS_SUCCESS;
134 /********************************************************************
135 ********************************************************************/
137 DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
138 TALLOC_CTX *mem_ctx,
139 struct dns_connection **conn )
141 switch ( dwType ) {
142 case DNS_TCP:
143 return dns_tcp_open( nameserver, mem_ctx, conn );
144 case DNS_UDP:
145 return dns_udp_open( nameserver, mem_ctx, conn );
148 return ERROR_DNS_INVALID_PARAMETER;
151 static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
153 size_t total = 0;
155 while (total < len) {
157 ssize_t ret = write(fd, data + total, len - total);
159 if (ret <= 0) {
161 * EOF or error
163 return ERROR_DNS_SOCKET_ERROR;
166 total += ret;
169 return ERROR_DNS_SUCCESS;
172 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
173 const struct dns_buffer *buf)
175 uint16 len = htons(buf->offset);
176 DNS_ERROR err;
178 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
179 if (!ERR_DNS_IS_OK(err)) return err;
181 return write_all(conn->s, buf->data, buf->offset);
184 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
185 const struct dns_buffer *buf)
187 ssize_t ret;
189 ret = sendto(conn->s, buf->data, buf->offset, 0,
190 (struct sockaddr *)&conn->RecvAddr,
191 sizeof(conn->RecvAddr));
193 if (ret != buf->offset) {
194 return ERROR_DNS_SOCKET_ERROR;
197 return ERROR_DNS_SUCCESS;
200 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
202 if (conn->hType == DNS_TCP) {
203 return dns_send_tcp(conn, buf);
206 if (conn->hType == DNS_UDP) {
207 return dns_send_udp(conn, buf);
210 return ERROR_DNS_INVALID_PARAMETER;
213 static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
215 size_t total = 0;
216 fd_set rfds;
217 struct timeval tv;
219 while (total < len) {
220 ssize_t ret;
221 int fd_ready;
223 FD_ZERO( &rfds );
224 FD_SET( fd, &rfds );
226 /* 10 second timeout */
227 tv.tv_sec = 10;
228 tv.tv_usec = 0;
230 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
231 if ( fd_ready == 0 ) {
232 /* read timeout */
233 return ERROR_DNS_SOCKET_ERROR;
236 ret = read(fd, data + total, len - total);
237 if (ret <= 0) {
238 /* EOF or error */
239 return ERROR_DNS_SOCKET_ERROR;
242 total += ret;
245 return ERROR_DNS_SUCCESS;
248 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
249 struct dns_connection *conn,
250 struct dns_buffer **presult)
252 struct dns_buffer *buf;
253 DNS_ERROR err;
254 uint16 len;
256 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
257 return ERROR_DNS_NO_MEMORY;
260 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
261 if (!ERR_DNS_IS_OK(err)) {
262 return err;
265 buf->size = ntohs(len);
267 if (buf->size) {
268 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
269 TALLOC_FREE(buf);
270 return ERROR_DNS_NO_MEMORY;
272 } else {
273 buf->data = NULL;
276 err = read_all(conn->s, buf->data, buf->size);
277 if (!ERR_DNS_IS_OK(err)) {
278 TALLOC_FREE(buf);
279 return err;
282 *presult = buf;
283 return ERROR_DNS_SUCCESS;
286 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
287 struct dns_connection *conn,
288 struct dns_buffer **presult)
290 struct dns_buffer *buf;
291 ssize_t received;
293 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
294 return ERROR_DNS_NO_MEMORY;
298 * UDP based DNS can only be 512 bytes
301 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
302 TALLOC_FREE(buf);
303 return ERROR_DNS_NO_MEMORY;
306 received = recv(conn->s, (void *)buf->data, 512, 0);
308 if (received == -1) {
309 TALLOC_FREE(buf);
310 return ERROR_DNS_SOCKET_ERROR;
313 if (received > 512) {
314 TALLOC_FREE(buf);
315 return ERROR_DNS_BAD_RESPONSE;
318 buf->size = received;
319 buf->offset = 0;
321 *presult = buf;
322 return ERROR_DNS_SUCCESS;
325 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
326 struct dns_buffer **presult)
328 if (conn->hType == DNS_TCP) {
329 return dns_receive_tcp(mem_ctx, conn, presult);
332 if (conn->hType == DNS_UDP) {
333 return dns_receive_udp(mem_ctx, conn, presult);
336 return ERROR_DNS_INVALID_PARAMETER;
339 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
340 const struct dns_request *req,
341 struct dns_request **resp)
343 struct dns_buffer *buf = NULL;
344 DNS_ERROR err;
346 err = dns_marshall_request(conn, req, &buf);
347 if (!ERR_DNS_IS_OK(err)) goto error;
349 err = dns_send(conn, buf);
350 if (!ERR_DNS_IS_OK(err)) goto error;
351 TALLOC_FREE(buf);
353 err = dns_receive(mem_ctx, conn, &buf);
354 if (!ERR_DNS_IS_OK(err)) goto error;
356 err = dns_unmarshall_request(mem_ctx, buf, resp);
358 error:
359 TALLOC_FREE(buf);
360 return err;
363 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
364 struct dns_connection *conn,
365 struct dns_update_request *up_req,
366 struct dns_update_request **up_resp)
368 struct dns_request *resp;
369 DNS_ERROR err;
371 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
372 &resp);
374 if (!ERR_DNS_IS_OK(err)) return err;
376 *up_resp = dns_request2update(resp);
377 return ERROR_DNS_SUCCESS;