diff options
-rw-r--r-- | lib/dns.c | 20 | ||||
-rw-r--r-- | lib/dns.h | 2 | ||||
-rw-r--r-- | src/builtin/dns.bi | 20 | ||||
-rw-r--r-- | src/spf.c | 34 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 8 | ||||
-rw-r--r-- | tests/resolv.c | 255 |
7 files changed, 301 insertions, 39 deletions
@@ -86,8 +86,7 @@ get_state(void) dnsbase_real_init(); return state; } - - + int dns_str_is_ipv4(const char *addr) { @@ -144,7 +143,7 @@ adns_to_dns_status(int e) return dns_failure; } } - + /* Return MX records for the given HOST. */ dns_status dns_get_mx_records(const char *host, struct dns_reply *reply) @@ -304,8 +303,9 @@ ptr_lookup(struct in_addr ip, struct dns_reply *reply) adns_answer *ans; char *name; + ip.s_addr = ntohl(ip.s_addr); mu_asprintf(&name, "%s.in-addr.arpa", inet_ntoa(ip)); - rc = adns_synchronous(get_state(), name, adns_r_ptr, + rc = adns_synchronous(get_state(), name, adns_r_ptr_raw, adns_qf_quoteok_cname|adns_qf_cname_loose, &ans); free(name); @@ -379,7 +379,7 @@ spf_lookup(const char *domain, char **rec) /* rfc4408, chapter 5.5 */ dns_status -ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount) +ptr_validate(const char *ipstr, struct dns_reply *reply) { struct in_addr ip; size_t i; @@ -420,11 +420,11 @@ ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount) if (sc == 0) { return dns_not_found; } - if (vcount) - *vcount = sc; - if (vnptr) - *vnptr = sv; - else + if (reply) { + reply->type = dns_reply_str; + reply->count = sc; + reply->data.str = sv; + } else mu_argcv_free(sc, sv); return dns_success; @@ -57,7 +57,7 @@ dns_status a_lookup(const char *host, struct dns_reply *repl); dns_status ptr_lookup(struct in_addr ip, struct dns_reply *repl); dns_status txt_lookup(const char *name, struct dns_reply *repl); -dns_status ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount); +dns_status ptr_validate(const char *ipstr, struct dns_reply *repl); dns_status spf_lookup(const char *domain, char **record); diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi index f63a2361..4bde9676 100644 --- a/src/builtin/dns.bi +++ b/src/builtin/dns.bi @@ -169,10 +169,10 @@ END MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) { mf_status mxstat; - struct dns_reply repl; + struct dns_reply reply; if (MF_OPTVAL(no_resolve)) { - mxstat = getmxip(domain, &repl); + mxstat = getmxip(domain, &reply); if (!mf_resolved(mxstat)) { MF_THROW(mf_status_to_exception(mxstat), _("cannot get MX records for %s"), domain); @@ -183,20 +183,20 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) int i; MF_OBSTACK_BEGIN(); - for (i = 0; i < repl.count; i++) { + for (i = 0; i < reply.count; i++) { struct in_addr s; - s.s_addr = htonl(repl.data.ip[i]); + s.s_addr = htonl(reply.data.ip[i]); if (i > 0) MF_OBSTACK_1GROW(' '); MF_OBSTACK_GROW(inet_ntoa(s)); } MF_OBSTACK_1GROW(0); - dns_reply_free(&repl); + dns_reply_free(&reply); MF_RETURN_OBSTACK(); } } else { - mxstat = getmx(domain, &repl); + mxstat = getmx(domain, &reply); if (!mf_resolved(mxstat)) { MF_THROW(mf_status_to_exception(mxstat), _("cannot get MX records for %s"), domain); @@ -207,13 +207,13 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER no_resolve) int i; MF_OBSTACK_BEGIN(); - for (i = 0; i < repl.count; i++) { + for (i = 0; i < reply.count; i++) { if (i > 0) MF_OBSTACK_1GROW(' '); - MF_OBSTACK_GROW(repl.data.str[i]); + MF_OBSTACK_GROW(reply.data.str[i]); } MF_OBSTACK_1GROW(0); - dns_reply_free(&repl); + dns_reply_free(&reply); MF_RETURN_OBSTACK(); } } @@ -286,7 +286,7 @@ END MF_DEFUN(ptr_validate, NUMBER, STRING s) { int rc, res; - switch (rc = ptr_validate(s, NULL, NULL)) { + switch (rc = ptr_validate(s, NULL)) { case dns_success: res = 1; break; @@ -334,32 +334,31 @@ spf_expand_do(struct spf_data *dat, int allow_exp, const char **pptr) int rc; size_t i; char *name = NULL; - char **vnames; - size_t vcount; - dns_status status = ptr_validate(dat->q.ipstr, - &vnames, &vcount); + struct dns_reply reply; + dns_status status = ptr_validate(dat->q.ipstr, &reply); if (status != dns_success) return spf_transform(dat, "unknown", 0, pptr); - for (i = 0; i < vcount; i++) - if (strcasecmp(vnames[i], dat->q.domain) == 0) { - name = vnames[i]; + for (i = 0; i < reply.count; i++) + if (strcasecmp(reply.data.str[i], dat->q.domain) == 0) { + name = reply.data.str[i]; break; } if (!name) { - for (i = 0; i < vcount; i++) - if (domain_match(vnames[i], dat->q.domain)) { - name = vnames[i]; + for (i = 0; i < reply.count; i++) + if (domain_match(reply.data.str[i], + dat->q.domain)) { + name = reply.data.str[i]; break; } if (!name) - name = vnames[0]; + name = reply.data.str[0]; } rc = spf_transform(dat, name, 0, pptr); - mu_argcv_free(vcount, vnames); + dns_reply_free(&reply); return rc; } @@ -698,8 +697,7 @@ mech_mx(spf_data *dat, spf_term_arg *arg, unsigned long masklen) static spf_term_result mech_ptr(spf_data *dat, spf_term_arg *arg, unsigned long masklen) { - char **vnames; - size_t vcount; + struct dns_reply reply; size_t i; const char *domain_spec; spf_term_result result = spf_term_nomatch; @@ -709,14 +707,14 @@ mech_ptr(spf_data *dat, spf_term_arg *arg, unsigned long masklen) else domain_spec = dat->q.domain; - DNS_CATCH(ptr_validate(dat->q.ipstr, &vnames, &vcount)); + DNS_CATCH(ptr_validate(dat->q.ipstr, &reply)); - for (i = 0; i < vcount; i++) - if (domain_match(vnames[i], domain_spec)) { + for (i = 0; i < reply.count; i++) + if (domain_match(reply.data.str[i], domain_spec)) { result = spf_term_match; break; } - mu_argcv_free(vcount, vnames); + dns_reply_free(&reply); return result; } diff --git a/tests/.gitignore b/tests/.gitignore index 33e4e9a5..fb1cd65c 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,3 +5,4 @@ status.mf testsuite testsuite.dir testsuite.log +resolv diff --git a/tests/Makefile.am b/tests/Makefile.am index 7def02b3..2f840fc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -156,6 +156,14 @@ TESTSUITE_AT = \ TESTSUITE = $(srcdir)/testsuite M4=m4 +noinst_PROGRAMS = \ + resolv + +resolv_CPPFLAGS = -I$(top_srcdir)/lib +resolv_LDADD = \ + ../lib/libmf.a \ + $(MAILUTILS_LIBS) + AUTOTEST = $(AUTOM4TE) --language=autotest $(TESTSUITE): package.m4 $(TESTSUITE_AT) $(AM_V_GEN)$(AUTOTEST) -I $(srcdir) testsuite.at -o $@.tmp diff --git a/tests/resolv.c b/tests/resolv.c new file mode 100644 index 00000000..460b14b2 --- /dev/null +++ b/tests/resolv.c @@ -0,0 +1,255 @@ +#include <config.h> +#include <stdio.h> +#include <stdio.h> +#include <assert.h> +#include <mailutils/mailutils.h> +#include "dns.h" + +void +status_print(dns_status status) +{ + switch (status) { + case dns_success: + printf("OK"); + break; + case dns_not_found: + printf("NOTFOUND"); + break; + case dns_failure: + printf("FAILURE"); + break; + case dns_temp_failure: + printf("TEMPFAIL"); + break; + default: + mu_error("%s:%d: unrecognized status", __FILE__, __LINE__); + abort(); + } + putchar('\n'); +} + +static int +hostname_cmp(const void *a, const void *b) +{ + return strcmp(*(const char**) a, *(const char**) b); +} + +void +reply_print_str(struct dns_reply *reply) +{ + int i; + + qsort(reply->data.str, reply->count, sizeof reply->data.str[0], + hostname_cmp); + for (i = 0; i < reply->count; i++) { + printf("%s\n", reply->data.str[i]); + } +} + +static int +ipaddr_cmp(const void *a, const void *b) +{ + GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a); + GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b); + if (ipa < ipb) + return -1; + if (ipa > ipb) + return 1; + return 0; +} + +void +reply_print_ip(struct dns_reply *reply) +{ + int i; + + qsort(reply->data.ip, reply->count, sizeof reply->data.ip[0], + ipaddr_cmp); + for (i = 0; i < reply->count; i++) { + struct in_addr ip; + ip.s_addr = reply->data.ip[i]; + printf("%s\n", inet_ntoa(ip)); + } +} + +void +reply_print(struct dns_reply *reply) +{ + switch (reply->type) { + case dns_reply_str: + reply_print_str(reply); + break; + case dns_reply_ip: + reply_print_ip(reply); + break; + default: + mu_error("%s:%d: unrecognized reply type", __FILE__, __LINE__); + abort(); + } +} + +static int +res_a(int argc, char **argv) +{ + dns_status status; + struct dns_reply reply; + + assert(argc == 1); + status = a_lookup(argv[0], &reply); + status_print(status); + if (status == dns_success) { + reply_print(&reply); + dns_reply_free(&reply); + } + return 0; +} + +static int +res_ptr(int argc, char **argv) +{ + dns_status status; + struct dns_reply reply; + struct in_addr in; + + assert(argc == 1); + if (!inet_aton(argv[0], &in)) { + mu_error("%s: can't convert address", argv[0]); + return 1; + } + + status = ptr_lookup(in, &reply); + status_print(status); + if (status == dns_success) { + reply_print(&reply); + dns_reply_free(&reply); + } + return 0; +} + +static int +res_ptr_val(int argc, char **argv) +{ + dns_status status; + struct dns_reply reply; + + assert(argc == 1); + status = ptr_validate(argv[0], &reply); + status_print(status); + if (status == dns_success) { + reply_print(&reply); + dns_reply_free(&reply); + } + return 0; +} + +static int +res_txt(int argc, char **argv) +{ + dns_status status; + struct dns_reply reply; + + assert(argc == 1); + status = txt_lookup(argv[0], &reply); + status_print(status); + if (status == dns_success) { + reply_print(&reply); + dns_reply_free(&reply); + } + return 0; +} + +static int +res_mx(int argc, char **argv) +{ + dns_status status; + struct dns_reply reply; + + assert(argc == 1); + status = dns_get_mx_records(argv[0], &reply); + status_print(status); + if (status == dns_success) { + reply_print(&reply); + dns_reply_free(&reply); + } + return 0; +} + +static int +res_spf(int argc, char **argv) +{ + dns_status status; + char *record; + + status = spf_lookup(argv[0], &record); + status_print(status); + if (status == dns_success) { + printf("%s\n", record); + free(record); + } + return 0; +} + +static int +res_host(int argc, char **argv) +{ + dns_status status; + char *str; + + assert(argc == 1 || argc == 2); + status = dns_resolve_ipstr(argv[0], argv[1], &str); + status_print(status); + if (status == dns_success) { + printf("%s\n", str); + free(str); + } + return 0; +} + +static int +res_ip(int argc, char **argv) +{ + dns_status status; + char *str; + + assert(argc == 1); + status = dns_resolve_hostname(argv[0], &str); + status_print(status); + if (status == dns_success) { + printf("%s\n", str); + free(str); + } + return 0; +} + +struct mode { + char const *name; + int (*func)(int, char **); +}; + +struct mode mode[] = { + { "host", res_host }, + { "ip", res_ip }, + { "a", res_a }, + { "ptr", res_ptr }, + { "txt", res_txt }, + { "mx", res_mx }, + { "ptr_val", res_ptr_val }, + { "spf", res_spf }, + { NULL } +}; + +int +main(int argc, char **argv) +{ + int i; + + mu_set_program_name(argv[0]); + mu_stdstream_setup(MU_STDSTREAM_RESET_NONE); + assert(argc > 2); + for (i = 0; mode[i].name; i++) { + if (strcmp(mode[i].name, argv[1]) == 0) + exit(mode[i].func(argc - 2, argv + 2)); + } + mu_error("%s:%d: unrecognized mode", __FILE__, __LINE__); + abort(); +} |