libcli: Use "all_zero" where appropriate
[sfrench/samba-autobuild/.git] / libcli / dns / dns.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Small async DNS library for Samba with socketwrapper support
5
6    Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "replace.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "libcli/dns/libdns.h"
27 #include "lib/util/tevent_unix.h"
28 #include "lib/util/samba_util.h"
29 #include "libcli/util/error.h"
30 #include "librpc/gen_ndr/dns.h"
31
32 struct dns_udp_request_state {
33         struct tevent_context *ev;
34         struct tdgram_context *dgram;
35         size_t query_len;
36         uint8_t *reply;
37         size_t reply_len;
38 };
39
40 #define DNS_REQUEST_TIMEOUT 2
41
42 /* Declare callback functions used below. */
43 static void dns_udp_request_get_reply(struct tevent_req *subreq);
44 static void dns_udp_request_done(struct tevent_req *subreq);
45
46 struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
47                                         struct tevent_context *ev,
48                                         const char *server_addr_string,
49                                         const uint8_t *query,
50                                         size_t query_len)
51 {
52         struct tevent_req *req, *subreq;
53         struct dns_udp_request_state *state;
54         struct tsocket_address *local_addr, *server_addr;
55         struct tdgram_context *dgram;
56         int ret;
57
58         req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
59         if (req == NULL) {
60                 return NULL;
61         }
62
63         state->ev = ev;
64
65         /* Use connected UDP sockets */
66         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
67                                                 &local_addr);
68         if (ret != 0) {
69                 tevent_req_error(req, errno);
70                 return tevent_req_post(req, ev);
71         }
72
73         ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
74                                                 DNS_SERVICE_PORT, &server_addr);
75         if (ret != 0) {
76                 tevent_req_error(req, errno);
77                 return tevent_req_post(req, ev);
78         }
79
80         ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
81         if (ret != 0) {
82                 tevent_req_error(req, errno);
83                 return tevent_req_post(req, ev);
84         }
85
86         state->dgram = dgram;
87         state->query_len = query_len;
88
89         dump_data(10, query, query_len);
90
91         subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
92         if (tevent_req_nomem(subreq, req)) {
93                 return tevent_req_post(req, ev);
94         }
95
96         if (!tevent_req_set_endtime(req, ev,
97                                 timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
98                 tevent_req_oom(req);
99                 return tevent_req_post(req, ev);
100         }
101
102         tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
103         return req;
104 }
105
106 static void dns_udp_request_get_reply(struct tevent_req *subreq)
107 {
108         struct tevent_req *req = tevent_req_callback_data(subreq,
109                                                 struct tevent_req);
110         struct dns_udp_request_state *state = tevent_req_data(req,
111                                                 struct dns_udp_request_state);
112         ssize_t len;
113         int err = 0;
114
115         len = tdgram_sendto_recv(subreq, &err);
116         TALLOC_FREE(subreq);
117
118         if (len == -1 && err != 0) {
119                 tevent_req_error(req, err);
120                 return;
121         }
122
123         if (len != state->query_len) {
124                 tevent_req_error(req, EIO);
125                 return;
126         }
127
128         subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
129         if (tevent_req_nomem(subreq, req)) {
130                 return;
131         }
132
133         tevent_req_set_callback(subreq, dns_udp_request_done, req);
134 }
135
136 static void dns_udp_request_done(struct tevent_req *subreq)
137 {
138         struct tevent_req *req = tevent_req_callback_data(subreq,
139                                                 struct tevent_req);
140         struct dns_udp_request_state *state = tevent_req_data(req,
141                                                 struct dns_udp_request_state);
142
143         ssize_t len;
144         int err = 0;
145
146         len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
147         TALLOC_FREE(subreq);
148
149         if (len == -1 && err != 0) {
150                 tevent_req_error(req, err);
151                 return;
152         }
153
154         state->reply_len = len;
155         dump_data(10, state->reply, state->reply_len);
156         tevent_req_done(req);
157 }
158
159 int dns_udp_request_recv(struct tevent_req *req,
160                          TALLOC_CTX *mem_ctx,
161                          uint8_t **reply,
162                          size_t *reply_len)
163 {
164         struct dns_udp_request_state *state = tevent_req_data(req,
165                         struct dns_udp_request_state);
166         int err;
167
168         if (tevent_req_is_unix_error(req, &err)) {
169                 tevent_req_received(req);
170                 return err;
171         }
172
173         *reply = talloc_move(mem_ctx, &state->reply);
174         *reply_len = state->reply_len;
175         tevent_req_received(req);
176
177         return 0;
178 }