summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2012-07-09 12:16:25 +0000
committerEric Faurot <eric@cvs.openbsd.org>2012-07-09 12:16:25 +0000
commite1500ec08c8cc5149f862d71a1a672e0b0dbf54f (patch)
tree3250073bd46268fbc672b76eefe65283478c59a3
parent926cbb49e90c480760e541cfbe54a79fe32e7297 (diff)
move to the new resolver implementation, with temporary glue to use
the relevant files from asr directly. ok gilles@
-rw-r--r--usr.sbin/smtpd/asr.c2535
-rw-r--r--usr.sbin/smtpd/asr.h92
-rw-r--r--usr.sbin/smtpd/dname.c175
-rw-r--r--usr.sbin/smtpd/dns.c115
-rw-r--r--usr.sbin/smtpd/pack.c464
-rw-r--r--usr.sbin/smtpd/print.c396
-rw-r--r--usr.sbin/smtpd/res_random.c270
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile15
-rw-r--r--usr.sbin/smtpd/sockaddr.c240
-rw-r--r--usr.sbin/smtpd/thread_private.h2
10 files changed, 59 insertions, 4245 deletions
diff --git a/usr.sbin/smtpd/asr.c b/usr.sbin/smtpd/asr.c
deleted file mode 100644
index 48ee21b9efb..00000000000
--- a/usr.sbin/smtpd/asr.c
+++ /dev/null
@@ -1,2535 +0,0 @@
-/* $OpenBSD: asr.c,v 1.11 2011/12/15 19:51:23 eric Exp $ */
-/*
- * Copyright (c) 2010,2011 Eric Faurot <eric@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "asr.h"
-#include "dnsutil.h"
-
-#define unused __attribute__ ((unused))
-
-#define DEFAULT_CONFFILE "/etc/resolv.conf"
-#define DEFAULT_HOSTFILE "/etc/hosts"
-#define DEFAULT_CONF "lookup bind file\nnameserver 127.0.0.1\n"
-#define DEFAULT_LOOKUP "lookup bind file"
-
-#define ASR_MAXNS 5
-#define ASR_MAXDB 3
-#define ASR_MAXDOM 10
-
-enum asr_query_type {
- ASR_QUERY_DNS,
- ASR_QUERY_HOST,
- ASR_QUERY_ADDRINFO,
- ASR_QUERY_CNAME,
-};
-
-enum asr_db_type {
- ASR_DB_FILE,
- ASR_DB_DNS,
- ASR_DB_YP,
-};
-struct asr_db {
- int ad_type;
- char *ad_path;
- int ad_timeout;
- int ad_retries;
- int ad_count;
- struct sockaddr *ad_sa[ASR_MAXNS];
-};
-
-struct asr_ctx {
- int ac_refcount;
- int ac_ndots;
- int ac_forcetcp;
- char *ac_domain;
- int ac_domcount;
- char *ac_dom[ASR_MAXDOM];
- int ac_dbcount;
- struct asr_db ac_db[ASR_MAXDB];
- int ac_family[3];
-};
-
-struct asr {
- char *a_path;
- time_t a_mtime;
- struct asr_ctx *a_ctx;
-};
-
-struct asr_query {
-
- struct asr_ctx *aq_ctx;
- int aq_type;
- int aq_flags;
- int aq_state;
-
- int aq_timeout;
- int aq_fd;
-
- int aq_dom_idx;
- int aq_family_idx;
- int aq_db_idx;
- int aq_ns_idx;
- int aq_ns_cycles;
- /* for dns */
- char *aq_fqdn; /* the fqdn being looked for */
- struct query aq_query;
- uint16_t aq_reqid;
- char *aq_buf;
- size_t aq_buflen;
- size_t aq_bufsize;
- size_t aq_bufoffset; /* for TCP */
- uint16_t aq_datalen; /* for TCP */
- struct packed aq_packed;
- int aq_nanswer;
-
- /* for host */
- char *aq_host;
- int aq_family;
- int aq_count;
- FILE *aq_file;
-
- /* for cname */
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } aq_sa;
-
- /* for addrinfo */
- char *aq_hostname;
- char *aq_servname;
- struct addrinfo aq_hints;
- struct asr_query *aq_subq;
- struct addrinfo *aq_aifirst;
- struct addrinfo *aq_ailast;
-};
-
-#define AQ_FAMILY(p) ((p)->aq_ctx->ac_family[(p)->aq_family_idx])
-#define AQ_DB(p) (&((p)->aq_ctx->ac_db[(p)->aq_db_idx]))
-#define AQ_NS_SA(p) (AQ_DB(p)->ad_sa[(p)->aq_ns_idx])
-#define AQ_BUF_LEFT(p) ((p)->aq_bufsize - (p)->aq_buflen)
-#define AQ_BUF_DATA(p) ((p)->aq_buf + (p)->aq_bufoffset)
-#define AQ_BUF_LEN(p) ((p)->aq_buflen - (p)->aq_bufoffset)
-#define AQ_BUF_WPOS(p) ((p)->aq_buf + (p)->aq_buflen)
-
-enum asr_state {
- ASR_STATE_INIT,
- ASR_STATE_NEXT_DOMAIN,
- ASR_STATE_SEARCH_DOMAIN,
- ASR_STATE_NEXT_DB,
- ASR_STATE_QUERY_DB,
- ASR_STATE_NEXT_FAMILY,
- ASR_STATE_LOOKUP_FAMILY,
- ASR_STATE_NEXT_NS,
- ASR_STATE_QUERY_NS,
- ASR_STATE_READ_RR,
- ASR_STATE_QUERY_FILE,
- ASR_STATE_READ_FILE,
- ASR_STATE_UDP_SEND,
- ASR_STATE_UDP_RECV,
- ASR_STATE_TCP_WRITE,
- ASR_STATE_TCP_READ,
- ASR_STATE_PACKET,
- ASR_STATE_SUBQUERY,
- ASR_STATE_HALT,
-};
-
-/* misc utility functions */
-
-int asr_ndots(const char *);
-int asr_is_fqdn(const char *);
-int asr_cmp_fqdn_name(const char*, char*);
-char *asr_make_fqdn(const char *, const char *);
-int asr_parse_nameserver(struct sockaddr *, const char *);
-
-/* query functions */
-int asr_run_dns(struct asr_query *, struct asr_result *);
-int asr_run_host(struct asr_query *, struct asr_result *);
-int asr_run_addrinfo(struct asr_query *, struct asr_result *);
-int asr_run_cname(struct asr_query *, struct asr_result *);
-
-/* a few helpers */
-const char * asr_error(int);
-
-void asr_check_reload(struct asr *);
-void asr_query_free(struct asr_query *);
-int asr_iter_family(struct asr_query *, int);
-int asr_ensure_buf(struct asr_query *, size_t);
-int asr_setup_packet(struct asr_query *);
-int asr_validate_packet(struct asr_query *);
-int asr_udp_send(struct asr_query *);
-int asr_udp_recv(struct asr_query *);
-int asr_tcp_write(struct asr_query *);
-int asr_tcp_read(struct asr_query *);
-int asr_parse_hosts_cb(char **, int, void*, void*);
-int asr_parse_namedb_line(FILE *, char **, int);
-int asr_get_port(const char *, const char *, int);
-int asr_add_sockaddr(struct asr_query *, struct sockaddr *);
-int asr_add_sockaddr2(struct asr_query *, struct sockaddr *, int, int);
-int asr_db_add_nameserver(struct asr_db *, const char *);
-void asr_db_done(struct asr_db *);
-
-struct asr_ctx *asr_ctx_create(void);
-int asr_ctx_unref(struct asr_ctx *);
-int asr_ctx_add_searchdomain(struct asr_ctx *, const char *);
-int asr_ctx_from_file(struct asr_ctx *, const char *);
-int asr_ctx_from_string(struct asr_ctx *, const char *);
-int asr_ctx_parse_cb(const char *,
- int (*)(char**, int, void*, void*),
- void *, void *);
-struct asr_query *asr_ctx_query(struct asr_ctx *, int);
-struct asr_query *asr_ctx_query_host(struct asr_ctx *, const char *, int);
-
-#ifdef ASR_DEBUG
-
-void asr_dump(struct asr *);
-void asr_dump_query(struct asr_query *);
-
-struct kv { int code; const char *name; };
-
-static const char* kvlookup(struct kv *, int);
-
-int asr_debug = 0;
-
-void
-asr_dump(struct asr *a)
-{
- char buf[256];
- int i, j;
- struct asr_db *ad;
- struct asr_ctx *ac;
-
- ac = a->a_ctx;
-
- printf("--------- ASR CONFIG ---------------\n");
- printf("DOMAIN \"%s\"\n", ac->ac_domain);
- printf("SEARCH\n");
- for(i = 0; i < ac->ac_domcount; i++)
- printf(" \"%s\"\n", ac->ac_dom[i]);
- printf("OPTIONS\n");
- printf(" forcetcp: %i\n", ac->ac_forcetcp);
- printf(" ndots: %i\n", ac->ac_ndots);
- printf(" family: ");
- for(i = 0; ac->ac_family[i] != -1; i++)
- printf(" %s", (ac->ac_family[i] == AF_INET) ? "inet" : "inet6");
- printf("\n");
- printf("DB\n");
- for(ad = ac->ac_db, i = 0; i < ac->ac_dbcount; i++, ad++) {
- switch (ad->ad_type) {
- case ASR_DB_FILE:
- printf(" FILE \"%s\"\n", ad->ad_path);
- break;
- case ASR_DB_DNS:
- printf(" DNS timeout %ims, retries %i\n",
- ad->ad_timeout,
- ad->ad_retries);
- for(j = 0; j < ad->ad_count; j++)
- printf(" NS %s\n",
- print_addr(ad->ad_sa[j], buf,
- sizeof buf));
- break;
- case ASR_DB_YP:
- printf(" YP\n");
- break;
- default:
- printf(" - ???? %i\n", ad->ad_type);
- }
- }
- printf("------------------------------------\n");
-}
-
-static const char *
-kvlookup(struct kv *kv, int code)
-{
- while (kv->name) {
- if (kv->code == code)
- return (kv->name);
- kv++;
- }
- return "???";
-}
-
-struct kv kv_query_type[] = {
- { ASR_QUERY_DNS, "ASR_QUERY_DNS" },
- { ASR_QUERY_HOST, "ASR_QUERY_HOST" },
- { ASR_QUERY_ADDRINFO, "ASR_QUERY_ADDRINFO" },
- { ASR_QUERY_CNAME, "ASR_QUERY_CNAME" },
- { 0, NULL }
-};
-
-struct kv kv_db_type[] = {
- { ASR_DB_FILE, "ASR_DB_FILE" },
- { ASR_DB_DNS, "ASR_DB_DNS" },
- { ASR_DB_YP, "ASR_DB_YP" },
- { 0, NULL }
-};
-
-struct kv kv_state[] = {
- { ASR_STATE_INIT, "ASR_STATE_INIT" },
- { ASR_STATE_NEXT_DOMAIN, "ASR_STATE_NEXT_DOMAIN" },
- { ASR_STATE_SEARCH_DOMAIN, "ASR_STATE_SEARCH_DOMAIN" },
- { ASR_STATE_NEXT_DB, "ASR_STATE_NEXT_DB" },
- { ASR_STATE_QUERY_DB, "ASR_STATE_QUERY_DB" },
- { ASR_STATE_NEXT_FAMILY, "ASR_STATE_NEXT_FAMILY" },
- { ASR_STATE_LOOKUP_FAMILY, "ASR_STATE_LOOKUP_FAMILY" },
- { ASR_STATE_NEXT_NS, "ASR_STATE_NEXT_NS" },
- { ASR_STATE_QUERY_NS, "ASR_STATE_QUERY_NS" },
- { ASR_STATE_READ_RR, "ASR_STATE_READ_RR" },
- { ASR_STATE_QUERY_FILE, "ASR_STATE_QUERY_FILE" },
- { ASR_STATE_READ_FILE, "ASR_STATE_READ_FILE" },
- { ASR_STATE_UDP_SEND, "ASR_STATE_UDP_SEND" },
- { ASR_STATE_UDP_RECV, "ASR_STATE_UDP_RECV" },
- { ASR_STATE_TCP_WRITE, "ASR_STATE_TCP_WRITE" },
- { ASR_STATE_TCP_READ, "ASR_STATE_TCP_READ" },
- { ASR_STATE_PACKET, "ASR_STATE_PACKET" },
- { ASR_STATE_SUBQUERY, "ASR_STATE_SUBQUERY" },
- { ASR_STATE_HALT, "ASR_STATE_HALT" },
- { 0, NULL }
-};
-
-struct kv kv_transition[] = {
- { ASR_COND, "ASR_COND" },
- { ASR_YIELD, "ASR_YIELD" },
- { ASR_DONE, "ASR_DONE" },
- { 0, NULL }
-};
-
-void
-asr_dump_query(struct asr_query *aq)
-{
- char buf[64];
-
- printf("state=%s flags=%i fd=%i timeout=%i\n"
- " dom_idx=%i family_idx=%i db_idx=%i ns_idx=%i ns_cycles=%i\n"
- " fqdn=\"%s\" reqid=%u buf=%p buflen=%zu bufsize=%zu bufoffset=%zu datalen=%u nanswer=%i\n"
- " host=\"%s\" family=%i count=%i file=%p\n"
- " sa=\"%s\"\n"
- " hostname=\"%s\" servname=\"%s\" subq=%p\n",
-
- kvlookup(kv_state, aq->aq_state),
- aq->aq_flags,
- aq->aq_fd,
- aq->aq_timeout,
-
- aq->aq_dom_idx,
- aq->aq_family_idx,
- aq->aq_db_idx,
- aq->aq_ns_idx,
- aq->aq_ns_cycles,
-
- aq->aq_fqdn,
- (unsigned int)aq->aq_reqid,
- aq->aq_buf,
- aq->aq_buflen,
- aq->aq_bufsize,
- aq->aq_bufoffset,
- (unsigned int)aq->aq_datalen,
- aq->aq_nanswer,
-
- aq->aq_host,
- aq->aq_family,
- aq->aq_count,
- aq->aq_file,
-
- print_addr(&aq->aq_sa.sa, buf, sizeof(buf)),
-
- aq->aq_hostname,
- aq->aq_servname,
- aq->aq_subq);
-}
-
-#endif /* ASR_DEBUG */
-
-struct asr *
-asr_resolver(const char *conf)
-{
- int r;
- struct asr *asr;
-
-#ifdef ASR_DEBUG
- if (asr_debug == 0)
- if(getenv("ASR_DEBUG")) {
- printf("asr: %zu\n", sizeof(struct asr));
- printf("asr_ctx: %zu\n", sizeof(struct asr_ctx));
- printf("asr_db: %zu\n", sizeof(struct asr_db));
- printf("asr_query: %zu\n", sizeof(struct asr_query));
- printf("asr_result: %zu\n", sizeof(struct asr_result));
- asr_debug = 1;
- }
-#endif
- if ((asr = calloc(1, sizeof(*asr))) == NULL)
- return (NULL);
-
- if ((asr->a_ctx = asr_ctx_create()) == NULL) {
- free(asr);
- return (NULL);
- }
-
- if (conf == NULL)
- conf = DEFAULT_CONFFILE;
-
- if (conf[0] == '!') {
- r = asr_ctx_from_string(asr->a_ctx, conf + 1);
- } else {
- r = 0;
- asr->a_path = strdup(conf);
- asr_check_reload(asr);
- if (asr->a_ctx == NULL)
- r = asr_ctx_from_string(asr->a_ctx, DEFAULT_CONF);
- }
-
- if (r == -1) {
- asr_ctx_unref(asr->a_ctx);
- free(asr);
- return (NULL);
- }
-
-#ifdef ASR_DEBUG
- if (asr_debug)
- asr_dump(asr);
-#endif
-
- return (asr);
-}
-
-void
-asr_abort(struct asr_query *aq)
-{
- asr_query_free(aq);
-}
-
-int
-asr_run(struct asr_query *aq, struct asr_result *ar)
-{
- int r;
-
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf("-> QUERY %p(%p) %s\n",
- aq, aq->aq_ctx,
- kvlookup(kv_query_type, aq->aq_type));
- }
-#endif
-
- switch(aq->aq_type) {
- case ASR_QUERY_DNS:
- r = asr_run_dns(aq, ar);
- break;
- case ASR_QUERY_HOST:
- r = asr_run_host(aq, ar);
- break;
- case ASR_QUERY_ADDRINFO:
- r = asr_run_addrinfo(aq, ar);
- break;
- case ASR_QUERY_CNAME:
- r = asr_run_cname(aq, ar);
- break;
- default:
- ar->ar_err = EOPNOTSUPP;
- ar->ar_errstr = "unknown query type";
- r = ASR_DONE;
- }
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf("<- ");
- asr_dump_query(aq);
- printf(" = %s\n", kvlookup(kv_transition, r));
- }
-#endif
- if (r == ASR_DONE)
- asr_query_free(aq);
-
- return (r);
-}
-
-int
-asr_run_sync(struct asr_query *aq, struct asr_result *ar)
-{
- struct pollfd fds[1];
- int r;
-
- while((r = asr_run(aq, ar)) == ASR_COND) {
- fds[0].fd = ar->ar_fd;
- fds[0].events = (ar->ar_cond == ASR_READ) ? POLLIN : POLLOUT;
- again:
- r = poll(fds, 1, ar->ar_timeout);
- if (r == -1 && errno == EINTR)
- goto again;
- if (r == -1) /* impossible? */
- err(1, "poll");
- }
-
- return (r);
-}
-
-void
-asr_check_reload(struct asr *asr)
-{
- struct stat st;
- struct asr_ctx *ac;
-
- if (asr->a_path == NULL)
- return;
-
- if (stat(asr->a_path, &st) == -1)
- return;
-
- if (asr->a_mtime == st.st_mtime)
- return;
-
- if ((ac = asr_ctx_create()) == NULL)
- return;
-
- asr->a_mtime = st.st_mtime;
-
- if (asr_ctx_from_file(ac, asr->a_path) == -1) {
- asr_ctx_unref(ac);
- return;
- }
-
- if (asr->a_ctx)
- asr_ctx_unref(asr->a_ctx);
- asr->a_ctx = ac;
-}
-
-struct asr_ctx *
-asr_ctx_create(void)
-{
- struct asr_ctx *ac;
-
- if ((ac = calloc(1, sizeof(*ac))) == NULL)
- return (NULL);
-
- ac->ac_refcount = 1;
- ac->ac_ndots = 1;
- ac->ac_family[0] = AF_INET;
- ac->ac_family[1] = AF_INET6;
- ac->ac_family[2] = -1;
-
- return (ac);
-}
-
-int
-asr_ctx_unref(struct asr_ctx *ac)
-{
- int i;
-
- ac->ac_refcount--;
-
- if (ac->ac_refcount == 0) {
- if (ac->ac_domain)
- free(ac->ac_domain);
-
- for(i = 0; i < ac->ac_dbcount; i++)
- asr_db_done(&ac->ac_db[i]);
-
- for(i = 0; i < ac->ac_domcount; i++)
- free(ac->ac_dom[i]);
-
- free(ac);
- return (0);
- }
-
- return (ac->ac_refcount);
-}
-
-int
-asr_ctx_add_searchdomain(struct asr_ctx *ac, const char *domain)
-{
- if (ac->ac_domcount == ASR_MAXDOM)
- return (-1);
-
- if ((ac->ac_dom[ac->ac_domcount] = asr_make_fqdn(domain, NULL)) == NULL)
- return (0);
-
- ac->ac_domcount += 1;
-
- return (1);
-}
-
-static int
-pass0(char **tok, int n, void *a0, void *a1)
-{
- struct asr_ctx *ac = (struct asr_ctx*)a0;
- struct asr_db *ad;
- int *nscount = (int*)a1;
- int i, j, d;
- const char *e;
-
- /* search for lookup, domain, family, options, and count nameservers */
-
- if (!strcmp(tok[0], "nameserver")) {
- *nscount += 1;
-
- } else if (!strcmp(tok[0], "domain")) {
- if (n != 2)
- return (0);
- if (ac->ac_domain)
- return (0);
- ac->ac_domain = strdup(tok[1]);
- } else if (!strcmp(tok[0], "lookup")) {
- /* ignore the line if we already set lookup */
- if (ac->ac_dbcount != 0)
- return (0);
- if (n - 1 > ASR_MAXDB)
- return (0);
- /* ensure that each lookup is only given once */
- for(i = 1; i < n; i++)
- for(j = i + 1; j < n; j++)
- if (!strcmp(tok[i], tok[j]))
- return (0);
- for(i = 1, ad = ac->ac_db; i < n;
- i++, ac->ac_dbcount++, ad++) {
-
- if (!strcmp(tok[i], "yp")) {
- ad->ad_type = ASR_DB_YP;
-
- } else if (!strcmp(tok[i], "bind")) {
- ad->ad_type = ASR_DB_DNS;
- ad->ad_count = 0;
- ad->ad_timeout = 1000;
- ad->ad_retries = 3;
-
- } else if (!strcmp(tok[i], "file")) {
- ad->ad_type = ASR_DB_FILE;
- ad->ad_path = strdup(DEFAULT_HOSTFILE);
- } else {
- /* ignore the line */
- ac->ac_dbcount = 0;
- return (0);
- }
- }
- } else if (!strcmp(tok[0], "search")) {
- /* resolv.conf says the last line wins */
- for(i = 0; i < ac->ac_domcount; i++)
- free(ac->ac_dom[i]);
- ac->ac_domcount = 0;
- for(i = 1; i < n; i++)
- asr_ctx_add_searchdomain(ac, tok[i]);
- } else if (!strcmp(tok[0], "family")) {
- if (n == 1 || n > 3)
- return (0);
- for (i = 1; i < n; i++)
- if (strcmp(tok[i], "inet4") && strcmp(tok[i], "inet6"))
- return (0);
- for (i = 1; i < n; i++)
- ac->ac_family[i - 1] = strcmp(tok[i], "inet4") ? \
- AF_INET6 : AF_INET;
- ac->ac_family[i - 1] = -1;
- } else if (!strcmp(tok[0], "option")) {
- for(i = 1; i < n; i++) {
- if (!strcmp(tok[i], "tcp"))
- ac->ac_forcetcp = 1;
- else if ((!strncmp(tok[i], "ndots:", 6))) {
- e = NULL;
- d = strtonum(tok[i] + 6, 1, 16, &e);
- if (e == NULL)
- ac->ac_ndots = d;
- }
- }
- }
-
- return (0);
-}
-
-static int
-pass1(char **tok, int n, void *a0, unused void *a1)
-{
- struct asr_db *ad = (struct asr_db*) a0;
-
- /* fill the DNS db with the specified nameservers */
-
- if (!strcmp(tok[0], "nameserver")) {
- if (n != 2)
- return (0);
- asr_db_add_nameserver(ad, tok[1]);
- }
- return (0);
-}
-
-int
-asr_ctx_from_string(struct asr_ctx *ac, const char *str)
-{
- char buf[512], *ch;
- struct asr_db *ad;
- int i;
- int nscount = 0;
-
- asr_ctx_parse_cb(str, pass0, ac, &nscount);
-
- if (ac->ac_dbcount == 0) {
- /* no lookup directive */
- asr_ctx_parse_cb(DEFAULT_LOOKUP, pass0, ac, &nscount);
- }
-
- ad = NULL;
- for(i = 0; i < ac->ac_dbcount; i++)
- if (ac->ac_db[i].ad_type == ASR_DB_DNS) {
- ad = &ac->ac_db[i];
- break;
- }
-
- if (nscount && ad)
- asr_ctx_parse_cb(str, pass1, ad, NULL);
-
- if (ac->ac_domain == NULL)
- if (gethostname(buf, sizeof buf) == 0) {
- ch = strchr(buf, '.');
- if (ch)
- ac->ac_domain = strdup(ch + 1);
- else /* assume root. see resolv.conf(5) */
- ac->ac_domain = strdup("");
- }
-
- if (ac->ac_domcount == 0)
- for(ch = ac->ac_domain; ch; ) {
- asr_ctx_add_searchdomain(ac, ch);
- ch = strchr(ch, '.');
- if (ch && asr_ndots(++ch) == 0)
- break;
- }
-
- return (0);
-}
-
-int
-asr_ctx_from_file(struct asr_ctx *ac, const char *path)
-{
- FILE *cf;
- char buf[1024];
- ssize_t r;
-
- cf = fopen(path, "r");
- if (cf == NULL)
- return (-1);
-
- /* XXX make sure we read the whole file */
- r = fread(buf, 1, sizeof buf - 1, cf);
- fclose(cf);
- if (r == -1)
- return (-1);
- buf[r] = '\0';
-
- return asr_ctx_from_string(ac, buf);
-}
-
-int
-asr_ctx_parse_cb(const char *str,
- int (*cb)(char**, int, void*, void*),
- void *arg0,
- void *arg1)
-{
- size_t len;
- const char *line;
- char buf[1024];
- char *tok[10], **tp, *cp;
- int ntok;
-
- line = str;
- while (*line) {
- len = strcspn(line, "\n\0");
- if (len < sizeof buf) {
- memmove(buf, line, len);
- buf[len] = '\0';
- } else
- buf[0] = '\0';
- line += len;
- if (*line == '\n')
- line++;
- buf[strcspn(buf, ";#")] = '\0';
- for(cp = buf, tp = tok, ntok = 0;
- tp < &tok[10] && (*tp = strsep(&cp, " \t")) != NULL;)
- if (**tp != '\0') {
- tp++;
- ntok++;
- }
- *tp = NULL;
-
- if (tok[0] == NULL)
- continue;
-
- if (cb(tok, ntok, arg0, arg1))
- break;
- }
-
- return (0);
-}
-
-struct asr_query *
-asr_ctx_query(struct asr_ctx *ac, int type)
-{
- struct asr_query *aq;
-
- if ((aq = calloc(1, sizeof(*aq))) == NULL)
- return (NULL);
-
- ac->ac_refcount += 1;
-
- aq->aq_ctx = ac;
- aq->aq_fd = -1;
- aq->aq_type = type;
- aq->aq_state = ASR_STATE_INIT;
-
- return (aq);
-}
-
-void
-asr_done(struct asr *asr)
-{
- asr_ctx_unref(asr->a_ctx);
- if (asr->a_path)
- free(asr->a_path);
- free(asr);
-}
-
-int
-asr_parse_hosts_cb(char **tok, int n, void *a0, void *a1)
-{
- struct asr_query *aq = (struct asr_query*) a0;
- struct asr_result *ar = (struct asr_result*) a1;
- int i;
-
- for (i = 1; i < n; i++) {
- if (strcmp(tok[i], aq->aq_host))
- continue;
- if (sockaddr_from_str(&ar->ar_sa.sa, aq->aq_family, tok[0]) == -1)
- continue;
- ar->ar_cname = strdup(tok[1]);
- return (1);
- }
-
- return (0);
-}
-
-/*
- * utility functions
- */
-
-int
-asr_parse_nameserver(struct sockaddr *sa, const char *s)
-{
- const char *estr;
- char buf[256];
- char *port = NULL;
- in_port_t portno = 53;
-
- if (*s == '[') {
- strlcpy(buf, s + 1, sizeof buf);
- s = buf;
- port = strchr(buf, ']');
- if (port == NULL)
- return (-1);
- *port++ = '\0';
- if (*port != ':')
- return (-1);
- port++;
- }
-
- if (port) {
- portno = strtonum(port, 1, USHRT_MAX, &estr);
- if (estr)
- return (-1);
- }
-
- if (sockaddr_from_str(sa, PF_UNSPEC, s) == -1)
- return (-1);
-
- sockaddr_set_port(sa, portno);
-
- return (0);
-}
-
-int
-asr_db_add_nameserver(struct asr_db *ad, const char *nameserver)
-{
- struct sockaddr_storage ss;
-
- if (ad->ad_type != ASR_DB_DNS)
- return (-1);
-
- if (ad->ad_count == ASR_MAXNS)
- return (-1);
-
- if (asr_parse_nameserver((struct sockaddr*)&ss, nameserver))
- return (-1);
-
- if ((ad->ad_sa[ad->ad_count] = calloc(1, ss.ss_len)) == NULL)
- return (0);
-
- memmove(ad->ad_sa[ad->ad_count], &ss, ss.ss_len);
- ad->ad_count += 1;
-
- return (1);
-}
-
-void
-asr_db_done(struct asr_db *ad)
-{
- int i;
-
- switch(ad->ad_type) {
- case ASR_DB_DNS:
- for(i = 0; i < ad->ad_count; i++)
- free(ad->ad_sa[i]);
- break;
-
- case ASR_DB_YP:
- break;
-
- case ASR_DB_FILE:
- free(ad->ad_path);
- break;
- default:
- errx(1, "asr_db_done: unknown db type");
- }
-}
-
-int
-asr_parse_namedb_line(FILE *file, char **tokens, int ntoken)
-{
- size_t len;
- char *buf, *cp, **tp;
- int ntok;
-
- again:
- if ((buf = fgetln(file, &len)) == NULL)
- return (-1);
-
- if (buf[len - 1] == '\n')
- len--;
-
- buf[len] = '\0';
- buf[strcspn(buf, "#")] = '\0';
- for(cp = buf, tp = tokens, ntok = 0;
- ntok < ntoken && (*tp = strsep(&cp, " \t")) != NULL;)
- if (**tp != '\0') {
- tp++;
- ntok++;
- }
- *tp = NULL;
- if (tokens[0] == NULL)
- goto again;
-
- return (ntok);
-}
-
-const char *
-asr_error(int v)
-{
- switch(v) {
- case ASR_OK:
- return "no error";
- case EASR_MEMORY:
- return "out of memory";
- case EASR_TIMEDOUT:
- return "all nameservers timed out";
- case EASR_NAMESERVER:
- return "no nameserver specified";
- case EASR_FAMILY:
- return "invalid address family";
- case EASR_NOTFOUND:
- return "not found";
- case EASR_NAME:
- return "invalid domain name";
- default:
- return "unknown error code";
- }
-}
-
-int
-asr_cmp_fqdn_name(const char *fqdn, char *name)
-{
- int i;
-
- /* compare a fqdn with a name that may not end with a dot */
-
- for (i = 0; fqdn[i] && name[i]; i++)
- if (fqdn[i] != name[i])
- return (-1);
-
- if (fqdn[i] == name[i])
- return (0);
-
- if (fqdn[i] == 0 || fqdn[i] != '.' || fqdn[i+1] != 0)
- return (-1);
-
- return (0);
-}
-
-int
-asr_ndots(const char *s)
-{
- int n;
-
- for(n = 0; *s; s++)
- if (*s == '.')
- n += 1;
-
- return (n);
-}
-
-int
-asr_is_fqdn(const char *name)
-{
- size_t len;
-
- len = strlen(name);
- return (len > 0 && name[len -1] == '.');
-}
-
-char *
-asr_make_fqdn(const char *name, const char *domain)
-{
- char *fqdn;
- size_t len;
-
- if (domain == NULL)
- domain = ".";
-#ifdef ASR_DEBUG
- else
- if (!asr_is_fqdn(domain))
- errx(1, "domain is not FQDN: %s", domain);
-#endif
-
- len = strlen(name);
- if (len == 0) {
- fqdn = strdup(domain);
- } else if (name[len - 1] != '.') {
- if (domain[0] == '.')
- domain += 1;
- len += strlen(domain) + 2;
- fqdn = malloc(len);
- if (fqdn == NULL)
- return (NULL);
- strlcpy(fqdn, name, len);
- strlcat(fqdn, ".", len);
- strlcat(fqdn, domain, len);
- } else {
- fqdn = strdup(name);
- }
-
- return (fqdn);
-}
-
-void
-asr_query_free(struct asr_query *aq)
-{
- if (aq->aq_aifirst)
- freeaddrinfo(aq->aq_aifirst);
- if (aq->aq_subq)
- asr_abort(aq->aq_subq);
- if (aq->aq_host)
- free(aq->aq_host);
- if (aq->aq_fqdn)
- free(aq->aq_fqdn);
- if (aq->aq_buf)
- free(aq->aq_buf);
- if (aq->aq_hostname)
- free(aq->aq_hostname);
- if (aq->aq_servname)
- free(aq->aq_servname);
- if (aq->aq_fd != -1)
- close(aq->aq_fd);
- asr_ctx_unref(aq->aq_ctx);
- free(aq);
-}
-
-/*
- * for asr_query_dns
- */
-
-struct asr_query *
-asr_query_dns(struct asr *asr,
- uint16_t type,
- uint16_t class,
- const char *name,
- int flags)
-{
- struct asr_query *aq;
-
- asr_check_reload(asr);
-
- if ((aq = asr_ctx_query(asr->a_ctx, ASR_QUERY_DNS)) == NULL)
- return (NULL);
-
- aq->aq_flags = flags;
- aq->aq_query.q_type = type;
- aq->aq_query.q_class = class;
- aq->aq_fqdn = asr_make_fqdn(name, NULL);
- if (aq->aq_fqdn == NULL)
- goto abort;
-
- return (aq);
- abort:
- asr_query_free(aq);
- return (NULL);
-}
-
-int
-asr_setup_packet(struct asr_query *aq)
-{
- struct packed p;
- struct header h;
-
- if (dname_from_fqdn(aq->aq_fqdn,
- aq->aq_query.q_dname,
- sizeof(aq->aq_query.q_dname)) == -1) {
- return (-1);
- }
-
- aq->aq_reqid = res_randomid();
-
- memset(&h, 0, sizeof h);
- h.id = aq->aq_reqid;
- if (!(aq->aq_flags & ASR_NOREC))
- h.flags |= RD_MASK;
- h.qdcount = 1;
-
- if (aq->aq_buf == NULL) {
- aq->aq_bufsize = PACKET_MAXLEN;
- if ((aq->aq_buf = malloc(aq->aq_bufsize)) == NULL)
- return (-2);
- }
- aq->aq_bufoffset = 0;
-
- packed_init(&p, aq->aq_buf, aq->aq_bufsize);
- pack_header(&p, &h);
- pack_query(&p, aq->aq_query.q_type, aq->aq_query.q_class,
- aq->aq_query.q_dname);
- aq->aq_buflen = p.offset;
-
- return (0);
-}
-
-int
-asr_ensure_buf(struct asr_query *aq, size_t n)
-{
- char *t;
-
- if (aq->aq_buf == NULL) {
- aq->aq_buf = malloc(n);
- if (aq->aq_buf == NULL)
- return (-1);
- aq->aq_bufsize = n;
- return (0);
- }
-
- if (aq->aq_bufsize >= n)
- return (0);
-
- t = realloc(aq->aq_buf, n);
- if (t == NULL)
- return (-1);
- aq->aq_buf = t;
- aq->aq_bufsize = n;
-
- return (0);
-}
-
-int
-asr_validate_packet(struct asr_query *aq)
-{
- struct packed p;
- struct header h;
- struct query q;
- struct rr rr;
- int r;
-
- packed_init(&p, aq->aq_buf, aq->aq_buflen);
-
- unpack_header(&p, &h);
- if (p.err)
- return (-1);
- if (h.id != aq->aq_reqid)
- return (-1);
- if (h.qdcount != 1)
- return (-1);
- if ((h.flags & Z_MASK) != 0)
- return (-1); /* should be zero, we could allow this */
- if (h.flags & TC_MASK)
- return (-2);
- if (OPCODE(h.flags) != OP_QUERY)
- return (-1); /* actually, it depends on the request */
- if ((h.flags & QR_MASK) == 0)
- return (-1); /* not a response */
-
- unpack_query(&p, &q);
- if (p.err)
- return (-1);
- if (q.q_type != aq->aq_query.q_type ||
- q.q_class != aq->aq_query.q_class ||
- strcasecmp(q.q_dname, aq->aq_query.q_dname))
- return (-1);
-
- /* validate the rest of the packet */
- for(r = h.ancount + h.nscount + h.arcount; r; r--)
- unpack_rr(&p, &rr);
-
- if (p.err || (p.offset != aq->aq_buflen))
- return (-1);
-
- return (0);
-}
-
-int
-asr_udp_send(struct asr_query *aq)
-{
- ssize_t n;
- int errno_save;
-
- aq->aq_fd = sockaddr_connect(AQ_NS_SA(aq), SOCK_DGRAM);
- if (aq->aq_fd == -1)
- return (-1);
-
- aq->aq_timeout = AQ_DB(aq)->ad_timeout;
-
- n = send(aq->aq_fd, aq->aq_buf, aq->aq_buflen, 0);
- if (n == -1) {
- errno_save = errno;
- close(aq->aq_fd);
- aq->aq_fd = -1;
- if (errno_save == EAGAIN)
- return (-2); /* timeout */
- return (-1);
- }
-
- return (0);
-}
-
-int
-asr_udp_recv(struct asr_query *aq)
-{
- ssize_t n;
- int errno_save;
-
- n = recv(aq->aq_fd, aq->aq_buf, aq->aq_bufsize, 0);
- errno_save = errno;
- close(aq->aq_fd);
- aq->aq_fd = -1;
- if (n == -1) {
- if (errno_save == EAGAIN)
- return (-2); /* timeout */
- return (-1);
- }
-
- aq->aq_buflen = n;
-
- switch (asr_validate_packet(aq)) {
- case -2:
- return (1); /* truncated */
- case -1:
- return (-1);
- default:
- break;
- }
-
- return (0);
-}
-
-int
-asr_tcp_write(struct asr_query *aq)
-{
- struct iovec iov[2];
- uint16_t len;
- ssize_t n;
- int i, ret, se;
- socklen_t sl;
-
- if (aq->aq_fd == -1) { /* connect */
- aq->aq_fd = sockaddr_connect(AQ_NS_SA(aq), SOCK_STREAM);
- if (aq->aq_fd == -1)
- return (-1);
- aq->aq_timeout = AQ_DB(aq)->ad_timeout;
- return (1);
- }
-
- ret = -1;
- i = 0;
- if (aq->aq_datalen == 0) {
- /* check connection first */
- sl = sizeof(se);
- if (getsockopt(aq->aq_fd, SOL_SOCKET, SO_ERROR, &se, &sl) == -1) {
- warn("getsockopt");
- goto close;
- }
- if (se)
- goto close;
-
- /* need to send datalen first */
- len = htons(aq->aq_buflen);
- iov[i].iov_base = &len;
- iov[i].iov_len = sizeof(len);
- i++;
- }
-
- iov[i].iov_base = AQ_BUF_DATA(aq);
- iov[i].iov_len = AQ_BUF_LEN(aq);
- i++;
-
- n = writev(aq->aq_fd, iov, i);
- if (n == -1) {
- if (errno == EAGAIN)
- ret = -2;
- else
- warn("writev");
- goto close;
- }
-
- if (aq->aq_datalen == 0 && n < 2) {
- /* we want to write the data len */
- warnx("short write");
- goto close;
- }
-
- if (aq->aq_datalen == 0) {
- aq->aq_datalen = len;
- n -= 2;
- }
-
- aq->aq_bufoffset += n;
- if (aq->aq_bufoffset == aq->aq_buflen) {
- aq->aq_datalen = 0;
- return (0); /* all sent */
- }
-
- aq->aq_timeout = AQ_DB(aq)->ad_timeout;
- return (1);
-
-close:
- close(aq->aq_fd);
- aq->aq_fd = -1;
- return (ret);
-}
-
-int
-asr_tcp_read(struct asr_query *aq)
-{
- uint16_t len;
- ssize_t n;
- int ret;
-
- ret = -1;
-
- if (aq->aq_datalen == 0) {
- n = read(aq->aq_fd, &len, sizeof(len));
- if (n == -1) {
- if (errno == EAGAIN) /* timeout */
- ret = -2;
- else
- warn("read");
- goto close;
- }
- if (n < 2) {
- warnx("short read");
- goto close;
- }
- aq->aq_datalen = ntohs(len);
- aq->aq_bufoffset = 0;
- aq->aq_buflen = 0;
-
- if (asr_ensure_buf(aq, aq->aq_datalen) == -1) {
- ret = -3;
- goto close;
- }
-
- return (1); /* need more data */
- }
-
- n = read(aq->aq_fd, AQ_BUF_WPOS(aq), AQ_BUF_LEFT(aq));
- if (n == -1) {
- if (errno == EAGAIN) /* timeout */
- ret = -2;
- else
- warn("read");
- goto close;
- }
- if (n == 0) {
- warnx("closed");
- goto close;
- }
- aq->aq_buflen += n;
-
- if (aq->aq_buflen != aq->aq_datalen)
- return (1); /* need more data */
-
- if (asr_validate_packet(aq) != 0)
- goto close;
-
- ret = 0;
-
-close:
- close(aq->aq_fd);
- aq->aq_fd = -1;
- return (ret);
-}
-
-int
-asr_run_dns(struct asr_query *aq, struct asr_result *ar)
-{
- for(;;) { /* block not indented on purpose */
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf(" - ");
- asr_dump_query(aq);
- }
-#endif
- switch(aq->aq_state) {
-
- case ASR_STATE_INIT:
- aq->aq_ns_cycles = -1;
- aq->aq_db_idx = 0;
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_NEXT_DB:
- aq->aq_db_idx += 1;
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_QUERY_DB:
- if (aq->aq_db_idx >= aq->aq_ctx->ac_dbcount) {
- if (aq->aq_ns_cycles == -1)
- ar->ar_err = EASR_NAMESERVER;
- else
- ar->ar_err = EASR_TIMEDOUT;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
-
- if (AQ_DB(aq)->ad_type != ASR_DB_DNS) {
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_ns_cycles = 0;
- aq->aq_ns_idx = 0;
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
-
- case ASR_STATE_NEXT_NS:
- aq->aq_ns_idx += 1;
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_ns_idx = 0;
- aq->aq_ns_cycles++;
- }
- if (aq->aq_ns_cycles >= AQ_DB(aq)->ad_retries) {
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
-
- case ASR_STATE_QUERY_NS:
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- }
- switch (asr_setup_packet(aq)) {
- case -2:
- ar->ar_err = EASR_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- case -1:
- ar->ar_err = EASR_NAME;
- aq->aq_state = ASR_STATE_HALT;
- break;
- default:
- break;
- }
- if (aq->aq_ctx->ac_forcetcp)
- aq->aq_state = ASR_STATE_TCP_WRITE;
- else
- aq->aq_state = ASR_STATE_UDP_SEND;
- break;
-
- case ASR_STATE_UDP_SEND:
- if (asr_udp_send(aq) == 0) {
- aq->aq_state = ASR_STATE_UDP_RECV;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
-
- case ASR_STATE_UDP_RECV:
- switch (asr_udp_recv(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0: /* done */
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1: /* truncated */
- aq->aq_state = ASR_STATE_TCP_WRITE;
- break;
- }
- break;
-
- case ASR_STATE_TCP_WRITE:
- switch (asr_tcp_write(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_TCP_READ;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- case 1:
- ar->ar_cond = ASR_WRITE;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_TCP_READ:
- switch (asr_tcp_read(aq)) {
- case -3:
- aq->aq_state = ASR_STATE_HALT;
- ar->ar_err = EASR_MEMORY;
- break;
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1:
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_PACKET:
- memmove(&ar->ar_sa.sa, AQ_NS_SA(aq), AQ_NS_SA(aq)->sa_len);
- ar->ar_datalen = aq->aq_buflen;
- ar->ar_data = aq->aq_buf;
- aq->aq_buf = NULL;
- ar->ar_err = ASR_OK;
- aq->aq_state = ASR_STATE_HALT;
- break;
-
- case ASR_STATE_HALT:
- ar->ar_errstr = asr_error(ar->ar_err);
- if (ar->ar_err)
- ar->ar_data = NULL;
- return (ASR_DONE);
-
- default:
- errx(1, "asr_run_dns: unknown state");
- }}
-}
-
-/*
- * for asr_query_host
- */
-
-struct asr_query *
-asr_query_host(struct asr *asr, const char *host, int family)
-{
- asr_check_reload(asr);
-
- return asr_ctx_query_host(asr->a_ctx, host, family);
-}
-
-struct asr_query *
-asr_ctx_query_host(struct asr_ctx *ac, const char *host, int family)
-{
- struct asr_query *aq;
-
- if ((aq = asr_ctx_query(ac, ASR_QUERY_HOST)) == NULL)
- return (NULL);
-
- aq->aq_family = family;
- aq->aq_host = strdup(host);
- if (aq->aq_host)
- return (aq);
-
- asr_query_free(aq);
- return (NULL);
-}
-
-int
-asr_run_host(struct asr_query *aq, struct asr_result *ar)
-{
- struct header h;
- struct query q;
- struct rr rr;
- char *tok[10];
- int ntok = 10, i, n, family;
-
- for(;;) { /* block not indented on purpose */
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf(" - ");
- asr_dump_query(aq);
- }
-#endif
- switch(aq->aq_state) {
-
- case ASR_STATE_INIT:
- if (aq->aq_family != AF_INET &&
- aq->aq_family != AF_INET6 &&
- aq->aq_family != AF_UNSPEC) {
- ar->ar_err = EASR_FAMILY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- aq->aq_count = 0;
- aq->aq_dom_idx = 0;
- /* check if we need to try it as an absolute name first */
- if (asr_ndots(aq->aq_host) >= aq->aq_ctx->ac_ndots)
- aq->aq_dom_idx = -1;
- aq->aq_state = ASR_STATE_SEARCH_DOMAIN;
- break;
-
- case ASR_STATE_NEXT_DOMAIN:
- /* no domain search for fully qualified names */
- if (asr_is_fqdn(aq->aq_host)) {
- ar->ar_err = EASR_NOTFOUND;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- aq->aq_dom_idx += 1;
- aq->aq_state = ASR_STATE_SEARCH_DOMAIN;
- break;
-
- case ASR_STATE_SEARCH_DOMAIN:
- if (aq->aq_dom_idx >= aq->aq_ctx->ac_domcount) {
- ar->ar_err = EASR_NOTFOUND;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- if (aq->aq_fqdn)
- free(aq->aq_fqdn);
-
- if (aq->aq_dom_idx == -1) /* try as absolute first */
- aq->aq_fqdn = asr_make_fqdn(aq->aq_host, NULL);
- else
- aq->aq_fqdn = asr_make_fqdn(aq->aq_host,
- aq->aq_ctx->ac_dom[aq->aq_dom_idx]);
-
- if (aq->aq_fqdn == NULL) {
- ar->ar_err = EASR_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- aq->aq_db_idx = 0;
- aq->aq_family_idx = 0;
- aq->aq_state = ASR_STATE_LOOKUP_FAMILY;
- break;
-
- case ASR_STATE_NEXT_FAMILY:
- aq->aq_family_idx += 1;
- if ((aq->aq_family != AF_UNSPEC) || (AQ_FAMILY(aq) == -1)) {
- /* The family was specified, or we have
- * tried all families with this DB
- */
- if (aq->aq_count) {
- ar->ar_count = aq->aq_count;
- ar->ar_err = ASR_OK;
- aq->aq_state = ASR_STATE_HALT;
- } else
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_state = ASR_STATE_LOOKUP_FAMILY;
- break;
-
- case ASR_STATE_LOOKUP_FAMILY:
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_NEXT_DB:
- aq->aq_db_idx += 1;
- aq->aq_family_idx = 0;
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_QUERY_DB:
- if (aq->aq_db_idx >= aq->aq_ctx->ac_dbcount) {
- aq->aq_state = ASR_STATE_NEXT_DOMAIN;
- break;
- }
-
- switch(AQ_DB(aq)->ad_type) {
- case ASR_DB_DNS:
- family = aq->aq_family;
- if (family == AF_UNSPEC)
- family = AQ_FAMILY(aq);
- if (family == AF_INET)
- aq->aq_query.q_type = T_A;
- else if (family == AF_INET6)
- aq->aq_query.q_type = T_AAAA;
- else
- errx(1, "bad family: %i", family);
- aq->aq_query.q_class = C_IN;
- aq->aq_flags = 0;
- aq->aq_ns_cycles = 0;
- aq->aq_ns_idx = 0;
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
- case ASR_DB_FILE:
- aq->aq_state = ASR_STATE_QUERY_FILE;
- break;
- default:
- aq->aq_state = ASR_STATE_NEXT_DB;
- }
- break;
-
- case ASR_STATE_NEXT_NS:
- aq->aq_ns_idx += 1;
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_ns_idx = 0;
- aq->aq_ns_cycles++;
- }
- if (aq->aq_ns_cycles >= AQ_DB(aq)->ad_retries) {
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
-
- case ASR_STATE_QUERY_NS:
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- }
- switch (asr_setup_packet(aq)) {
- case -2:
- ar->ar_err = EASR_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- case -1:
- ar->ar_err = EASR_NAME;
- aq->aq_state = ASR_STATE_HALT;
- break;
- default:
- break;
- }
- if (aq->aq_ctx->ac_forcetcp)
- aq->aq_state = ASR_STATE_TCP_WRITE;
- else
- aq->aq_state = ASR_STATE_UDP_SEND;
- break;
-
- case ASR_STATE_UDP_SEND:
- if (asr_udp_send(aq) == 0) {
- aq->aq_state = ASR_STATE_UDP_RECV;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
-
- case ASR_STATE_UDP_RECV:
- switch (asr_udp_recv(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0: /* done */
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1: /* truncated */
- aq->aq_state = ASR_STATE_TCP_WRITE;
- break;
- }
- break;
-
- case ASR_STATE_TCP_WRITE:
- switch (asr_tcp_write(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_TCP_READ;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- case 1:
- ar->ar_cond = ASR_WRITE;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_TCP_READ:
- switch (asr_tcp_read(aq)) {
- case -3:
- aq->aq_state = ASR_STATE_HALT;
- ar->ar_err = EASR_MEMORY;
- break;
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1:
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_PACKET:
- packed_init(&aq->aq_packed, aq->aq_buf, aq->aq_buflen);
- unpack_header(&aq->aq_packed, &h);
- aq->aq_nanswer = h.ancount;
- for(; h.qdcount; h.qdcount--)
- unpack_query(&aq->aq_packed, &q);
- aq->aq_state = ASR_STATE_READ_RR;
- break;
-
- case ASR_STATE_READ_RR:
- if (aq->aq_nanswer == 0) {
- free(aq->aq_buf);
- aq->aq_buf = NULL;
- /* done with this NS, try with next family */
- aq->aq_state = ASR_STATE_NEXT_FAMILY;
- break;
- }
- aq->aq_nanswer -= 1;
- unpack_rr(&aq->aq_packed, &rr);
- if (rr.rr_type == aq->aq_query.q_type &&
- rr.rr_class == aq->aq_query.q_class) {
- aq->aq_count += 1;
- ar->ar_count = aq->aq_count;
- sockaddr_from_rr(&ar->ar_sa.sa, &rr);
- ar->ar_cname = NULL; /* XXX */
- return (ASR_YIELD);
- }
- break;
-
- case ASR_STATE_QUERY_FILE:
- aq->aq_file = fopen(AQ_DB(aq)->ad_path, "r");
- if (aq->aq_file == NULL)
- aq->aq_state = ASR_STATE_NEXT_DB;
- else
- aq->aq_state = ASR_STATE_READ_FILE;
- break;
-
- case ASR_STATE_READ_FILE:
- n = asr_parse_namedb_line(aq->aq_file, tok, ntok);
- if (n == -1) {
- fclose(aq->aq_file);
- aq->aq_file = NULL;
- /* XXX as an optimization, the file could be parsed only once */
- aq->aq_state = ASR_STATE_NEXT_FAMILY;
- break;
- }
-
- for (i = 1; i < n; i++) {
- /* for the first round, try the host as-is */
- /* XXX not nice */
- if (aq->aq_dom_idx <= 0 && !strcmp(aq->aq_host, tok[i])) {
- } else if (asr_cmp_fqdn_name(aq->aq_fqdn, tok[i]) == -1)
- continue;
- family = aq->aq_family;
- if (family == AF_UNSPEC)
- family = AQ_FAMILY(aq);
- if (sockaddr_from_str(&ar->ar_sa.sa, family, tok[0]) == -1)
- continue;
-
- aq->aq_count += 1;
- ar->ar_count = aq->aq_count;
- ar->ar_cname = strdup(tok[1]);
- return (ASR_YIELD);
- }
- break;
-
- case ASR_STATE_HALT:
- ar->ar_count = aq->aq_count;
- ar->ar_errstr = asr_error(ar->ar_err);
- return (ASR_DONE);
-
- default:
- errx(1, "asr_run_host: unknown state");
- }}
-}
-
-
-
-/*
- * for asr_query_addrinfo
- */
-
-struct asr_query *
-asr_query_addrinfo(struct asr *asr,
- const char *hostname,
- const char *servname,
- const struct addrinfo *hints)
-{
- struct asr_query *aq;
-
- asr_check_reload(asr);
-
- if ((aq = asr_ctx_query(asr->a_ctx, ASR_QUERY_ADDRINFO)) == NULL)
- return (NULL);
-
- if (hostname && (aq->aq_hostname = strdup(hostname)) == NULL)
- goto abort;
- if (servname && (aq->aq_servname = strdup(servname)) == NULL)
- goto abort;
- if (hints)
- memmove(&aq->aq_hints, hints, sizeof *hints);
- else {
- memset(&aq->aq_hints, 0, sizeof aq->aq_hints);
- aq->aq_hints.ai_family = PF_UNSPEC;
- }
-
- return (aq);
- abort:
- asr_query_free(aq);
- return (NULL);
-}
-
-int
-asr_get_port(const char *servname, const char *proto, int numonly)
-{
- struct servent se;
- struct servent_data sed;
- int port, r;
- const char* e;
-
- if (servname == NULL)
- return (0);
-
- e = NULL;
- port = strtonum(servname, 0, USHRT_MAX, &e);
- if (e == NULL)
- return (port);
- if (errno == ERANGE)
- return (-3); /* invalid */
- if (numonly)
- return (-3);
-
- memset(&sed, 0, sizeof(sed));
- r = getservbyname_r(servname, proto, &se, &sed);
- port = ntohs(se.s_port);
- endservent_r(&sed);
-
- if (r == -1)
- return (-2); /* not found */
-
- return (port);
-}
-
-int
-asr_add_sockaddr2(struct asr_query *aq,
- struct sockaddr *sa,
- int socktype,
- int protocol)
-{
- struct addrinfo *ai;
- const char *proto;
- int port;
-
- switch (protocol) {
- case IPPROTO_TCP:
- proto = "tcp";
- break;
- case IPPROTO_UDP:
- proto = "udp";
- break;
- default:
- proto = NULL;
- }
-
- port = -1;
- if (proto) {
- port = asr_get_port(aq->aq_servname, proto,
- aq->aq_hints.ai_flags & AI_NUMERICSERV);
- if (port < 0)
- return (port);
- }
-
- ai = calloc(1, sizeof *ai + sa->sa_len);
- if (ai == NULL)
- return (-1); /* no mem */
- ai->ai_family = sa->sa_family;
- ai->ai_socktype = socktype;
- ai->ai_protocol = protocol;
- ai->ai_addrlen = sa->sa_len;
- ai->ai_addr = (void*)(ai + 1);
- memmove(ai->ai_addr, sa, sa->sa_len);
-
- if (port != -1)
- sockaddr_set_port((struct sockaddr*)ai->ai_addr, port);
-
- if (aq->aq_aifirst == NULL)
- aq->aq_aifirst = ai;
- if (aq->aq_ailast)
- aq->aq_ailast->ai_next = ai;
- aq->aq_ailast = ai;
-
- aq->aq_count += 1;
-
- return (0);
-}
-
-struct match {
- int family;
- int socktype;
- int protocol;
-};
-
-static const struct match matches[] = {
- { PF_INET, SOCK_DGRAM, IPPROTO_UDP },
- { PF_INET, SOCK_STREAM, IPPROTO_TCP },
- { PF_INET, SOCK_RAW, 0 },
- { PF_INET6, SOCK_DGRAM, IPPROTO_UDP },
- { PF_INET6, SOCK_STREAM, IPPROTO_TCP },
- { PF_INET6, SOCK_RAW, 0 },
- { -1, 0, 0, },
-};
-
-#define MATCH_FAMILY(a, b) ((a) == matches[(b)].family || (a) == PF_UNSPEC)
-#define MATCH_PROTO(a, b) ((a) == matches[(b)].protocol || (a) == 0)
-/* do not match SOCK_RAW unless explicitely specified */
-#define MATCH_SOCKTYPE(a, b) ((a) == matches[(b)].socktype || ((a) == 0 && \
- matches[(b)].socktype != SOCK_RAW))
-
-int
-asr_add_sockaddr(struct asr_query *aq, struct sockaddr *sa)
-{
- int i, e;
-
- for(i = 0; matches[i].family != -1; i++) {
- if (matches[i].family != sa->sa_family ||
- !MATCH_SOCKTYPE(aq->aq_hints.ai_socktype, i) ||
- !MATCH_PROTO(aq->aq_hints.ai_protocol, i))
- continue;
- e = asr_add_sockaddr2(aq, sa, matches[i].socktype, matches[i].protocol);
- switch(e) {
- case -3:
- return (EAI_NONAME);
- case -2:
- /* Only report bad service if the protocol was specified */
- if (aq->aq_hints.ai_protocol == 0)
- break;
- return (EAI_SERVICE);
- case -1:
- return (EAI_MEMORY);
- }
- }
-
- return (0);
-}
-
-int
-asr_iter_family(struct asr_query *aq, int first)
-{
- if (first) {
- aq->aq_family_idx = 0;
- if (aq->aq_hints.ai_family != PF_UNSPEC)
- return aq->aq_hints.ai_family;
- return AQ_FAMILY(aq);
- }
-
- if (aq->aq_hints.ai_family != PF_UNSPEC)
- return (-1);
-
- aq->aq_family_idx++;
-
- return AQ_FAMILY(aq);
-}
-
-int
-asr_run_addrinfo(struct asr_query *aq, struct asr_result *ar)
-{
- const char *str;
- struct addrinfo *ai;
- int i, family, r;
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } sa;
-
- for(;;) { /* block not indented on purpose */
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf(" - ");
- asr_dump_query(aq);
- }
-#endif
- switch(aq->aq_state) {
-
- case ASR_STATE_INIT:
- aq->aq_count = 0;
- aq->aq_state = ASR_STATE_HALT;
- ar->ar_err = 0;
-
- if (aq->aq_hostname == NULL &&
- aq->aq_servname == NULL) {
- ar->ar_err = EAI_BADHINTS;
- break;
- }
-
- ai = &aq->aq_hints;
-
- if (ai->ai_addrlen ||
- ai->ai_canonname ||
- ai->ai_addr ||
- ai->ai_next) {
- ar->ar_err = EAI_BADHINTS;
- break;
- }
-
- if (ai->ai_flags & ~AI_MASK) {
- ar->ar_err = EAI_BADHINTS;
- break;
- }
-
- if (ai->ai_family != PF_UNSPEC &&
- ai->ai_family != PF_INET &&
- ai->ai_family != PF_INET6) {
- ar->ar_err = EAI_FAMILY;
- break;
- }
-
- if (ai->ai_socktype &&
- ai->ai_socktype != SOCK_DGRAM &&
- ai->ai_socktype != SOCK_STREAM &&
- ai->ai_socktype != SOCK_RAW) {
- ar->ar_err = EAI_SOCKTYPE;
- break;
- }
-
- if (ai->ai_protocol &&
- ai->ai_protocol != IPPROTO_UDP &&
- ai->ai_protocol != IPPROTO_TCP) {
- ar->ar_err = EAI_PROTOCOL;
- break;
- }
-
- if (ai->ai_socktype == SOCK_RAW &&
- aq->aq_servname != NULL) {
- ar->ar_err = EAI_SERVICE;
- break;
- }
-
- /* make sure there is at least a valid combination */
- for (i = 0; matches[i].family != -1; i++)
- if (MATCH_FAMILY(ai->ai_family, i) &&
- MATCH_SOCKTYPE(ai->ai_socktype, i) &&
- MATCH_PROTO(ai->ai_protocol, i))
- break;
- if (matches[i].family == -1) {
- ar->ar_err = EAI_BADHINTS;
- break;
- }
-
- if (aq->aq_hostname == NULL) {
- for(family = asr_iter_family(aq, 1);
- family != -1;
- family = asr_iter_family(aq, 0)) {
- if (family == PF_INET)
- str = (ai->ai_flags & AI_PASSIVE) ? \
- "0.0.0.0" : "127.0.0.1";
- else /* PF_INET6 */
- str = (ai->ai_flags & AI_PASSIVE) ? \
- "::" : "::1";
- /* can't fail */
- sockaddr_from_str(&sa.sa, family, str);
- if ((r = asr_add_sockaddr(aq, &sa.sa))) {
- ar->ar_err = r;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- }
- if (ar->ar_err == 0 && aq->aq_count == 0)
- ar->ar_err = EAI_NODATA;
- break;
- }
-
- /* try numeric addresses */
- for(family = asr_iter_family(aq, 1);
- family != -1;
- family = asr_iter_family(aq, 0)) {
-
- if (sockaddr_from_str(&sa.sa, family,
- aq->aq_hostname) == -1)
- continue;
-
- if ((r = asr_add_sockaddr(aq, &sa.sa))) {
- ar->ar_err = r;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
-
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- if (ar->ar_err || aq->aq_count)
- break;
-
- if (ai->ai_flags & AI_NUMERICHOST) {
- ar->ar_err = EAI_FAIL;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
-
- /* subquery for hostname */
- if ((aq->aq_subq = asr_ctx_query_host(aq->aq_ctx,
- aq->aq_hostname,
- ai->ai_family)) == NULL) {
- ar->ar_err = EAI_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- }
-
- aq->aq_state = ASR_STATE_SUBQUERY;
- break;
-
- case ASR_STATE_SUBQUERY:
- switch ((r = asr_run(aq->aq_subq, ar))) {
- case ASR_COND:
- return (r);
- case ASR_YIELD:
- if ((r = asr_add_sockaddr(aq, &ar->ar_sa.sa))) {
- ar->ar_err = r;
- aq->aq_state = ASR_STATE_HALT;
- }
- free(ar->ar_cname);
- break;
- case ASR_DONE:
- aq->aq_subq = NULL;
- if (ar->ar_count == 0)
- ar->ar_err = EAI_NODATA;
- else if (aq->aq_count == 0)
- ar->ar_err = EAI_NONAME;
- else
- ar->ar_err = 0;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- break;
-
- case ASR_STATE_HALT:
- if (ar->ar_err == 0) {
- ar->ar_errstr = NULL;
- ar->ar_count = aq->aq_count;
- ar->ar_ai = aq->aq_aifirst;
- aq->aq_aifirst = NULL;
- } else {
- ar->ar_ai = NULL;
- ar->ar_errstr = gai_strerror(ar->ar_err);
- }
- return (ASR_DONE);
-
- default:
- errx(1, "asr_run_addrinfo: unknown state");
- }}
-}
-
-
-struct asr_query *
-asr_query_cname(struct asr *asr,
- const struct sockaddr *sa,
- socklen_t sl)
-{
- struct asr_query *aq;
-
- asr_check_reload(asr);
-
- if ((aq = asr_ctx_query(asr->a_ctx, ASR_QUERY_CNAME)) == NULL)
- return (NULL);
-
- memmove(&aq->aq_sa.sa, sa, sl);
- aq->aq_sa.sa.sa_len = sl;
-
- return (aq);
-}
-
-int
-asr_run_cname(struct asr_query *aq, struct asr_result *ar)
-{
- struct header h;
- struct query q;
- struct rr rr;
- char *tok[10], buf[DOMAIN_MAXLEN];
- int ntok = 10, n;
-
- for(;;) { /* block not indented on purpose */
-#ifdef ASR_DEBUG
- if (asr_debug) {
- printf(" - ");
- asr_dump_query(aq);
- }
-#endif
- switch(aq->aq_state) {
-
- case ASR_STATE_INIT:
- if (aq->aq_sa.sa.sa_family != AF_INET &&
- aq->aq_sa.sa.sa_family != AF_INET6) {
- ar->ar_err = EASR_FAMILY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- aq->aq_db_idx = 0;
- aq->aq_count = 0;
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_NEXT_DB:
- /* stop here if we already have at least one answer */
- if (aq->aq_count) {
- ar->ar_err = 0;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
-
- aq->aq_db_idx += 1;
- aq->aq_state = ASR_STATE_QUERY_DB;
- break;
-
- case ASR_STATE_QUERY_DB:
- if (aq->aq_db_idx >= aq->aq_ctx->ac_dbcount) {
- ar->ar_err = EASR_NOTFOUND;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
-
- switch(AQ_DB(aq)->ad_type) {
- case ASR_DB_DNS:
- if (aq->aq_fqdn == NULL) {
- sockaddr_as_fqdn(&aq->aq_sa.sa, buf, sizeof(buf));
- if ((aq->aq_fqdn = strdup(buf)) == NULL) {
- ar->ar_err = EASR_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- }
- }
- aq->aq_query.q_type = T_PTR;
- aq->aq_query.q_class = C_IN;
- aq->aq_flags = 0;
- aq->aq_ns_cycles = 0;
- aq->aq_ns_idx = 0;
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
- case ASR_DB_FILE:
- aq->aq_state = ASR_STATE_QUERY_FILE;
- break;
- default:
- aq->aq_state = ASR_STATE_NEXT_DB;
- }
- break;
-
- case ASR_STATE_NEXT_NS:
- aq->aq_ns_idx += 1;
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_ns_idx = 0;
- aq->aq_ns_cycles++;
- }
- if (aq->aq_ns_cycles >= AQ_DB(aq)->ad_retries) {
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_state = ASR_STATE_QUERY_NS;
- break;
-
- case ASR_STATE_QUERY_NS:
- if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) {
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- }
- switch (asr_setup_packet(aq)) {
- case -2:
- ar->ar_err = EASR_MEMORY;
- aq->aq_state = ASR_STATE_HALT;
- break;
- case -1:
- ar->ar_err = EASR_NAME; /* XXX impossible */
- aq->aq_state = ASR_STATE_HALT;
- break;
- default:
- break;
- }
- if (aq->aq_ctx->ac_forcetcp)
- aq->aq_state = ASR_STATE_TCP_WRITE;
- else
- aq->aq_state = ASR_STATE_UDP_SEND;
- break;
-
- case ASR_STATE_UDP_SEND:
- if (asr_udp_send(aq) == 0) {
- aq->aq_state = ASR_STATE_UDP_RECV;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
-
- case ASR_STATE_UDP_RECV:
- switch (asr_udp_recv(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0: /* done */
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1: /* truncated */
- aq->aq_state = ASR_STATE_TCP_WRITE;
- break;
- }
- break;
-
- case ASR_STATE_TCP_WRITE:
- switch (asr_tcp_write(aq)) {
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_TCP_READ;
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- case 1:
- ar->ar_cond = ASR_WRITE;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_TCP_READ:
- switch (asr_tcp_read(aq)) {
- case -3:
- aq->aq_state = ASR_STATE_HALT;
- ar->ar_err = EASR_MEMORY;
- break;
- case -2: /* timeout */
- case -1: /* fail */
- aq->aq_state = ASR_STATE_NEXT_NS;
- break;
- case 0:
- aq->aq_state = ASR_STATE_PACKET;
- break;
- case 1:
- ar->ar_cond = ASR_READ;
- ar->ar_fd = aq->aq_fd;
- ar->ar_timeout = aq->aq_timeout;
- return (ASR_COND);
- }
- break;
-
- case ASR_STATE_PACKET:
- packed_init(&aq->aq_packed, aq->aq_buf, aq->aq_buflen);
- unpack_header(&aq->aq_packed, &h);
- aq->aq_nanswer = h.ancount;
- for(; h.qdcount; h.qdcount--)
- unpack_query(&aq->aq_packed, &q);
- aq->aq_state = ASR_STATE_READ_RR;
- break;
-
- case ASR_STATE_READ_RR:
- if (aq->aq_nanswer == 0) {
- free(aq->aq_buf);
- aq->aq_buf = NULL;
- /* done with this NS, try with next family */
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- aq->aq_nanswer -= 1;
- unpack_rr(&aq->aq_packed, &rr);
- if (rr.rr_type == aq->aq_query.q_type &&
- rr.rr_class == aq->aq_query.q_class) {
- aq->aq_count += 1;
- ar->ar_count = aq->aq_count;
- print_dname(rr.rr.ptr.ptrname, buf, sizeof(buf));
- ar->ar_cname = strdup(buf);
- ar->ar_cname[strlen(buf) - 1] = 0;
- return (ASR_YIELD);
- }
- break;
-
- case ASR_STATE_QUERY_FILE:
- aq->aq_file = fopen(AQ_DB(aq)->ad_path, "r");
- if (aq->aq_file == NULL)
- aq->aq_state = ASR_STATE_NEXT_DB;
- else
- aq->aq_state = ASR_STATE_READ_FILE;
- break;
-
- case ASR_STATE_READ_FILE:
- n = asr_parse_namedb_line(aq->aq_file, tok, ntok);
- if (n == -1) {
- fclose(aq->aq_file);
- aq->aq_file = NULL;
- /* XXX as an optimization, the file could be parsed only once */
- aq->aq_state = ASR_STATE_NEXT_DB;
- break;
- }
- if (sockaddr_from_str(&ar->ar_sa.sa, aq->aq_sa.sa.sa_family, tok[0]) == -1)
- break;
- if (ar->ar_sa.sa.sa_len != aq->aq_sa.sa.sa_len ||
- memcmp(&ar->ar_sa.sa, &aq->aq_sa.sa, aq->aq_sa.sa.sa_len))
- break;
-
- aq->aq_count += 1;
- ar->ar_count = aq->aq_count;
- ar->ar_cname = strdup(tok[1]);
- return (ASR_YIELD);
-
- case ASR_STATE_HALT:
- ar->ar_count = aq->aq_count;
- ar->ar_errstr = asr_error(ar->ar_err);
- return (ASR_DONE);
-
- default:
- errx(1, "asr_run_cname: unknown state %i", aq->aq_state);
- }}
-}
diff --git a/usr.sbin/smtpd/asr.h b/usr.sbin/smtpd/asr.h
deleted file mode 100644
index 348c4910ec7..00000000000
--- a/usr.sbin/smtpd/asr.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* $OpenBSD: asr.h,v 1.5 2011/07/13 14:52:21 eric Exp $ */
-/*
- * Copyright (c) 2010,2011 Eric Faurot <eric@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netdb.h>
-#include <netinet/in.h>
-
-enum {
- ASR_COND,
- ASR_YIELD,
- ASR_DONE
-};
-
-#define ASR_READ 1
-#define ASR_WRITE 2
-
-#define ASR_NOREC 0x01
-
-enum {
- ASR_OK = 0,
- EASR_MEMORY,
- EASR_TIMEDOUT,
- EASR_NAMESERVER,
- EASR_FAMILY,
- EASR_NOTFOUND,
- EASR_NAME,
- EASR_PARAM
-};
-
-struct asr_result {
- int ar_err;
- const char *ar_errstr;
-
- int ar_cond;
- int ar_fd;
- int ar_timeout;
-
- int ar_count;
- struct addrinfo *ar_ai;
- char *ar_cname;
- void *ar_data;
- size_t ar_datalen;
- union {
- struct sockaddr sa;
- struct sockaddr_in sain;
- struct sockaddr_in6 sain6;
- } ar_sa;
-};
-
-struct asr_query;
-
-struct asr *asr_resolver(const char*);
-void asr_done(struct asr*);
-
-int asr_run(struct asr_query*, struct asr_result*);
-int asr_run_sync(struct asr_query*, struct asr_result*);
-void asr_abort(struct asr_query*);
-
-struct asr_query *asr_query_dns(struct asr*,
- uint16_t,
- uint16_t,
- const char*,
- int);
-
-struct asr_query *asr_query_host(struct asr*,
- const char*,
- int);
-
-struct asr_query *asr_query_addrinfo(struct asr*,
- const char*,
- const char*,
- const struct addrinfo*);
-
-struct asr_query *asr_query_cname(struct asr*,
- const struct sockaddr*,
- socklen_t);
diff --git a/usr.sbin/smtpd/dname.c b/usr.sbin/smtpd/dname.c
deleted file mode 100644
index 2e12cfbabf2..00000000000
--- a/usr.sbin/smtpd/dname.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/* $OpenBSD: dname.c,v 1.4 2011/04/02 15:59:17 eric Exp $ */
-/*
- * Copyright (c) 2009,2010 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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "dnsutil.h"
-
-size_t
-dname_len(const char *dname)
-{
- size_t l;
-
- l = 0;
-
- while(dname[l])
- l += dname[l] + 1;
-
- return l;
-}
-
-size_t
-dname_depth(const char *dname)
-{
- size_t l;
-
- l = 0;
-
- while(*dname) {
- l += 1;
- dname += *dname + 1;
- }
-
- return l;
-}
-
-const char*
-dname_up(const char *dname, unsigned int n)
-{
- while(n--) {
- if (dname[0] == '\0')
- return (NULL);
- dname += *dname + 1;
- }
- return (dname);
-}
-
-
-int
-dname_is_in(const char *dname, const char *domain)
-{
- size_t l, ld;
-
- l = dname_depth(dname);
- ld = dname_depth(domain);
-
- if (ld > l)
- return (0);
-
- dname = dname_up(dname, l - ld);
-
- if (strcasecmp(dname, domain) == 0)
- return (1);
-
- return (0);
-}
-
-int
-dname_is_reverse(const char *dname)
-{
- static int init = 0;
- static char arpa[15];
-
- if (init == 0) {
- init = 1;
- dname_from_fqdn("in-addr.arpa.", arpa, sizeof arpa);
- }
-
- return (dname_is_in(dname, arpa));
-}
-
-int
-dname_is_wildcard(const char *dname)
-{
- return (dname[0] == 1 && dname[1] == '*');
-}
-
-int
-dname_check_label(const char *s, size_t l)
-{
- if (l == 0 || l > 63)
- return (-1);
-
- for(l--; l; l--, s++)
- if (!(isalnum(*s) || *s == '_' || *s == '-'))
- return (-1);
-
- return (0);
-}
-
-ssize_t
-dname_from_fqdn(const char *str, char *dst, size_t max)
-{
- ssize_t res;
- size_t l, n;
- char *d;
-
- res = 0;
-
- /* special case: the root domain */
- if (str[0] == '.') {
- if (str[1] != '\0')
- return (-1);
- if (dst && max >= 1)
- *dst = '\0';
- return (1);
- }
-
- for(; *str; str = d + 1) {
-
- d = strchr(str, '.');
- if (d == NULL || d == str)
- return (-1);
-
- l = (d - str);
-
- if (dname_check_label(str, l) == -1)
- return (-1);
-
- res += l + 1;
-
- if (dst) {
- *dst++ = l;
- max -= 1;
- n = (l > max) ? max : l;
- memmove(dst, str, n);
- max -= n;
- if (max == 0)
- dst = NULL;
- else
- dst += n;
- }
- }
-
- if (dst)
- *dst++ = '\0';
-
- return (res + 1);
-}
-
-ssize_t
-dname_from_sockaddr(const struct sockaddr *sa, char *dst, size_t max)
-{
- char buf[80];
-
- if (sockaddr_as_fqdn(sa, buf, sizeof(buf)) == -1)
- return (-1);
-
- return dname_from_fqdn(buf, dst, max);
-}
diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c
index 85e530f0822..f2abc42272d 100644
--- a/usr.sbin/smtpd/dns.c
+++ b/usr.sbin/smtpd/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.48 2012/04/14 13:31:46 eric Exp $ */
+/* $OpenBSD: dns.c,v 1.49 2012/07/09 12:16:24 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -26,6 +26,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <arpa/nameser.h>
#include <event.h>
#include <imsg.h>
@@ -34,8 +35,7 @@
#include <string.h>
#include "asr.h"
-#include "dnsdefs.h"
-#include "dnsutil.h"
+#include "asr_private.h"
#include "smtpd.h"
#include "log.h"
@@ -50,7 +50,7 @@ struct dnssession {
u_int64_t id;
struct dns query;
struct event ev;
- struct asr_query *aq;
+ struct async *as;
struct mx mxarray[MAX_MX_COUNT];
size_t mxarraysz;
size_t mxcurrent;
@@ -67,7 +67,7 @@ SPLAY_PROTOTYPE(dnstree, dnssession, nodes, dnssession_cmp);
static struct dnssession *dnssession_init(struct dns *);
static void dnssession_destroy(struct dnssession *);
static void dnssession_mx_insert(struct dnssession *, const char *, int);
-static void dns_asr_event_set(struct dnssession *, struct asr_result *);
+static void dns_asr_event_set(struct dnssession *, struct async_res *);
static void dns_asr_handler(int, short, void *);
static int dns_asr_error(int);
static void dns_asr_dispatch_host(struct dnssession *);
@@ -75,7 +75,7 @@ static void dns_asr_dispatch_mx(struct dnssession *);
static void dns_asr_dispatch_cname(struct dnssession *);
static void dns_reply(struct dns *, int);
-struct asr *asr = NULL;
+#define print_dname(a,b,c) asr_strdname(a, b, c)
/*
* User interface.
@@ -128,11 +128,6 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
{
struct dnssession *s;
- if (asr == NULL && (asr = asr_resolver(NULL)) == NULL) {
- log_warnx("dns_async: cannot create resolver");
- goto noasr;
- }
-
query->type = type;
query->asker = asker;
s = dnssession_init(query);
@@ -151,13 +146,15 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
}
dnssession_mx_insert(s, query->host, 0);
stat_increment(STATS_LKA_SESSION_HOST);
+ log_debug("dns: ready?");
dns_asr_dispatch_host(s);
return;
case IMSG_DNS_PTR:
- s->aq = asr_query_cname(asr, (struct sockaddr*)&query->ss,
- query->ss.ss_len);
+ s->as = getnameinfo_async((struct sockaddr*)&query->ss,
+ query->ss.ss_len,
+ s->query.host, sizeof(s->query.host), NULL, 0, 0, NULL);
stat_increment(STATS_LKA_SESSION_CNAME);
- if (s->aq == NULL) {
+ if (s->as == NULL) {
log_debug("dns_async: asr_query_cname error");
break;
}
@@ -165,9 +162,9 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
return;
case IMSG_DNS_MX:
log_debug("dns: lookup mx \"%s\"", query->host);
- s->aq = asr_query_dns(asr, T_MX, C_IN, query->host, 0);
+ s->as = res_query_async(query->host, C_IN, T_MX, NULL, 0, NULL);
stat_increment(STATS_LKA_SESSION_MX);
- if (s->aq == NULL) {
+ if (s->as == NULL) {
log_debug("dns_async: asr_query_dns error");
break;
}
@@ -180,9 +177,6 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
stat_increment(STATS_LKA_FAILURE);
dnssession_destroy(s);
-noasr:
- query->error = DNS_RETRY;
- dns_reply(query, type != IMSG_DNS_PTR ? IMSG_DNS_HOST_END : type);
}
static void
@@ -192,13 +186,13 @@ dns_reply(struct dns *query, int type)
}
static void
-dns_asr_event_set(struct dnssession *s, struct asr_result *ar)
+dns_asr_event_set(struct dnssession *s, struct async_res *ar)
{
struct timeval tv = { 0, 0 };
tv.tv_usec = ar->ar_timeout * 1000;
event_set(&s->ev, ar->ar_fd,
- ar->ar_cond == ASR_READ ? EV_READ : EV_WRITE, dns_asr_handler, s);
+ ar->ar_cond == ASYNC_READ ? EV_READ : EV_WRITE, dns_asr_handler, s);
event_add(&s->ev, &tv);
}
@@ -226,10 +220,10 @@ static int
dns_asr_error(int ar_err)
{
switch (ar_err) {
- case ASR_OK:
+ case 0:
return DNS_OK;
- case EASR_FAMILY:
- case EASR_NAME:
+ case NO_DATA:
+ case NO_RECOVERY:
stat_increment(STATS_LKA_FAILURE);
return DNS_EINVAL;
default:
@@ -241,22 +235,24 @@ static void
dns_asr_dispatch_mx(struct dnssession *s)
{
struct dns *query = &s->query;
- struct asr_result ar;
+ struct async_res ar;
struct packed pack;
struct header h;
struct query q;
struct rr rr;
char buf[512];
- if (asr_run(s->aq, &ar) == ASR_COND) {
+ if (async_run(s->as, &ar) == ASYNC_COND) {
dns_asr_event_set(s, &ar);
return;
}
- if (ar.ar_err) {
- query->error = dns_asr_error(ar.ar_err);
+ if (ar.ar_errno || ar.ar_h_errno || ar.ar_rcode == NXDOMAIN) {
+ query->error = ar.ar_rcode == NXDOMAIN ? \
+ DNS_ENONAME : dns_asr_error(ar.ar_h_errno);
dns_reply(query, IMSG_DNS_HOST_END);
dnssession_destroy(s);
+ free(ar.ar_data);
return;
}
@@ -264,15 +260,6 @@ dns_asr_dispatch_mx(struct dnssession *s)
unpack_header(&pack, &h);
unpack_query(&pack, &q);
- /* check if the domain name exists */
- /* XXX what about other DNS error codes? */
- if (RCODE(h.flags) == ERR_NAME) {
- query->error = DNS_ENONAME;
- dns_reply(query, IMSG_DNS_HOST_END);
- dnssession_destroy(s);
- return;
- }
-
if (h.ancount == 0)
/* fallback to host if no MX is found. */
dnssession_mx_insert(s, query->host, 0);
@@ -285,12 +272,11 @@ dns_asr_dispatch_mx(struct dnssession *s)
}
free(ar.ar_data);
- ar.ar_data = NULL;
/* Now we have a sorted list of MX to resolve. Simply "turn" this
* MX session into a regular host session.
*/
- s->aq = NULL;
+ s->as = NULL;
s->query.type = IMSG_DNS_HOST;
dns_asr_dispatch_host(s);
}
@@ -300,8 +286,8 @@ dns_asr_dispatch_host(struct dnssession *s)
{
struct dns *query = &s->query;
struct mx *mx;
- struct asr_result ar;
- int ret;
+ struct async_res ar;
+ struct addrinfo hints, *ai;
/* default to notfound, override with retry or ok later */
if (s->mxcurrent == 0)
@@ -309,7 +295,7 @@ dns_asr_dispatch_host(struct dnssession *s)
next:
/* query all listed hosts in turn */
- while (s->aq == NULL) {
+ while (s->as == NULL) {
if (s->mxcurrent == s->mxarraysz) {
if (s->mxfound)
query->error = DNS_OK;
@@ -317,26 +303,29 @@ next:
dnssession_destroy(s);
return;
}
- mx = s->mxarray + s->mxcurrent++;
- s->aq = asr_query_host(asr, mx->host, AF_UNSPEC);
- }
- while ((ret = asr_run(s->aq, &ar)) == ASR_YIELD) {
- free(ar.ar_cname);
- memcpy(&query->ss, &ar.ar_sa.sa, ar.ar_sa.sa.sa_len);
- dns_reply(query, IMSG_DNS_HOST);
- s->mxfound++;
+ mx = s->mxarray + s->mxcurrent++;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ s->as = getaddrinfo_async(mx->host, NULL, &hints, NULL);
}
- if (ret == ASR_COND) {
+ if (async_run(s->as, &ar) == ASYNC_COND) {
dns_asr_event_set(s, &ar);
return;
}
- if (dns_asr_error(ar.ar_err) == DNS_RETRY)
- query->error = DNS_RETRY;
+ if (ar.ar_gai_errno == 0) {
+ for (ai = ar.ar_addrinfo; ai; ai = ai->ai_next) {
+ memcpy(&query->ss, ai->ai_addr, ai->ai_addrlen);
+ dns_reply(query, IMSG_DNS_HOST);
+ s->mxfound++;
+ }
+ freeaddrinfo(ar.ar_addrinfo);
+ }
- s->aq = NULL;
+ s->as = NULL;
goto next;
}
@@ -344,23 +333,15 @@ static void
dns_asr_dispatch_cname(struct dnssession *s)
{
struct dns *query = &s->query;
- struct asr_result ar;
+ struct async_res ar;
- switch (asr_run(s->aq, &ar)) {
- case ASR_COND:
+ if (async_run(s->as, &ar) == ASYNC_COND) {
dns_asr_event_set(s, &ar);
return;
- case ASR_YIELD:
- /* Only return the first answer */
- query->error = DNS_OK;
- strlcpy(query->host, ar.ar_cname, sizeof (query->host));
- asr_abort(s->aq);
- free(ar.ar_cname);
- break;
- case ASR_DONE:
- query->error = dns_asr_error(ar.ar_err);
- break;
}
+
+ /* the error code could be more precise, but we don't currently care */
+ query->error = ar.ar_gai_errno ? DNS_ENOTFOUND : DNS_OK;
dns_reply(query, IMSG_DNS_PTR);
dnssession_destroy(s);
}
diff --git a/usr.sbin/smtpd/pack.c b/usr.sbin/smtpd/pack.c
deleted file mode 100644
index 04612d1a530..00000000000
--- a/usr.sbin/smtpd/pack.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* $OpenBSD: pack.c,v 1.3 2011/07/13 15:08:24 eric Exp $ */
-/*
- * Copyright (c) 2009,2010 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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <string.h>
-
-#include "dnsutil.h"
-
-int dname_check_label(const char*, size_t);
-const char* dname_nthlabel(int, const unsigned char*, size_t, size_t);
-ssize_t dname_count_labels(const unsigned char*, size_t, size_t);
-ssize_t dname_expand(const unsigned char*, size_t, size_t,
- size_t*, char *, size_t);
-
-
-void
-packed_init(struct packed *pack, char *data, size_t len)
-{
- pack->data = data;
- pack->len = len;
- pack->offset = 0;
- pack->err = NULL;
-}
-
-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 = ptr;
- continue;
- }
- if (offset + n + 1 > len)
- return (-1);
-
- if (dname_check_label(data + offset + 1, n) == -1)
- 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);
-}
-
-const char *
-dname_nthlabel(int n, const unsigned char *data, size_t len, size_t offset)
-{
- int i;
- size_t c, ptr, start;
-
- start = offset;
- for(i = 0;;) {
- c = data[offset];
- if (c == 0)
- return (NULL);
- if ((c & 0xc0) == 0xc0) {
- if (len < offset + 2)
- return (NULL);
- ptr = 256 * (c & ~0xc0) + data[offset + 1];
- if (ptr >= start)
- return (NULL);
- offset = ptr;
- continue;
- }
- if (i == n)
- break;
- offset += c + 1;
- i++;
- }
- return (data + offset);
-}
-
-ssize_t
-dname_count_labels(const unsigned char *data, size_t len, size_t offset)
-{
- size_t c, n, ptr, start;
-
- start = offset;
- for(n = 0; (c = data[offset]); ) {
- if ((c & 0xc0) == 0xc0) {
- if (len < offset + 2)
- return (-1);
- ptr = 256 * (c & ~0xc0) + data[offset + 1];
- if (ptr >= start)
- return (-1);
- offset = ptr;
- continue;
- }
- offset += c + 1;
- n += 1;
- }
-
- return (n);
-}
-
-int
-unpack_data(struct packed *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->data + p->offset, len);
- p->offset += len;
-
- return (0);
-}
-
-int
-unpack_u16(struct packed *p, uint16_t *u16)
-{
- if (unpack_data(p, u16, 2) == -1)
- return (-1);
-
- *u16 = ntohs(*u16);
-
- return (0);
-}
-
-int
-unpack_u32(struct packed *p, uint32_t *u32)
-{
- if (unpack_data(p, u32, 4) == -1)
- return (-1);
-
- *u32 = ntohl(*u32);
-
- return (0);
-}
-
-int
-unpack_inaddr(struct packed *p, struct in_addr *a)
-{
- return (unpack_data(p, a, 4));
-}
-
-int
-unpack_in6addr(struct packed *p, struct in6_addr *a6)
-{
- return (unpack_data(p, a6, 16));
-}
-
-int
-unpack_dname(struct packed *p, char *dst, size_t max)
-{
- ssize_t e;
-
- if (p->err)
- return (-1);
-
- e = dname_expand(p->data, p->len, p->offset, &p->offset, dst, max);
- if (e == -1) {
- p->err = "bad domain name";
- return (-1);
- }
- if (e < 0 || e > DOMAIN_MAXLEN) {
- p->err = "domain name too long";
- return (-1);
- }
-
- return (0);
-}
-
-int
-unpack_header(struct packed *p, struct header *h)
-{
- if (unpack_data(p, h, HEADER_LEN) == -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);
-}
-
-int
-unpack_query(struct packed *p, struct 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);
-}
-
-int
-unpack_rr(struct packed *p, struct 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->data + 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);
-}
-
-int
-pack_data(struct packed *p, const void *data, size_t len)
-{
- if (p->err)
- return (-1);
-
- if (p->len < p->offset + len) {
- p->err = "no space";
- return (-1);
- }
-
- memmove(p->data + p->offset, data, len);
- p->offset += len;
-
- return (0);
-}
-
-int
-pack_u16(struct packed *p, uint16_t v)
-{
- v = htons(v);
-
- return (pack_data(p, &v, 2));
-}
-
-int
-pack_u32(struct packed *p, uint32_t v)
-{
- v = htonl(v);
-
- return (pack_data(p, &v, 4));
-}
-
-int
-pack_inaddr(struct packed *p, struct in_addr a)
-{
- return (pack_data(p, &a, 4));
-}
-
-int
-pack_in6addr(struct packed *p, struct in6_addr a6)
-{
- return (pack_data(p, &a6, 16));
-}
-
-int
-pack_dname(struct packed *p, const char *dname)
-{
- /* dname compression would be nice to have here.
- * need additionnal context.
- */
- return (pack_data(p, dname, strlen(dname) + 1));
-}
-
-int
-pack_header(struct packed *p, const struct header *h)
-{
- struct header c;
-
- c.id = h->id;
- c.flags = htons(h->flags);
- c.qdcount = htons(h->qdcount);
- c.ancount = htons(h->ancount);
- c.nscount = htons(h->nscount);
- c.arcount = htons(h->arcount);
-
- return (pack_data(p, &c, HEADER_LEN));
-}
-
-int
-pack_query(struct packed *p, uint16_t type, uint16_t class, const char *dname)
-{
- pack_dname(p, dname);
- pack_u16(p, type);
- pack_u16(p, class);
-
- return (p->err) ? (-1) : (0);
-}
-
-int
-pack_rrdynamic(struct packed *p, const struct rr_dynamic *rd)
-{
- const union rr_subtype *rr;
- struct packed save;
-
- pack_dname(p, rd->rd_dname);
- pack_u16(p, rd->rd_type);
- pack_u16(p, rd->rd_class);
- pack_u32(p, rd->rd_ttl);
-
- save = *p;
- pack_u16(p, 0); /* rdlen */
-
- rr = &rd->rd;
- switch(rd->rd_type) {
- case T_CNAME:
- pack_dname(p, rr->cname.cname);
- break;
-
- case T_MX:
- pack_u16(p, rr->mx.preference);
- pack_dname(p, rr->mx.exchange);
- break;
-
- case T_NS:
- pack_dname(p, rr->ns.nsname);
- break;
-
- case T_PTR:
- pack_dname(p, rr->ptr.ptrname);
- break;
-
- case T_SOA:
- pack_dname(p, rr->soa.mname);
- pack_dname(p, rr->soa.rname);
- pack_u32(p, rr->soa.serial);
- pack_u32(p, rr->soa.refresh);
- pack_u32(p, rr->soa.retry);
- pack_u32(p, rr->soa.expire);
- pack_u32(p, rr->soa.minimum);
- break;
-
- case T_A:
- if (rd->rd_class != C_IN)
- goto other;
- pack_inaddr(p, rr->in_a.addr);
- break;
-
- case T_AAAA:
- if (rd->rd_class != C_IN)
- goto other;
- pack_in6addr(p, rr->in_aaaa.addr6);
- break;
- default:
- other:
- pack_data(p, rr->other.rdata, rr->other.rdlen);
- }
-
- if (p->err)
- return (-1);
-
- /* rewrite rdlen */
- pack_u16(&save, p->offset - save.offset - 2);
- p->err = save.err;
-
- return (p->err) ? (-1) : (0);
-}
diff --git a/usr.sbin/smtpd/print.c b/usr.sbin/smtpd/print.c
deleted file mode 100644
index ba85c228fab..00000000000
--- a/usr.sbin/smtpd/print.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/* $OpenBSD: print.c,v 1.4 2011/10/23 10:54:52 chl Exp $ */
-/*
- * Copyright (c) 2009,2010 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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "dnsutil.h"
-
-struct keyval {
- const char *key;
- uint16_t value;
-};
-
-struct keyval kv_class[] = {
- { "IN", C_IN },
- { "CS", C_CS },
- { "CH", C_CH },
- { "HS", C_HS },
-};
-
-struct keyval kv_type[] = {
- { "A", T_A },
- { "NS", T_NS },
- { "MD", T_MD },
- { "MF", T_MF },
- { "CNAME", T_CNAME },
- { "SOA", T_SOA },
- { "MB", T_MB },
- { "MG", T_MG },
- { "MR", T_MR },
- { "NULL", T_NULL },
- { "WKS", T_WKS },
- { "PTR", T_PTR },
- { "HINFO", T_HINFO },
- { "MINFO", T_MINFO },
- { "MX", T_MX },
- { "TXT", T_TXT },
-
- { "AXFR", T_AXFR },
- { "MAILB", T_MAILB },
- { "MAILA", T_MAILA },
- { "ALL", T_ALL },
-
- { "AAAA", T_AAAA },
-};
-
-struct keyval kv_rcode[] = {
- { "NOERROR", NOERR },
- { "ERR_FORMAT", ERR_FORMAT },
- { "ERR_SERVER", ERR_SERVER },
- { "ERR_NAME", ERR_NAME },
- { "ERR_NOFUNC", ERR_NOFUNC },
- { "ERR_REFUSED",ERR_REFUSED },
-};
-
-const char *
-typetostr(uint16_t v)
-{
- static char buf[16];
- size_t i;
-
- for(i = 0; i < sizeof(kv_type)/sizeof(kv_type[0]); i++)
- if (kv_type[i].value == v)
- return (kv_type[i].key);
-
- snprintf(buf, sizeof buf, "%"PRIu16"?", v);
-
- return (buf);
-}
-
-const char *
-classtostr(uint16_t v)
-{
- static char buf[16];
- size_t i;
-
- for(i = 0; i < sizeof(kv_class)/sizeof(kv_class[0]); i++)
- if (kv_class[i].value == v)
- return (kv_class[i].key);
-
- snprintf(buf, sizeof buf, "%"PRIu16"?", v);
-
- return (buf);
-}
-
-const char *
-rcodetostr(uint16_t v)
-{
- static char buf[16];
- size_t i;
-
- for(i = 0; i < sizeof(kv_rcode)/sizeof(kv_rcode[0]); i++)
- if (kv_rcode[i].value == v)
- return (kv_rcode[i].key);
-
- snprintf(buf, sizeof buf, "%"PRIu16"?", v);
-
- return (buf);
-}
-
-uint16_t
-strtotype(const char *name)
-{
- size_t i;
-
- for(i = 0; i < sizeof(kv_type)/sizeof(kv_type[0]); i++)
- if (!strcmp(kv_type[i].key, name))
- return (kv_type[i].value);
-
- return (0);
-}
-
-uint16_t
-strtoclass(const char *name)
-{
- size_t i;
-
- for(i = 0; i < sizeof(kv_class)/sizeof(kv_class[0]); i++)
- if (!strcmp(kv_class[i].key, name))
- return (kv_class[i].value);
-
- return (0);
-}
-
-const char *
-inet6_ntoa(struct in6_addr a)
-{
- static char buf[256];
- struct sockaddr_in6 si;
-
- si.sin6_len = sizeof(si);
- si.sin6_family = PF_INET6;
- si.sin6_addr = a;
-
- return print_host((struct sockaddr*)&si, buf, sizeof buf);
-}
-
-const char*
-print_rr(struct rr *rr, char *buf, size_t max)
-{
- char *res;
- char tmp[256];
- char tmp2[256];
- int r;
-
- res = buf;
-
- r = snprintf(buf, max, "%s %u %s %s ",
- print_dname(rr->rr_dname, tmp, sizeof tmp),
- rr->rr_ttl,
- classtostr(rr->rr_class),
- typetostr(rr->rr_type));
- if (r == -1) {
- buf[0] = '\0';
- return buf;
- }
-
- if ((size_t)r >= max)
- return buf;
-
- max -= r;
- buf += r;
-
- switch(rr->rr_type) {
- case T_CNAME:
- print_dname(rr->rr.cname.cname, buf, max);
- break;
- case T_MX:
- snprintf(buf, max, "%"PRIu32" %s",
- rr->rr.mx.preference,
- print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
- break;
- case T_NS:
- print_dname(rr->rr.ns.nsname, buf, max);
- break;
- case T_PTR:
- print_dname(rr->rr.ptr.ptrname, buf, max);
- break;
- case T_SOA:
- snprintf(buf, max,
- "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
- print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
- print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
- rr->rr.soa.serial,
- rr->rr.soa.refresh,
- rr->rr.soa.retry,
- rr->rr.soa.expire,
- rr->rr.soa.minimum);
- break;
- case T_A:
- if (rr->rr_class != C_IN)
- goto other;
- snprintf(buf, max, "%s", inet_ntoa(rr->rr.in_a.addr));
- break;
- case T_AAAA:
- if (rr->rr_class != C_IN)
- goto other;
- snprintf(buf, max, "%s", inet6_ntoa(rr->rr.in_aaaa.addr6));
- break;
- default:
- other:
- snprintf(buf, max, "(rdlen=%"PRIu16 ")", rr->rr.other.rdlen);
- break;
- }
-
- return (res);
-}
-
-const char*
-print_rrdynamic(struct rr_dynamic *rd, char *buf, size_t max)
-{
- char *res;
- char tmp[256];
- char tmp2[256];
- int r;
-
- res = buf;
-
- r = snprintf(buf, max, "%s %u %s %s ",
- print_dname(rd->rd_dname, tmp, sizeof tmp),
- rd->rd_ttl,
- classtostr(rd->rd_class),
- typetostr(rd->rd_type));
- if (r == -1) {
- buf[0] = '\0';
- return buf;
- }
-
- if ((size_t)r >= max)
- return buf;
-
- max -= r;
- buf += r;
-
- switch(rd->rd_type) {
- case T_CNAME:
- print_dname(rd->rd.cname.cname, buf, max);
- break;
- case T_MX:
- snprintf(buf, max, "%"PRIu32" %s",
- rd->rd.mx.preference,
- print_dname(rd->rd.mx.exchange, tmp, sizeof tmp));
- break;
- case T_NS:
- print_dname(rd->rd.ns.nsname, buf, max);
- break;
- case T_PTR:
- print_dname(rd->rd.ptr.ptrname, buf, max);
- break;
- case T_SOA:
- snprintf(buf, max,
- "%s %s %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32,
- print_dname(rd->rd.soa.rname, tmp, sizeof tmp),
- print_dname(rd->rd.soa.mname, tmp2, sizeof tmp2),
- rd->rd.soa.serial,
- rd->rd.soa.refresh,
- rd->rd.soa.retry,
- rd->rd.soa.expire,
- rd->rd.soa.minimum);
- break;
- case T_A:
- if (rd->rd_class != C_IN)
- goto other;
- snprintf(buf, max, "%s", inet_ntoa(rd->rd.in_a.addr));
- break;
- case T_AAAA:
- if (rd->rd_class != C_IN)
- goto other;
- snprintf(buf, max, "%s", inet6_ntoa(rd->rd.in_aaaa.addr6));
- break;
- default:
- other:
- snprintf(buf, max, "(rdlen=%"PRIu16 ")", rd->rd.other.rdlen);
- break;
- }
-
- return (res);
-}
-
-const char*
-print_query(struct query *q, char *buf, size_t max)
-{
- char b[256];
-
- snprintf(buf, max, "%s %s %s",
- print_dname(q->q_dname, b, sizeof b),
- classtostr(q->q_class), typetostr(q->q_type));
-
- return (buf);
-}
-
-const 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);
-}
-
-const char*
-print_header(struct header *h, char *buf, size_t max)
-{
- snprintf(buf, max,
- "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
- (int)h->id,
- (h->flags & QR_MASK) ? "QR":" ",
- (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
- (h->flags & AA_MASK) ? "AA":" ",
- (h->flags & TC_MASK) ? "TC":" ",
- (h->flags & RD_MASK) ? "RD":" ",
- (h->flags & RA_MASK) ? "RA":" ",
- ((h->flags & Z_MASK) >> Z_SHIFT),
- rcodetostr(RCODE(h->flags)),
- h->qdcount, h->ancount, h->nscount, h->arcount);
-
- return buf;
-}
-
-const char *
-print_host(struct sockaddr *sa, char *buf, size_t len)
-{
- int e;
-
- if ((e = getnameinfo(sa, sa->sa_len,
- buf, len, NULL, 0, NI_NUMERICHOST)) != 0) {
- buf[0] = '\0';
- return (NULL);
- }
- return (buf);
-}
-
-const char *
-print_addr(struct sockaddr *sa, char *buf, size_t len)
-{
- char h[256];
-
- print_host(sa, h, sizeof h);
-
- switch (sa->sa_family) {
- case AF_INET:
- snprintf(buf, len, "%s:%i", h,
- ntohs(((struct sockaddr_in*)(sa))->sin_port));
- break;
- case AF_INET6:
- snprintf(buf, len, "[%s]:%i", h,
- ntohs(((struct sockaddr_in6*)(sa))->sin6_port));
- break;
- default:
- snprintf(buf, len, "?");
- break;
- }
-
- return (buf);
-}
diff --git a/usr.sbin/smtpd/res_random.c b/usr.sbin/smtpd/res_random.c
deleted file mode 100644
index 18c777dce7d..00000000000
--- a/usr.sbin/smtpd/res_random.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copied from: lib/libc/net/res_random.c
- *
- * -- eric@
- */
-/* $OpenBSD: res_random.c,v 1.1 2010/11/29 15:25:56 gilles Exp $ */
-
-/*
- * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
- * Copyright 2008 Damien Miller <djm@openbsd.org>
- * All rights reserved.
- *
- * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using
- * such a mathematical system to generate more random (yet non-repeating)
- * ids to solve the resolver/named problem. But Niels designed the
- * actual system based on the constraints.
- *
- * Later modified by Damien Miller to wrap the LCG output in a 15-bit
- * permutation generator based on a Luby-Rackoff block cipher. This
- * ensures the output is non-repeating and preserves the MSB twiddle
- * trick, but makes it more resistant to LCG prediction.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * seed = random 15bit
- * n = prime, g0 = generator to n,
- * j = random so that gcd(j,n-1) == 1
- * g = g0^j mod n will be a generator again.
- *
- * X[0] = random seed.
- * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator
- * with a = 7^(even random) mod m,
- * b = random with gcd(b,m) == 1
- * m = 31104 and a maximal period of m-1.
- *
- * The transaction id is determined by:
- * id[n] = seed xor (g^X[n] mod n)
- *
- * Effectivly the id is restricted to the lower 15 bits, thus
- * yielding two different cycles by toggling the msb on and off.
- * This avoids reuse issues caused by reseeding.
- *
- * The output of this generator is then randomly permuted though a
- * custom 15 bit Luby-Rackoff block cipher.
- */
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dnsutil.h"
-
-#define RU_OUT 180 /* Time after wich will be reseeded */
-#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */
-#define RU_GEN 2 /* Starting generator */
-#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */
-#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */
-#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */
-#define RU_ROUNDS 11 /* Number of rounds for permute (odd) */
-
-struct prf_ctx {
- /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */
- u_char prf7[(RU_ROUNDS / 2) * (1 << 7)];
-
- /* PRF lookup table for even rounds (8 bits input to 7 bits output) */
- u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)];
-};
-
-#define PFAC_N 3
-static const u_int16_t pfacts[PFAC_N] = {
- 2,
- 3,
- 2729
-};
-
-static u_int16_t ru_x;
-static u_int16_t ru_seed, ru_seed2;
-static u_int16_t ru_a, ru_b;
-static u_int16_t ru_g;
-static u_int16_t ru_counter = 0;
-static u_int16_t ru_msb = 0;
-static struct prf_ctx *ru_prf = NULL;
-static long ru_reseed;
-
-static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t);
-static void res_initid(void);
-
-/*
- * Do a fast modular exponation, returned value will be in the range
- * of 0 - (mod-1)
- */
-static u_int16_t
-pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod)
-{
- u_int16_t s, t, u;
-
- s = 1;
- t = gen;
- u = exp;
-
- while (u) {
- if (u & 1)
- s = (s * t) % mod;
- u >>= 1;
- t = (t * t) % mod;
- }
- return (s);
-}
-
-/*
- * 15-bit permutation based on Luby-Rackoff block cipher
- */
-static u_int
-permute15(u_int in)
-{
- int i;
- u_int left, right, tmp;
-
- if (ru_prf == NULL)
- return in;
-
- left = (in >> 8) & 0x7f;
- right = in & 0xff;
-
- /*
- * Each round swaps the width of left and right. Even rounds have
- * a 7-bit left, odd rounds have an 8-bit left. Since this uses an
- * odd number of rounds, left is always 8 bits wide at the end.
- */
- for (i = 0; i < RU_ROUNDS; i++) {
- if ((i & 1) == 0)
- tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f;
- else
- tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right];
- tmp ^= left;
- left = right;
- right = tmp;
- }
-
- return (right << 8) | left;
-}
-
-/*
- * Initializes the seed and chooses a suitable generator. Also toggles
- * the msb flag. The msb flag is used to generate two distinct
- * cycles of random numbers and thus avoiding reuse of ids.
- *
- * This function is called from res_randomid() when needed, an
- * application does not have to worry about it.
- */
-static void
-res_initid(void)
-{
- u_int16_t j, i;
- u_int32_t tmp;
- int noprime = 1;
- struct timeval tv;
-
- ru_x = arc4random_uniform(RU_M);
-
- /* 15 bits of random seed */
- tmp = arc4random();
- ru_seed = (tmp >> 16) & 0x7FFF;
- ru_seed2 = tmp & 0x7FFF;
-
- /* Determine the LCG we use */
- tmp = arc4random();
- ru_b = (tmp & 0xfffe) | 1;
- ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M);
- while (ru_b % 3 == 0)
- ru_b += 2;
-
- j = arc4random_uniform(RU_N);
-
- /*
- * Do a fast gcd(j,RU_N-1), so we can find a j with
- * gcd(j, RU_N-1) == 1, giving a new generator for
- * RU_GEN^j mod RU_N
- */
-
- while (noprime) {
- for (i = 0; i < PFAC_N; i++)
- if (j % pfacts[i] == 0)
- break;
-
- if (i >= PFAC_N)
- noprime = 0;
- else
- j = (j + 1) % RU_N;
- }
-
- ru_g = pmod(RU_GEN, j, RU_N);
- ru_counter = 0;
-
- /* Initialise PRF for Luby-Rackoff permutation */
- if (ru_prf == NULL)
- ru_prf = malloc(sizeof(*ru_prf));
- if (ru_prf != NULL)
- arc4random_buf(ru_prf, sizeof(*ru_prf));
-
- gettimeofday(&tv, NULL);
- ru_reseed = tv.tv_sec + RU_OUT;
- ru_msb = ru_msb == 0x8000 ? 0 : 0x8000;
-}
-
-u_int
-res_randomid(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- if (ru_counter >= RU_MAX || tv.tv_sec > ru_reseed)
- res_initid();
-
- /* Linear Congruential Generator */
- ru_x = (ru_a * ru_x + ru_b) % RU_M;
- ru_counter++;
-
- return permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb;
-}
-
-#if 0
-int
-main(int argc, char **argv)
-{
- int i, n;
- u_int16_t wert;
-
- res_initid();
-
- printf("Generator: %u\n", ru_g);
- printf("Seed: %u\n", ru_seed);
- printf("Reseed at %ld\n", ru_reseed);
- printf("Ru_X: %u\n", ru_x);
- printf("Ru_A: %u\n", ru_a);
- printf("Ru_B: %u\n", ru_b);
-
- n = argc > 1 ? atoi(argv[1]) : 60001;
- for (i=0;i<n;i++) {
- wert = res_randomid();
- printf("%u\n", wert);
- }
- return 0;
-}
-#endif
-
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 33a65ead442..39f0eabcaec 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,4 +1,6 @@
-# $OpenBSD: Makefile,v 1.43 2012/07/09 09:57:53 gilles Exp $
+# $OpenBSD: Makefile,v 1.44 2012/07/09 12:16:24 eric Exp $
+
+.PATH: ${.CURDIR}/.. ${.CURDIR}/../../../lib/libc/asr
PROG= smtpd
SRCS= aliases.c auth.c auth_bsd.c auth_pwd.c bounce.c \
@@ -10,18 +12,21 @@ SRCS= aliases.c auth.c auth_bsd.c auth_pwd.c bounce.c \
mda.c mfa.c mfa_session.c mta.c mta_session.c parse.y \
queue.c ruleset.c scheduler.c scheduler_backend.c \
smtp.c \
- smtp_session.c smtpd.c ssl.c ssl_privsep.c util.c asr.c \
- print.c pack.c dname.c res_random.c sockaddr.c \
+ smtp_session.c smtpd.c ssl.c ssl_privsep.c util.c \
queue_backend.c queue_fsqueue.c \
user.c user_pwd.c stats.c scheduler_ramqueue.c \
map_static.c
+SRCS+= asr.c asr_debug.c asr_utils.c \
+ res_send_async.c hostaddr_async.c getaddrinfo_async.c \
+ getnameinfo_async.c gethostnamadr_async.c
+
MAN= smtpd.8 smtpd.conf.5
BINDIR= /usr/sbin
LDADD+= -levent -lutil -lssl -lcrypto -lm
DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBM}
-CFLAGS+= -g3 -ggdb -I${.CURDIR}/..
+CFLAGS+= -g3 -ggdb -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/asr
CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
@@ -30,6 +35,4 @@ CFLAGS+= -Wsign-compare -Wbounded
CFLAGS+= -DIO_SSL
YFLAGS=
-.PATH: ${.CURDIR}/..
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/smtpd/sockaddr.c b/usr.sbin/smtpd/sockaddr.c
deleted file mode 100644
index bc918ffc6d3..00000000000
--- a/usr.sbin/smtpd/sockaddr.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* $OpenBSD: sockaddr.c,v 1.5 2012/06/14 20:59:42 gilles Exp $ */
-/*
- * Copyright (c) 2010 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
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dnsutil.h"
-
-int
-sockaddr_from_rr(struct sockaddr *sa, struct rr *rr)
-{
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
-
- if (rr->rr_class != C_IN)
- return (-1);
-
- switch (rr->rr_type) {
- case T_A:
- sin = (struct sockaddr_in*)sa;
- memset(sin, 0, sizeof *sin);
- sin->sin_len = sizeof *sin;
- sin->sin_family = PF_INET;
- sin->sin_addr = rr->rr.in_a.addr;
- sin->sin_port = 0;
- return (0);
- case T_AAAA:
- sin6 = (struct sockaddr_in6*)sa;
- memset(sin6, 0, sizeof *sin6);
- sin6->sin6_len = sizeof *sin6;
- sin6->sin6_family = PF_INET6;
- sin6->sin6_addr = rr->rr.in_aaaa.addr6;
- sin6->sin6_port = 0;
- return (0);
-
- default:
- break;
- }
-
- return (-1);
-}
-
-int
-sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
-{
- struct in_addr ina;
- struct in6_addr in6a;
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
-
- switch (family) {
- case PF_UNSPEC:
- if (sockaddr_from_str(sa, PF_INET, str) == 0)
- return (0);
- return sockaddr_from_str(sa, PF_INET6, str);
-
- case PF_INET:
- if (inet_pton(PF_INET, str, &ina) != 1)
- return (-1);
-
- sin = (struct sockaddr_in *)sa;
- memset(sin, 0, sizeof *sin);
- sin->sin_len = sizeof(struct sockaddr_in);
- sin->sin_family = PF_INET;
- sin->sin_addr.s_addr = ina.s_addr;
- return (0);
-
- case PF_INET6:
- if (inet_pton(PF_INET6, str, &in6a) != 1)
- return (-1);
-
- sin6 = (struct sockaddr_in6 *)sa;
- memset(sin6, 0, sizeof *sin6);
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- sin6->sin6_family = PF_INET6;
- sin6->sin6_addr = in6a;
- return (0);
-
- default:
- break;
- }
-
- return (-1);
-}
-
-ssize_t
-sockaddr_as_fqdn(const struct sockaddr *sa, char *dst, size_t max)
-{
- const struct in6_addr *in6_addr;
- in_addr_t addr;
-
- switch (sa->sa_family) {
- case AF_INET:
- addr = ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
- snprintf(dst, max,
- "%d.%d.%d.%d.in-addr.arpa.",
- addr & 0xff,
- (addr >> 8) & 0xff,
- (addr >> 16) & 0xff,
- (addr >> 24) & 0xff);
- break;
- case AF_INET6:
- in6_addr = &((const struct sockaddr_in6 *)sa)->sin6_addr;
- snprintf(dst, max,
- "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
- "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
- "ip6.arpa.",
- in6_addr->s6_addr[15] & 0xf,
- (in6_addr->s6_addr[15] >> 4) & 0xf,
- in6_addr->s6_addr[14] & 0xf,
- (in6_addr->s6_addr[14] >> 4) & 0xf,
- in6_addr->s6_addr[13] & 0xf,
- (in6_addr->s6_addr[13] >> 4) & 0xf,
- in6_addr->s6_addr[12] & 0xf,
- (in6_addr->s6_addr[12] >> 4) & 0xf,
- in6_addr->s6_addr[11] & 0xf,
- (in6_addr->s6_addr[11] >> 4) & 0xf,
- in6_addr->s6_addr[10] & 0xf,
- (in6_addr->s6_addr[10] >> 4) & 0xf,
- in6_addr->s6_addr[9] & 0xf,
- (in6_addr->s6_addr[9] >> 4) & 0xf,
- in6_addr->s6_addr[8] & 0xf,
- (in6_addr->s6_addr[8] >> 4) & 0xf,
- in6_addr->s6_addr[7] & 0xf,
- (in6_addr->s6_addr[7] >> 4) & 0xf,
- in6_addr->s6_addr[6] & 0xf,
- (in6_addr->s6_addr[6] >> 4) & 0xf,
- in6_addr->s6_addr[5] & 0xf,
- (in6_addr->s6_addr[5] >> 4) & 0xf,
- in6_addr->s6_addr[4] & 0xf,
- (in6_addr->s6_addr[4] >> 4) & 0xf,
- in6_addr->s6_addr[3] & 0xf,
- (in6_addr->s6_addr[3] >> 4) & 0xf,
- in6_addr->s6_addr[2] & 0xf,
- (in6_addr->s6_addr[2] >> 4) & 0xf,
- in6_addr->s6_addr[1] & 0xf,
- (in6_addr->s6_addr[1] >> 4) & 0xf,
- in6_addr->s6_addr[0] & 0xf,
- (in6_addr->s6_addr[0] >> 4) & 0xf);
- break;
- default:
- break;
- }
-
- return (-1);
-}
-
-void
-sockaddr_set_port(struct sockaddr *sa, int portno)
-{
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
-
- switch (sa->sa_family) {
- case PF_INET:
- sin = (struct sockaddr_in *)sa;
- sin->sin_port = htons(portno);
- break;
- case PF_INET6:
- sin6 = (struct sockaddr_in6 *)sa;
- sin6->sin6_port = htons(portno);
- break;
- }
-}
-
-int
-sockaddr_connect(const struct sockaddr *sa, int socktype)
-{
- int errno_save, flags, sock;
-
- if ((sock = socket(sa->sa_family, socktype, 0)) == -1)
- goto fail;
-
- if ((flags = fcntl(sock, F_GETFL, 0)) == -1)
- goto fail;
-
- flags |= O_NONBLOCK;
-
- if ((flags = fcntl(sock, F_SETFL, flags)) == -1)
- goto fail;
-
- if (connect(sock, sa, sa->sa_len) == -1) {
- if (errno == EINPROGRESS)
- return (sock);
- goto fail;
- }
-
- return (sock);
-
- fail:
-
- if (sock != -1) {
- errno_save = errno;
- close(sock);
- errno = errno_save;
- }
-
- return (-1);
-}
-
-int
-sockaddr_listen(const struct sockaddr *sa, int socktype)
-{
- int errno_save, sock;
-
- if ((sock = socket(sa->sa_family, socktype, 0)) == -1)
- return (-1);
-
- if (bind(sock, sa, sa->sa_len) == -1) {
- errno_save = errno;
- close(sock);
- errno = errno_save;
- return (-1);
- }
-
- return (sock);
-}
diff --git a/usr.sbin/smtpd/thread_private.h b/usr.sbin/smtpd/thread_private.h
new file mode 100644
index 00000000000..434b0326e1c
--- /dev/null
+++ b/usr.sbin/smtpd/thread_private.h
@@ -0,0 +1,2 @@
+#define __THREAD_NAME(x) __ ## x
+#define _THREAD_PRIVATE(a, b, c) (c)