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

synos.c

/* $Id$ */

/*
 *
 * Copyright (C) 2004 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 "util/synos.h"

u_int32_t synos_mtu = 1500;

void
synos_clearfp (fpdat_t *fpp)
{
  VECTOR_CLEAR (&fpp->fp_opts);
  VECTOR_INIT (&fpp->fp_opts);
}

void
synos_clearos (osdat_t *odp)
{
  free (odp->od_name);
  odp->od_name = NULL;
  VECTOR_CLEAR (&odp->od_opts);
  VECTOR_INIT (&odp->od_opts);
}

int
synos_check (const fpdat_t *fpp, const osdat_t *odp)
{
  int i;
  u_int32_t mss = 0;
  int mss_valid = 0;

  if (fpp->fp_ttl > odp->od_ttl || fpp->fp_ttl + 40 < odp->od_ttl)
    return 0;
  if (fpp->fp_df != odp->od_df)
    return 0;
  if (fpp->fp_size != odp->od_size)
    return 0;
  if (fpp->fp_opts.v_size != odp->od_opts.v_size)
    return 0;

  for (i = 0; i < fpp->fp_opts.v_size; i++) {
    switch (odp->od_opts.v_vec[i].o_type) {
    case OPT_M:
      if (fpp->fp_opts.v_vec[i].o_type != OPT_M)
      return 0;
      mss = fpp->fp_opts.v_vec[i].o_val;
      mss_valid = 1;
      if (mss != odp->od_opts.v_vec[i].o_val)
      return 0;
      break;
    case OPT_MMOD:
      if (fpp->fp_opts.v_vec[i].o_type != OPT_M)
      return 0;
      mss = fpp->fp_opts.v_vec[i].o_val;
      mss_valid = 1;
      if (mss % odp->od_opts.v_vec[i].o_val)
      return 0;
      break;
    case OPT_MSTAR:
      if (fpp->fp_opts.v_vec[i].o_type != OPT_M)
      return 0;
      mss = fpp->fp_opts.v_vec[i].o_val;
      mss_valid = 1;
      break;
    default:
      if (odp->od_opts.v_vec[i].o_type != fpp->fp_opts.v_vec[i].o_type)
      return 0;
      break;
    }
  }

  switch (odp->od_wintype) {
  case WIN_ANY:
    break;
  case WIN_EQ:
    if (fpp->fp_win != odp->od_win)
      return 0;
    break;
  case WIN_S:
    if ((!synos_mtu || fpp->fp_win != odp->od_win * (synos_mtu - 40))
      && (!mss_valid || fpp->fp_win != odp->od_win * mss))
      return 0;
    break;
  case WIN_T:
    if ((!synos_mtu || fpp->fp_win != odp->od_win * synos_mtu)
      && (!mss_valid || fpp->fp_win != odp->od_win * (mss + 40)))
      return 0;
  case WIN_MOD:
    if (fpp->fp_win % odp->od_win)
      return 0;
    break;
  }

  return 1;
}

int
synos_parsefp (fpdat_t *fpp, const char *fps)
{
  int n;
  const char *s = fps;

  VECTOR_CLEAR (&fpp->fp_opts);
  VECTOR_INIT (&fpp->fp_opts);

  if (sscanf (s, "%u:%u:%d:%d%n", &fpp->fp_win, &fpp->fp_ttl,
            &fpp->fp_df, &fpp->fp_size, &n) != 4)
    return 0;
  s += n;

  for (;;) {
    tcpopt_t *opp;

    if (!*s || (s[0] == ':' && s[1] == '\0'))
      return 1;
    if (*s != ':' && *s != ',')
      return 0;
    
    s++;
    opp = VECTOR_NEXT (&fpp->fp_opts);
    switch (*s++) {
    case 'N':
      opp->o_type = OPT_N;
      break;
    case 'W':
      if (sscanf (s, "%u%n", &opp->o_val, &n) != 1)
      return 0;
      opp->o_type = OPT_W;
      s += n;
      break;
    case 'M':
      if (sscanf (s, "%u%n", &opp->o_val, &n) != 1)
      return 0;
      opp->o_type = OPT_M;
      s += n;
      break;
    case 'S':
      opp->o_type = OPT_S;
      break;
    case 'T':
      if (*s == '0') {
      opp->o_type = OPT_T0;
      s++;
      }
      else
      opp->o_type = OPT_T;
      break;
    default:
      return 0;
    }
  }
}

int
synos_parseos (osdat_t *odp, const char *line)
{
  int n;
  const char *s = line;
  int begin = 1;

  if (!*s || *s == '#' || *s == '\n')
    return -1;

  VECTOR_CLEAR (&odp->od_opts);
  VECTOR_INIT (&odp->od_opts);
  free (odp->od_name);
  odp->od_name = NULL;

  if (*s == '*') {
    odp->od_wintype = WIN_ANY;
    s++;
  }
  else {
    if (*s == '%')
      odp->od_wintype = WIN_MOD;
    else if (*s == 'S')
      odp->od_wintype = WIN_S;
    else if (*s == 'T')
      odp->od_wintype = WIN_T;
    else {
      odp->od_wintype = WIN_EQ;
      s--;
    }
    s++;
    if (sscanf (s, "%u%n", &odp->od_win, &n) != 1)
      return 0;
    s += n;
  }

  if (sscanf (s, ":%u:%d:%d:%n", &odp->od_ttl,
            &odp->od_df, &odp->od_size, &n) != 3)
    return 0;
  s += n - 1;

  for (;;) {
    tcpopt_t *opp;

    if (!*s)
      return 0;
    if (*s == ':' && !begin)
      break;
    if (*s != ':' && *s != ',')
      return 0;
    s++;
    if (begin && *s == '.') {
      s++;
      break;
    }
    begin = 0;
    
    opp = VECTOR_NEXT (&odp->od_opts);

    switch (*s++) {
    case 'N':
      opp->o_type = OPT_N;
      break;
    case 'W':
      if (*s == '*') {
      s++;
      opp->o_type = OPT_WSTAR;
      break;
      }
      if (*s == '%') {
      opp->o_type = OPT_WMOD;
      s++;
      }
      else
      opp->o_type = OPT_W;
      if (sscanf (s, "%u%n", &opp->o_val, &n) != 1)
      return 0;
      s += n;
      break;
    case 'M':
      if (*s == '*') {
      s++;
      opp->o_type = OPT_MSTAR;
      break;
      }
      if (*s == '%') {
      opp->o_type = OPT_MMOD;
      s++;
      }
      else
      opp->o_type = OPT_M;
      if (sscanf (s, "%u%n", &opp->o_val, &n) != 1)
      return 0;
      s += n;
      break;
    case 'S':
      opp->o_type = OPT_S;
      break;
    case 'T':
      if (*s == '0') {
      opp->o_type = OPT_T0;
      s++;
      }
      else
      opp->o_type = OPT_T;
      break;
    default:
      return 0;
    }
  }

  if ((s = strrchr (s, ':'))) {
    odp->od_name = xstrdup (s + 1);
    n = strlen (odp->od_name);
    if (n > 0 && odp->od_name[n - 1] == '\n')
      odp->od_name[n - 1] = '\0';
    return 1;
  }

  return 0;
}


#ifdef AVUTIL_MAIN

#include "getopt_long.h"

char *progname;
const char *opt_fpdb = DATADIR "/pf.os";
int opt_verbose;

static void usage (void) __attribute__ ((noreturn));
static void
usage (void)
{
  fprintf (stderr,
         "usage: %s [--mtu MTU] [--db FPDB] fingerprint\n",
         progname);
  exit (1);
}

static int
lookup (const char *fps)
{
  fpdat_t fp;
  osdat_t os;
  FILE *f;
  struct lnbuf buf;
  int line = 0;

  bzero (&fp, sizeof (fp));
  bzero (&os, sizeof (os));
  bzero (&buf, sizeof (buf));

  if (!synos_parsefp (&fp, fps)) {
    fprintf (stderr, "bad fingerprint '%s'\n", fps);
    synos_clearfp (&fp);
    return 1;
  }

  if (!(f = fopen (opt_fpdb, "r"))) {
    perror (opt_fpdb);
    exit (1);
  }

  while (readln (&buf, f, (size_t) -1) == LNBUF_OK) {
    int r = synos_parseos (&os, buf.buf);
    line++;
    if (r < 0)
      continue;
    if (r == 0) {
      fprintf (stderr, "%s:%d: syntax error\n", opt_fpdb, line);
      continue;
    }
    if (synos_check (&fp, &os)) {
      if (opt_verbose)
      printf ("%40s  %s\n", fps, os.od_name);
      else
      printf ("%s\n", os.od_name);

      synos_clearfp (&fp);
      synos_clearos (&os);
      fclose (f);
      return 0;
    }
  }

  if (opt_verbose)
    printf ("%40s  unknown\n", fps);
  synos_clearfp (&fp);
  synos_clearos (&os);
  fclose (f);
  return 1;
}

int
main (int argc, char **argv)
{
  struct option o[] = {
    { "version", no_argument, NULL, 256 + 'v' },
    { "mtu", required_argument, NULL, 'm' },
    { "db", required_argument, NULL, 'd' },
    { NULL, 0, NULL, 0 }
  };
  int c;
  int opt_fpdb_set = 0;

  progname = strrchr (argv[0], '/');
  if (progname)
    progname++;
  else
    progname = argv[0];

  while ((c = getopt_long (argc, argv, "+v", o, NULL)) != -1)
    switch (c) {
    case 'd':
      opt_fpdb = optarg;
      opt_fpdb_set = 1;
      break;
    case 'm':
      synos_mtu = atoi (optarg);
      if ((synos_mtu && synos_mtu < 40) || synos_mtu >= 0x10000)
      usage ();
    case 'v':
      opt_verbose = 1;
      break;
    case 256 + 'v':
      version (progname, 1);
      break;
    default:
      usage ();
      break;
    }

  if (!opt_verbose && optind + 1 != argc)
    usage ();

  if (!opt_fpdb_set && access (opt_fpdb, 0) && !access ("/etc/pf.os", 0))
    opt_fpdb = "/etc/pf.os";

  while (optind < argc)
    lookup (argv[optind++]);

  return 0;
}

#endif /* AVUTIL_MAIN */

Generated by  Doxygen 1.6.0   Back to index