/* $Id: synos.c,v 1.4 2005/12/09 07:04:07 dm Exp $ */
/*
*
* 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)
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 */
syntax highlighted by Code2HTML, v. 0.9.1