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