libcli-dns: Remove obsolete dns_host_file subsystem.
[obnox/samba/samba-obnox.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/util/werror.h"
27 #include "libcli/dns/libdns.h"
28 #include "lib/util/tevent_werror.h"
29 #include "lib/util/samba_util.h"
30 #include "libcli/util/error.h"
31 #include "librpc/gen_ndr/dns.h"
32
33 struct dns_udp_request_state {
34         struct tevent_context *ev;
35         struct tdgram_context *dgram;
36         size_t query_len;
37         uint8_t *reply;
38         size_t reply_len;
39 };
40
41 #define DNS_REQUEST_TIMEOUT 2
42
43 /* Declare callback functions used below. */
44 static void dns_udp_request_get_reply(struct tevent_req *subreq);
45 static void dns_udp_request_done(struct tevent_req *subreq);
46
47 struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
48                                         struct tevent_context *ev,
49                                         const char *server_addr_string,
50                                         const uint8_t *query,
51                                         size_t query_len)
52 {
53         struct tevent_req *req, *subreq;
54         struct dns_udp_request_state *state;
55         struct tsocket_address *local_addr, *server_addr;
56         struct tdgram_context *dgram;
57         int ret;
58
59         req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
60         if (req == NULL) {
61                 return NULL;
62         }
63
64         state->ev = ev;
65
66         /* Use connected UDP sockets */
67         ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
68                                                 &local_addr);
69         if (ret != 0) {
70                 tevent_req_werror(req, unix_to_werror(ret));
71                 return tevent_req_post(req, ev);
72         }
73
74         ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
75                                                 DNS_SERVICE_PORT, &server_addr);
76         if (ret != 0) {
77                 tevent_req_werror(req, unix_to_werror(ret));
78                 return tevent_req_post(req, ev);
79         }
80
81         ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
82         if (ret != 0) {
83                 tevent_req_werror(req, unix_to_werror(ret));
84                 return tevent_req_post(req, ev);
85         }
86
87         state->dgram = dgram;
88         state->query_len = query_len;
89
90         dump_data(10, query, query_len);
91
92         subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
93         if (tevent_req_nomem(subreq, req)) {
94                 return tevent_req_post(req, ev);
95         }
96
97         if (!tevent_req_set_endtime(req, ev,
98                                 timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
99                 return tevent_req_post(req, ev);
100         }
101
102
103         tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
104         return req;
105 }
106
107 static void dns_udp_request_get_reply(struct tevent_req *subreq)
108 {
109         struct tevent_req *req = tevent_req_callback_data(subreq,
110                                                 struct tevent_req);
111         struct dns_udp_request_state *state = tevent_req_data(req,
112                                                 struct dns_udp_request_state);
113         ssize_t len;
114         int err = 0;
115
116         len = tdgram_sendto_recv(subreq, &err);
117         TALLOC_FREE(subreq);
118
119         if (len == -1 && err != 0) {
120                 tevent_req_werror(req, unix_to_werror(err));
121                 return;
122         }
123
124         if (len != state->query_len) {
125                 tevent_req_werror(req, WERR_NET_WRITE_FAULT);
126                 return;
127         }
128
129         subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
130         if (tevent_req_nomem(subreq, req)) {
131                 return;
132         }
133
134         tevent_req_set_callback(subreq, dns_udp_request_done, req);
135         return;
136 }
137
138 static void dns_udp_request_done(struct tevent_req *subreq)
139 {
140         struct tevent_req *req = tevent_req_callback_data(subreq,
141                                                 struct tevent_req);
142         struct dns_udp_request_state *state = tevent_req_data(req,
143                                                 struct dns_udp_request_state);
144
145         ssize_t len;
146         int err = 0;
147
148         len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
149         TALLOC_FREE(subreq);
150
151         if (len == -1 && err != 0) {
152                 tevent_req_werror(req, unix_to_werror(err));
153                 return;
154         }
155
156         state->reply_len = len;
157         dump_data(10, state->reply, state->reply_len);
158         tevent_req_done(req);
159 }
160
161 WERROR dns_udp_request_recv(struct tevent_req *req,
162                             TALLOC_CTX *mem_ctx,
163                             uint8_t **reply,
164                             size_t *reply_len)
165 {
166         struct dns_udp_request_state *state = tevent_req_data(req,
167                         struct dns_udp_request_state);
168         WERROR w_error;
169
170         if (tevent_req_is_werror(req, &w_error)) {
171                 tevent_req_received(req);
172                 return w_error;
173         }
174
175         *reply = talloc_move(mem_ctx, &state->reply);
176         *reply_len = state->reply_len;
177         tevent_req_received(req);
178
179         return WERR_OK;
180 }