aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Faurot <eric@faurot.net>2014-03-26 10:36:55 +0100
committerEric Faurot <eric@faurot.net>2014-03-26 10:36:55 +0100
commitf227da67d98ecb8a5191d6c1b365504418dc33f6 (patch)
tree05b7e4c62ff99be904986754a5accc030f00a5c2
parentdocuemnt deliver as (diff)
downloadOpenSMTPD-opensmtpd-201403261203.tar.xz
OpenSMTPD-opensmtpd-201403261203.zip
update asr related code after latest API changesopensmtpd-201403261203
-rw-r--r--smtpd/dns.c427
-rw-r--r--smtpd/filters/asr_event.c20
-rw-r--r--smtpd/filters/asr_event.h12
-rw-r--r--smtpd/filters/filter_dnsbl.c4
4 files changed, 398 insertions, 65 deletions
diff --git a/smtpd/dns.c b/smtpd/dns.c
index 635df924..2536f7ad 100644
--- a/smtpd/dns.c
+++ b/smtpd/dns.c
@@ -3,7 +3,7 @@
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
* Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
- * Copyright (c) 2011-2012 Eric Faurot <eric@faurot.net>
+ * Copyright (c) 2011-2014 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
@@ -35,7 +35,6 @@
#include <string.h>
#include "asr.h"
-#include "asr_private.h"
#include "smtpd.h"
#include "log.h"
@@ -55,16 +54,92 @@ struct dns_session {
};
struct async_event;
-struct async_event * async_run_event(struct async *,
- void (*)(int, struct async_res *, void *), void *);
+struct async_event * async_run_event(struct asr_query *,
+ void (*)(struct asr_result *, void *), void *);
static void dns_lookup_host(struct dns_session *, const char *, int);
-static void dns_dispatch_host(int, struct async_res *, void *);
-static void dns_dispatch_ptr(int, struct async_res *, void *);
-static void dns_dispatch_mx(int, struct async_res *, void *);
-static void dns_dispatch_mx_preference(int, struct async_res *, void *);
+static void dns_dispatch_host(struct asr_result *, void *);
+static void dns_dispatch_ptr(struct asr_result *, void *);
+static void dns_dispatch_mx(struct asr_result *, void *);
+static void dns_dispatch_mx_preference(struct asr_result *, void *);
+
+struct unpack {
+ const char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct dns_header {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+struct dns_query {
+ char q_dname[MAXDNAME];
+ uint16_t q_type;
+ uint16_t q_class;
+};
+
+struct dns_rr {
+ char rr_dname[MAXDNAME];
+ uint16_t rr_type;
+ uint16_t rr_class;
+ uint32_t rr_ttl;
+ union {
+ struct {
+ char cname[MAXDNAME];
+ } cname;
+ struct {
+ uint16_t preference;
+ char exchange[MAXDNAME];
+ } mx;
+ struct {
+ char nsname[MAXDNAME];
+ } ns;
+ struct {
+ char ptrname[MAXDNAME];
+ } ptr;
+ struct {
+ char mname[MAXDNAME];
+ char rname[MAXDNAME];
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+ } soa;
+ struct {
+ struct in_addr addr;
+ } in_a;
+ struct {
+ struct in6_addr addr6;
+ } in_aaaa;
+ struct {
+ uint16_t rdlen;
+ const void *rdata;
+ } other;
+ } rr;
+};
+
+static char *print_dname(const char *, char *, size_t);
+static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
+ char *, size_t);
+static int unpack_data(struct unpack *, void *, size_t);
+static int unpack_u16(struct unpack *, uint16_t *);
+static int unpack_u32(struct unpack *, uint32_t *);
+static int unpack_inaddr(struct unpack *, struct in_addr *);
+static int unpack_in6addr(struct unpack *, struct in6_addr *);
+static int unpack_dname(struct unpack *, char *, size_t);
+static void unpack_init(struct unpack *, const char *, size_t);
+static int unpack_header(struct unpack *, struct dns_header *);
+static int unpack_query(struct unpack *, struct dns_query *);
+static int unpack_rr(struct unpack *, struct dns_rr *);
-#define print_dname(a,b,c) asr_strdname(a, b, c)
void
dns_query_host(uint64_t id, const char *host)
@@ -155,7 +230,7 @@ dns_imsg(struct mproc *p, struct imsg *imsg)
struct sockaddr_storage ss;
struct dns_session *s;
struct sockaddr *sa;
- struct async *as;
+ struct asr_query *as;
struct msg m;
const char *domain, *mx, *host;
socklen_t sl;
@@ -250,7 +325,7 @@ dns_imsg(struct mproc *p, struct imsg *imsg)
}
static void
-dns_dispatch_host(int ev, struct async_res *ar, void *arg)
+dns_dispatch_host(struct asr_result *ar, void *arg)
{
struct dns_session *s;
struct dns_lookup *lookup = arg;
@@ -284,7 +359,7 @@ dns_dispatch_host(int ev, struct async_res *ar, void *arg)
}
static void
-dns_dispatch_ptr(int ev, struct async_res *ar, void *arg)
+dns_dispatch_ptr(struct asr_result *ar, void *arg)
{
struct dns_session *s = arg;
@@ -299,13 +374,13 @@ dns_dispatch_ptr(int ev, struct async_res *ar, void *arg)
}
static void
-dns_dispatch_mx(int ev, struct async_res *ar, void *arg)
+dns_dispatch_mx(struct asr_result *ar, void *arg)
{
struct dns_session *s = arg;
- struct asr_unpack pack;
- struct asr_dns_header h;
- struct asr_dns_query q;
- struct asr_dns_rr rr;
+ struct unpack pack;
+ struct dns_header h;
+ struct dns_query q;
+ struct dns_rr rr;
char buf[512];
size_t found;
@@ -325,13 +400,13 @@ dns_dispatch_mx(int ev, struct async_res *ar, void *arg)
return;
}
- asr_unpack_init(&pack, ar->ar_data, ar->ar_datalen);
- asr_unpack_header(&pack, &h);
- asr_unpack_query(&pack, &q);
+ unpack_init(&pack, ar->ar_data, ar->ar_datalen);
+ unpack_header(&pack, &h);
+ unpack_query(&pack, &q);
found = 0;
for (; h.ancount; h.ancount--) {
- asr_unpack_rr(&pack, &rr);
+ unpack_rr(&pack, &rr);
if (rr.rr_type != T_MX)
continue;
print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
@@ -347,13 +422,13 @@ dns_dispatch_mx(int ev, struct async_res *ar, void *arg)
}
static void
-dns_dispatch_mx_preference(int ev, struct async_res *ar, void *arg)
+dns_dispatch_mx_preference(struct asr_result *ar, void *arg)
{
struct dns_session *s = arg;
- struct asr_unpack pack;
- struct asr_dns_header h;
- struct asr_dns_query q;
- struct asr_dns_rr rr;
+ struct unpack pack;
+ struct dns_header h;
+ struct dns_query q;
+ struct dns_rr rr;
char buf[512];
int error;
@@ -368,11 +443,11 @@ dns_dispatch_mx_preference(int ev, struct async_res *ar, void *arg)
}
else {
error = DNS_ENOTFOUND;
- asr_unpack_init(&pack, ar->ar_data, ar->ar_datalen);
- asr_unpack_header(&pack, &h);
- asr_unpack_query(&pack, &q);
+ unpack_init(&pack, ar->ar_data, ar->ar_datalen);
+ unpack_header(&pack, &h);
+ unpack_query(&pack, &q);
for (; h.ancount; h.ancount--) {
- asr_unpack_rr(&pack, &rr);
+ unpack_rr(&pack, &rr);
if (rr.rr_type != T_MX)
continue;
print_dname(rr.rr.mx.exchange, buf, sizeof(buf));
@@ -400,7 +475,7 @@ dns_lookup_host(struct dns_session *s, const char *host, int preference)
{
struct dns_lookup *lookup;
struct addrinfo hints;
- struct async *as;
+ void *as;
lookup = xcalloc(1, sizeof *lookup, "dns_lookup_host");
lookup->preference = preference;
@@ -417,17 +492,17 @@ dns_lookup_host(struct dns_session *s, const char *host, int preference)
/* Generic libevent glue for asr */
struct async_event {
- struct async *async;
+ struct asr_query *async;
struct event ev;
- void (*callback)(int, struct async_res *, void *);
+ void (*callback)(struct asr_result *, void *);
void *arg;
};
static void async_event_dispatch(int, short, void *);
struct async_event *
-async_run_event(struct async * async,
- void (*cb)(int, struct async_res *, void *), void *arg)
+async_run_event(struct asr_query * async,
+ void (*cb)(struct asr_result *, void *), void *arg)
{
struct async_event *aev;
struct timeval tv;
@@ -449,23 +524,285 @@ static void
async_event_dispatch(int fd, short ev, void *arg)
{
struct async_event *aev = arg;
- struct async_res ar;
- int r;
+ struct asr_result ar;
struct timeval tv;
- while ((r = asr_async_run(aev->async, &ar)) == ASYNC_YIELD)
- aev->callback(r, &ar, aev->arg);
-
event_del(&aev->ev);
- if (r == ASYNC_COND) {
+
+ if (asr_run(aev->async, &ar) == 0) {
event_set(&aev->ev, ar.ar_fd,
- ar.ar_cond == ASYNC_READ ? EV_READ : EV_WRITE,
- async_event_dispatch, aev);
+ ar.ar_cond == ASR_WANT_READ ? EV_READ : EV_WRITE,
+ async_event_dispatch, aev);
tv.tv_sec = ar.ar_timeout / 1000;
tv.tv_usec = (ar.ar_timeout % 1000) * 1000;
event_add(&aev->ev, &tv);
- } else { /* ASYNC_DONE */
- aev->callback(r, &ar, aev->arg);
+ } else {
+ aev->callback(&ar, aev->arg);
free(aev);
}
}
+
+static char *
+print_dname(const char *_dname, char *buf, size_t max)
+{
+ const unsigned char *dname = _dname;
+ char *res;
+ size_t left, n, count;
+
+ if (_dname[0] == 0) {
+ strlcpy(buf, ".", max);
+ return buf;
+ }
+
+ res = buf;
+ left = max - 1;
+ for (n = 0; dname[0] && left; n += dname[0]) {
+ count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
+ memmove(buf, dname + 1, count);
+ dname += dname[0] + 1;
+ left -= count;
+ buf += count;
+ if (left) {
+ left -= 1;
+ *buf++ = '.';
+ }
+ }
+ buf[0] = 0;
+
+ return (res);
+}
+
+static ssize_t
+dname_expand(const unsigned char *data, size_t len, size_t offset,
+ size_t *newoffset, char *dst, size_t max)
+{
+ size_t n, count, end, ptr, start;
+ ssize_t res;
+
+ if (offset >= len)
+ return (-1);
+
+ res = 0;
+ end = start = offset;
+
+ for (; (n = data[offset]); ) {
+ if ((n & 0xc0) == 0xc0) {
+ if (offset + 2 > len)
+ return (-1);
+ ptr = 256 * (n & ~0xc0) + data[offset + 1];
+ if (ptr >= start)
+ return (-1);
+ if (end < offset + 2)
+ end = offset + 2;
+ offset = start = ptr;
+ continue;
+ }
+ if (offset + n + 1 > len)
+ return (-1);
+
+ /* copy n + at offset+1 */
+ if (dst != NULL && max != 0) {
+ count = (max < n + 1) ? (max) : (n + 1);
+ memmove(dst, data + offset, count);
+ dst += count;
+ max -= count;
+ }
+ res += n + 1;
+ offset += n + 1;
+ if (end < offset)
+ end = offset;
+ }
+ if (end < offset + 1)
+ end = offset + 1;
+
+ if (dst != NULL && max != 0)
+ dst[0] = 0;
+ if (newoffset)
+ *newoffset = end;
+ return (res + 1);
+}
+
+void
+unpack_init(struct unpack *unpack, const char *buf, size_t len)
+{
+ unpack->buf = buf;
+ unpack->len = len;
+ unpack->offset = 0;
+ unpack->err = NULL;
+}
+
+static int
+unpack_data(struct unpack *p, void *data, size_t len)
+{
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < len) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ memmove(data, p->buf + p->offset, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+unpack_u16(struct unpack *p, uint16_t *u16)
+{
+ if (unpack_data(p, u16, 2) == -1)
+ return (-1);
+
+ *u16 = ntohs(*u16);
+
+ return (0);
+}
+
+static int
+unpack_u32(struct unpack *p, uint32_t *u32)
+{
+ if (unpack_data(p, u32, 4) == -1)
+ return (-1);
+
+ *u32 = ntohl(*u32);
+
+ return (0);
+}
+
+static int
+unpack_inaddr(struct unpack *p, struct in_addr *a)
+{
+ return (unpack_data(p, a, 4));
+}
+
+static int
+unpack_in6addr(struct unpack *p, struct in6_addr *a6)
+{
+ return (unpack_data(p, a6, 16));
+}
+
+static int
+unpack_dname(struct unpack *p, char *dst, size_t max)
+{
+ ssize_t e;
+
+ if (p->err)
+ return (-1);
+
+ e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
+ if (e == -1) {
+ p->err = "bad domain name";
+ return (-1);
+ }
+ if (e < 0 || e > MAXDNAME) {
+ p->err = "domain name too long";
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+unpack_header(struct unpack *p, struct dns_header *h)
+{
+ if (unpack_data(p, h, HFIXEDSZ) == -1)
+ return (-1);
+
+ h->flags = ntohs(h->flags);
+ h->qdcount = ntohs(h->qdcount);
+ h->ancount = ntohs(h->ancount);
+ h->nscount = ntohs(h->nscount);
+ h->arcount = ntohs(h->arcount);
+
+ return (0);
+}
+
+static int
+unpack_query(struct unpack *p, struct dns_query *q)
+{
+ unpack_dname(p, q->q_dname, sizeof(q->q_dname));
+ unpack_u16(p, &q->q_type);
+ unpack_u16(p, &q->q_class);
+
+ return (p->err) ? (-1) : (0);
+}
+
+static int
+unpack_rr(struct unpack *p, struct dns_rr *rr)
+{
+ uint16_t rdlen;
+ size_t save_offset;
+
+ unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
+ unpack_u16(p, &rr->rr_type);
+ unpack_u16(p, &rr->rr_class);
+ unpack_u32(p, &rr->rr_ttl);
+ unpack_u16(p, &rdlen);
+
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < rdlen) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ save_offset = p->offset;
+
+ switch (rr->rr_type) {
+
+ case T_CNAME:
+ unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
+ break;
+
+ case T_MX:
+ unpack_u16(p, &rr->rr.mx.preference);
+ unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
+ break;
+
+ case T_NS:
+ unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
+ break;
+
+ case T_PTR:
+ unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
+ break;
+
+ case T_SOA:
+ unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
+ unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
+ unpack_u32(p, &rr->rr.soa.serial);
+ unpack_u32(p, &rr->rr.soa.refresh);
+ unpack_u32(p, &rr->rr.soa.retry);
+ unpack_u32(p, &rr->rr.soa.expire);
+ unpack_u32(p, &rr->rr.soa.minimum);
+ break;
+
+ case T_A:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_inaddr(p, &rr->rr.in_a.addr);
+ break;
+
+ case T_AAAA:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
+ break;
+ default:
+ other:
+ rr->rr.other.rdata = p->buf + p->offset;
+ rr->rr.other.rdlen = rdlen;
+ p->offset += rdlen;
+ }
+
+ if (p->err)
+ return (-1);
+
+ /* make sure that the advertised rdlen is really ok */
+ if (p->offset - save_offset != rdlen)
+ p->err = "bad dlen";
+
+ return (p->err) ? (-1) : (0);
+}
diff --git a/smtpd/filters/asr_event.c b/smtpd/filters/asr_event.c
index a59fcaea..a6eaf867 100644
--- a/smtpd/filters/asr_event.c
+++ b/smtpd/filters/asr_event.c
@@ -25,8 +25,8 @@
void async_event_dispatch(int, short, void *);
struct async_event *
-async_run_event(struct async * async,
- void (*cb)(int, struct async_res *, void *), void *arg)
+async_run_event(struct asr_query * async,
+ void (*cb)(struct asr_result *, void *), void *arg)
{
struct async_event *aev;
struct timeval tv;
@@ -46,23 +46,19 @@ void
async_event_dispatch(int fd, short ev, void *arg)
{
struct async_event *aev = arg;
- struct async_res ar;
- int r;
+ struct asr_result ar;
struct timeval tv;
- while ((r = asr_async_run(aev->async, &ar)) == ASYNC_YIELD)
- aev->callback(r, &ar, aev->arg);
-
event_del(&aev->ev);
- if (r == ASYNC_COND) {
+ if (asr_run(aev->async, &ar) == 0) {
event_set(&aev->ev, ar.ar_fd,
- ar.ar_cond == ASYNC_READ ? EV_READ : EV_WRITE,
- async_event_dispatch, aev);
+ ar.ar_cond == ASR_WANT_READ ? EV_READ : EV_WRITE,
+ async_event_dispatch, aev);
tv.tv_sec = ar.ar_timeout / 1000;
tv.tv_usec = (ar.ar_timeout % 1000) * 1000;
event_add(&aev->ev, &tv);
- } else { /* ASYNC_DONE */
- aev->callback(r, &ar, aev->arg);
+ } else { /* done */
+ aev->callback(&ar, aev->arg);
free(aev);
}
}
diff --git a/smtpd/filters/asr_event.h b/smtpd/filters/asr_event.h
index 17b199ed..823b276e 100644
--- a/smtpd/filters/asr_event.h
+++ b/smtpd/filters/asr_event.h
@@ -20,15 +20,15 @@
#include <event.h>
-struct async;
-struct async_res;
+struct asr_query;
+struct asr_result;
struct async_event {
- struct async *async;
+ struct asr_query *async;
struct event ev;
- void (*callback)(int, struct async_res *, void *);
+ void (*callback)(struct asr_result *, void *);
void *arg;
};
-struct async_event * async_run_event(struct async *,
- void (*)(int, struct async_res *, void *), void *);
+struct async_event * async_run_event(struct asr_query *,
+ void (*)(struct asr_result *, void *), void *);
diff --git a/smtpd/filters/filter_dnsbl.c b/smtpd/filters/filter_dnsbl.c
index 1d8a2316..a998e6e6 100644
--- a/smtpd/filters/filter_dnsbl.c
+++ b/smtpd/filters/filter_dnsbl.c
@@ -32,7 +32,7 @@
const char * dnsbl_host = "dnsbl.sorbs.net";
static void
-dnsbl_event_dispatch(int ret, struct async_res *ar, void *arg)
+dnsbl_event_dispatch(struct asr_result *ar, void *arg)
{
uint64_t *q = arg;
@@ -52,7 +52,7 @@ dnsbl_on_connect(uint64_t id, struct filter_connect *conn)
struct addrinfo hints;
struct sockaddr_in *sain;
in_addr_t in_addr;
- struct async *as;
+ struct asr_query *as;
uint64_t *q;
char buf[512];