Logo Search packages:      
Sourcecode: mailavenger version File versions  Download package

mxcheck.C

/* $Id$ */

/*
 *
 * Copyright (C) 2003 David Mazieres (dm@uun.org)
 *
 * 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 2, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */


#include "asmtpd.h"
#include "init.h"

static u_int64_t mxcache_initno;
static qhash<str, int> mxcache;
static bhash<in_addr> addrcache;


struct mxcheck {
  const str relay;
  cbi cb;
  vec<dnsreq *> dnsv;
  vec<str> mxes;
  u_int done;
  int err;
  u_int not_best;

  mxcheck (str r, cbi c);
  ~mxcheck ();
  void finish (int e) { (*cb) (e); delete this; }
  void init (ptr<mxlist> mxl);
  void getmx (ptr<mxlist> mxl, int err);
  void geta (int i, ptr<hostent> h, int thiserr);
};

mxcheck::mxcheck (str r, cbi c)
  : relay (r), cb (c), done (0), err (0)
{
}

mxcheck::~mxcheck ()
{
  for (dnsreq **rp = dnsv.base (); rp < dnsv.lim (); rp++)
    if (*rp)
      dnsreq_cancel (*rp);
}

void
mxcheck::init (ptr<mxlist> mxl)
{
  dnsv.push_back (NULL);
  if (mxl)
    getmx (mxl, 0);
  else if (dnsreq *rq = dns_mxbyname (relay, wrap (this, &mxcheck::getmx)))
    dnsv[0] = rq;
}

void
mxcheck::getmx (ptr<mxlist> mxl, int thiserr)
{
  dnsv[0] = NULL;
  if (thiserr && dns_tmperr (thiserr)) {
    maybe_warn (strbuf () << relay << " (MX query): "
            << dns_strerror (thiserr) << "\n");
    finish (thiserr);
    return;
  }
  if (!mxl) {
#if 0
    if (!strcasecmp (relay, opt->hostname)) {
      not_best = 1;
      mxes.push_back (relay);
    }
    else
#endif
      {
      /* The old implicit MX record approach is deprecated...  people
       * should specify explicit MX records if they want mail. */
      finish (NXDOMAIN);
      return;
      }
  }
  else
    for (u_int i = 0; i < mxl->m_nmx; i++) {
      if (mxl->m_mxes[i].pref <= mxl->m_mxes[0].pref)
      not_best = i + 1;
      mxes.push_back (mxl->m_mxes[i].name);
    }

  err = NXDOMAIN;
  dnsv.setsize (mxes.size ());
  for (u_int i = 0; i < mxes.size (); i++) {
    if (dnsreq *rp
      = dns_hostbyname (mxes[i], wrap (this, &mxcheck::geta, i)))
      dnsv[i] = rp;
  }
}

void
mxcheck::geta (int i, ptr<hostent> h, int thiserr)
{
  dnsv[i] = NULL;
  done++;

  if (thiserr && dns_tmperr (thiserr) && err > 0) {
    maybe_warn (strbuf () << mxes[i] << " (A query): "
            << dns_strerror (thiserr) << "\n");
    err = thiserr;
  }

  if (h)
    for (char **ap = h->h_addr_list; *ap; ap++)
      if (addrcache[*(in_addr *) *ap]) {
      if (i < int (not_best)) {
        mxcache.insert (relay, 0);
        finish (0);
        return;
      }
      else {
        err = -1;
        mxcache.insert (relay, -1);
      }
      }

  if (done >= mxes.size ())
    finish (err);
}

static void
addrcache_init ()
{
  static ifchgcb_t *ccb;
  bool any = false;

  mxcache.clear ();
  addrcache.clear ();
  mxcache_initno = opt->configno;

  for (const sockaddr_in *ap = opt->bindaddrv.base ();
       ap < opt->bindaddrv.lim (); ap++) {
    if (ap->sin_addr.s_addr == htonl (INADDR_ANY))
      any = true;
    else
      addrcache.insert (ap->sin_addr);
  }

  if (any) {
    vec<in_addr> addrs;
    if (!myipaddrs (&addrs))
      fatal ("Failed to get my own IP address\n");
    for (in_addr *ap = addrs.base (); ap < addrs.lim (); ap++)
      addrcache.insert (*ap);

    if (!ccb)
      ccb = ifchgcb (wrap (addrcache_init));
  }
  else if (ccb)
    ifchgcb_remove (ccb);
}

void
ismxlocal (str relay, cbi cb, ptr<mxlist> mxl)
{
  if (mxcache_initno != opt->configno)
    addrcache_init ();

  relay = mytolower (relay);
  if (int *ip = mxcache[relay])
    (*cb) (*ip);
  else
    (New mxcheck (relay, cb))->init (mxl);
}


Generated by  Doxygen 1.6.0   Back to index