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

osguess.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 "qhash.h"
#include "list.h"
#include "util/synos.h"

struct oscell : public osdat {
private:
  oscell (const oscell &);
  oscell &operator= (const oscell &);
public:
  tailq_entry<oscell> link;
  oscell () { bzero ((osdat_t *) this, sizeof (osdat_t)); }
  ~oscell () { synos_clearos (this); }
};

struct oslist {
private:
  oslist (const oslist &);
  oslist &operator= (const oslist &);
public:
  tailq<oscell, &oscell::link> q;
  oslist () {}
  ~oslist ();
  oscell *lookup (const fpdat_t *fpp);
  void insert (oscell *oc) { q.insert_tail (oc); }
};

static u_int64_t ostab_initno;
static qhash<u_int, ref<oslist> > ostab;

oslist::~oslist ()
{
  while (oscell *oc = q.first) {
    q.remove (oc);
    delete oc;
  }
}

oscell *
oslist::lookup (const fpdat_t *fpp)
{
  for (oscell *oc = q.first; oc; oc = q.next (oc))
    if (synos_check (fpp, oc))
      return oc;
  return NULL;
}

inline char
optletter (int type)
{
  switch (type) {
  case tcpopt::OPT_M:
  case tcpopt::OPT_MMOD:
  case tcpopt::OPT_MSTAR:
    return 'M';
  case tcpopt::OPT_N:
    return 'N';
  case tcpopt::OPT_T:
    return 'T';
  case tcpopt::OPT_T0:
    return '0';
  case tcpopt::OPT_S:
    return 'S';
  case tcpopt::OPT_W:
  case tcpopt::OPT_WMOD:
  case tcpopt::OPT_WSTAR:
    return 'W';
  default:
    panic ("bad TCP option type %d\n", type);
    return 0;
  }
}

static u_int
hash_fixed (bool df, u_int16_t size, const tcpopt_t *opts, u_int nopts)
{
  char c = df;
  u_int seed = hash_bytes (&c, 1);
  seed = hash_bytes (&size, 2, seed);
  for (u_int i = 0; i < nopts; i++) {
    c = optletter (opts[i].o_type);
    seed = hash_bytes (&c, 1, seed);
  }
  return seed;
}

static bool
ostab_init ()
{
  ostab.clear ();
  ostab_initno = 0;

  int fd = open (path_pfos, O_RDONLY);
  if (fd < 0) {
    warn ("%s: %m\n", path_pfos.cstr ());
    ostab_initno = opt->configno;
    return false;
  }

  suio buf;
  u_int lineno = 0, nfp = 0;
  while (buf.input (fd) > 0)
    while (str line = suio_getline (&buf)) {
      lineno++;
      if (!line.len () || line[0] == '#')
      continue;
      oscell *oc = New oscell;
      if (synos_parseos (oc, line)) {
      u_int ln = hash_fixed (oc->od_df, oc->od_size,
                         oc->od_opts.v_vec, oc->od_opts.v_size);
      ptr<oslist> ol = ostab[ln];
      if (!ol) {
        ol = New refcounted<oslist>;
        ostab.insert (ln, ol);
      }
      ol->insert (oc);
      nfp++;
      }
      else {
      warn << path_pfos << ":" << lineno << " bad fingerprint template\n";
      delete oc;
      }
    }

  warn ("%s: %d fingerprints, %ld buckets\n", path_pfos.cstr (),
      nfp, long (ostab.size ()));

  ostab_initno = opt->configno;
  return true;
}

const char *
synos_guess (str synfp)
{
  if (!synfp)
    return NULL;

  fpdat_t fp;
  bzero (&fp, sizeof (fp));
  if (!synos_parsefp (&fp, synfp)) {
    warn << "bad syn fingerprint `" << synfp << "'\n";
    synos_clearfp (&fp);
    return NULL;
  }

  if (ostab_initno != opt->configno) {
    synos_mtu = opt->osguess_mtu;
    ostab_init ();
  }

  const char *ret = NULL;
  u_int ln = hash_fixed (fp.fp_df, fp.fp_size,
                   fp.fp_opts.v_vec, fp.fp_opts.v_size);
  if (oslist *ol = ostab[ln])
    if (oscell *oc = ol->lookup (&fp))
      ret = oc->od_name;
    
  synos_clearfp (&fp);
  return ret;
}

Generated by  Doxygen 1.6.0   Back to index