diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2011-03-31 10:41:00 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2011-03-31 10:41:00 +0000 |
commit | f61a70912812ce01d407ce472fb9577b748efc75 (patch) | |
tree | 5e1c9ed8dc884cfdbbeeee97d70013f54e0573ac /usr.sbin | |
parent | e6afa8d9323fde46a5d11c7bc09a6715bf448dc9 (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.c | 270 |
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 |