summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2011-03-31 10:41:00 +0000
committerEric Faurot <eric@cvs.openbsd.org>2011-03-31 10:41:00 +0000
commitf61a70912812ce01d407ce472fb9577b748efc75 (patch)
tree5e1c9ed8dc884cfdbbeeee97d70013f54e0573ac /usr.sbin
parente6afa8d9323fde46a5d11c7bc09a6715bf448dc9 (diff)
cleanup and simplification following the asr update.
- use a specific dispatch function for each type of query - make the host handler work on a list of hosts by default (single host queries are just a particular case) and use that to resolve the MX list - various other code cleanup - remove unused headers - remove orphaned prototypes - update copyright ok gilles@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/dns.c270
1 files changed, 102 insertions, 168 deletions
diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c
index f5079c73ab1..ed244452099 100644
--- a/usr.sbin/smtpd/dns.c
+++ b/usr.sbin/smtpd/dns.c
@@ -1,8 +1,9 @@
-/* $OpenBSD: dns.c,v 1.37 2011/03/29 20:43:51 eric Exp $ */
+/* $OpenBSD: dns.c,v 1.38 2011/03/31 10:40:59 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
* Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
+ * Copyright (c) 2011 Eric Faurot <eric@faurot.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,22 +20,16 @@
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/queue.h>
#include <sys/tree.h>
-#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <arpa/nameser.h>
#include <event.h>
#include <imsg.h>
-#include <netdb.h>
-#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include "asr.h"
#include "dnsdefs.h"
@@ -44,14 +39,12 @@
struct dnssession *dnssession_init(struct smtpd *, struct dns *);
void dnssession_destroy(struct smtpd *, struct dnssession *);
-void dnssession_mx_insert(struct dnssession *, struct mx *);
-void dns_asr_event_set(struct dnssession *, struct asr_result *, void(*)(int, short, void*));
+void dnssession_mx_insert(struct dnssession *, const char *, int);
+void dns_asr_event_set(struct dnssession *, struct asr_result *);
void dns_asr_handler(int, short, void *);
-void dns_asr_mx_handler(int, short, void *);
+void dns_asr_dispatch_host(struct dnssession *);
+void dns_asr_dispatch_mx(struct dnssession *);
void dns_asr_dispatch_cname(struct dnssession *);
-void lookup_host(struct imsgev *, struct dns *, int, int);
-void lookup_mx(struct imsgev *, struct dns *);
-void lookup_ptr(struct imsgev *, struct dns *);
struct asr *asr = NULL;
@@ -115,33 +108,35 @@ dns_async(struct smtpd *env, struct imsgev *asker, int type, struct dns *query)
query->type = type;
query->asker = asker;
dnssession = dnssession_init(env, query);
-
+
switch (type) {
case IMSG_DNS_HOST:
- dnssession->aq = asr_query_host(asr, query->host, AF_UNSPEC);
- break;
+ dnssession_mx_insert(dnssession, query->host, 0);
+ dns_asr_dispatch_host(dnssession);
+ return;
case IMSG_DNS_PTR:
dnssession->aq = asr_query_cname(asr,
(struct sockaddr*)&query->ss, query->ss.ss_len);
- break;
+ if (dnssession->aq == NULL) {
+ log_debug("dns_async: asr_query_cname error");
+ break;
+ }
+ dns_asr_dispatch_cname(dnssession);
+ return;
case IMSG_DNS_MX:
dnssession->aq = asr_query_dns(asr, T_MX, C_IN, query->host, 0);
- break;
+ if (dnssession->aq == NULL) {
+ log_debug("dns_async: asr_query_dns error");
+ break;
+ }
+ dns_asr_dispatch_mx(dnssession);
+ return;
default:
- goto err;
+ log_debug("dns_async: bad request");
+ break;
}
- /* query and set up event to handle answer */
- if (dnssession->aq == NULL)
- goto err;
- dns_asr_handler(-1, -1, dnssession);
- return;
-
-err:
- log_debug("dns_async: ASR error while attempting to resolve `%s'",
- query->host);
dnssession_destroy(env, dnssession);
-
noasr:
query->error = EAI_AGAIN;
if (type != IMSG_DNS_PTR)
@@ -150,15 +145,14 @@ noasr:
}
void
-dns_asr_event_set(struct dnssession *dnssession, struct asr_result *ar,
- void (*handler)(int, short, void*))
+dns_asr_event_set(struct dnssession *dnssession, struct asr_result *ar)
{
struct timeval tv = { 0, 0 };
tv.tv_usec = ar->ar_timeout * 1000;
event_set(&dnssession->ev, ar->ar_fd,
ar->ar_cond == ASR_READ ? EV_READ : EV_WRITE,
- handler, dnssession);
+ dns_asr_handler, dnssession);
event_add(&dnssession->ev, &tv);
}
@@ -166,168 +160,106 @@ void
dns_asr_handler(int fd, short event, void *arg)
{
struct dnssession *dnssession = arg;
- struct dns *query = &dnssession->query;
- struct smtpd *env = query->env;
- struct packed pack;
- struct header h;
- struct query q;
- struct rr rr;
- struct mx mx;
- struct asr_result ar;
- char *p;
- int ret;
-
- if (dnssession->query.type == IMSG_DNS_PTR) {
- dns_asr_dispatch_cname(dnssession);
- return;
- }
-
- switch ((ret = asr_run(dnssession->aq, &ar))) {
- case ASR_COND:
- dns_asr_event_set(dnssession, &ar, dns_asr_handler);
- return;
- case ASR_YIELD:
- case ASR_DONE:
+ switch(dnssession->query.type) {
+ case IMSG_DNS_HOST:
+ dns_asr_dispatch_host(dnssession);
+ break;
+ case IMSG_DNS_PTR:
+ dns_asr_dispatch_cname(dnssession);
break;
+ case IMSG_DNS_MX:
+ dns_asr_dispatch_mx(dnssession);
+ break;
+ default:
+ fatalx("bad query type");
}
+}
- query->error = EAI_AGAIN;
-
- if (ret == ASR_YIELD) {
- free(ar.ar_cname);
- memcpy(&query->ss, &ar.ar_sa.sa, ar.ar_sa.sa.sa_len);
- query->error = 0;
- imsg_compose_event(query->asker, IMSG_DNS_HOST, 0, 0, -1, query,
- sizeof(*query));
- dns_asr_handler(-1, -1, dnssession);
+void
+dns_asr_dispatch_mx(struct dnssession *dnssession)
+{
+ struct dns *query = &dnssession->query;
+ struct asr_result ar;
+ struct packed pack;
+ struct header h;
+ struct query q;
+ struct rr rr;
+ char buf[512];
+
+ if (asr_run(dnssession->aq, &ar) == ASR_COND) {
+ dns_asr_event_set(dnssession, &ar);
return;
}
- /* ASR_DONE */
- if (ar.ar_err) {
- query->error = ar.ar_err;
- goto err;
- }
-
- if (query->type == IMSG_DNS_HOST) {
- query->error = 0;
- imsg_compose_event(query->asker, IMSG_DNS_HOST_END, 0, 0, -1,
- query, sizeof(*query));
- dnssession_destroy(env, dnssession);
- return;
- }
+ if (ar.ar_err)
+ goto hosts; /* empty list */
- /* MX */
packed_init(&pack, ar.ar_data, ar.ar_datalen);
- if (unpack_header(&pack, &h) < 0 || unpack_query(&pack, &q) < 0)
- goto err;
-
- if (h.ancount == 0) {
- /* we were looking for MX and got no answer,
- * fallback to host.
- */
- query->type = IMSG_DNS_HOST;
- dnssession->aq = asr_query_host(asr, query->host,
- AF_UNSPEC);
- if (dnssession->aq == NULL)
- goto err;
- dns_asr_handler(-1, -1, dnssession);
- return;
- }
-
- for (; h.ancount; h.ancount--) {
- if (unpack_rr(&pack, &rr) < 0)
- goto err;
+ unpack_header(&pack, &h);
+ unpack_query(&pack, &q);
- print_dname(rr.rr.mx.exchange, mx.host, sizeof (mx.host));
- if ((p = strrchr(mx.host, '.')) != NULL)
- *p = '\0';
- mx.prio = rr.rr.mx.preference;
+ if (h.ancount == 0)
+ /* fallback to host if no MX is found. */
+ dnssession_mx_insert(dnssession, query->host, 0);
- /* sorted insert that will not overflow MAX_MX_COUNT */
- dnssession_mx_insert(dnssession, &mx);
+ for (; h.ancount; h.ancount--) {
+ unpack_rr(&pack, &rr);
+ print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
+ buf[strlen(buf) - 1] = '\0';
+ dnssession_mx_insert(dnssession, buf, rr.rr.mx.preference);
}
+
free(ar.ar_data);
ar.ar_data = NULL;
- /* The T_MX scenario is a bit tricky.
- * Rather than forwarding the answers to the process that queried,
- * we retrieve a set of MX hosts ... that need to be resolved. The
- * loop above sorts them by priority, all we have left to do is to
- * perform T_A lookups on all of them sequentially and provide the
- * process that queried with the answers.
- *
- * To make it easier, we do this in another handler.
- *
- * -- gilles@
+hosts:
+ /* Now we have a sorted list of MX to resolve. Simply "turn" this
+ * MX session into a regular host session.
*/
- dnssession->mxfound = 0;
- dnssession->mxcurrent = 0;
- dnssession->aq = asr_query_host(asr,
- dnssession->mxarray[dnssession->mxcurrent].host, AF_UNSPEC);
- if (dnssession->aq == NULL)
- goto err;
-
- dns_asr_mx_handler(-1, -1, dnssession);
- return;
-
-err:
- free(ar.ar_data);
- query->type = IMSG_DNS_HOST_END;
- imsg_compose_event(query->asker, query->type, 0, 0, -1, query,
- sizeof(*query));
- dnssession_destroy(env, dnssession);
+ dnssession->aq = NULL;
+ dnssession->query.type = IMSG_DNS_HOST;
+ dns_asr_dispatch_host(dnssession);
}
-/* only handle MX requests */
void
-dns_asr_mx_handler(int fd, short event, void *arg)
+dns_asr_dispatch_host(struct dnssession *dnssession)
{
- struct dnssession *dnssession = arg;
- struct dns *query = &dnssession->query;
- struct smtpd *env = query->env;
- struct asr_result ar;
- int ret;
-
- switch ((ret = asr_run(dnssession->aq, &ar))) {
- case ASR_COND:
- dns_asr_event_set(dnssession, &ar, dns_asr_mx_handler);
- return;
+ struct dns *query = &dnssession->query;
+ struct mx *mx;
+ struct asr_result ar;
+ int ret;
+
+next:
+ /* query all listed hosts in turn */
+ while (dnssession->aq == NULL) {
+ if (dnssession->mxcurrent == dnssession->mxarraysz) {
+ query->error = (dnssession->mxfound) ? 0 : EAI_NONAME;
+ imsg_compose_event(query->asker, IMSG_DNS_HOST_END, 0,
+ 0, -1, query, sizeof(*query));
+ dnssession_destroy(query->env, dnssession);
+ return;
+ }
+ mx = dnssession->mxarray + dnssession->mxcurrent++;
+ dnssession->aq = asr_query_host(asr, mx->host, AF_UNSPEC);
+ }
- case ASR_YIELD:
+ while ((ret = asr_run(dnssession->aq, &ar)) == ASR_YIELD) {
free(ar.ar_cname);
memcpy(&query->ss, &ar.ar_sa.sa, ar.ar_sa.sa.sa_len);
query->error = 0;
imsg_compose_event(query->asker, IMSG_DNS_HOST, 0, 0, -1, query,
sizeof(*query));
dnssession->mxfound++;
- dns_asr_mx_handler(-1, -1, dnssession);
- return;
-
- case ASR_DONE:
- break;
}
- if (++dnssession->mxcurrent == dnssession->mxarraysz)
- goto end;
-
- dnssession->aq = asr_query_host(asr,
- dnssession->mxarray[dnssession->mxcurrent].host, AF_UNSPEC);
- if (dnssession->aq == NULL)
- goto end;
- dns_asr_mx_handler(-1, -1, dnssession);
- return;
+ if (ret == ASR_COND) {
+ dns_asr_event_set(dnssession, &ar);
+ return;
+ }
-end:
- if (dnssession->mxfound == 0)
- query->error = EAI_NONAME;
- else
- query->error = 0;
- imsg_compose_event(query->asker, IMSG_DNS_HOST_END, 0, 0, -1, query,
- sizeof(*query));
- dnssession_destroy(env, dnssession);
- return;
+ dnssession->aq = NULL;
+ goto next;
}
void
@@ -338,7 +270,7 @@ dns_asr_dispatch_cname(struct dnssession *dnssession)
switch (asr_run(dnssession->aq, &ar)) {
case ASR_COND:
- dns_asr_event_set(dnssession, &ar, dns_asr_handler);
+ dns_asr_event_set(dnssession, &ar);
return;
case ASR_YIELD:
/* Only return the first answer */
@@ -381,12 +313,12 @@ dnssession_destroy(struct smtpd *env, struct dnssession *dnssession)
}
void
-dnssession_mx_insert(struct dnssession *dnssession, struct mx *mx)
+dnssession_mx_insert(struct dnssession *dnssession, const char *host, int prio)
{
size_t i, j;
for (i = 0; i < dnssession->mxarraysz; i++)
- if (mx->prio < dnssession->mxarray[i].prio)
+ if (prio < dnssession->mxarray[i].prio)
break;
if (i == MAX_MX_COUNT)
@@ -398,7 +330,9 @@ dnssession_mx_insert(struct dnssession *dnssession, struct mx *mx)
for (j = dnssession->mxarraysz - 1; j > i; j--)
dnssession->mxarray[j] = dnssession->mxarray[j - 1];
- dnssession->mxarray[i] = *mx;
+ dnssession->mxarray[i].prio = prio;
+ strlcpy(dnssession->mxarray[i].host, host,
+ sizeof (dnssession->mxarray[i].host));
}
int