dns-lookup.c revision a8c5a86d183db25a57bf193c06b41e092ec2e151
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2010-2014 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "ioloop.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "net.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "llist.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "istream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "write-full.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "time-util.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "dns-lookup.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <stdio.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <unistd.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define MAX_INBUF_SIZE 512
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct dns_lookup {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup *prev, *next;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dns_client *client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen bool ptr_lookup;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct timeout *to;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen struct timeval start_time;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen unsigned int warn_msecs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dns_lookup_result result;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct ip_addr *ips;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen unsigned int ip_idx;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen char *name;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_callback_t *callback;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen void *context;
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainenstruct dns_client {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen int fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen char *path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen unsigned int timeout_msecs, idle_timeout_msecs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct istream *input;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct io *io;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct timeout *to_idle;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dns_lookup *head, *tail;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen bool deinit_client_at_free;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#undef dns_lookup
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#undef dns_lookup_ptr
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#undef dns_client_lookup
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#undef dns_client_lookup_ptr
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void dns_client_disconnect(struct dns_client *client, const char *error)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup *lookup;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup_result result;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen memset(&result, 0, sizeof(result));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen result.ret = EAI_FAIL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen result.error = error;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen while (client->head != NULL) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup = client->head;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->callback(&result, lookup->context);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_free(&lookup);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (client->to_idle != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen timeout_remove(&client->to_idle);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (client->io != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen io_remove(&client->io);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (client->input != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_stream_destroy(&client->input);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (client->fd != -1) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (close(client->fd) < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_error("close(%s) failed: %m", client->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->fd = -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int dns_lookup_input_line(struct dns_lookup *lookup, const char *line)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup_result *result = &lookup->result;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen if (result->ips_count == 0) {
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen if (lookup->ptr_lookup) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen /* <ret> [<name>] */
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (strncmp(line, "0 ", 2) == 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen result->name = lookup->name =
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen i_strdup(line + 2);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen result->ret = 0;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen } else {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (str_to_int(line, &result->ret) < 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen result->error = net_gethosterror(result->ret);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen return 1;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen /* first line: <ret> <ip count> */
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (sscanf(line, "%d %u", &result->ret,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen &result->ips_count) != 2)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (result->ret != 0) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen result->error = net_gethosterror(result->ret);
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return 1;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch }
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (result->ips_count == 0)
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return -1;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch result->ips = lookup->ips =
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen i_new(struct ip_addr, result->ips_count);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (net_addr2ip(line, &lookup->ips[lookup->ip_idx]) < 0)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (++lookup->ip_idx == result->ips_count) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen result->ret = 0;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 1;
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void dns_lookup_save_msecs(struct dns_lookup *lookup)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct timeval now;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int diff;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (gettimeofday(&now, NULL) < 0)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_fatal("gettimeofday() failed: %m");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen diff = timeval_diff_msecs(&now, &lookup->start_time);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (diff > 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen lookup->result.msecs = diff;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainenstatic void dns_client_input(struct dns_client *client)
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *line;
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen struct dns_lookup *lookup = client->head;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen bool retry = FALSE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen int ret = 0;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen while ((line = i_stream_read_next_line(client->input)) != NULL) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (lookup == NULL) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_disconnect(client, t_strdup_printf(
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen "Unexpected input from %s", client->path));
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen ret = dns_lookup_input_line(lookup, line);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (ret > 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen break;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (ret < 0) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_disconnect(client, t_strdup_printf(
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen "Invalid input from %s", client->path));
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (ret != 0 && lookup->result.error != NULL) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen /* already got the error */
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen } else if (client->input->stream_errno != 0) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_disconnect(client, t_strdup_printf(
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen "read(%s) failed: %s", client->path,
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen i_stream_get_error(client->input)));
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen } else if (client->input->eof) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_disconnect(client, t_strdup_printf(
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen "Unexpected EOF from %s", client->path));
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret > 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_save_msecs(lookup);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen lookup->callback(&lookup->result, lookup->context);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen retry = !lookup->client->deinit_client_at_free;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_free(&lookup);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen if (retry)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_input(client);
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen}
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainenstatic void dns_lookup_timeout(struct dns_lookup *lookup)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen{
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen lookup->result.error = "DNS lookup timed out";
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen lookup->callback(&lookup->result, lookup->context);
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen dns_lookup_free(&lookup);
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen}
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainenint dns_lookup(const char *host, const struct dns_lookup_settings *set,
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen dns_lookup_callback_t *callback, void *context,
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen struct dns_lookup **lookup_r)
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dns_client *client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen client = dns_client_init(set);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen client->deinit_client_at_free = TRUE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (dns_client_lookup(client, host, callback, context, lookup_r) < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_client_deinit(&client);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenint dns_lookup_ptr(const struct ip_addr *ip,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const struct dns_lookup_settings *set,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_lookup_callback_t *callback, void *context,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup **lookup_r)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_client *client;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client = dns_client_init(set);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->deinit_client_at_free = TRUE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (dns_client_lookup_ptr(client, ip, callback, context, lookup_r) < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_client_deinit(&client);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void dns_client_idle_timeout(struct dns_client *client)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(client->head == NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_client_disconnect(client, "Idle timeout");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen struct dns_lookup *lookup = *_lookup;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen struct dns_client *client = lookup->client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *_lookup = NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen DLLIST2_REMOVE(&client->head, &client->tail, lookup);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (lookup->to != NULL)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen timeout_remove(&lookup->to);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen i_free(lookup->name);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen i_free(lookup->ips);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (client->deinit_client_at_free)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_deinit(&client);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen else if (client->head == NULL) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen client->to_idle = timeout_add(client->idle_timeout_msecs,
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dns_client_idle_timeout, client);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(lookup);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen}
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid dns_lookup_abort(struct dns_lookup **lookup)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_free(lookup);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen}
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenvoid dns_lookup_switch_ioloop(struct dns_lookup *lookup)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (lookup->to != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->to = io_loop_move_timeout(&lookup->to);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->client->io = io_loop_move_io(&lookup->client->io);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct dns_client *dns_client_init(const struct dns_lookup_settings *set)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_client *client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client = i_new(struct dns_client, 1);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen client->path = i_strdup(set->dns_client_socket_path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->timeout_msecs = set->timeout_msecs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->idle_timeout_msecs = set->idle_timeout_msecs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->fd = -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return client;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenvoid dns_client_deinit(struct dns_client **_client)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dns_client *client = *_client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *_client = NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(client->head == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_client_disconnect(client, "deinit");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(client->path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(client);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenint dns_client_connect(struct dns_client *client, const char **error_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (client->fd != -1)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->fd = net_connect_unix(client->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (client->fd == -1) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen *error_r = t_strdup_printf("connect(%s) failed: %m",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client->input = i_stream_create_fd(client->fd, MAX_INBUF_SIZE, FALSE);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen client->io = io_add(client->fd, IO_READ, dns_client_input, client);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainendns_client_send_request(struct dns_client *client, const char *cmd,
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen const char **error_r)
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen{
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen int ret;
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen if (client->fd == -1) {
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen if (dns_client_connect(client, error_r) < 0)
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen return -1;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = -1;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen } else {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* already connected. if write() fails, retry connecting */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (write_full(client->fd, cmd, strlen(cmd)) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *error_r = t_strdup_printf("write(%s) failed: %m", client->path);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen return ret;
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen }
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen return 1;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen}
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen
a78468f42df768399d6e3890381a936b439297b0Timo Sirainenstatic int
a78468f42df768399d6e3890381a936b439297b0Timo Sirainendns_client_lookup_common(struct dns_client *client,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen const char *cmd, bool ptr_lookup,
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen dns_lookup_callback_t *callback, void *context,
9ec1ecbc19af5a312877c0f19d6adf5bc38a7111Timo Sirainen struct dns_lookup **lookup_r)
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen{
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen struct dns_lookup *lookup;
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen struct dns_lookup_result result;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen memset(&result, 0, sizeof(result));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen result.ret = EAI_FAIL;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if ((ret = dns_client_send_request(client, cmd, &result.error)) <= 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret == 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* retry once */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = dns_client_send_request(client, cmd, &result.error);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (ret <= 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen callback(&result, context);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup = i_new(struct dns_lookup, 1);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->client = client;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->ptr_lookup = ptr_lookup;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (client->timeout_msecs != 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->to = timeout_add(client->timeout_msecs,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dns_lookup_timeout, lookup);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->result.ret = EAI_FAIL;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen lookup->callback = callback;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen lookup->context = context;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (gettimeofday(&lookup->start_time, NULL) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_fatal("gettimeofday() failed: %m");
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen if (client->to_idle != NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen timeout_remove(&client->to_idle);
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen DLLIST2_APPEND(&client->head, &client->tail, lookup);
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen *lookup_r = lookup;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenint dns_client_lookup(struct dns_client *client, const char *host,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dns_lookup_callback_t *callback, void *context,
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen struct dns_lookup **lookup_r)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen{
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen const char *cmd = t_strconcat("IP\t", host, "\n", NULL);
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen return dns_client_lookup_common(client, cmd, FALSE,
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen callback, context, lookup_r);
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen}
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenint dns_client_lookup_ptr(struct dns_client *client, const struct ip_addr *ip,
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen dns_lookup_callback_t *callback, void *context,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dns_lookup **lookup_r)
2a45e925383d56510d318ea47334e939f7d58130Timo Sirainen{
2a45e925383d56510d318ea47334e939f7d58130Timo Sirainen const char *cmd = t_strconcat("NAME\t", net_ip2addr(ip), "\n", NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return dns_client_lookup_common(client, cmd, TRUE,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen callback, context, lookup_r);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen