dns-lookup.c revision a943ed0f901e312445fd393249b91932797bba79
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int ip_idx;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen unsigned int timeout_msecs, idle_timeout_msecs;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_disconnect(struct dns_client *client, const char *error)
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd_path(&client->fd, client->path);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic int dns_lookup_input_line(struct dns_lookup *lookup, const char *line)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_lookup_result *result = &lookup->result;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen /* <ret> [<name>] */
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen result->error = net_gethosterror(result->ret);
eb2091a2dedf5513dded8a980b79e206c716962dTimo Sirainen /* first line: <ret> [<ip count>] */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen result->error = net_gethosterror(result->ret);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (net_addr2ip(line, &lookup->ips[lookup->ip_idx]) < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_save_msecs(struct dns_lookup *lookup)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen diff = timeval_diff_msecs(&now, &lookup->start_time);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_input(struct dns_client *client)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen while ((line = i_stream_read_next_line(client->input)) != NULL) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, t_strdup_printf(
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 dns_client_disconnect(client, t_strdup_printf(
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->callback(&lookup->result, lookup->context);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen retry = !lookup->client->deinit_client_at_free;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_timeout(struct dns_lookup *lookup)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen lookup->result.error = "DNS lookup timed out";
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen lookup->callback(&lookup->result, lookup->context);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_lookup(const char *host, const struct dns_lookup_settings *set,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (dns_client_lookup(client, host, callback, context, lookup_r) < 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (dns_client_lookup_ptr(client, ip, callback, context, lookup_r) < 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic void dns_client_idle_timeout(struct dns_client *client)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_client_disconnect(client, "Idle timeout");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_lookup_free(struct dns_lookup **_lookup)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen DLLIST2_REMOVE(&client->head, &client->tail, lookup);
f1b04cf99c9e45c318f31e6c5ade595ee7e595a5Stephan Bosch else if (client->head == NULL && client->fd != -1) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->to_idle = timeout_add(client->idle_timeout_msecs,
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainenvoid dns_lookup_abort(struct dns_lookup **lookup)
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Boschvoid dns_lookup_switch_ioloop(struct dns_lookup *lookup)
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch lookup->to = io_loop_move_timeout(&lookup->to);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen lookup->client->io = io_loop_move_io(&lookup->client->io);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstruct dns_client *dns_client_init(const struct dns_lookup_settings *set)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->path = i_strdup(set->dns_client_socket_path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen client->idle_timeout_msecs = set->idle_timeout_msecs;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenvoid dns_client_deinit(struct dns_client **_client)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_client_connect(struct dns_client *client, const char **error_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen *error_r = t_strdup_printf("connect(%s) failed: %m",
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);
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainendns_client_send_request(struct dns_client *client, const char *cmd,
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen const char **error_r)
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen /* already connected. if write() fails, retry connecting */
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (write_full(client->fd, cmd, strlen(cmd)) < 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen *error_r = t_strdup_printf("write(%s) failed: %m", client->path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainendns_client_lookup_common(struct dns_client *client,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if ((ret = dns_client_send_request(client, cmd, &result.error)) <= 0) {
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen /* retry once */
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen ret = dns_client_send_request(client, cmd, &result.error);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen lookup->to = timeout_add(client->timeout_msecs,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (gettimeofday(&lookup->start_time, NULL) < 0)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen DLLIST2_APPEND(&client->head, &client->tail, lookup);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenint dns_client_lookup(struct dns_client *client, const char *host,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen dns_lookup_callback_t *callback, void *context,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *cmd = t_strconcat("IP\t", host, "\n", NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return dns_client_lookup_common(client, cmd, FALSE,
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 const char *cmd = t_strconcat("NAME\t", net_ip2addr(ip), "\n", NULL);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen return dns_client_lookup_common(client, cmd, TRUE,
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainenvoid dns_client_switch_ioloop(struct dns_client *client)
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen client->to_idle = io_loop_move_timeout(&client->to_idle);
994a2b017b5b7da97914baa1ef711b124c8d15a7Timo Sirainen for (lookup = client->head; lookup != NULL; lookup = lookup->next)