/* Unix SMB/CIFS implementation. Small async DNS library for Samba with socketwrapper support Copyright (C) 2010 Kai Blin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "replace.h" #include "system/network.h" #include #include "lib/tsocket/tsocket.h" #include "libcli/util/werror.h" #include "libcli/dns/libdns.h" #include "lib/util/tevent_werror.h" #include "lib/util/samba_util.h" #include "libcli/util/error.h" #include "librpc/gen_ndr/dns.h" struct dns_udp_request_state { struct tevent_context *ev; struct tdgram_context *dgram; size_t query_len; uint8_t *reply; size_t reply_len; }; #define DNS_REQUEST_TIMEOUT 2 /* Declare callback functions used below. */ static void dns_udp_request_get_reply(struct tevent_req *subreq); static void dns_udp_request_done(struct tevent_req *subreq); struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, const char *server_addr_string, const uint8_t *query, size_t query_len) { struct tevent_req *req, *subreq; struct dns_udp_request_state *state; struct tsocket_address *local_addr, *server_addr; struct tdgram_context *dgram; int ret; req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state); if (req == NULL) { return NULL; } state->ev = ev; /* Use connected UDP sockets */ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr); if (ret != 0) { tevent_req_werror(req, unix_to_werror(ret)); return tevent_req_post(req, ev); } ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string, DNS_SERVICE_PORT, &server_addr); if (ret != 0) { tevent_req_werror(req, unix_to_werror(ret)); return tevent_req_post(req, ev); } ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram); if (ret != 0) { tevent_req_werror(req, unix_to_werror(ret)); return tevent_req_post(req, ev); } state->dgram = dgram; state->query_len = query_len; dump_data(10, query, query_len); subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) { return tevent_req_post(req, ev); } tevent_req_set_callback(subreq, dns_udp_request_get_reply, req); return req; } static void dns_udp_request_get_reply(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct dns_udp_request_state *state = tevent_req_data(req, struct dns_udp_request_state); ssize_t len; int err = 0; len = tdgram_sendto_recv(subreq, &err); TALLOC_FREE(subreq); if (len == -1 && err != 0) { tevent_req_werror(req, unix_to_werror(err)); return; } if (len != state->query_len) { tevent_req_werror(req, WERR_NET_WRITE_FAULT); return; } subreq = tdgram_recvfrom_send(state, state->ev, state->dgram); if (tevent_req_nomem(subreq, req)) { return; } tevent_req_set_callback(subreq, dns_udp_request_done, req); return; } static void dns_udp_request_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct dns_udp_request_state *state = tevent_req_data(req, struct dns_udp_request_state); ssize_t len; int err = 0; len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL); TALLOC_FREE(subreq); if (len == -1 && err != 0) { tevent_req_werror(req, unix_to_werror(err)); return; } state->reply_len = len; dump_data(10, state->reply, state->reply_len); tevent_req_done(req); } WERROR dns_udp_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint8_t **reply, size_t *reply_len) { struct dns_udp_request_state *state = tevent_req_data(req, struct dns_udp_request_state); WERROR w_error; if (tevent_req_is_werror(req, &w_error)) { tevent_req_received(req); return w_error; } *reply = talloc_move(mem_ctx, &state->reply); *reply_len = state->reply_len; tevent_req_received(req); return WERR_OK; }