build: format the header check for netinet/ip.h more nicely
[Samba/bb.git] / source / libaddns / dnssock.c
blob7c8bd418e5765e5dc97ccd3e85a1c0dfb8aca1f9
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 ZERO_STRUCT(RecvAddr);
122 RecvAddr.sin_family = AF_INET;
123 RecvAddr.sin_port = htons( DNS_UDP_PORT );
124 RecvAddr.sin_addr.s_addr = ulAddress;
126 conn->hType = DNS_UDP;
127 memcpy( &conn->RecvAddr, &RecvAddr, sizeof( struct sockaddr_in ) );
129 *result = conn;
130 return ERROR_DNS_SUCCESS;
133 /********************************************************************
134 ********************************************************************/
136 DNS_ERROR dns_open_connection( const char *nameserver, int32 dwType,
137 TALLOC_CTX *mem_ctx,
138 struct dns_connection **conn )
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 );
147 return ERROR_DNS_INVALID_PARAMETER;
150 static DNS_ERROR write_all(int fd, uint8 *data, size_t len)
152 size_t total = 0;
154 while (total < len) {
156 ssize_t ret = write(fd, data + total, len - total);
158 if (ret <= 0) {
160 * EOF or error
162 return ERROR_DNS_SOCKET_ERROR;
165 total += ret;
168 return ERROR_DNS_SUCCESS;
171 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
172 const struct dns_buffer *buf)
174 uint16 len = htons(buf->offset);
175 DNS_ERROR err;
177 err = write_all(conn->s, (uint8 *)&len, sizeof(len));
178 if (!ERR_DNS_IS_OK(err)) return err;
180 return write_all(conn->s, buf->data, buf->offset);
183 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
184 const struct dns_buffer *buf)
186 ssize_t ret;
188 ret = sendto(conn->s, buf->data, buf->offset, 0,
189 (struct sockaddr *)&conn->RecvAddr,
190 sizeof(conn->RecvAddr));
192 if (ret != buf->offset) {
193 return ERROR_DNS_SOCKET_ERROR;
196 return ERROR_DNS_SUCCESS;
199 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
201 if (conn->hType == DNS_TCP) {
202 return dns_send_tcp(conn, buf);
205 if (conn->hType == DNS_UDP) {
206 return dns_send_udp(conn, buf);
209 return ERROR_DNS_INVALID_PARAMETER;
212 static DNS_ERROR read_all(int fd, uint8 *data, size_t len)
214 size_t total = 0;
215 fd_set rfds;
216 struct timeval tv;
218 while (total < len) {
219 ssize_t ret;
220 int fd_ready;
222 FD_ZERO( &rfds );
223 FD_SET( fd, &rfds );
225 /* 10 second timeout */
226 tv.tv_sec = 10;
227 tv.tv_usec = 0;
229 fd_ready = select( fd+1, &rfds, NULL, NULL, &tv );
230 if ( fd_ready == 0 ) {
231 /* read timeout */
232 return ERROR_DNS_SOCKET_ERROR;
235 ret = read(fd, data + total, len - total);
236 if (ret <= 0) {
237 /* EOF or error */
238 return ERROR_DNS_SOCKET_ERROR;
241 total += ret;
244 return ERROR_DNS_SUCCESS;
247 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
248 struct dns_connection *conn,
249 struct dns_buffer **presult)
251 struct dns_buffer *buf;
252 DNS_ERROR err;
253 uint16 len;
255 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
256 return ERROR_DNS_NO_MEMORY;
259 err = read_all(conn->s, (uint8 *)&len, sizeof(len));
260 if (!ERR_DNS_IS_OK(err)) {
261 return err;
264 buf->size = ntohs(len);
266 if (buf->size) {
267 if (!(buf->data = TALLOC_ARRAY(buf, uint8, buf->size))) {
268 TALLOC_FREE(buf);
269 return ERROR_DNS_NO_MEMORY;
271 } else {
272 buf->data = NULL;
275 err = read_all(conn->s, buf->data, buf->size);
276 if (!ERR_DNS_IS_OK(err)) {
277 TALLOC_FREE(buf);
278 return err;
281 *presult = buf;
282 return ERROR_DNS_SUCCESS;
285 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
286 struct dns_connection *conn,
287 struct dns_buffer **presult)
289 struct dns_buffer *buf;
290 ssize_t received;
292 if (!(buf = TALLOC_ZERO_P(mem_ctx, struct dns_buffer))) {
293 return ERROR_DNS_NO_MEMORY;
297 * UDP based DNS can only be 512 bytes
300 if (!(buf->data = TALLOC_ARRAY(buf, uint8, 512))) {
301 TALLOC_FREE(buf);
302 return ERROR_DNS_NO_MEMORY;
305 received = recv(conn->s, (void *)buf->data, 512, 0);
307 if (received == -1) {
308 TALLOC_FREE(buf);
309 return ERROR_DNS_SOCKET_ERROR;
312 if (received > 512) {
313 TALLOC_FREE(buf);
314 return ERROR_DNS_BAD_RESPONSE;
317 buf->size = received;
318 buf->offset = 0;
320 *presult = buf;
321 return ERROR_DNS_SUCCESS;
324 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
325 struct dns_buffer **presult)
327 if (conn->hType == DNS_TCP) {
328 return dns_receive_tcp(mem_ctx, conn, presult);
331 if (conn->hType == DNS_UDP) {
332 return dns_receive_udp(mem_ctx, conn, presult);
335 return ERROR_DNS_INVALID_PARAMETER;
338 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
339 const struct dns_request *req,
340 struct dns_request **resp)
342 struct dns_buffer *buf = NULL;
343 DNS_ERROR err;
345 err = dns_marshall_request(conn, req, &buf);
346 if (!ERR_DNS_IS_OK(err)) goto error;
348 err = dns_send(conn, buf);
349 if (!ERR_DNS_IS_OK(err)) goto error;
350 TALLOC_FREE(buf);
352 err = dns_receive(mem_ctx, conn, &buf);
353 if (!ERR_DNS_IS_OK(err)) goto error;
355 err = dns_unmarshall_request(mem_ctx, buf, resp);
357 error:
358 TALLOC_FREE(buf);
359 return err;
362 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
363 struct dns_connection *conn,
364 struct dns_update_request *up_req,
365 struct dns_update_request **up_resp)
367 struct dns_request *resp;
368 DNS_ERROR err;
370 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
371 &resp);
373 if (!ERR_DNS_IS_OK(err)) return err;
375 *up_resp = dns_request2update(resp);
376 return ERROR_DNS_SUCCESS;