Events: dns:fail Bug 3011
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 5 May 2024 17:11:45 +0000 (18:11 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 5 May 2024 17:11:45 +0000 (18:11 +0100)
14 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/acl.c
src/src/dns.c
test/confs/5708 [new file with mode: 0644]
test/confs/5709 [new file with mode: 0644]
test/log/5708 [new file with mode: 0644]
test/rejectlog/5708 [new file with mode: 0644]
test/scripts/5700-events/5708 [new file with mode: 0644]
test/scripts/5709_dnsdb_events/5709 [new file with mode: 0644]
test/scripts/5709_dnsdb_events/REQUIRES [new file with mode: 0644]
test/stderr/5709 [new file with mode: 0644]
test/stdout/5708 [new file with mode: 0644]
test/stdout/5709 [new file with mode: 0644]

index 1b4a2572d2e0dd367ff56fa4be8063fdb2546084..af5f51d6c4de2b925c2010d2d9527e8cc702b0ad 100644 (file)
@@ -43020,6 +43020,7 @@ The current list of events is:
 .itable all 0 0 4 25* left 10* center 15* center 50* left
 .row auth:fail             after    both       "per driver per authentication attempt"
 .row dane:fail              after    transport  "per connection"
 .itable all 0 0 4 25* left 10* center 15* center 50* left
 .row auth:fail             after    both       "per driver per authentication attempt"
 .row dane:fail              after    transport  "per connection"
+.row dns:fail               after    both       "per lookup"
 .row msg:complete           after    main       "per message"
 .row msg:defer              after    transport  "per message per delivery try"
 .row msg:delivery           after    transport  "per recipient"
 .row msg:complete           after    main       "per message"
 .row msg:defer              after    transport  "per message per delivery try"
 .row msg:delivery           after    transport  "per recipient"
@@ -43053,6 +43054,7 @@ with the event type:
 .itable all 0 0 2 20* left 80* left
 .row auth:fail           "smtp response"
 .row dane:fail            "failure reason"
 .itable all 0 0 2 20* left 80* left
 .row auth:fail           "smtp response"
 .row dane:fail            "failure reason"
+.row dns:fail             "failure reason, key and lookup-type"
 .row msg:defer            "error string"
 .row msg:delivery         "smtp confirmation message"
 .row msg:fail:internal    "failure reason"
 .row msg:defer            "error string"
 .row msg:delivery         "smtp confirmation message"
 .row msg:fail:internal    "failure reason"
index 58ab945beb113ca70a54e5a1f9a29489cd6acd6f..1781e05b17080eaa831862ecaa1aa1ca32a4fcde 100644 (file)
@@ -13,13 +13,15 @@ Version 4.98
  2. The dkim_verbose logging control also enables logging of signing
 
  3. The dkim_timestamps signing option now accepts zero to include a current
  2. The dkim_verbose logging control also enables logging of signing
 
  3. The dkim_timestamps signing option now accepts zero to include a current
-    timestamp but no extiry timestamp.  Code by Simon Arlott; testsuite
+    timestamp but no expiry timestamp.  Code by Simon Arlott; testsuite
     additions by jgh.
 
  4. The recipients_max main option is now expanded.
 
  5. Setting variables for "exim -be" can set a tainted value.
 
     additions by jgh.
 
  4. The recipients_max main option is now expanded.
 
  5. Setting variables for "exim -be" can set a tainted value.
 
+ 6. A dns:fail event.
+
 Version 4.97
 ------------
 
 Version 4.97
 ------------
 
index d719a937b4187d2f8c63c908fa3ca12dc8bf9fd7..4e88fc1acd126dbf5b64168fa1d2e9da92263d78 100644 (file)
@@ -4450,7 +4450,7 @@ while ((acl_current = acl))
        verbs[acl->verb], acl_name);
       if (basic_errno != ERRNO_CALLOUTDEFER)
        {
        verbs[acl->verb], acl_name);
       if (basic_errno != ERRNO_CALLOUTDEFER)
        {
-       if (search_error_message != NULL && *search_error_message != 0)
+       if (search_error_message && *search_error_message)
          *log_msgptr = search_error_message;
        if (smtp_return_error_details) f.acl_temp_details = TRUE;
        }
          *log_msgptr = search_error_message;
        if (smtp_return_error_details) f.acl_temp_details = TRUE;
        }
index 74c5a58c538df86abf3c37ea78d9db5462185313..b22f4d32701b41c8722d7d13a7d3f99e9e76a370 100644 (file)
@@ -1010,7 +1010,7 @@ won't return any.
 If fully_qualified_name is not NULL, set it to point to the full name
 returned by the resolver, if this is different to what it is given, unless
 the returned name starts with "*" as some nameservers seem to be returning
 If fully_qualified_name is not NULL, set it to point to the full name
 returned by the resolver, if this is different to what it is given, unless
 the returned name starts with "*" as some nameservers seem to be returning
-wildcards in this form.  In international mode "different" means "alabel
+wildcards in this form.  In international mode "different" means "a-label
 forms are different".
 
 Arguments:
 forms are different".
 
 Arguments:
@@ -1028,11 +1028,13 @@ Returns:                DNS_SUCCEED   successful lookup
 */
 
 int
 */
 
 int
-dns_lookup(dns_answer *dnsa, const uschar *name, int type,
-  const uschar **fully_qualified_name)
+dns_lookup(dns_answer * dnsa, const uschar * name, int type,
+  const uschar ** fully_qualified_name)
 {
 {
-const uschar *orig_name = name;
+const uschar * orig_name = name;
 BOOL secure_so_far = TRUE;
 BOOL secure_so_far = TRUE;
+int rc = DNS_FAIL;
+const uschar * errstr = NULL;
 
 /* By default, assume the resolver follows CNAME chains (and returns NODATA for
 an unterminated one). If it also does that for a CNAME loop, fine; if it returns
 
 /* By default, assume the resolver follows CNAME chains (and returns NODATA for
 an unterminated one). If it also does that for a CNAME loop, fine; if it returns
@@ -1046,12 +1048,11 @@ for (int i = 0; i <= dns_cname_loops; i++)
   uschar * data;
   dns_record cname_rr, type_rr;
   dns_scan dnss;
   uschar * data;
   dns_record cname_rr, type_rr;
   dns_scan dnss;
-  int rc;
 
   /* DNS lookup failures get passed straight back. */
 
   if ((rc = dns_basic_lookup(dnsa, name, type)) != DNS_SUCCEED)
 
   /* DNS lookup failures get passed straight back. */
 
   if ((rc = dns_basic_lookup(dnsa, name, type)) != DNS_SUCCEED)
-    return rc;
+    goto not_good;
 
   /* We should have either records of the required type, or a CNAME record,
   or both. We need to know whether both exist for getting the fully qualified
 
   /* We should have either records of the required type, or a CNAME record,
   or both. We need to know whether both exist for getting the fully qualified
@@ -1105,13 +1106,19 @@ for (int i = 0; i <= dns_cname_loops; i++)
   its not existing. */
 
   if (!cname_rr.data)
   its not existing. */
 
   if (!cname_rr.data)
-    return DNS_FAIL;
+    {
+    errstr = US"no_hit_yet_no_cname";
+    goto not_good;
+    }
 
   /* DNS data comes from the outside, hence tainted */
   data = store_get(256, GET_TAINTED);
   if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
       cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
 
   /* DNS data comes from the outside, hence tainted */
   data = store_get(256, GET_TAINTED);
   if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
       cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
-    return DNS_FAIL;
+    {
+    errstr = US"bad_expand";
+    goto not_good;
+    }
   name = data;
 
   if (!dns_is_secure(dnsa))
   name = data;
 
   if (!dns_is_secure(dnsa))
@@ -1120,11 +1127,48 @@ for (int i = 0; i <= dns_cname_loops; i++)
   DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
   }       /* Loop back to do another lookup */
 
   DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
   }       /* Loop back to do another lookup */
 
-/*Control reaches here after 10 times round the CNAME loop. Something isn't
+/* Control reaches here after 10 times round the CNAME loop. Something isn't
 right... */
 
 log_write(0, LOG_MAIN, "CNAME loop for %s encountered", orig_name);
 right... */
 
 log_write(0, LOG_MAIN, "CNAME loop for %s encountered", orig_name);
-return DNS_FAIL;
+errstr = US"cname_loop";
+
+not_good:
+  {
+  const uschar * s = NULL;
+  BOOL save_flag = f.search_find_defer;
+  uschar * save_serr = search_error_message;
+
+  if (!transport_name)
+    s = event_action;
+  else
+    for(transport_instance * tp = transports; tp; tp = tp->next)
+      if (Ustrcmp(tp->name, transport_name) == 0)
+       { s = tp->event_action; break; }
+
+  if (s)
+    {
+    if (Ustrchr(name, ':'))    /* unlikely, but may as well bugproof */
+      {
+      gstring * g = NULL;
+      while (*name)
+       {
+       if (*name == ':') g = string_catn(g, name, 1);
+       g = string_catn(g, name++, 1);
+       }
+      name = string_from_gstring(g);
+      }
+    event_raise(s, US"dns:fail",
+      string_sprintf("%s:%s:%s",
+       errstr ? errstr : dns_rc_names[rc], name, dns_text_type(type)),
+      NULL);
+    }
+
+  /*XXX what other state could an expansion in the eventhandler mess up? */
+  search_error_message = save_serr;
+  f.search_find_defer = save_flag;
+  return rc;
+  }
 }
 
 
 }
 
 
diff --git a/test/confs/5708 b/test/confs/5708
new file mode 100644 (file)
index 0000000..4fc0e9b
--- /dev/null
@@ -0,0 +1,32 @@
+# Exim test configuration 5708
+# Check for event on dns lookup fail
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept verify = helo
+
+event_action = ${acl {accept logwrite = M <$event_name> <$event_data>}}
+
+# ----- Routers -----
+begin routers
+all:
+  driver = accept
+  transport = all
+  errors_to = ""
+
+# ----- Transports -----
+begin transports
+all:
+  driver = smtp
+  hosts = ${if inlist {$domain} {nonexistent.test.ex} {$value}}
+  event_action = ${acl {accept logwrite = T <$event_name> <$event_data>}}
+
+# ------ Retries ----
+begin retry
+* * F,10m,2d
+
+# End
diff --git a/test/confs/5709 b/test/confs/5709
new file mode 100644 (file)
index 0000000..e663b86
--- /dev/null
@@ -0,0 +1,8 @@
+# Exim test configuration 5709
+# Check for event on dnsdb lookup fail
+
+.include DIR/aux-var/std_conf_prefix
+primary_hostname = myhost.test.ex
+event_action = ${acl {accept logwrite = <$event_name> <$event_data>}}
+
+# End
diff --git a/test/log/5708 b/test/log/5708
new file mode 100644 (file)
index 0000000..89eba81
--- /dev/null
@@ -0,0 +1,16 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=p1234, no queue runs, listening for SMTP on port PORT_D
+1999-03-02 09:44:33 M <dns:fail> <DNS_NOMATCH:nonexistent.test.ex:AAAA>
+1999-03-02 09:44:33 M <dns:fail> <DNS_NOMATCH:nonexistent.test.ex:A>
+1999-03-02 09:44:33 H=(nonexistent.test.ex) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
+1999-03-02 09:44:33 M <dns:fail> <DNS_NOMATCH:rhubarb.test.ex:AAAA>
+1999-03-02 09:44:33 M <dns:fail> <DNS_NOMATCH:rhubarb.test.ex:A>
+1999-03-02 09:44:33 H=(badcname.test.ex) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
+1999-03-02 09:44:33 M <dns:fail> <DNS_AGAIN:test.again.dns:AAAA>
+1999-03-02 09:44:33 M <dns:fail> <DNS_AGAIN:test.again.dns:A>
+1999-03-02 09:44:33 H=(test.again.dns) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 <= a@b H=(localhost) [127.0.0.1] P=smtp S=sss
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 T <dns:fail> <DNS_NOMATCH:nonexistent.test.ex:AAAA>
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 T <dns:fail> <DNS_NOMATCH:nonexistent.test.ex:A>
+1999-03-02 09:44:33 10HmaX-000000005vi-0000 == bad_a@nonexistent.test.ex <bad_A@nonexistent.test.ex> R=all T=all defer (-32): failed to lookup IP address for nonexistent.test.ex
diff --git a/test/rejectlog/5708 b/test/rejectlog/5708
new file mode 100644 (file)
index 0000000..98f38cd
--- /dev/null
@@ -0,0 +1,5 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 H=(nonexistent.test.ex) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
+1999-03-02 09:44:33 H=(badcname.test.ex) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
+1999-03-02 09:44:33 H=(test.again.dns) [127.0.0.1] F=<a@b> rejected RCPT <c@d>
diff --git a/test/scripts/5700-events/5708 b/test/scripts/5700-events/5708
new file mode 100644 (file)
index 0000000..9cb9508
--- /dev/null
@@ -0,0 +1,62 @@
+# event on dns lookup fail
+
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# no A record
+client 127.0.0.1 PORT_D
+??? 220
+HELO nonexistent.test.ex
+??? 250
+MAIL FROM:<a@b>
+??? 250
+RCPT TO:<c@d>
+??? 550
+QUIT
+??? 221
+****
+# CNAME to no-A-record
+client 127.0.0.1 PORT_D
+??? 220
+HELO badcname.test.ex
+??? 250
+MAIL FROM:<a@b>
+??? 250
+RCPT TO:<c@d>
+??? 550
+QUIT
+??? 221
+****
+# defer from dns lookup
+client 127.0.0.1 PORT_D
+??? 220
+HELO test.again.dns
+??? 250
+MAIL FROM:<a@b>
+??? 250
+RCPT TO:<c@d>
+??? 550
+QUIT
+??? 221
+****
+# success in RCPT ACL; no-A in transport
+client 127.0.0.1 PORT_D
+??? 220
+HELO localhost
+??? 250
+MAIL FROM:<a@b>
+??? 250
+RCPT TO:<bad_A@nonexistent.test.ex>
+??? 250 Accepted
+DATA
+??? 354
+Subject: test
+.
+??? 250
+QUIT
+??? 221
+****
+#
+sleep 1
+killdaemon
+no_msglog_check
diff --git a/test/scripts/5709_dnsdb_events/5709 b/test/scripts/5709_dnsdb_events/5709
new file mode 100644 (file)
index 0000000..03ca7ed
--- /dev/null
@@ -0,0 +1,8 @@
+# event on dnsdb lookup fail
+
+exim -be
+bad_a                  ${lookup dnsdb{a=nonexistent.test.ex}{$value}{FAIL}}
+badcname               ${lookup dnsdb{a=badcname.test.ex}{$value}{FAIL}}
+defer                  ${lookup dnsdb{a=test.again.dns}{$value}{FAIL}}
+good                   ${lookup dnsdb{txt=test.ex}{$value}{FAIL}}
+****
diff --git a/test/scripts/5709_dnsdb_events/REQUIRES b/test/scripts/5709_dnsdb_events/REQUIRES
new file mode 100644 (file)
index 0000000..22e0978
--- /dev/null
@@ -0,0 +1,2 @@
+lookup dnsdb
+support Event
diff --git a/test/stderr/5709 b/test/stderr/5709
new file mode 100644 (file)
index 0000000..279f0ba
--- /dev/null
@@ -0,0 +1,3 @@
+1999-03-02 09:44:33 <dns:fail> <DNS_NOMATCH:nonexistent.test.ex:A>
+1999-03-02 09:44:33 <dns:fail> <DNS_NOMATCH:rhubarb.test.ex:A>
+1999-03-02 09:44:33 <dns:fail> <DNS_AGAIN:test.again.dns:A>
diff --git a/test/stdout/5708 b/test/stdout/5708
new file mode 100644 (file)
index 0000000..d2c78b4
--- /dev/null
@@ -0,0 +1,71 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO nonexistent.test.ex
+??? 250
+<<< 250 myhost.test.ex Hello nonexistent.test.ex [127.0.0.1]
+>>> MAIL FROM:<a@b>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<c@d>
+??? 550
+<<< 550 Administrative prohibition
+>>> QUIT
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO badcname.test.ex
+??? 250
+<<< 250 myhost.test.ex Hello badcname.test.ex [127.0.0.1]
+>>> MAIL FROM:<a@b>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<c@d>
+??? 550
+<<< 550 Administrative prohibition
+>>> QUIT
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO test.again.dns
+??? 250
+<<< 250 myhost.test.ex Hello test.again.dns [127.0.0.1]
+>>> MAIL FROM:<a@b>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<c@d>
+??? 550
+<<< 550 Administrative prohibition
+>>> QUIT
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO localhost
+??? 250
+<<< 250 myhost.test.ex Hello localhost [127.0.0.1]
+>>> MAIL FROM:<a@b>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<bad_A@nonexistent.test.ex>
+??? 250 Accepted
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: test
+>>> .
+??? 250
+<<< 250 OK id=10HmaX-000000005vi-0000
+>>> QUIT
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
diff --git a/test/stdout/5709 b/test/stdout/5709
new file mode 100644 (file)
index 0000000..c1a7fde
--- /dev/null
@@ -0,0 +1,5 @@
+> bad_a                        FAIL
+> badcname             FAIL
+> Failed: lookup of "a=test.again.dns" gave DEFER: 
+> good                 A TXT record for test.ex.
+>