summaryrefslogtreecommitdiffstats
path: root/src/dns/dns-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns/dns-client.c')
-rw-r--r--src/dns/dns-client.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/dns/dns-client.c b/src/dns/dns-client.c
new file mode 100644
index 0000000..381c2ea
--- /dev/null
+++ b/src/dns/dns-client.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream.h"
+#include "ostream.h"
+#include "array.h"
+#include "strfuncs.h"
+#include "connection.h"
+#include "restrict-access.h"
+#include "master-service.h"
+
+#include <unistd.h>
+
+static struct event_category event_category_dns = {
+ .name = "dns-worker"
+};
+
+static struct connection_list *dns_clients = NULL;
+
+static int dns_client_input_args(struct connection *client, const char *const *args)
+{
+ struct ip_addr *ips, ip;
+ const char *name;
+ struct event *event;
+ unsigned int i, ips_count;
+ int ret;
+ struct event_passthrough *e;
+
+ if (strcmp(args[0], "QUIT") == 0) {
+ return -1;
+ } else if (args[1] == NULL) {
+ e_error(client->event, "Got empty request");
+ return -1;
+ }
+
+ event = event_create(client->event);
+ event_set_append_log_prefix(event, t_strconcat(args[1], ": ", NULL));
+
+ e = event_create_passthrough(event)->
+ set_name("dns_worker_request_started")->
+ add_str("name", args[1]);
+ e_debug(e->event(), "Resolving");
+
+ e = event_create_passthrough(event)->
+ set_name("dns_worker_request_finished")->
+ add_str("name", args[1]);
+
+ if (strcmp(args[0], "IP") == 0) {
+ ret = net_gethostbyname(args[1], &ips, &ips_count);
+ if (ret == 0 && ips_count == 0) {
+ /* shouldn't happen, but fix it anyway.. */
+ ret = EAI_NONAME;
+ }
+ /* update timestamp after hostname lookup so the event duration
+ field gets set correctly */
+ io_loop_time_refresh();
+ if (ret != 0) {
+ const char *err = net_gethosterror(ret);
+ e->add_int("error_code", ret);
+ e->add_str("error", err);
+ e_debug(e->event(), "Resolve failed: %s", err);
+ o_stream_nsend_str(client->output,
+ t_strdup_printf("%d\t%s\n", ret, err));
+ } else {
+ ARRAY_TYPE(const_string) tmp;
+ t_array_init(&tmp, ips_count);
+ o_stream_nsend_str(client->output, "0\t");
+ for (i = 0; i < ips_count; i++) {
+ const char *ip = net_ip2addr(&ips[i]);
+ array_push_back(&tmp, &ip);
+ }
+ array_append_zero(&tmp);
+ e_debug(e->event(), "Resolve success: %s",
+ t_strarray_join(array_front(&tmp), ", "));
+ o_stream_nsend_str(client->output,
+ t_strarray_join(array_front(&tmp), "\t"));
+ o_stream_nsend_str(client->output, "\n");
+ }
+ } else if (strcmp(args[0], "NAME") == 0) {
+ if (net_addr2ip(args[1], &ip) < 0) {
+ e->add_int("error_code", EAI_FAIL);
+ e->add_str("error", "Not an IP");
+ e_debug(e->event(), "Resolve failed: Not an IP");
+ o_stream_nsend_str(client->output, "-1\tNot an IP\n");
+ } else if ((ret = net_gethostbyaddr(&ip, &name)) != 0) {
+ const char *err = net_gethosterror(ret);
+ e->add_int("error_code", ret);
+ e->add_str("error", err);
+ e_debug(e->event(), "Resolve failed: %s", err);
+ o_stream_nsend_str(client->output,
+ t_strdup_printf("%d\t%s\n", ret, err));
+ } else {
+ e_debug(e->event(), "Resolve success: %s", name);
+ o_stream_nsend_str(client->output,
+ t_strdup_printf("0\t%s\n", name));
+ }
+ } else {
+ e->add_str("error", "Unknown command");
+ e_error(e->event(), "Unknown command '%s'", args[0]);
+ o_stream_nsend_str(client->output, "-1\tUnknown command\n");
+ }
+
+ event_unref(&event);
+
+ return 1;
+}
+
+static void dns_client_destroy(struct connection *client)
+{
+ connection_deinit(client);
+ event_unref(&client->event);
+ i_free(client);
+ master_service_client_connection_destroyed(master_service);
+}
+
+static const struct connection_vfuncs dns_client_vfuncs = {
+ .input_args = dns_client_input_args,
+ .destroy = dns_client_destroy
+};
+
+static const struct connection_settings dns_client_set = {
+ .service_name_in = "dns-client",
+ .service_name_out = "dns",
+ .major_version = 1,
+ .minor_version = 0,
+ .input_max_size = SIZE_MAX,
+ .output_max_size = SIZE_MAX
+};
+
+static void client_connected(struct master_service_connection *master_conn)
+{
+ struct connection *conn = i_new(struct connection, 1);
+ master_service_client_connection_accept(master_conn);
+ connection_init_server(dns_clients, conn, master_conn->name,
+ master_conn->fd, master_conn->fd);
+ event_add_category(conn->event, &event_category_dns);
+}
+
+int main(int argc, char *argv[])
+{
+ master_service = master_service_init("dns-client", 0,
+ &argc, &argv, "");
+ if (master_getopt(master_service) > 0)
+ return FATAL_DEFAULT;
+
+ master_service_init_log(master_service);
+ restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
+ restrict_access_allow_coredumps(TRUE);
+
+ /* setup connection list */
+ dns_clients = connection_list_init(&dns_client_set, &dns_client_vfuncs);
+
+ master_service_init_finish(master_service);
+ master_service_run(master_service, client_connected);
+
+ /* disconnect all clients */
+ connection_list_deinit(&dns_clients);
+
+ master_service_deinit(&master_service);
+ return 0;
+}