From e1500ec08c8cc5149f862d71a1a672e0b0dbf54f Mon Sep 17 00:00:00 2001 From: Eric Faurot Date: Mon, 9 Jul 2012 12:16:25 +0000 Subject: move to the new resolver implementation, with temporary glue to use the relevant files from asr directly. ok gilles@ --- usr.sbin/smtpd/asr.c | 2535 --------------------------------------- usr.sbin/smtpd/asr.h | 92 -- usr.sbin/smtpd/dname.c | 175 --- usr.sbin/smtpd/dns.c | 115 +- usr.sbin/smtpd/pack.c | 464 ------- usr.sbin/smtpd/print.c | 396 ------ usr.sbin/smtpd/res_random.c | 270 ----- usr.sbin/smtpd/smtpd/Makefile | 15 +- usr.sbin/smtpd/sockaddr.c | 240 ---- usr.sbin/smtpd/thread_private.h | 2 + 10 files changed, 59 insertions(+), 4245 deletions(-) delete mode 100644 usr.sbin/smtpd/asr.c delete mode 100644 usr.sbin/smtpd/asr.h delete mode 100644 usr.sbin/smtpd/dname.c delete mode 100644 usr.sbin/smtpd/pack.c delete mode 100644 usr.sbin/smtpd/print.c delete mode 100644 usr.sbin/smtpd/res_random.c delete mode 100644 usr.sbin/smtpd/sockaddr.c create mode 100644 usr.sbin/smtpd/thread_private.h 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 - * - * 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 -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 - * - * 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 -#include - -#include -#include - -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 - * - * 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 -#include -#include - -#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 @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -34,8 +35,7 @@ #include #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 - * - * 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 - -#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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#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 - * Copyright 2008 Damien Miller - * All rights reserved. - * - * Theo de Raadt 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 -#include -#include - -#include -#include -#include - -#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 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 - * - * 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 -#include - -#include -#include - -#include -#include -#include -#include -#include - -#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) -- cgit v1.2.3