aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dns.c264
-rw-r--r--lib/dns.h10
-rw-r--r--lib/libmf.h2
-rw-r--r--src/builtin/dns.bi67
-rw-r--r--src/main.c9
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/atlocal.in15
-rw-r--r--tests/hasmx.at2
-rw-r--r--tests/hostname.at13
-rw-r--r--tests/ismx.at3
-rw-r--r--tests/rescname.at11
-rw-r--r--tests/resolv.c121
-rw-r--r--tests/resolv_a.at38
-rw-r--r--tests/resolv_mx.at30
-rw-r--r--tests/resolv_ptr.at33
-rw-r--r--tests/resolv_ptr_val.at29
-rw-r--r--tests/resolv_spf.at27
-rw-r--r--tests/resolv_txt.at28
-rw-r--r--tests/resolve.at11
-rw-r--r--tests/testsuite.at11
20 files changed, 566 insertions, 164 deletions
diff --git a/lib/dns.c b/lib/dns.c
index b73145af..f3b1879c 100644
--- a/lib/dns.c
+++ b/lib/dns.c
@@ -31,10 +31,8 @@
#include "mailutils/io.h"
#include "mailutils/stream.h"
-struct mx_buffer {
- unsigned pref;
- char *name;
-};
+#define DEFAULT_QFLAGS \
+ (adns_qf_quoteok_cname|adns_qf_cname_loose)
static mu_debug_handle_t debug_handle;
static adns_state state;
@@ -63,30 +61,153 @@ dnsbase_init(void)
}
void
-dnsbase_real_init(void)
+dnsbase_real_init(char *configtext)
{
int rc;
int flags;
mu_debug_level_t lev;
flags = adns_if_nosigpipe;
- if (mu_debug_get_category_level(debug_handle, &lev) == 0 && lev)
+ if (mu_debug_get_category_level(debug_handle, &lev) == 0
+ && (lev & MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9)))
flags |= adns_if_debug;
- rc = adns_init_logfn(&state, flags, NULL, dns_log_cb, NULL);
+ rc = adns_init_logfn(&state, flags, configtext, dns_log_cb, NULL);
if (rc) {
mu_diag_funcall(MU_DIAG_ERROR, "adns_init", NULL, rc);
exit(1);
}
}
+void
+dnsbase_file_init(char *filename)
+{
+ if (!filename)
+ dnsbase_real_init(NULL);
+ else {
+ mu_stream_t str;
+ mu_off_t sz;
+ int rc;
+ char *cfg;
+
+ rc = mu_file_stream_create(&str, filename, MU_STREAM_READ);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_file_stream_create",
+ filename, rc);
+ return;
+ }
+ rc = mu_stream_size(str, &sz);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_size",
+ filename, rc);
+ mu_stream_destroy(&str);
+ return;
+ }
+
+ if (sz > ((size_t)~0)) {
+ mu_error(_("%s too big"), filename);
+ mu_stream_destroy(&str);
+ return;
+ }
+
+ cfg = mu_alloc(sz + 1);
+
+ rc = mu_stream_read(str, cfg, sz, NULL);
+ mu_stream_destroy(&str);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "mu_stream_read",
+ filename, rc);
+ return;
+ }
+ cfg[sz] = 0;
+ dnsbase_real_init(cfg);
+ free(cfg);
+ }
+}
+
static adns_state
get_state(void)
{
if (!state)
- dnsbase_real_init();
+ dnsbase_real_init(NULL);
return state;
}
-
+
+static inline size_t
+dns_reply_elsize(struct dns_reply *reply)
+{
+ switch (reply->type) {
+ case dns_reply_ip:
+ return sizeof(reply->data.ip[0]);
+ case dns_reply_str:
+ return sizeof(reply->data.str[0]);
+ }
+ abort();
+}
+
+void
+dns_reply_init(struct dns_reply *reply, dns_reply_type type, size_t count)
+{
+ reply->type = type;
+ reply->count = count;
+ reply->maxcount = count;
+ if (count)
+ reply->data.ptr = mu_calloc(count, dns_reply_elsize(reply));
+ else
+ reply->data.ptr = NULL;
+}
+
+void
+dns_reply_ip_push(struct dns_reply *reply, void *item)
+{
+ if (reply->count == reply->maxcount)
+ reply->data.ip = mu_2nrealloc(reply->data.ip,
+ &reply->maxcount,
+ sizeof(reply->data.ip[0]));
+ reply->data.ip[reply->count++] = *(GACOPYZ_UINT32_T*)item;
+}
+
+void
+dns_reply_str_push(struct dns_reply *reply, void *item)
+{
+ if (reply->count == reply->maxcount)
+ reply->data.str = mu_2nrealloc(reply->data.ip,
+ &reply->maxcount,
+ sizeof(reply->data.str[0]));
+ reply->data.str[reply->count++] = item;
+}
+
+void
+dns_reply_push(struct dns_reply *reply, void *item)
+{
+ switch (reply->type) {
+ case dns_reply_ip:
+ dns_reply_ip_push(reply, item);
+ break;
+ case dns_reply_str:
+ dns_reply_str_push(reply, item);
+ break;
+ default:
+ abort();
+ }
+}
+
+void
+dns_reply_free(struct dns_reply *reply)
+{
+ int i;
+
+ switch (reply->type) {
+ case dns_reply_str:
+ for (i = 0; i < reply->count; i++)
+ free(reply->data.str[i]);
+ free(reply->data.str);
+ break;
+ case dns_reply_ip:
+ free(reply->data.ip);
+ break;
+ }
+}
+
int
dns_str_is_ipv4(const char *addr)
{
@@ -144,35 +265,53 @@ adns_to_dns_status(int e)
}
}
+dns_status
+soa_check(const char *name, int ip, struct dns_reply *reply)
+{
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+
+ rc = adns_synchronous(get_state(), name, adns_r_soa_raw,
+ DEFAULT_QFLAGS,
+ &ans);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success) {
+ if (ip) {
+ status = a_lookup(ans->rrs.soa->mname, reply);
+ } else {
+ dns_reply_init(reply, dns_reply_str, 1);
+ reply->data.str[0] = mu_strdup (ans->rrs.soa->mname);
+ }
+ free(ans);
+ }
+ return status;
+}
+
static dns_status
dns_reply_resolve(struct dns_reply *reply)
{
- GACOPYZ_UINT32_T *ipbuf = NULL;
- size_t ipcount = 0;
- size_t ipmax = 0;
size_t i;
-
- ipcount = 0;
+ struct dns_reply res;
+
+ dns_reply_init(&res, dns_reply_ip, 0);
for (i = 0; i < reply->count; i++) {
struct dns_reply r;
dns_status stat = a_lookup(reply->data.str[i], &r);
if (stat == dns_success) {
size_t n;
- for (n = 0; n < r.count; n++, ipcount++) {
- if (ipcount == ipmax)
- ipbuf = mu_2nrealloc(ipbuf, &ipmax,
- sizeof(ipbuf));
- ipbuf[ipcount] = r.data.ip[n];
+ for (n = 0; n < r.count; n++) {
+ dns_reply_push(&res, &r.data.ip[n]);
}
dns_reply_free(&r);
}
}
dns_reply_free(reply);
- if (ipcount == 0)
+ *reply = res;
+ if (res.count == 0)
return dns_not_found;
- reply->type = dns_reply_ip;
- reply->count = ipcount;
- reply->data.ip = ipbuf;
return dns_success;
}
@@ -186,7 +325,7 @@ mx_lookup(const char *host, int resolve, struct dns_reply *reply)
int i;
rc = adns_synchronous(get_state(), host, adns_r_mx,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ DEFAULT_QFLAGS,
&ans);
if (rc)
return errno_to_dns_status(rc);
@@ -194,10 +333,7 @@ mx_lookup(const char *host, int resolve, struct dns_reply *reply)
if (status != dns_success)
return status;
- reply->type = dns_reply_str;
- reply->count = ans->nrrs;
- reply->data.str = mu_calloc(reply->count,
- sizeof(reply->data.str[0]));
+ dns_reply_init(reply, dns_reply_str, ans->nrrs);
for (i = 0; i < ans->nrrs; i++)
reply->data.str[i] = mu_strdup(ans->rrs.inthostaddr[i].ha.host);
free(ans);
@@ -207,23 +343,6 @@ mx_lookup(const char *host, int resolve, struct dns_reply *reply)
return status;
}
-
-void
-dns_reply_free(struct dns_reply *reply)
-{
- int i;
-
- switch (reply->type) {
- case dns_reply_str:
- for (i = 0; i < reply->count; i++)
- free(reply->data.str[i]);
- free(reply->data.str);
- break;
- case dns_reply_ip:
- free(reply->data.ip);
- break;
- }
-}
typedef char IPBUF[3*4+3+1];
@@ -272,8 +391,8 @@ dns_resolve_ipstr(const char *ipstr, const char *domain, char **hbuf)
mu_asprintf(&name, "%s.%s", ipstr, domain);
}
- rc = adns_synchronous(get_state(), name, adns_r_ptr,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ rc = adns_synchronous(get_state(), name, adns_r_ptr_raw,
+ DEFAULT_QFLAGS,
&ans);
free(name);
if (rc)
@@ -293,7 +412,7 @@ dns_resolve_hostname(const char *host, char **ipbuf)
adns_answer *ans;
rc = adns_synchronous(get_state(), host, adns_r_a,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ DEFAULT_QFLAGS,
&ans);
if (rc)
return errno_to_dns_status(rc);
@@ -313,17 +432,14 @@ a_lookup(const char *host, struct dns_reply *reply)
adns_answer *ans;
rc = adns_synchronous(get_state(), host, adns_r_a,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ DEFAULT_QFLAGS,
&ans);
if (rc)
return errno_to_dns_status(rc);
status = adns_to_dns_status(ans->status);
if (status == dns_success) {
int i;
- reply->type = dns_reply_ip;
- reply->count = ans->nrrs;
- reply->data.ip = mu_calloc(reply->count,
- sizeof(reply->data.ip[0]));
+ dns_reply_init(reply, dns_reply_ip, ans->nrrs);
for (i = 0; i < ans->nrrs; i++)
reply->data.ip[i] = ans->rrs.inaddr[i].s_addr;
}
@@ -342,7 +458,7 @@ ptr_lookup(struct in_addr ip, struct dns_reply *reply)
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_raw,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ DEFAULT_QFLAGS,
&ans);
free(name);
if (rc)
@@ -350,10 +466,7 @@ ptr_lookup(struct in_addr ip, struct dns_reply *reply)
status = adns_to_dns_status(ans->status);
if (status == dns_success) {
int i;
- reply->type = dns_reply_str;
- reply->count = ans->nrrs;
- reply->data.str = mu_calloc(reply->count,
- sizeof(reply->data.str[0]));
+ dns_reply_init(reply, dns_reply_str, ans->nrrs);
for (i = 0; i < ans->nrrs; i++)
reply->data.str[i] = mu_strdup(ans->rrs.str[i]);
}
@@ -369,17 +482,14 @@ txt_lookup(const char *name, struct dns_reply *reply)
adns_answer *ans;
rc = adns_synchronous(get_state(), name, adns_r_txt,
- adns_qf_quoteok_cname|adns_qf_cname_loose,
+ DEFAULT_QFLAGS,
&ans);
if (rc)
return errno_to_dns_status(rc);
status = adns_to_dns_status(ans->status);
if (status == dns_success) {
int i;
- reply->type = dns_reply_str;
- reply->count = ans->nrrs;
- reply->data.str = mu_calloc(reply->count,
- sizeof(reply->data.str[0]));
+ dns_reply_init(reply, dns_reply_str, ans->nrrs);
for (i = 0; i < ans->nrrs; i++)
reply->data.str[i] = mu_strdup(ans->rrs.manyistr[i]->str);
}
@@ -419,11 +529,9 @@ ptr_validate(const char *ipstr, struct dns_reply *reply)
{
struct in_addr ip;
size_t i;
- int status;
+ dns_status status;
struct dns_reply ptr_reply;
- char **sv = NULL;
- size_t sc = 0;
- size_t sn = 0;
+ dns_status result = dns_not_found;
if (!inet_aton(ipstr, &ip))
return dns_failure;
@@ -433,6 +541,8 @@ ptr_validate(const char *ipstr, struct dns_reply *reply)
if (status != dns_success)
return status;
+ if (reply)
+ dns_reply_init(reply, dns_reply_str, 0);
for (i = 0; i < ptr_reply.count; i++) {
struct dns_reply r;
status = a_lookup(ptr_reply.data.str[i], &r);
@@ -441,10 +551,10 @@ ptr_validate(const char *ipstr, struct dns_reply *reply)
for (k = 0; k < r.count; k++) {
if (r.data.ip[k] == ip.s_addr) {
- if (sc == sn)
- sv = mu_2nrealloc(sv, &sn,
- sizeof(sv[0]));
- sv[sc++] = mu_strdup(ptr_reply.data.str[i]);
+ result = dns_success;
+ if (reply)
+ dns_reply_push(reply,
+ mu_strdup(ptr_reply.data.str[i]));
break;
}
}
@@ -453,17 +563,7 @@ ptr_validate(const char *ipstr, struct dns_reply *reply)
}
dns_reply_free(&ptr_reply);
- if (sc == 0) {
- return dns_not_found;
- }
- if (reply) {
- reply->type = dns_reply_str;
- reply->count = sc;
- reply->data.str = sv;
- } else
- mu_argcv_free(sc, sv);
-
- return dns_success;
+ return result;
}
diff --git a/lib/dns.h b/lib/dns.h
index 697d5a2f..832c8730 100644
--- a/lib/dns.h
+++ b/lib/dns.h
@@ -32,14 +32,20 @@ typedef enum {
} dns_reply_type;
struct dns_reply {
- int count;
dns_reply_type type;
+ int count;
+ size_t maxcount;
union {
char **str;
GACOPYZ_UINT32_T *ip;
+ void *ptr;
} data;
};
+void dnsbase_real_init(char *configtext);
+void dnsbase_file_init(char *file);
+
+void dns_reply_init(struct dns_reply *reply, dns_reply_type type, size_t count);
void dns_reply_free(struct dns_reply *r);
int dns_str_is_ipv4(const char *addr);
@@ -51,6 +57,8 @@ dns_status dns_resolve_ipstr(const char *ipstr, const char *domain,
dns_status dns_resolve_hostname(const char *host, char **ipbuf);
+dns_status soa_check(const char *name, int ip, struct dns_reply *repl);
+
dns_status a_lookup(const char *host, struct dns_reply *repl);
dns_status ptr_lookup(struct in_addr ip, struct dns_reply *repl);
diff --git a/lib/libmf.h b/lib/libmf.h
index ebfd0e3e..b2c88801 100644
--- a/lib/libmf.h
+++ b/lib/libmf.h
@@ -279,7 +279,7 @@ size_t format_time_str(FILE *fp, time_t timestamp);
/* dns.c */
-void dnsbase_init();
+void dnsbase_init(void);
mf_status dns_to_mf_status(dns_status stat);
dns_status mf_to_dns_status(mf_status stat);
mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf);
diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi
index 336d8f40..0b7bfdbc 100644
--- a/src/builtin/dns.bi
+++ b/src/builtin/dns.bi
@@ -203,59 +203,52 @@ MF_DEFUN(getmx, STRING, STRING domain, OPTIONAL, NUMBER resolve)
}
END
-static int
-resolve_host(const char *string, unsigned long *ip)
+static dns_status
+resolve_host(const char *string, struct dns_reply *reply)
{
- int rc;
struct in_addr addr;
- char *ipstr;
if (inet_aton(string, &addr)) {
- *ip = addr.s_addr;
- return 0;
+ dns_reply_init(reply, dns_reply_ip, 1);
+ reply->data.ip[0] = addr.s_addr;
+ return dns_success;
}
-
- if (resolve_hostname(string, &ipstr) != mf_success)
- return 1;
+ return a_lookup(string, reply);
+}
- rc = inet_aton(ipstr, &addr);
- free(ipstr);
- if (rc == 0) {
- mu_error(_("INTERNAL ERROR at %s:%d: resolve_hostname returned "
- "invalid IP address: %s"),
- __FILE__, __LINE__, ipstr);
- return 1;
+static int
+dns_replies_intersect(struct dns_reply const *a, struct dns_reply const *b)
+{
+ int i, j;
+
+ if (a->type == b->type && a->type == dns_reply_ip) {
+ for (i = 0; i < a->count; i++)
+ for (j = 0; j < b->count; j++)
+ if (a->data.ip[i] == b->data.ip[j])
+ return 1;
}
- *ip = addr.s_addr;
return 0;
}
MF_DEFUN(primitive_ismx, NUMBER, STRING domain, STRING ipstr)
{
- struct dns_reply reply;
- mf_status mxstat;
- unsigned long ip;
+ struct dns_reply areply, mxreply;
+ dns_status status;
int rc = 0;
- int i;
-
- MF_ASSERT(resolve_host(ipstr, &ip) == 0, mfe_noresolve,
- _("cannot resolve host name %s"), ipstr);
- ip = ntohl(ip);
-
- mxstat = dns_to_mf_status(mx_lookup(domain, 1, &reply));
- if (mxstat != mf_success) {
- MF_THROW(mf_status_to_exception(mxstat),
+ status = resolve_host(ipstr, &areply);
+ MF_ASSERT(status == dns_success,
+ mf_status_to_exception(dns_to_mf_status(status)),
+ _("cannot resolve host name %s"), ipstr);
+ status = mx_lookup(domain, 1, &mxreply);
+ if (status != dns_success) {
+ dns_reply_free(&areply);
+ MF_THROW(mf_status_to_exception(dns_to_mf_status(status)),
_("cannot get MXs for %s"), domain);
}
-
- for (i = 0; i < reply.count; i++) {
- if (reply.data.ip[i] == ip) {
- rc = 1;
- break;
- }
- }
- dns_reply_free(&reply);
+ rc = dns_replies_intersect(&areply, &mxreply);
+ dns_reply_free(&areply);
+ dns_reply_free(&mxreply);
MF_RETURN(rc);
}
END
diff --git a/src/main.c b/src/main.c
index 9873ed0f..dcc7d432 100644
--- a/src/main.c
+++ b/src/main.c
@@ -82,6 +82,8 @@ mu_stream_t mf_strecho; /* Output stream for 'echo' statements */
static int trace_option = ARG_UNSET;
static mu_list_t trace_modules;
+
+static char *resolv_conf_file;
/* Preprocessor helper function */
static void
@@ -563,6 +565,9 @@ static struct mu_option mailfromd_options[] = {
{ "relayed-domain-file", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("read relayed domains from FILE"),
mu_c_string, NULL, opt_relayed_domain_file },
+ { "resolv-conf-file", 0, N_("FILE"), MU_OPTION_DEFAULT,
+ N_("read resolver configuration from FILE"),
+ mu_c_string, &resolv_conf_file },
MU_OPTION_GROUP(N_("Preprocessor options")),
{ "preprocessor", 0, N_("COMMAND"), MU_OPTION_DEFAULT,
@@ -1269,7 +1274,9 @@ main(int argc, char **argv)
exit(EX_USAGE);
init_relayed_domains();
-
+ if (resolv_conf_file)
+ dnsbase_file_init(resolv_conf_file);
+
if (trace_option != ARG_UNSET)
do_trace = trace_option;
if (trace_modules) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2f840fc3..672865fd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -115,6 +115,12 @@ TESTSUITE_AT = \
relayed02.at\
rescname.at\
resolve.at\
+ resolv_a.at\
+ resolv_ptr.at\
+ resolv_txt.at\
+ resolv_mx.at\
+ resolv_spf.at\
+ resolv_ptr_val.at\
rset.at\
shadow.at\
shellmagic.at\
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 0bbe0350..d015213e 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -57,3 +57,18 @@ puszcza_addr() {
host puszcza.gnu.org.ua |\
sed -n '1s/puszcza.gnu.org.ua has address \(.*\)/\1/p'
}
+
+: ${MF_TOPDOMAIN:=mf.gnu.org.ua}
+: ${MF_NAMESERVER:=$(resolv -qq soa -ip $MF_TOPDOMAIN)}
+export MF_TOPDOMAIN MF_NAMESERVER
+
+at_resolv_conf() {
+ if [ -n "$MF_NAMESERVER" ]; then
+ cat > resolv.conf <<EOF
+nameserver $MF_NAMESERVER
+EOF
+ MFOPTS="$MFOPTS --resolv-conf=resolv.conf"
+ fi
+}
+
+export RES_CONF_TEXT
diff --git a/tests/hasmx.at b/tests/hasmx.at
index d633ac3f..06df6b9c 100644
--- a/tests/hasmx.at
+++ b/tests/hasmx.at
@@ -20,7 +20,7 @@ AT_KEYWORDS([dns hasmx])
AT_CHECK([
AT_REQUIRE_DNS
cleardb
-mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=hasmx arg1=gnu.org.ua],
+mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=hasmx arg1=test1.$MF_TOPDOMAIN],
[EX_OK],
[State envfrom: continue
],
diff --git a/tests/hostname.at b/tests/hostname.at
index 7f5294a2..0bb5ab26 100644
--- a/tests/hostname.at
+++ b/tests/hostname.at
@@ -14,19 +14,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-AT_SETUP([Resolve cname])
+AT_SETUP([Resolve hostname])
AT_KEYWORDS([dns hostname])
-if `AT_REQUIRE_DNS`; then
- IPADDR=`puszcza_addr`
- host -tPTR $IPADDR |\
- sed -n '1s/.*\.in-addr.arpa domain name pointer \(.*\)./\1/p' > experr
-fi
-
AT_CHECK([
-test -f experr || AT_SKIP_TEST # Same as AT_REQUIRE_DNS
+AT_REQUIRE_DNS
cleardb
-mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=hostname arg1=$IPADDR],
+echo mail1.test2.$MF_TOPDOMAIN > experr
+mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=hostname arg1=198.51.100.2],
[EX_OK],
[State envfrom: continue
],
diff --git a/tests/ismx.at b/tests/ismx.at
index 63be924b..762ce66d 100644
--- a/tests/ismx.at
+++ b/tests/ismx.at
@@ -20,8 +20,7 @@ AT_KEYWORDS([dns ismx])
AT_CHECK([
AT_REQUIRE_DNS
cleardb
-name=`host -tMX gnu.org.ua | sed 's/gnu.org.ua mail is handled by [[0-9]][[0-9]]* \(.*\)\./\1/' | head -n 1`
-mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=ismx arg1=gnu.org.ua arg2=$name
+mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=ismx arg1=test1.$MF_TOPDOMAIN arg2=mail.test2.$MF_TOPDOMAIN
],
[EX_OK],
[State envfrom: continue
diff --git a/tests/rescname.at b/tests/rescname.at
index 4c8c894d..d451bb26 100644
--- a/tests/rescname.at
+++ b/tests/rescname.at
@@ -17,18 +17,15 @@
AT_SETUP([Resolve cname])
AT_KEYWORDS([dns rescname])
-if `AT_REQUIRE_DNS`; then
- puszcza_addr > experr
-fi
-
AT_CHECK([
-test -f experr || AT_SKIP_TEST # Same as AT_REQUIRE_DNS
+AT_REQUIRE_DNS
cleardb
-mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=resolve arg1=ps.gnu.org.ua],
+mailfromd MAILFROMD_OPTIONS --test $ETCDIR/dns.rc mode=resolve arg1=smtp.test1.$MF_TOPDOMAIN],
[EX_OK],
[State envfrom: continue
],
-[experr])
+[192.0.2.2
+])
AT_CLEANUP
diff --git a/tests/resolv.c b/tests/resolv.c
index 35d2d80a..a0cbc62c 100644
--- a/tests/resolv.c
+++ b/tests/resolv.c
@@ -2,14 +2,24 @@
#include <stdio.h>
#include <stdio.h>
#include <assert.h>
+#include <unistd.h>
#include <mailutils/mailutils.h>
+#include "libmf.h"
#include "dns.h"
+static int quiet = 0;
+static char const *suffix;
+static int suffix_len;
+
void
status_print(dns_status status)
{
+ if (quiet > 1)
+ return;
switch (status) {
case dns_success:
+ if (quiet)
+ return;
printf("OK");
break;
case dns_not_found:
@@ -27,7 +37,7 @@ status_print(dns_status status)
}
putchar('\n');
}
-
+
static int
hostname_cmp(const void *a, const void *b)
{
@@ -43,7 +53,12 @@ reply_print_str(struct dns_reply *reply, int sorted)
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]);
+ char const *str = reply->data.str[i];
+ int len = strlen(str);
+ if (len > suffix_len
+ && memcmp(str + len - suffix_len, suffix, suffix_len) == 0)
+ len -= suffix_len;
+ printf("%*.*s\n", len, len, reply->data.str[i]);
}
}
@@ -77,6 +92,8 @@ reply_print_ip(struct dns_reply *reply, int sorted)
void
reply_print(struct dns_reply *reply, int sorted)
{
+ if (quiet > 2)
+ return;
switch (reply->type) {
case dns_reply_str:
reply_print_str(reply, sorted);
@@ -89,6 +106,29 @@ reply_print(struct dns_reply *reply, int sorted)
abort();
}
}
+
+ static int
+ res_soa(int argc, char **argv)
+ {
+ int ip = 0;
+ struct dns_reply reply;
+ dns_status status;
+
+ if (argc >= 2) {
+ if (strcmp(argv[0], "-ip") == 0) {
+ ip = 1;
+ argc--;
+ argv++;
+ }
+ }
+ status = soa_check(argv[0], ip, &reply);
+ status_print(status);
+ if (status == dns_success) {
+ reply_print(&reply, 1);
+ dns_reply_free(&reply);
+ }
+ return status;
+ }
static int
res_a(int argc, char **argv)
@@ -103,7 +143,7 @@ res_a(int argc, char **argv)
reply_print(&reply, 1);
dns_reply_free(&reply);
}
- return 0;
+ return status;
}
static int
@@ -116,7 +156,7 @@ res_ptr(int argc, char **argv)
assert(argc == 1);
if (!inet_aton(argv[0], &in)) {
mu_error("%s: can't convert address", argv[0]);
- return 1;
+ return dns_failure;
}
status = ptr_lookup(in, &reply);
@@ -125,7 +165,7 @@ res_ptr(int argc, char **argv)
reply_print(&reply, 1);
dns_reply_free(&reply);
}
- return 0;
+ return status;
}
static int
@@ -141,7 +181,7 @@ res_ptr_val(int argc, char **argv)
reply_print(&reply, 1);
dns_reply_free(&reply);
}
- return 0;
+ return status;
}
static int
@@ -157,7 +197,7 @@ res_txt(int argc, char **argv)
reply_print(&reply, 1);
dns_reply_free(&reply);
}
- return 0;
+ return status;
}
static int
@@ -184,7 +224,7 @@ res_mx(int argc, char **argv)
reply_print(&reply, 0);
dns_reply_free(&reply);
}
- return 0;
+ return status;
}
static int
@@ -199,7 +239,7 @@ res_spf(int argc, char **argv)
printf("%s\n", record);
free(record);
}
- return 0;
+ return status;
}
static int
@@ -215,7 +255,7 @@ res_host(int argc, char **argv)
printf("%s\n", str);
free(str);
}
- return 0;
+ return status;
}
static int
@@ -231,7 +271,7 @@ res_ip(int argc, char **argv)
printf("%s\n", str);
free(str);
}
- return 0;
+ return status;
}
struct mode {
@@ -240,6 +280,7 @@ struct mode {
};
struct mode mode[] = {
+ { "soa", res_soa },
{ "host", res_host },
{ "ip", res_ip },
{ "a", res_a },
@@ -255,13 +296,65 @@ int
main(int argc, char **argv)
{
int i;
+ mu_opool_t op = NULL;
+ char *stmt;
+ char *resolv_conf = NULL;
mu_set_program_name(argv[0]);
mu_stdstream_setup(MU_STDSTREAM_RESET_NONE);
- assert(argc > 2);
+ dnsbase_init();
+ while ((i = getopt(argc, argv, "+df:h:qs:S:")) != EOF) {
+ switch (i) {
+ case 'd':
+ mu_debug_enable_category("dns", 3,
+ MU_DEBUG_LEVEL_UPTO(MU_DEBUG_PROT));
+ break;
+ case 'f':
+ resolv_conf = optarg;
+ break;
+ case 'h':
+ mu_asprintf(&stmt, "nameserver %s\n", optarg);
+ if (!op)
+ mu_opool_create(&op, MU_OPOOL_ENOMEMABRT);
+ mu_opool_appendz(op, stmt);
+ free(stmt);
+ break;
+ case 'q':
+ quiet++;
+ break;
+ case 's':
+ if (!op)
+ mu_opool_create(&op, MU_OPOOL_ENOMEMABRT);
+ mu_opool_appendz(op, optarg);
+ mu_opool_append_char(op, '\n');
+ break;
+ case 'S':
+ suffix = optarg;
+ suffix_len = strlen(suffix);
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ assert(!(resolv_conf && op));
+
+ if (resolv_conf)
+ dnsbase_file_init(resolv_conf);
+
+ if (op) {
+ mu_opool_append_char(op, 0);
+ stmt = mu_opool_finish(op, NULL);
+ dnsbase_real_init(stmt);
+ mu_opool_destroy(&op);
+ }
+
+ argc -= optind;
+ argv += optind;
+ assert(argc > 1);
for (i = 0; mode[i].name; i++) {
- if (strcmp(mode[i].name, argv[1]) == 0)
- exit(mode[i].func(argc - 2, argv + 2));
+ if (strcmp(mode[i].name, argv[0]) == 0)
+ exit(mode[i].func(argc - 1, argv + 1));
}
mu_error("%s:%d: unrecognized mode", __FILE__, __LINE__);
abort();
diff --git a/tests/resolv_a.at b/tests/resolv_a.at
new file mode 100644
index 00000000..42ab0437
--- /dev/null
+++ b/tests/resolv_a.at
@@ -0,0 +1,38 @@
+# This file is part of Mailfromd testsuite. -*- Autotest -*-
+# Copyright (C) 2017 Sergey Poznyakoff
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([A lookup])
+AT_KEYWORDS([dns resolv resolv_a])
+AT_CHECK([
+AT_REQUIRE_DNS
+resolv -f resolv.conf a bkmx.test1.$MF_TOPDOMAIN
+],
+[0],
+[OK
+192.0.2.3
+192.0.2.4
+192.0.2.5
+])
+
+AT_CHECK([
+AT_REQUIRE_DNS
+resolv a nonexistent.$MF_TOPDOMAIN
+],
+[1],
+[NOTFOUND
+])
+
+AT_CLEANUP
diff --git a/tests/resolv_mx.at b/tests/resolv_mx.at
new file mode 100644
index 00000000..58f5dd32
--- /dev/null
+++ b/tests/resolv_mx.at
@@ -0,0 +1,30 @@
+# This file is part of Mailfromd testsuite. -*- Autotest -*-
+# Copyright (C) 2017 Sergey Poznyakoff
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([MX lookup])
+AT_KEYWORDS([dns resolv resolv_mx])
+AT_CHECK([
+AT_REQUIRE_DNS
+resolv -f resolv.conf -S .$MF_TOPDOMAIN mx test1.$MF_TOPDOMAIN
+],
+[0],
+[OK
+mail.test1
+mail.test2
+bkmx.test1
+])
+AT_CLEANUP
+
diff --git a/tests/resolv_ptr.at b/tests/resolv_ptr.at
new file mode 100644
index 00000000..b6b1351b
--- /dev/null
+++ b/