r23799: updated old Franklin Street FSF addresses to new URL
[Samba.git] / source / libaddns / dnssock.c
blob72bbf60d45c6c03dd0ab4e5df7783eb6a2a897e8
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, see <http://www.gnu.org/licenses/>.
25 #include "dns.h"
26 #include <sys/time.h>
27 #include <unistd.h>
29 static int destroy_dns_connection(struct dns_connection *conn)
31 return close(conn->s);
34 /********************************************************************
35 ********************************************************************/
37 static DNS_ERROR dns_tcp_open( const char *nameserver,
38 TALLOC_CTX *mem_ctx,
39 struct dns_connection **result )
41 uint32_t ulAddress;
42 struct hostent *pHost;
43 struct sockaddr_in s_in;
44 struct dns_connection *conn;
45 int res;
47 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
48 return ERROR_DNS_NO_MEMORY;
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;
56 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
59 conn->s = socket( PF_INET, SOCK_STREAM, 0 );
60 if (conn->s == -1) {
61 TALLOC_FREE(conn);
62 return ERROR_DNS_CONNECTION_FAILED;
65 talloc_set_destructor(conn, destroy_dns_connection);
67 s_in.sin_family = AF_INET;
68 s_in.sin_addr.s_addr = ulAddress;
69 s_in.sin_port = htons( DNS_TCP_PORT );
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;
77 conn->hType = DNS_TCP;
79 *result = conn;
80 return ERROR_DNS_SUCCESS;
83 /********************************************************************
84 ********************************************************************/
86 static DNS_ERROR dns_udp_open( const char *nameserver,
87 TALLOC_CTX *mem_ctx,
88 struct dns_connection **result )
90 unsigned long ulAddress;
91 struct hostent *pHost;
92 struct sockaddr_in RecvAddr;
93 struct dns_connection *conn;
95 if (!(conn = talloc(NULL, struct dns_connection))) {
96 return ERROR_DNS_NO_MEMORY;
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;
104 memcpy( &ulAddress, pHost->h_addr, pHost->h_length );
107 /* Create a socket for sending data */
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;
115 talloc_set_destructor(conn, destroy_dns_connection);
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. */
121 RecvAddr.sin_family = AF_INET;
122 RecvAddr.sin_port = htons( DNS_UDP_PORT );
123 RecvAddr.sin_addr.s_addr = ulAddress;
125 conn->hType = DNS_UDP;
126 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
128 *result = conn;
129 return ERROR_DNS_SUCCESS;
132 /********************************************************************
133 ********************************************************************/
135 DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
136 TALLOC_CTX *mem_ctx,
137 struct dns_connection **conn )
139 switch ( dwType ) {
140 case DNS_TCP:
141 return dns_tcp_open( nameserver, mem_ctx, conn );
142 case DNS_UDP:
143 return dns_udp_open( nameserver, mem_ctx, conn );
146 return ERROR_DNS_INVALID_PARAMETER;
149 static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
151 size_t total = 0;
153 while (total < len) {
155 ssize_t ret = write(fd, data + total, len - total);
157 if (ret <= 0) {
159 * EOF or error
161 return ERROR_DNS_SOCKET_ERROR;
164 total += ret;
167 return ERROR_DNS_SUCCESS;
170 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
171 const struct dns_buffer *buf)
173 uint16 len = htons(buf->offset);
174 DNS_ERROR err;
176 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
177 if (!ERR_DNS_IS_OK(err)) return err;
179 return write_all(conn->s, buf->data, buf->offset);
182 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
183 const struct dns_buffer *buf)
185 ssize_t ret;
187 ret = sendto(conn->s, buf->data, buf->offset, 0,
188 (struct sockaddr *)&conn->RecvAddr,
189 sizeof(conn->RecvAddr));
191 if (ret != buf->offset) {
192 return ERROR_DNS_SOCKET_ERROR;
195 return ERROR_DNS_SUCCESS;
198 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
200 if (conn->hType == DNS_TCP) {
201 return dns_send_tcp(conn, buf);
204 if (conn->hType == DNS_UDP) {
205 return dns_send_udp(conn, buf);
208 return ERROR_DNS_INVALID_PARAMETER;
211 static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
213 size_t total = 0;
214 fd_set rfds;
215 struct timeval tv;
217 while (total < len) {
218 ssize_t ret;
219 int fd_ready;
221 FD_ZERO( &rfds );
222 FD_SET( fd, &rfds );
224 /* 10 second timeout */
225 tv.tv_sec = 10;
226 tv.tv_usec = 0;
228 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
229 if ( fd_ready == 0 ) {
230 /* read timeout */
231 return ERROR_DNS_SOCKET_ERROR;
234 ret = read(fd, data + total, len - total);
235 if (ret <= 0) {
236 /* EOF or error */
237 return ERROR_DNS_SOCKET_ERROR;
240 total += ret;
243 return ERROR_DNS_SUCCESS;
246 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
247 struct dns_connection *conn,
248 struct dns_buffer **presult)
250 struct dns_buffer *buf;
251 DNS_ERROR err;
252 uint16 len;
254 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
255 return ERROR_DNS_NO_MEMORY;
258 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
259 if (!ERR_DNS_IS_OK(err)) {
260 return err;
263 buf->size = ntohs(len);
265 if (buf->size) {
266 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
267 TALLOC_FREE(buf);
268 return ERROR_DNS_NO_MEMORY;
270 } else {
271 buf->data = NULL;
274 err = read_all(conn->s, buf->data, buf->size);
275 if (!ERR_DNS_IS_OK(err)) {
276 TALLOC_FREE(buf);
277 return err;
280 *presult = buf;
281 return ERROR_DNS_SUCCESS;
284 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
285 struct dns_connection *conn,
286 struct dns_buffer **presult)
288 struct dns_buffer *buf;
289 ssize_t received;
291 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
292 return ERROR_DNS_NO_MEMORY;
296 * UDP based DNS can only be 512 bytes
299 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
300 TALLOC_FREE(buf);
301 return ERROR_DNS_NO_MEMORY;
304 received = recv(conn->s, (void *)buf->data, 512, 0);
306 if (received == -1) {
307 TALLOC_FREE(buf);
308 return ERROR_DNS_SOCKET_ERROR;
311 if (received > 512) {
312 TALLOC_FREE(buf);
313 return ERROR_DNS_BAD_RESPONSE;
316 buf->size = received;
317 buf->offset = 0;
319 *presult = buf;
320 return ERROR_DNS_SUCCESS;
323 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
324 struct dns_buffer **presult)
326 if (conn->hType == DNS_TCP) {
327 return dns_receive_tcp(mem_ctx, conn, presult);
330 if (conn->hType == DNS_UDP) {
331 return dns_receive_udp(mem_ctx, conn, presult);
334 return ERROR_DNS_INVALID_PARAMETER;
337 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
338 const struct dns_request *req,
339 struct dns_request **resp)
341 struct dns_buffer *buf = NULL;
342 DNS_ERROR err;
344 err = dns_marshall_request(conn, req, &buf);
345 if (!ERR_DNS_IS_OK(err)) goto error;
347 err = dns_send(conn, buf);
348 if (!ERR_DNS_IS_OK(err)) goto error;
349 TALLOC_FREE(buf);
351 err = dns_receive(mem_ctx, conn, &buf);
352 if (!ERR_DNS_IS_OK(err)) goto error;
354 err = dns_unmarshall_request(mem_ctx, buf, resp);
356 error:
357 TALLOC_FREE(buf);
358 return err;
361 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
362 struct dns_connection *conn,
363 struct dns_update_request *up_req,
364 struct dns_update_request **up_resp)
366 struct dns_request *resp;
367 DNS_ERROR err;
369 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
370 &resp);
372 if (!ERR_DNS_IS_OK(err)) return err;
374 *up_resp = dns_request2update(resp);
375 return ERROR_DNS_SUCCESS;