dns-lookup.c revision a943ed0f901e312445fd393249b91932797bba79
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "lib.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#include "llist.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "istream.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "write-full.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "time-util.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "dns-lookup.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include <stdio.h>
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include <unistd.h>
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#define MAX_INBUF_SIZE 512
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstruct dns_lookup {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup *prev, *next;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen bool ptr_lookup;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct timeout *to;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct timeval start_time;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int warn_msecs;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_lookup_result result;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct ip_addr *ips;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int ip_idx;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen char *name;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_lookup_callback_t *callback;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen void *context;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen};
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstruct dns_client {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen int fd;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen char *path;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen unsigned int timeout_msecs, idle_timeout_msecs;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct istream *input;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct io *io;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct timeout *to_idle;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup *head, *tail;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen bool deinit_client_at_free;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen};
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#undef dns_lookup
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#undef dns_lookup_ptr
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#undef dns_client_lookup
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#undef dns_client_lookup_ptr
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_disconnect(struct dns_client *client, const char *error)
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen{
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch struct dns_lookup *lookup, *next;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup_result result;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_idle);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
be5773cb4d6edae8a5d9f300c3c7375cdd33826eJosef 'Jeff' Sipek i_stream_destroy(&client->input);
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd_path(&client->fd, client->path);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch result.ret = EAI_FAIL;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch result.error = error;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch lookup = client->head;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch client->head = NULL;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch while (lookup != NULL) {
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch next = lookup->next;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch lookup->callback(&result, lookup->context);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch dns_lookup_free(&lookup);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch lookup = next;
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch }
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen}
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic int dns_lookup_input_line(struct dns_lookup *lookup, const char *line)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_lookup_result *result = &lookup->result;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (result->ips_count == 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen if (lookup->ptr_lookup) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen /* <ret> [<name>] */
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen if (strncmp(line, "0 ", 2) == 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen result->name = lookup->name =
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen i_strdup(line + 2);
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen result->ret = 0;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen } else {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen if (str_to_int(line, &result->ret) < 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen return -1;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen }
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen result->error = net_gethosterror(result->ret);
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen }
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen return 1;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen }
eb2091a2dedf5513dded8a980b79e206c716962dTimo Sirainen /* first line: <ret> [<ip count>] */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (sscanf(line, "%d %u", &result->ret,
eb2091a2dedf5513dded8a980b79e206c716962dTimo Sirainen &result->ips_count) < 1)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (result->ret != 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen result->error = net_gethosterror(result->ret);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (result->ips_count == 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen result->ips = lookup->ips =
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_new(struct ip_addr, result->ips_count);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen } else {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (net_addr2ip(line, &lookup->ips[lookup->ip_idx]) < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (++lookup->ip_idx == result->ips_count) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen result->ret = 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_save_msecs(struct dns_lookup *lookup)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct timeval now;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen int diff;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (gettimeofday(&now, NULL) < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_fatal("gettimeofday() failed: %m");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen diff = timeval_diff_msecs(&now, &lookup->start_time);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (diff > 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen lookup->result.msecs = diff;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_input(struct dns_client *client)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen const char *line;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup *lookup = client->head;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen bool retry = FALSE;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen int ret = 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen while ((line = i_stream_read_next_line(client->input)) != NULL) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (lookup == NULL) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen "Unexpected input from %s", client->path));
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen ret = dns_lookup_input_line(lookup, line);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (ret > 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen break;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (ret < 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen "Invalid input from %s", client->path));
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
28715adb0aa53197a25aac72f1bdd44f44df3cd1Timo Sirainen if (ret != 0 && lookup->result.error != NULL) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen /* already got the error */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen } else if (client->input->stream_errno != 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen "read(%s) failed: %s", client->path,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_stream_get_error(client->input)));
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen } else if (client->input->eof) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen "Unexpected EOF from %s", client->path));
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (ret > 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_lookup_save_msecs(lookup);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->callback(&lookup->result, lookup->context);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen retry = !lookup->client->deinit_client_at_free;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_lookup_free(&lookup);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (retry)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_input(client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_timeout(struct dns_lookup *lookup)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen lookup->result.error = "DNS lookup timed out";
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen lookup->callback(&lookup->result, lookup->context);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_lookup_free(&lookup);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_lookup(const char *host, const struct dns_lookup_settings *set,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup **lookup_r)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client = dns_client_init(set);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->deinit_client_at_free = TRUE;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (dns_client_lookup(client, host, callback, context, lookup_r) < 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_deinit(&client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainenint dns_lookup_ptr(const struct ip_addr *ip,
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen const struct dns_lookup_settings *set,
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen dns_lookup_callback_t *callback, void *context,
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen struct dns_lookup **lookup_r)
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client = dns_client_init(set);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->deinit_client_at_free = TRUE;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (dns_client_lookup_ptr(client, ip, callback, context, lookup_r) < 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_deinit(&client);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return -1;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return 0;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_idle_timeout(struct dns_client *client)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_assert(client->head == NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, "Idle timeout");
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen}
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_lookup *lookup = *_lookup;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client = lookup->client;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen *_lookup = NULL;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen DLLIST2_REMOVE(&client->head, &client->tail, lookup);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&lookup->to);
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen i_free(lookup->name);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_free(lookup->ips);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (client->deinit_client_at_free)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_deinit(&client);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch else if (client->head == NULL && client->fd != -1) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->to_idle = timeout_add(client->idle_timeout_msecs,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_idle_timeout, client);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_free(lookup);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainenvoid dns_lookup_abort(struct dns_lookup **lookup)
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen{
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen dns_lookup_free(lookup);
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen}
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Boschvoid dns_lookup_switch_ioloop(struct dns_lookup *lookup)
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch{
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch if (lookup->to != NULL)
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch lookup->to = io_loop_move_timeout(&lookup->to);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen if (lookup->client->deinit_client_at_free)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen lookup->client->io = io_loop_move_io(&lookup->client->io);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstruct dns_client *dns_client_init(const struct dns_lookup_settings *set)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client = i_new(struct dns_client, 1);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->path = i_strdup(set->dns_client_socket_path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->timeout_msecs = set->timeout_msecs;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->idle_timeout_msecs = set->idle_timeout_msecs;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->fd = -1;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return client;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenvoid dns_client_deinit(struct dns_client **_client)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_client *client = *_client;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen *_client = NULL;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_assert(client->head == NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, "deinit");
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_free(client->path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_free(client);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_client_connect(struct dns_client *client, const char **error_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (client->fd != -1)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return 0;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->fd = net_connect_unix(client->path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (client->fd == -1) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen *error_r = t_strdup_printf("connect(%s) failed: %m",
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return -1;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->input = i_stream_create_fd(client->fd, MAX_INBUF_SIZE);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->io = io_add(client->fd, IO_READ, dns_client_input, client);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return 0;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainenstatic int
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainendns_client_send_request(struct dns_client *client, const char *cmd,
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen const char **error_r)
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen{
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen int ret;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (client->fd == -1) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (dns_client_connect(client, error_r) < 0)
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen return -1;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen ret = -1;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen } else {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen /* already connected. if write() fails, retry connecting */
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen ret = 0;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen }
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (write_full(client->fd, cmd, strlen(cmd)) < 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen *error_r = t_strdup_printf("write(%s) failed: %m", client->path);
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen return ret;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen }
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen return 1;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen}
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic int
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainendns_client_lookup_common(struct dns_client *client,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *cmd, bool ptr_lookup,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup **lookup_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup *lookup;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup_result result;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen int ret;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen result.ret = EAI_FAIL;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if ((ret = dns_client_send_request(client, cmd, &result.error)) <= 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (ret == 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen /* retry once */
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen ret = dns_client_send_request(client, cmd, &result.error);
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen }
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (ret <= 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen callback(&result, context);
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen return -1;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup = i_new(struct dns_lookup, 1);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->client = client;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->ptr_lookup = ptr_lookup;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (client->timeout_msecs != 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->to = timeout_add(client->timeout_msecs,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_timeout, lookup);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen }
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->result.ret = EAI_FAIL;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->callback = callback;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->context = context;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (gettimeofday(&lookup->start_time, NULL) < 0)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_fatal("gettimeofday() failed: %m");
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_idle);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen DLLIST2_APPEND(&client->head, &client->tail, lookup);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen *lookup_r = lookup;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return 0;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_client_lookup(struct dns_client *client, const char *host,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup **lookup_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *cmd = t_strconcat("IP\t", host, "\n", NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return dns_client_lookup_common(client, cmd, FALSE,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen callback, context, lookup_r);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen}
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_client_lookup_ptr(struct dns_client *client, const struct ip_addr *ip,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct dns_lookup **lookup_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen{
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *cmd = t_strconcat("NAME\t", net_ip2addr(ip), "\n", NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return dns_client_lookup_common(client, cmd, TRUE,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen callback, context, lookup_r);
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch}
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainenvoid dns_client_switch_ioloop(struct dns_client *client)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen{
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen struct dns_lookup *lookup;
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen if (client->io != NULL)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen client->io = io_loop_move_io(&client->io);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen if (client->to_idle != NULL)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen client->to_idle = io_loop_move_timeout(&client->to_idle);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen for (lookup = client->head; lookup != NULL; lookup = lookup->next)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen dns_lookup_switch_ioloop(lookup);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen}