Line data Source code
1 : /*
2 : Linux DNS client library implementation
3 :
4 : Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 : Copyright (C) 2006 Gerald Carter <jerry@samba.org>
6 :
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
10 :
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.
15 :
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.
20 :
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/>.
23 : */
24 :
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"
31 :
32 86 : static int destroy_dns_connection(struct dns_connection *conn)
33 : {
34 86 : return close(conn->s);
35 : }
36 :
37 : /********************************************************************
38 : ********************************************************************/
39 :
40 86 : 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)
45 : {
46 0 : int ret;
47 0 : struct addrinfo *rp;
48 86 : struct addrinfo *ai_result = NULL;
49 86 : struct dns_connection *conn = NULL;
50 :
51 86 : if (!(conn = talloc(mem_ctx, struct dns_connection))) {
52 0 : return ERROR_DNS_NO_MEMORY;
53 : }
54 :
55 86 : ret = getaddrinfo(nameserver, service, hints, &ai_result);
56 86 : if (ret != 0) {
57 0 : DEBUG(1,("dns_tcp_open: getaddrinfo: %s\n", gai_strerror(ret)));
58 0 : TALLOC_FREE(conn);
59 0 : return ERROR_DNS_INVALID_NAME_SERVER;
60 : }
61 :
62 86 : for (rp = ai_result; rp != NULL; rp = rp->ai_next) {
63 86 : conn->s = socket(rp->ai_family,
64 : rp->ai_socktype,
65 : rp->ai_protocol);
66 86 : if (conn->s == -1) {
67 0 : continue;
68 : }
69 0 : do {
70 86 : ret = connect(conn->s, rp->ai_addr, rp->ai_addrlen);
71 86 : } while ((ret == -1) && (errno == EINTR));
72 86 : if (ret != -1) {
73 : /* Successful connect */
74 86 : break;
75 : }
76 0 : close(conn->s);
77 : }
78 :
79 86 : freeaddrinfo(ai_result);
80 :
81 86 : if (rp == NULL) {
82 0 : TALLOC_FREE(conn);
83 0 : return ERROR_DNS_CONNECTION_FAILED;
84 : }
85 :
86 86 : talloc_set_destructor(conn, destroy_dns_connection);
87 :
88 86 : *ret_conn = conn;
89 86 : return ERROR_DNS_SUCCESS;
90 : }
91 :
92 86 : static DNS_ERROR dns_tcp_open( const char *nameserver,
93 : TALLOC_CTX *mem_ctx,
94 : struct dns_connection **result )
95 : {
96 0 : struct addrinfo hints;
97 0 : struct dns_connection *conn;
98 0 : DNS_ERROR dns_ret;
99 0 : char service[16];
100 :
101 86 : snprintf(service, sizeof(service), "%d", DNS_TCP_PORT);
102 :
103 86 : memset(&hints, 0, sizeof(struct addrinfo));
104 86 : hints.ai_family = AF_UNSPEC;
105 86 : hints.ai_socktype = SOCK_STREAM;
106 86 : hints.ai_flags = 0;
107 86 : hints.ai_protocol = IPPROTO_TCP;
108 :
109 86 : dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
110 86 : if (!ERR_DNS_IS_OK(dns_ret)) {
111 0 : return dns_ret;
112 : }
113 :
114 86 : conn->hType = DNS_TCP;
115 86 : *result = conn;
116 86 : return ERROR_DNS_SUCCESS;
117 : }
118 :
119 : /********************************************************************
120 : * ********************************************************************/
121 :
122 0 : static DNS_ERROR dns_udp_open( const char *nameserver,
123 : TALLOC_CTX *mem_ctx,
124 : struct dns_connection **result )
125 : {
126 0 : struct addrinfo hints;
127 0 : struct sockaddr_storage RecvAddr;
128 0 : struct dns_connection *conn = NULL;
129 0 : DNS_ERROR dns_ret;
130 0 : socklen_t RecvAddrLen;
131 0 : char service[16];
132 :
133 0 : snprintf(service, sizeof(service), "%d", DNS_UDP_PORT);
134 :
135 0 : memset(&hints, 0, sizeof(struct addrinfo));
136 0 : hints.ai_family = AF_UNSPEC;
137 0 : hints.ai_socktype = SOCK_DGRAM;
138 0 : hints.ai_flags = 0;
139 0 : hints.ai_protocol = IPPROTO_UDP;
140 :
141 0 : dns_ret = dns_open_helper(nameserver, service, &hints, mem_ctx, &conn);
142 0 : if (!ERR_DNS_IS_OK(dns_ret)) {
143 0 : TALLOC_FREE(conn);
144 0 : return dns_ret;
145 : }
146 :
147 : /* Set up the RecvAddr structure with the IP address of
148 : the receiver and the specified port number. */
149 :
150 0 : RecvAddrLen = sizeof(RecvAddr);
151 0 : if (getpeername(conn->s,
152 : (struct sockaddr *)&RecvAddr,
153 : &RecvAddrLen) == -1) {
154 0 : return ERROR_DNS_CONNECTION_FAILED;
155 : }
156 :
157 0 : conn->hType = DNS_UDP;
158 0 : memcpy(&conn->RecvAddr, &RecvAddr, sizeof(struct sockaddr_storage));
159 :
160 0 : *result = conn;
161 0 : return ERROR_DNS_SUCCESS;
162 : }
163 :
164 : /********************************************************************
165 : ********************************************************************/
166 :
167 86 : DNS_ERROR dns_open_connection( const char *nameserver, int32_t dwType,
168 : TALLOC_CTX *mem_ctx,
169 : struct dns_connection **conn )
170 : {
171 86 : switch ( dwType ) {
172 86 : case DNS_TCP:
173 86 : return dns_tcp_open( nameserver, mem_ctx, conn );
174 0 : case DNS_UDP:
175 0 : return dns_udp_open( nameserver, mem_ctx, conn );
176 : }
177 :
178 0 : return ERROR_DNS_INVALID_PARAMETER;
179 : }
180 :
181 340 : static DNS_ERROR write_all(int fd, uint8_t *data, size_t len)
182 : {
183 340 : size_t total = 0;
184 :
185 722 : while (total < len) {
186 :
187 0 : ssize_t ret;
188 :
189 0 : do {
190 382 : ret = write(fd, data + total, len - total);
191 382 : } while ((ret == -1) && (errno == EINTR));
192 :
193 382 : if (ret <= 0) {
194 : /*
195 : * EOF or error
196 : */
197 0 : return ERROR_DNS_SOCKET_ERROR;
198 : }
199 :
200 382 : total += ret;
201 : }
202 :
203 340 : return ERROR_DNS_SUCCESS;
204 : }
205 :
206 170 : static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
207 : const struct dns_buffer *buf)
208 : {
209 170 : uint16_t len = htons(buf->offset);
210 0 : DNS_ERROR err;
211 :
212 170 : err = write_all(conn->s, (uint8_t *)&len, sizeof(len));
213 170 : if (!ERR_DNS_IS_OK(err)) return err;
214 :
215 170 : return write_all(conn->s, buf->data, buf->offset);
216 : }
217 :
218 0 : static DNS_ERROR dns_send_udp(struct dns_connection *conn,
219 : const struct dns_buffer *buf)
220 : {
221 0 : ssize_t ret;
222 :
223 0 : do {
224 0 : ret = send(conn->s, buf->data, buf->offset, 0);
225 0 : } while ((ret == -1) && (errno == EINTR));
226 :
227 0 : if (ret != buf->offset) {
228 0 : return ERROR_DNS_SOCKET_ERROR;
229 : }
230 :
231 0 : return ERROR_DNS_SUCCESS;
232 : }
233 :
234 170 : DNS_ERROR dns_send(struct dns_connection *conn, const struct dns_buffer *buf)
235 : {
236 170 : if (conn->hType == DNS_TCP) {
237 170 : return dns_send_tcp(conn, buf);
238 : }
239 :
240 0 : if (conn->hType == DNS_UDP) {
241 0 : return dns_send_udp(conn, buf);
242 : }
243 :
244 0 : return ERROR_DNS_INVALID_PARAMETER;
245 : }
246 :
247 340 : static DNS_ERROR read_all(int fd, uint8_t *data, size_t len)
248 : {
249 340 : size_t total = 0;
250 :
251 680 : while (total < len) {
252 0 : struct pollfd pfd;
253 0 : ssize_t ret;
254 0 : int fd_ready;
255 :
256 340 : ZERO_STRUCT(pfd);
257 340 : pfd.fd = fd;
258 340 : pfd.events = POLLIN|POLLHUP;
259 :
260 340 : fd_ready = poll(&pfd, 1, 10000);
261 340 : if (fd_ready == -1) {
262 0 : if (errno == EINTR) {
263 0 : continue;
264 : }
265 0 : return ERROR_DNS_SOCKET_ERROR;
266 : }
267 340 : if ( fd_ready == 0 ) {
268 : /* read timeout */
269 0 : return ERROR_DNS_SOCKET_ERROR;
270 : }
271 :
272 0 : do {
273 340 : ret = read(fd, data + total, len - total);
274 340 : } while ((ret == -1) && (errno == EINTR));
275 :
276 340 : if (ret <= 0) {
277 : /* EOF or error */
278 0 : return ERROR_DNS_SOCKET_ERROR;
279 : }
280 :
281 340 : total += ret;
282 : }
283 :
284 340 : return ERROR_DNS_SUCCESS;
285 : }
286 :
287 170 : static DNS_ERROR dns_receive_tcp(TALLOC_CTX *mem_ctx,
288 : struct dns_connection *conn,
289 : struct dns_buffer **presult)
290 : {
291 0 : struct dns_buffer *buf;
292 0 : DNS_ERROR err;
293 0 : uint16_t len;
294 :
295 170 : if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
296 0 : return ERROR_DNS_NO_MEMORY;
297 : }
298 :
299 170 : err = read_all(conn->s, (uint8_t *)&len, sizeof(len));
300 170 : if (!ERR_DNS_IS_OK(err)) {
301 0 : return err;
302 : }
303 :
304 170 : buf->size = ntohs(len);
305 :
306 170 : if (buf->size == 0) {
307 0 : *presult = buf;
308 0 : return ERROR_DNS_SUCCESS;
309 : }
310 :
311 170 : if (!(buf->data = talloc_array(buf, uint8_t, buf->size))) {
312 0 : TALLOC_FREE(buf);
313 0 : return ERROR_DNS_NO_MEMORY;
314 : }
315 :
316 170 : err = read_all(conn->s, buf->data, talloc_get_size(buf->data));
317 170 : if (!ERR_DNS_IS_OK(err)) {
318 0 : TALLOC_FREE(buf);
319 0 : return err;
320 : }
321 :
322 170 : *presult = buf;
323 170 : return ERROR_DNS_SUCCESS;
324 : }
325 :
326 0 : static DNS_ERROR dns_receive_udp(TALLOC_CTX *mem_ctx,
327 : struct dns_connection *conn,
328 : struct dns_buffer **presult)
329 : {
330 0 : struct dns_buffer *buf;
331 0 : ssize_t received;
332 :
333 0 : if (!(buf = talloc_zero(mem_ctx, struct dns_buffer))) {
334 0 : return ERROR_DNS_NO_MEMORY;
335 : }
336 :
337 : /*
338 : * UDP based DNS can only be 512 bytes
339 : */
340 :
341 0 : if (!(buf->data = talloc_array(buf, uint8_t, 512))) {
342 0 : TALLOC_FREE(buf);
343 0 : return ERROR_DNS_NO_MEMORY;
344 : }
345 :
346 0 : do {
347 0 : received = recv(conn->s, (void *)buf->data, 512, 0);
348 0 : } while ((received == -1) && (errno == EINTR));
349 :
350 0 : if (received == -1) {
351 0 : TALLOC_FREE(buf);
352 0 : return ERROR_DNS_SOCKET_ERROR;
353 : }
354 :
355 0 : if (received > 512) {
356 0 : TALLOC_FREE(buf);
357 0 : return ERROR_DNS_BAD_RESPONSE;
358 : }
359 :
360 0 : buf->size = received;
361 0 : buf->offset = 0;
362 :
363 0 : *presult = buf;
364 0 : return ERROR_DNS_SUCCESS;
365 : }
366 :
367 170 : DNS_ERROR dns_receive(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
368 : struct dns_buffer **presult)
369 : {
370 170 : if (conn->hType == DNS_TCP) {
371 170 : return dns_receive_tcp(mem_ctx, conn, presult);
372 : }
373 :
374 0 : if (conn->hType == DNS_UDP) {
375 0 : return dns_receive_udp(mem_ctx, conn, presult);
376 : }
377 :
378 0 : return ERROR_DNS_INVALID_PARAMETER;
379 : }
380 :
381 128 : DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx, struct dns_connection *conn,
382 : const struct dns_request *req,
383 : struct dns_request **resp)
384 : {
385 128 : struct dns_buffer *buf = NULL;
386 0 : DNS_ERROR err;
387 :
388 128 : err = dns_marshall_request(mem_ctx, req, &buf);
389 128 : if (!ERR_DNS_IS_OK(err)) goto error;
390 :
391 128 : err = dns_send(conn, buf);
392 128 : if (!ERR_DNS_IS_OK(err)) goto error;
393 128 : TALLOC_FREE(buf);
394 :
395 128 : err = dns_receive(mem_ctx, conn, &buf);
396 128 : if (!ERR_DNS_IS_OK(err)) goto error;
397 :
398 128 : err = dns_unmarshall_request(mem_ctx, buf, resp);
399 :
400 128 : error:
401 128 : TALLOC_FREE(buf);
402 128 : return err;
403 : }
404 :
405 127 : 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)
409 : {
410 0 : struct dns_request *resp;
411 0 : DNS_ERROR err;
412 :
413 127 : err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
414 : &resp);
415 :
416 127 : if (!ERR_DNS_IS_OK(err)) return err;
417 :
418 127 : *up_resp = dns_request2update(resp);
419 127 : return ERROR_DNS_SUCCESS;
420 : }
|