bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "lib.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "ioloop.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "istream.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "ostream.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "restrict-access.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include "master-service.h"
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#include <unistd.h>
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstruct dns_client {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen int fd;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct istream *input;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct ostream *output;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct io *io;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen};
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#define MAX_INBUF_SIZE 1024
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#define MAX_OUTBUF_SIZE (1024*64)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#define INPUT_TIMEOUT_MSECS (1000*10)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic struct dns_client *dns_client = NULL;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_client_destroy(struct dns_client **client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic int dns_client_input_line(struct dns_client *client, const char *line)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen struct ip_addr *ips, ip;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen const char *name;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int i, ips_count;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen int ret;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (strncmp(line, "IP\t", 3) == 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen ret = net_gethostbyname(line + 3, &ips, &ips_count);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (ret == 0 && ips_count == 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen /* shouldn't happen, but fix it anyway.. */
c8ef5fc9c4bfa0ee237f9e1d1d94ac5ac2f1bc04Timo Sirainen ret = EAI_NONAME;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (ret != 0) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(client->output,
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen t_strdup_printf("%d\n", ret));
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen } else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(client->output,
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen t_strdup_printf("0 %u\n", ips_count));
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen for (i = 0; i < ips_count; i++) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(client->output, t_strconcat(
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen net_ip2addr(&ips[i]), "\n", NULL));
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen } else if (strncmp(line, "NAME\t", 5) == 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen if (net_addr2ip(line+5, &ip) < 0)
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen o_stream_nsend_str(client->output, "-1\n");
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen else if ((ret = net_gethostbyaddr(&ip, &name)) != 0) {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen o_stream_nsend_str(client->output,
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen t_strdup_printf("%d\n", ret));
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen } else {
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen o_stream_nsend_str(client->output,
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen t_strdup_printf("0 %s\n", name));
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen } else if (strcmp(line, "QUIT") == 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen } else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(client->output, "Unknown command\n");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (client->output->overflow)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_client_input(struct dns_client *client)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen const char *line;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen int ret = 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen o_stream_cork(client->output);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen while ((line = i_stream_read_next_line(client->input)) != NULL) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (dns_client_input_line(client, line) < 0) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen ret = -1;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen break;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen o_stream_uncork(client->output);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (client->input->eof || client->input->stream_errno != 0 || ret < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_client_destroy(&client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic struct dns_client *dns_client_create(int fd)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_client *client;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen client = i_new(struct dns_client, 1);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen client->fd = fd;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen client->io = io_add(fd, IO_READ, dns_client_input, client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return client;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic void dns_client_destroy(struct dns_client **_client)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen struct dns_client *client = *_client;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen *_client = NULL;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen io_remove(&client->io);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_stream_destroy(&client->input);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen o_stream_destroy(&client->output);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (close(client->fd) < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_error("close() failed: %m");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_free(client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_client = NULL;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen master_service_client_connection_destroyed(master_service);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
db693bf6fcae96d834567f1782257517b7207655Timo Sirainenstatic void client_connected(struct master_service_connection *conn)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (dns_client != NULL) {
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen i_error("dns-client must be configured with client_limit=1");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen }
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen master_service_client_connection_accept(conn);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_client = dns_client_create(conn->fd);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenint main(int argc, char *argv[])
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen master_service = master_service_init("dns-client", 0, &argc, &argv, "");
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (master_getopt(master_service) > 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return FATAL_DEFAULT;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen master_service_init_log(master_service, "dns-client: ");
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen restrict_access_allow_coredumps(TRUE);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen master_service_init_finish(master_service);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen master_service_run(master_service, client_connected);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen if (dns_client != NULL)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen dns_client_destroy(&dns_client);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen master_service_deinit(&master_service);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return 0;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen}