selftest: Add test for initial link attribute RMD_VERSION value
[Samba.git] / lib / addns / dnssock.c
blobec42b7ca6892428d9efbb3320c338584fe0174ee
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 "replace.h"
26 #include "dns.h"
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include "system/select.h"
30 #include "../lib/util/debug.h"
32 static int destroy_dns_connection(struct dns_connection *conn)
34 return close(conn->s);
37 /********************************************************************
38 ********************************************************************/
40 static DNS_ERROR dns_open_helper(const char *nameserver,
41 const char *service,
42 struct addrinfo *hints,
43 TALLOC_CTX *mem_ctx,
44 struct dns_connection **ret_conn)
46 int ret;
47 struct addrinfo *rp;
48 struct addrinfo *ai_result = NULL;
49 struct dns_connection *conn = NULL;
51 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
52 return ERROR_DNS_NO_MEMORY;
55 ret = getaddrinfo(nameserver, service, hints, &ai_result);
56 if (ret != 0) {
57 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
58 TALLOC_FREE(conn);
59 return ERROR_DNS_INVALID_NAME_SERVER;
62 for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
63 conn->s = socket(rp->ai_family,
64 rp->ai_socktype,
65 rp->ai_protocol);
66 if (conn->s == -1) {
67 continue;
69 do {
70 ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
71 } while ((ret == -1) && (errno == EINTR));
72 if (ret != -1) {
73 /* Successful connect */
74 break;
76 close(conn->s);
79 freeaddrinfo(ai_result);
81 if (rp == NULL) {
82 TALLOC_FREE(conn);
83 return ERROR_DNS_CONNECTION_FAILED;
86 talloc_set_destructor(conn, destroy_dns_connection);
88 *ret_conn = conn;
89 return ERROR_DNS_SUCCESS;
92 static DNS_ERROR dns_tcp_open( const char *nameserver,
93 TALLOC_CTX *mem_ctx,
94 struct dns_connection **result )
96 struct addrinfo hints;
97 struct dns_connection *conn;
98 DNS_ERROR dns_ret;
99 char service[16];
101 snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
103 memset(&hints, 0, sizeof(struct addrinfo));
104 hints.ai_family = AF_UNSPEC;
105 hints.ai_socktype = SOCK_STREAM;
106 hints.ai_flags = 0;
107 hints.ai_protocol = IPPROTO_TCP;
109 dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
110 if (!ERR_DNS_IS_OK(dns_ret)) {
111 return dns_ret;
114 conn->hType = DNS_TCP;
115 *result = conn;
116 return ERROR_DNS_SUCCESS;
119 /********************************************************************
120 * ********************************************************************/
122 static DNS_ERROR dns_udp_open( const char *nameserver,
123 TALLOC_CTX *mem_ctx,
124 struct dns_connection **result )
126 struct addrinfo hints;
127 struct sockaddr_storage RecvAddr;
128 struct dns_connection *conn;
129 DNS_ERROR dns_ret;
130 socklen_t RecvAddrLen;
131 char service[16];
133 snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
135 memset(&hints, 0, sizeof(struct addrinfo));
136 hints.ai_family = AF_UNSPEC;
137 hints.ai_socktype = SOCK_DGRAM;
138 hints.ai_flags = 0;
139 hints.ai_protocol = IPPROTO_UDP;
141 dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
142 if (!ERR_DNS_IS_OK(dns_ret)) {
143 TALLOC_FREE(conn);
144 return dns_ret;
147 /* Set up the RecvAddr structure with the IP address of
148 the receiver and the specified port number. */
150 RecvAddrLen = sizeof(RecvAddr);
151 if (getpeername(conn->s,
152 (struct sockaddr *)&RecvAddr,
153 &RecvAddrLen) == -1) {
154 return ERROR_DNS_CONNECTION_FAILED;
157 conn->hType = DNS_UDP;
158 memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
160 *result = conn;
161 return ERROR_DNS_SUCCESS;
164 /********************************************************************
165 ********************************************************************/
167 DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
168 TALLOC_CTX *mem_ctx,
169 struct dns_connection **conn )
171 switch ( dwType ) {
172 case DNS_TCP:
173 return dns_tcp_open( nameserver, mem_ctx, conn );
174 case DNS_UDP:
175 return dns_udp_open( nameserver, mem_ctx, conn );
178 return ERROR_DNS_INVALID_PARAMETER;
181 static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
183 size_t total = 0;
185 while (total < len) {
187 ssize_t ret;
189 do {
190 ret = write(fd, data + total, len - total);
191 } while ((ret == -1) && (errno == EINTR));
193 if (ret <= 0) {
195 * EOF or error
197 return ERROR_DNS_SOCKET_ERROR;
200 total += ret;
203 return ERROR_DNS_SUCCESS;
206 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
207 const struct dns_buffer *buf)
209 uint16_t len = htons(buf->offset);
210 DNS_ERROR err;
212 err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
213 if (!ERR_DNS_IS_OK(err)) return err;
215 return write_all(conn->s, buf->data, buf->offset);
218 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
219 const struct dns_buffer *buf)
221 ssize_t ret;
223 do {
224 ret = sendto(conn->s, buf->data, buf->offset, 0,
225 (struct sockaddr *)&conn->RecvAddr,
226 sizeof(conn->RecvAddr));
227 } while ((ret == -1) && (errno == EINTR));
229 if (ret != buf->offset) {
230 return ERROR_DNS_SOCKET_ERROR;
233 return ERROR_DNS_SUCCESS;
236 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
238 if (conn->hType == DNS_TCP) {
239 return dns_send_tcp(conn, buf);
242 if (conn->hType == DNS_UDP) {
243 return dns_send_udp(conn, buf);
246 return ERROR_DNS_INVALID_PARAMETER;
249 static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
251 size_t total = 0;
253 while (total < len) {
254 struct pollfd pfd;
255 ssize_t ret;
256 int fd_ready;
258 ZERO_STRUCT(pfd);
259 pfd.fd = fd;
260 pfd.events = POLLIN|POLLHUP;
262 fd_ready = poll(&pfd, 1, 10000);
263 if (fd_ready == -1) {
264 if (errno == EINTR) {
265 continue;
267 return ERROR_DNS_SOCKET_ERROR;
269 if ( fd_ready == 0 ) {
270 /* read timeout */
271 return ERROR_DNS_SOCKET_ERROR;
274 do {
275 ret = read(fd, data + total, len - total);
276 } while ((ret == -1) && (errno == EINTR));
278 if (ret <= 0) {
279 /* EOF or error */
280 return ERROR_DNS_SOCKET_ERROR;
283 total += ret;
286 return ERROR_DNS_SUCCESS;
289 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
290 struct dns_connection *conn,
291 struct dns_buffer **presult)
293 struct dns_buffer *buf;
294 DNS_ERROR err;
295 uint16_t len;
297 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
298 return ERROR_DNS_NO_MEMORY;
301 err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
302 if (!ERR_DNS_IS_OK(err)) {
303 return err;
306 buf->size = ntohs(len);
308 if (buf->size == 0) {
309 *presult = buf;
310 return ERROR_DNS_SUCCESS;
313 if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
314 TALLOC_FREE(buf);
315 return ERROR_DNS_NO_MEMORY;
318 err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
319 if (!ERR_DNS_IS_OK(err)) {
320 TALLOC_FREE(buf);
321 return err;
324 *presult = buf;
325 return ERROR_DNS_SUCCESS;
328 static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
329 struct dns_connection *conn,
330 struct dns_buffer **presult)
332 struct dns_buffer *buf;
333 ssize_t received;
335 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
336 return ERROR_DNS_NO_MEMORY;
340 * UDP based DNS can only be 512 bytes
343 if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
344 TALLOC_FREE(buf);
345 return ERROR_DNS_NO_MEMORY;
348 do {
349 received = recv(conn->s, (void *)buf->data, 512, 0);
350 } while ((received == -1) && (errno == EINTR));
352 if (received == -1) {
353 TALLOC_FREE(buf);
354 return ERROR_DNS_SOCKET_ERROR;
357 if (received > 512) {
358 TALLOC_FREE(buf);
359 return ERROR_DNS_BAD_RESPONSE;
362 buf->size = received;
363 buf->offset = 0;
365 *presult = buf;
366 return ERROR_DNS_SUCCESS;
369 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
370 struct dns_buffer **presult)
372 if (conn->hType == DNS_TCP) {
373 return dns_receive_tcp(mem_ctx, conn, presult);
376 if (conn->hType == DNS_UDP) {
377 return dns_receive_udp(mem_ctx, conn, presult);
380 return ERROR_DNS_INVALID_PARAMETER;
383 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
384 const struct dns_request *req,
385 struct dns_request **resp)
387 struct dns_buffer *buf = NULL;
388 DNS_ERROR err;
390 err = dns_marshall_request(mem_ctx, req, &buf);
391 if (!ERR_DNS_IS_OK(err)) goto error;
393 err = dns_send(conn, buf);
394 if (!ERR_DNS_IS_OK(err)) goto error;
395 TALLOC_FREE(buf);
397 err = dns_receive(mem_ctx, conn, &buf);
398 if (!ERR_DNS_IS_OK(err)) goto error;
400 err = dns_unmarshall_request(mem_ctx, buf, resp);
402 error:
403 TALLOC_FREE(buf);
404 return err;
407 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
408 struct dns_connection *conn,
409 struct dns_update_request *up_req,
410 struct dns_update_request **up_resp)
412 struct dns_request *resp;
413 DNS_ERROR err;
415 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
416 &resp);
418 if (!ERR_DNS_IS_OK(err)) return err;
420 *up_resp = dns_request2update(resp);
421 return ERROR_DNS_SUCCESS;