Back to index

citadel  8.12
domain.c
Go to the documentation of this file.
00001 /*
00002  * DNS lookup for SMTP sender
00003  *
00004  * Copyright (c) 1987-2011 by the citadel.org team
00005  *
00006  * This program is open source software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 #include "sysdep.h"
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <string.h>
00025 #include <netinet/in.h>
00026 #include <stdio.h>
00027 #include <syslog.h>
00028 
00029 #ifdef HAVE_RESOLV_H
00030 #include <arpa/nameser.h>
00031 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
00032 #include <arpa/nameser_compat.h>
00033 #endif
00034 #include <resolv.h>
00035 #endif
00036 #include <libcitadel.h>
00037 #include "sysdep_decls.h"
00038 #include "citadel.h"
00039 #include "domain.h"
00040 #include "server.h"
00041 #include "internet_addressing.h"
00042 
00043 
00044 /*
00045  * get_hosts() checks the Internet configuration for various types of
00046  * entries and returns them in the same format as getmx() does -- fill the
00047  * buffer with a delimited list of hosts and return the number of hosts.
00048  * 
00049  * This is used to fetch MX smarthosts, SpamAssassin hosts, etc.
00050  */
00051 int get_hosts(char *mxbuf, char *rectype) {
00052        int config_lines;
00053        int i;
00054        char buf[256];
00055        char host[256], type[256];
00056        int total_smarthosts = 0;
00057 
00058        if (inetcfg == NULL) return(0);
00059        strcpy(mxbuf, "");
00060 
00061        config_lines = num_tokens(inetcfg, '\n');
00062        for (i=0; i<config_lines; ++i) {
00063               extract_token(buf, inetcfg, i, '\n', sizeof buf);
00064               extract_token(host, buf, 0, '|', sizeof host);
00065               extract_token(type, buf, 1, '|', sizeof type);
00066 
00067               if (!strcasecmp(type, rectype)) {
00068                      strcat(mxbuf, host);
00069                      strcat(mxbuf, "|");
00070                      ++total_smarthosts;
00071               }
00072        }
00073 
00074        return(total_smarthosts);
00075 }
00076 
00077 
00078 /*
00079  * Compare the preference of two MX records.  First check by the actual
00080  * number listed in the MX record.  If they're identical, randomize the
00081  * result.
00082  */
00083 int mx_compare_pref(const void *mx1, const void *mx2) {
00084        int pref1;
00085        int pref2;
00086 
00087        pref1 = ((const struct mx *)mx1)->pref;
00088        pref2 = ((const struct mx *)mx2)->pref;
00089 
00090        if (pref1 > pref2) {
00091               return(1);
00092        }
00093        else if (pref1 < pref2) {
00094               return(0);
00095        }
00096        else {
00097               return(rand() % 2);
00098        }
00099 }
00100 
00101 
00102 /* 
00103  * getmx()
00104  *
00105  * Return one or more MX's for a mail destination.
00106  *
00107  * Upon success, it fills 'mxbuf' with one or more MX hosts, separated by
00108  * vertical bar characters, and returns the number of hosts as its return
00109  * value.  If no MX's are found, it returns 0.
00110  *
00111  */
00112 int getmx(char *mxbuf, char *dest) {
00113 
00114 #ifdef HAVE_RESOLV_H
00115        union {
00116                      u_char bytes[1024];
00117                      HEADER header;
00118     } answer;
00119 #endif
00120 
00121        int ret;
00122        unsigned char *startptr, *endptr, *ptr;
00123        char expanded_buf[1024];
00124        unsigned short pref, type;
00125        int n = 0;
00126        int qdcount;
00127 
00128        struct mx *mxrecs = NULL;
00129        int num_mxrecs = 0;
00130        
00131        /* If we're configured to send all mail to a smart-host, then our
00132         * job here is really easy.
00133         */
00134        n = get_hosts(mxbuf, "smarthost");
00135        if (n > 0) return(n);
00136 
00137        /*
00138         * No smart-host?  Look up the best MX for a site.
00139         * Make a call to the resolver library.
00140         */
00141 
00142        ret = res_query(
00143               dest,
00144               C_IN, T_MX, (unsigned char *)answer.bytes, sizeof(answer)  );
00145 
00146        if (ret < 0) {
00147               mxrecs = malloc(sizeof(struct mx));
00148               mxrecs[0].pref = 0;
00149               strcpy(mxrecs[0].host, dest);
00150               num_mxrecs = 1;
00151        }
00152        else {
00153 
00154               /* If we had to truncate, shrink the number to avoid fireworks */
00155               if (ret > sizeof(answer))
00156                      ret = sizeof(answer);
00157        
00158               startptr = &answer.bytes[0];              /* start and end of buffer */
00159               endptr = &answer.bytes[ret];
00160               ptr = startptr + HFIXEDSZ;  /* advance past header */
00161        
00162               for (qdcount = ntohs(answer.header.qdcount); qdcount--; ptr += ret + QFIXEDSZ) {
00163                      if ((ret = dn_skipname(ptr, endptr)) < 0) {
00164                             syslog(LOG_DEBUG, "dn_skipname error\n");
00165                             return(0);
00166                      }
00167               }
00168        
00169               while(1) {
00170                      memset(expanded_buf, 0, sizeof(expanded_buf));
00171                      ret = dn_expand(startptr,
00172                                    endptr,
00173                                    ptr,
00174                                    expanded_buf,
00175                                    sizeof(expanded_buf)
00176                                    );
00177                      if (ret < 0) break;
00178                      ptr += ret;
00179        
00180                      GETSHORT(type, ptr);
00181                      ptr += INT16SZ + INT32SZ;
00182                      GETSHORT(n, ptr);
00183        
00184                      if (type != T_MX) {
00185                             ptr += n;
00186                      }
00187        
00188                      else {
00189                             GETSHORT(pref, ptr);
00190                             ret = dn_expand(startptr,
00191                                           endptr,
00192                                           ptr,
00193                                           expanded_buf,
00194                                           sizeof(expanded_buf)
00195                                           );
00196                             ptr += ret;
00197        
00198                             ++num_mxrecs;
00199                             if (mxrecs == NULL) {
00200                                    mxrecs = malloc(sizeof(struct mx));
00201                             }
00202                             else {
00203                                    mxrecs = realloc(mxrecs,
00204                                        (sizeof(struct mx) * num_mxrecs) );
00205                             }
00206        
00207                             mxrecs[num_mxrecs - 1].pref = pref;
00208                             strcpy(mxrecs[num_mxrecs - 1].host,
00209                                    expanded_buf);
00210                      }
00211               }
00212        }
00213 
00214        /* Sort the MX records by preference */
00215        if (num_mxrecs > 1) {
00216               qsort(mxrecs, num_mxrecs, sizeof(struct mx), mx_compare_pref);
00217        }
00218 
00219        strcpy(mxbuf, "");
00220        for (n=0; n<num_mxrecs; ++n) {
00221               strcat(mxbuf, mxrecs[n].host);
00222               strcat(mxbuf, "|");
00223        }
00224        free(mxrecs);
00225 
00226        /* Append any fallback smart hosts we have configured.
00227         */
00228        num_mxrecs += get_hosts(&mxbuf[strlen(mxbuf)], "fallbackhost");
00229        return(num_mxrecs);
00230 }