]> git.ipfire.org Git - people/ms/dma.git/blobdiff - dns.c
dma - Fix security hole (#46)
[people/ms/dma.git] / dns.c
diff --git a/dns.c b/dns.c
index f62036d9e25fd5d050fc77e78ed6b0ec5ab338e3..bd28c4db724c9706f152bfc677a3743212cf79bd 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,8 +1,9 @@
 /*
+ * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>.
  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
- * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
+ * by Simon Schubert <2@0x2c.org>.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +34,7 @@
  */
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
@@ -66,11 +68,7 @@ add_host(int pref, const char *host, int port, struct mx_hostentry **he, size_t
        struct addrinfo hints, *res, *res0 = NULL;
        char servname[10];
        struct mx_hostentry *p;
-       size_t onhosts;
        const int count_inc = 10;
-       int err;
-
-       onhosts = *ps;
 
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_UNSPEC;
@@ -78,9 +76,26 @@ add_host(int pref, const char *host, int port, struct mx_hostentry **he, size_t
        hints.ai_protocol = IPPROTO_TCP;
 
        snprintf(servname, sizeof(servname), "%d", port);
-       err = getaddrinfo(host, servname, &hints, &res0);
-       if (err)
-               return (-1);
+       switch (getaddrinfo(host, servname, &hints, &res0)) {
+       case 0:
+               break;
+       case EAI_AGAIN:
+       case EAI_NONAME:
+               /*
+                * EAI_NONAME gets returned for:
+                * SMARTHOST set but DNS server not reachable -> defer
+                * SMARTHOST set but DNS server returns "host does not exist"
+                *           -> buggy configuration
+                *           -> either defer or bounce would be ok -> defer
+                * MX entry was returned by DNS server but name doesn't resolve
+                *           -> hopefully transient situation -> defer
+                * all other DNS problems should have been caught earlier
+                * in dns_get_mx_list().
+                */
+               goto out;
+       default:
+               return(-1);
+       }
 
        for (res = res0; res != NULL; res = res->ai_next) {
                if (*ps + 1 >= roundup(*ps, count_inc)) {
@@ -105,12 +120,12 @@ add_host(int pref, const char *host, int port, struct mx_hostentry **he, size_t
        }
        freeaddrinfo(res0);
 
-       return (*ps - onhosts);
+       return (0);
 
 out:
        if (res0 != NULL)
                freeaddrinfo(res0);
-       return (-1);
+       return (1);
 }
 
 int
@@ -127,6 +142,7 @@ dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx)
        size_t anssz;
        int pref;
        int cname_recurse;
+       int have_mx = 0;
        int err;
        int i;
 
@@ -183,6 +199,7 @@ repeat:
 
                switch (ns_rr_type(rr)) {
                case ns_t_mx:
+                       have_mx = 1;
                        pref = ns_get16(cp);
                        cp += 2;
                        err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg),
@@ -190,7 +207,9 @@ repeat:
                        if (err < 0)
                                goto transerr;
 
-                       add_host(pref, outname, port, &hosts, &nhosts);
+                       err = add_host(pref, outname, port, &hosts, &nhosts);
+                       if (err == -1)
+                               goto err;
                        break;
 
                case ns_t_cname:
@@ -225,17 +244,23 @@ err:
 
        free(ans);
 
-       if (!err) {
-               /*
-                * If we didn't find any MX, use the hostname instead.
-                */
-               if (nhosts == 0)
-                       add_host(0, searchhost, port, &hosts, &nhosts);
-
-               qsort(hosts, nhosts, sizeof(*hosts), sort_pref);
+       if (err == 0) {
+               if (!have_mx) {
+                       /*
+                        * If we didn't find any MX, use the hostname instead.
+                        */
+                       err = add_host(0, host, port, &hosts, &nhosts);
+               } else if (nhosts == 0) {
+                       /*
+                        * We did get MX, but couldn't resolve any of them
+                        * due to transient errors.
+                        */
+                       err = 1;
+               }
        }
 
        if (nhosts > 0) {
+               qsort(hosts, nhosts, sizeof(*hosts), sort_pref);
                /* terminate list */
                *hosts[nhosts].host = 0;
        } else {