auth/gensec: make sure gensec_start_mech_by_authtype() resets SIGN/SEAL before starting
[Samba.git] / lib / addns / dnssock.c
blobbab20a4b9e90374707ce36cc5068e7afff66f830
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_tcp_open( const char *nameserver,
41 TALLOC_CTX *mem_ctx,
42 struct dns_connection **result )
44 struct addrinfo hints;
45 struct addrinfo *ai_result = NULL;
46 struct addrinfo *rp;
47 struct dns_connection *conn;
48 int ret;
49 char service[16];
51 snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
53 if (!(conn = talloc(mem_ctx, struct dns_connection))) {
54 return ERROR_DNS_NO_MEMORY;
57 memset(&hints, 0, sizeof(struct addrinfo));
58 hints.ai_family = AF_UNSPEC;
59 hints.ai_socktype = SOCK_STREAM;
60 hints.ai_flags = 0;
61 hints.ai_protocol = IPPROTO_TCP;
63 ret = getaddrinfo(nameserver, service, &hints, &ai_result);
64 if (ret != 0) {
65 DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
66 return ERROR_DNS_INVALID_NAME_SERVER;
69 for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
70 conn->s = socket(rp->ai_family,
71 rp->ai_socktype,
72 rp->ai_protocol);
73 if (conn->s == -1) {
74 continue;
76 do {
77 ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
78 } while ((ret == -1) && (errno == EINTR));
79 if (ret != -1) {
80 /* Successful connect */
81 break;
83 close(conn->s);
86 freeaddrinfo(ai_result);
88 /* Failed to connect with any address */
89 if (rp == NULL) {
90 TALLOC_FREE(conn);
91 return ERROR_DNS_CONNECTION_FAILED;
94 talloc_set_destructor(conn, destroy_dns_connection);
96 conn->hType = DNS_TCP;
98 *result = conn;
99 return ERROR_DNS_SUCCESS;
102 /********************************************************************
103 ********************************************************************/
105 static DNS_ERROR dns_udp_open( const char *nameserver,
106 TALLOC_CTX *mem_ctx,
107 struct dns_connection **result )
109 struct addrinfo hints;
110 struct addrinfo *ai_result = NULL;
111 struct addrinfo *rp;
112 struct sockaddr_storage RecvAddr;
113 struct dns_connection *conn;
114 int ret;
115 socklen_t RecvAddrLen;
116 char service[16];
118 snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
120 if (!(conn = talloc(NULL, struct dns_connection))) {
121 return ERROR_DNS_NO_MEMORY;
124 memset(&hints, 0, sizeof(struct addrinfo));
125 hints.ai_family = AF_UNSPEC;
126 hints.ai_socktype = SOCK_DGRAM;
127 hints.ai_flags = 0;
128 hints.ai_protocol = IPPROTO_UDP;
130 ret = getaddrinfo(nameserver, service, &hints, &ai_result);
131 if (ret != 0) {
132 DEBUG(1,("dns_ucp_open:getaddrinfo: %s\n", gai_strerror(ret)));
133 TALLOC_FREE(conn);
134 return ERROR_DNS_INVALID_NAME_SERVER;
137 for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
138 conn->s = socket(rp->ai_family,
139 rp->ai_socktype,
140 rp->ai_protocol);
141 if (conn->s == -1) {
142 continue;
144 ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
145 if (ret != -1) {
146 /* Successful connect */
147 break;
149 close(conn->s);
152 freeaddrinfo(ai_result);
154 /* Failed to connect with any address */
155 if (rp == NULL) {
156 TALLOC_FREE(conn);
157 return ERROR_DNS_CONNECTION_FAILED;
160 talloc_set_destructor(conn, destroy_dns_connection);
162 /* Set up the RecvAddr structure with the IP address of
163 the receiver and the specified port number. */
165 RecvAddrLen = sizeof(RecvAddr);
166 if (getpeername(conn->s,
167 (struct sockaddr *)&RecvAddr,
168 &RecvAddrLen) == -1) {
169 TALLOC_FREE(conn);
170 return ERROR_DNS_CONNECTION_FAILED;
173 conn->hType = DNS_UDP;
174 memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
176 *result = conn;
177 return ERROR_DNS_SUCCESS;
180 /********************************************************************
181 ********************************************************************/
183 DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
184 TALLOC_CTX *mem_ctx,
185 struct dns_connection **conn )
187 switch ( dwType ) {
188 case DNS_TCP:
189 return dns_tcp_open( nameserver, mem_ctx, conn );
190 case DNS_UDP:
191 return dns_udp_open( nameserver, mem_ctx, conn );
194 return ERROR_DNS_INVALID_PARAMETER;
197 static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
199 size_t total = 0;
201 while (total < len) {
203 ssize_t ret = write(fd, data + total, len - total);
205 if (ret <= 0) {
207 * EOF or error
209 return ERROR_DNS_SOCKET_ERROR;
212 total += ret;
215 return ERROR_DNS_SUCCESS;
218 static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
219 const struct dns_buffer *buf)
221 uint16_t len = htons(buf->offset);
222 DNS_ERROR err;
224 err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
225 if (!ERR_DNS_IS_OK(err)) return err;
227 return write_all(conn->s, buf->data, buf->offset);
230 static DNS_ERROR dns_send_udp(struct dns_connection *conn,
231 const struct dns_buffer *buf)
233 ssize_t ret;
235 ret = sendto(conn->s, buf->data, buf->offset, 0,
236 (struct sockaddr *)&conn->RecvAddr,
237 sizeof(conn->RecvAddr));
239 if (ret != buf->offset) {
240 return ERROR_DNS_SOCKET_ERROR;
243 return ERROR_DNS_SUCCESS;
246 DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
248 if (conn->hType == DNS_TCP) {
249 return dns_send_tcp(conn, buf);
252 if (conn->hType == DNS_UDP) {
253 return dns_send_udp(conn, buf);
256 return ERROR_DNS_INVALID_PARAMETER;
259 static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
261 size_t total = 0;
263 while (total < len) {
264 struct pollfd pfd;
265 ssize_t ret;
266 int fd_ready;
268 ZERO_STRUCT(pfd);
269 pfd.fd = fd;
270 pfd.events = POLLIN|POLLHUP;
272 fd_ready = poll(&pfd, 1, 10000);
273 if ( fd_ready == 0 ) {
274 /* read timeout */
275 return ERROR_DNS_SOCKET_ERROR;
278 ret = read(fd, data + total, len - total);
279 if (ret <= 0) {
280 /* EOF or error */
281 return ERROR_DNS_SOCKET_ERROR;
284 total += ret;
287 return ERROR_DNS_SUCCESS;
290 static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
291 struct dns_connection *conn,
292 struct dns_buffer **presult)
294 struct dns_buffer *buf;
295 DNS_ERROR err;
296 uint16_t len;
298 if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
299 return ERROR_DNS_NO_MEMORY;
302 err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
303 if (!ERR_DNS_IS_OK(err)) {
304 return err;
307 buf->size = ntohs(len);
309 if (buf->size) {
310 if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
311 TALLOC_FREE(buf);
312 return ERROR_DNS_NO_MEMORY;
314 } else {
315 buf->data = NULL;
318 err = read_all(conn->s, buf->data, buf->size);
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 received = recv(conn->s, (void *)buf->data, 512, 0);
350 if (received == -1) {
351 TALLOC_FREE(buf);
352 return ERROR_DNS_SOCKET_ERROR;
355 if (received > 512) {
356 TALLOC_FREE(buf);
357 return ERROR_DNS_BAD_RESPONSE;
360 buf->size = received;
361 buf->offset = 0;
363 *presult = buf;
364 return ERROR_DNS_SUCCESS;
367 DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
368 struct dns_buffer **presult)
370 if (conn->hType == DNS_TCP) {
371 return dns_receive_tcp(mem_ctx, conn, presult);
374 if (conn->hType == DNS_UDP) {
375 return dns_receive_udp(mem_ctx, conn, presult);
378 return ERROR_DNS_INVALID_PARAMETER;
381 DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
382 const struct dns_request *req,
383 struct dns_request **resp)
385 struct dns_buffer *buf = NULL;
386 DNS_ERROR err;
388 err = dns_marshall_request(mem_ctx, req, &buf);
389 if (!ERR_DNS_IS_OK(err)) goto error;
391 err = dns_send(conn, buf);
392 if (!ERR_DNS_IS_OK(err)) goto error;
393 TALLOC_FREE(buf);
395 err = dns_receive(mem_ctx, conn, &buf);
396 if (!ERR_DNS_IS_OK(err)) goto error;
398 err = dns_unmarshall_request(mem_ctx, buf, resp);
400 error:
401 TALLOC_FREE(buf);
402 return err;
405 DNS_ERROR dns_update_transaction(TALLOC_CTX *mem_ctx,
406 struct dns_connection *conn,
407 struct dns_update_request *up_req,
408 struct dns_update_request **up_resp)
410 struct dns_request *resp;
411 DNS_ERROR err;
413 err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
414 &resp);
416 if (!ERR_DNS_IS_OK(err)) return err;
418 *up_resp = dns_request2update(resp);
419 return ERROR_DNS_SUCCESS;