Annotation of sys/net/pf_osfp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: *
! 18: */
! 19:
! 20: #include <sys/param.h>
! 21: #include <sys/socket.h>
! 22: #ifdef _KERNEL
! 23: # include <sys/systm.h>
! 24: #endif /* _KERNEL */
! 25: #include <sys/mbuf.h>
! 26:
! 27: #include <netinet/in.h>
! 28: #include <netinet/in_systm.h>
! 29: #include <netinet/ip.h>
! 30: #include <netinet/tcp.h>
! 31:
! 32: #include <net/if.h>
! 33: #include <net/pfvar.h>
! 34:
! 35: #include <netinet/ip6.h>
! 36: #ifdef _KERNEL
! 37: #include <netinet6/in6_var.h>
! 38: #endif
! 39:
! 40:
! 41: #ifdef _KERNEL
! 42: # define DPFPRINTF(format, x...) \
! 43: if (pf_status.debug >= PF_DEBUG_NOISY) \
! 44: printf(format , ##x)
! 45: typedef struct pool pool_t;
! 46:
! 47: #else
! 48: /* Userland equivalents so we can lend code to tcpdump et al. */
! 49:
! 50: # include <arpa/inet.h>
! 51: # include <errno.h>
! 52: # include <stdio.h>
! 53: # include <stdlib.h>
! 54: # include <string.h>
! 55: # include <netdb.h>
! 56: # define pool_t int
! 57: # define pool_get(pool, flags) malloc(*(pool))
! 58: # define pool_put(pool, item) free(item)
! 59: # define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size)
! 60:
! 61: # ifdef PFDEBUG
! 62: # include <sys/stdarg.h>
! 63: # define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
! 64: # else
! 65: # define DPFPRINTF(format, x...) ((void)0)
! 66: # endif /* PFDEBUG */
! 67: #endif /* _KERNEL */
! 68:
! 69:
! 70: SLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list;
! 71: pool_t pf_osfp_entry_pl;
! 72: pool_t pf_osfp_pl;
! 73:
! 74: struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *,
! 75: struct pf_os_fingerprint *, u_int8_t);
! 76: struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *,
! 77: struct pf_os_fingerprint *);
! 78: void pf_osfp_insert(struct pf_osfp_list *,
! 79: struct pf_os_fingerprint *);
! 80:
! 81:
! 82: #ifdef _KERNEL
! 83: /*
! 84: * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only)
! 85: * Returns the list of possible OSes.
! 86: */
! 87: struct pf_osfp_enlist *
! 88: pf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off,
! 89: const struct tcphdr *tcp)
! 90: {
! 91: struct ip *ip;
! 92: struct ip6_hdr *ip6;
! 93: char hdr[60];
! 94:
! 95: if ((pd->af != PF_INET && pd->af != PF_INET6) ||
! 96: pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp))
! 97: return (NULL);
! 98:
! 99: if (pd->af == PF_INET) {
! 100: ip = mtod(m, struct ip *);
! 101: ip6 = (struct ip6_hdr *)NULL;
! 102: } else {
! 103: ip = (struct ip *)NULL;
! 104: ip6 = mtod(m, struct ip6_hdr *);
! 105: }
! 106: if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL,
! 107: pd->af)) return (NULL);
! 108:
! 109: return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
! 110: }
! 111: #endif /* _KERNEL */
! 112:
! 113: struct pf_osfp_enlist *
! 114: pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp)
! 115: {
! 116: struct pf_os_fingerprint fp, *fpresult;
! 117: int cnt, optlen = 0;
! 118: const u_int8_t *optp;
! 119: #ifdef _KERNEL
! 120: char srcname[128];
! 121: #else
! 122: char srcname[NI_MAXHOST];
! 123: #endif
! 124:
! 125: if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
! 126: return (NULL);
! 127: if (ip) {
! 128: if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
! 129: return (NULL);
! 130: }
! 131:
! 132: memset(&fp, 0, sizeof(fp));
! 133:
! 134: if (ip) {
! 135: #ifndef _KERNEL
! 136: struct sockaddr_in sin;
! 137: #endif
! 138:
! 139: fp.fp_psize = ntohs(ip->ip_len);
! 140: fp.fp_ttl = ip->ip_ttl;
! 141: if (ip->ip_off & htons(IP_DF))
! 142: fp.fp_flags |= PF_OSFP_DF;
! 143: #ifdef _KERNEL
! 144: strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname));
! 145: #else
! 146: memset(&sin, 0, sizeof(sin));
! 147: sin.sin_family = AF_INET;
! 148: sin.sin_len = sizeof(struct sockaddr_in);
! 149: sin.sin_addr = ip->ip_src;
! 150: (void)getnameinfo((struct sockaddr *)&sin,
! 151: sizeof(struct sockaddr_in), srcname, sizeof(srcname),
! 152: NULL, 0, NI_NUMERICHOST);
! 153: #endif
! 154: }
! 155: #ifdef INET6
! 156: else if (ip6) {
! 157: #ifndef _KERNEL
! 158: struct sockaddr_in6 sin6;
! 159: #endif
! 160:
! 161: /* jumbo payload? */
! 162: fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
! 163: fp.fp_ttl = ip6->ip6_hlim;
! 164: fp.fp_flags |= PF_OSFP_DF;
! 165: fp.fp_flags |= PF_OSFP_INET6;
! 166: #ifdef _KERNEL
! 167: strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src),
! 168: sizeof(srcname));
! 169: #else
! 170: memset(&sin6, 0, sizeof(sin6));
! 171: sin6.sin6_family = AF_INET6;
! 172: sin6.sin6_len = sizeof(struct sockaddr_in6);
! 173: sin6.sin6_addr = ip6->ip6_src;
! 174: (void)getnameinfo((struct sockaddr *)&sin6,
! 175: sizeof(struct sockaddr_in6), srcname, sizeof(srcname),
! 176: NULL, 0, NI_NUMERICHOST);
! 177: #endif
! 178: }
! 179: #endif
! 180: else
! 181: return (NULL);
! 182: fp.fp_wsize = ntohs(tcp->th_win);
! 183:
! 184:
! 185: cnt = (tcp->th_off << 2) - sizeof(*tcp);
! 186: optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp));
! 187: for (; cnt > 0; cnt -= optlen, optp += optlen) {
! 188: if (*optp == TCPOPT_EOL)
! 189: break;
! 190:
! 191: fp.fp_optcnt++;
! 192: if (*optp == TCPOPT_NOP) {
! 193: fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) |
! 194: PF_OSFP_TCPOPT_NOP;
! 195: optlen = 1;
! 196: } else {
! 197: if (cnt < 2)
! 198: return (NULL);
! 199: optlen = optp[1];
! 200: if (optlen > cnt || optlen < 2)
! 201: return (NULL);
! 202: switch (*optp) {
! 203: case TCPOPT_MAXSEG:
! 204: if (optlen >= TCPOLEN_MAXSEG)
! 205: memcpy(&fp.fp_mss, &optp[2],
! 206: sizeof(fp.fp_mss));
! 207: fp.fp_tcpopts = (fp.fp_tcpopts <<
! 208: PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS;
! 209: NTOHS(fp.fp_mss);
! 210: break;
! 211: case TCPOPT_WINDOW:
! 212: if (optlen >= TCPOLEN_WINDOW)
! 213: memcpy(&fp.fp_wscale, &optp[2],
! 214: sizeof(fp.fp_wscale));
! 215: NTOHS(fp.fp_wscale);
! 216: fp.fp_tcpopts = (fp.fp_tcpopts <<
! 217: PF_OSFP_TCPOPT_BITS) |
! 218: PF_OSFP_TCPOPT_WSCALE;
! 219: break;
! 220: case TCPOPT_SACK_PERMITTED:
! 221: fp.fp_tcpopts = (fp.fp_tcpopts <<
! 222: PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK;
! 223: break;
! 224: case TCPOPT_TIMESTAMP:
! 225: if (optlen >= TCPOLEN_TIMESTAMP) {
! 226: u_int32_t ts;
! 227: memcpy(&ts, &optp[2], sizeof(ts));
! 228: if (ts == 0)
! 229: fp.fp_flags |= PF_OSFP_TS0;
! 230:
! 231: }
! 232: fp.fp_tcpopts = (fp.fp_tcpopts <<
! 233: PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS;
! 234: break;
! 235: default:
! 236: return (NULL);
! 237: }
! 238: }
! 239: optlen = MAX(optlen, 1); /* paranoia */
! 240: }
! 241:
! 242: DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
! 243: "(TS=%s,M=%s%d,W=%s%d)\n",
! 244: srcname, ntohs(tcp->th_sport),
! 245: fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
! 246: fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
! 247: (fp.fp_flags & PF_OSFP_TS0) ? "0" : "",
! 248: (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
! 249: (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
! 250: fp.fp_mss,
! 251: (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
! 252: (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
! 253: fp.fp_wscale);
! 254:
! 255: if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp,
! 256: PF_OSFP_MAXTTL_OFFSET)))
! 257: return (&fpresult->fp_oses);
! 258: return (NULL);
! 259: }
! 260:
! 261: /* Match a fingerprint ID against a list of OSes */
! 262: int
! 263: pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
! 264: {
! 265: struct pf_osfp_entry *entry;
! 266: int os_class, os_version, os_subtype;
! 267: int en_class, en_version, en_subtype;
! 268:
! 269: if (os == PF_OSFP_ANY)
! 270: return (1);
! 271: if (list == NULL) {
! 272: DPFPRINTF("osfp no match against %x\n", os);
! 273: return (os == PF_OSFP_UNKNOWN);
! 274: }
! 275: PF_OSFP_UNPACK(os, os_class, os_version, os_subtype);
! 276: SLIST_FOREACH(entry, list, fp_entry) {
! 277: PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype);
! 278: if ((os_class == PF_OSFP_ANY || en_class == os_class) &&
! 279: (os_version == PF_OSFP_ANY || en_version == os_version) &&
! 280: (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) {
! 281: DPFPRINTF("osfp matched %s %s %s %x==%x\n",
! 282: entry->fp_class_nm, entry->fp_version_nm,
! 283: entry->fp_subtype_nm, os, entry->fp_os);
! 284: return (1);
! 285: }
! 286: }
! 287: DPFPRINTF("fingerprint 0x%x didn't match\n", os);
! 288: return (0);
! 289: }
! 290:
! 291: /* Initialize the OS fingerprint system */
! 292: void
! 293: pf_osfp_initialize(void)
! 294: {
! 295: pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
! 296: "pfosfpen", &pool_allocator_nointr);
! 297: pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
! 298: "pfosfp", &pool_allocator_nointr);
! 299: SLIST_INIT(&pf_osfp_list);
! 300: }
! 301:
! 302: /* Flush the fingerprint list */
! 303: void
! 304: pf_osfp_flush(void)
! 305: {
! 306: struct pf_os_fingerprint *fp;
! 307: struct pf_osfp_entry *entry;
! 308:
! 309: while ((fp = SLIST_FIRST(&pf_osfp_list))) {
! 310: SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next);
! 311: while ((entry = SLIST_FIRST(&fp->fp_oses))) {
! 312: SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry);
! 313: pool_put(&pf_osfp_entry_pl, entry);
! 314: }
! 315: pool_put(&pf_osfp_pl, fp);
! 316: }
! 317: }
! 318:
! 319:
! 320: /* Add a fingerprint */
! 321: int
! 322: pf_osfp_add(struct pf_osfp_ioctl *fpioc)
! 323: {
! 324: struct pf_os_fingerprint *fp, fpadd;
! 325: struct pf_osfp_entry *entry;
! 326:
! 327: memset(&fpadd, 0, sizeof(fpadd));
! 328: fpadd.fp_tcpopts = fpioc->fp_tcpopts;
! 329: fpadd.fp_wsize = fpioc->fp_wsize;
! 330: fpadd.fp_psize = fpioc->fp_psize;
! 331: fpadd.fp_mss = fpioc->fp_mss;
! 332: fpadd.fp_flags = fpioc->fp_flags;
! 333: fpadd.fp_optcnt = fpioc->fp_optcnt;
! 334: fpadd.fp_wscale = fpioc->fp_wscale;
! 335: fpadd.fp_ttl = fpioc->fp_ttl;
! 336:
! 337: DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d "
! 338: "(TS=%s,M=%s%d,W=%s%d) %x\n",
! 339: fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm,
! 340: fpioc->fp_os.fp_subtype_nm,
! 341: (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" :
! 342: (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" :
! 343: (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" :
! 344: (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "",
! 345: fpadd.fp_wsize,
! 346: fpadd.fp_ttl,
! 347: (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0,
! 348: (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" :
! 349: (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "",
! 350: fpadd.fp_psize,
! 351: (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt,
! 352: (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "",
! 353: (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" :
! 354: (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "",
! 355: fpadd.fp_mss,
! 356: (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" :
! 357: (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "",
! 358: fpadd.fp_wscale,
! 359: fpioc->fp_os.fp_os);
! 360:
! 361:
! 362: if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) {
! 363: SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
! 364: if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os))
! 365: return (EEXIST);
! 366: }
! 367: if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL)
! 368: return (ENOMEM);
! 369: } else {
! 370: if ((fp = pool_get(&pf_osfp_pl, PR_NOWAIT)) == NULL)
! 371: return (ENOMEM);
! 372: memset(fp, 0, sizeof(*fp));
! 373: fp->fp_tcpopts = fpioc->fp_tcpopts;
! 374: fp->fp_wsize = fpioc->fp_wsize;
! 375: fp->fp_psize = fpioc->fp_psize;
! 376: fp->fp_mss = fpioc->fp_mss;
! 377: fp->fp_flags = fpioc->fp_flags;
! 378: fp->fp_optcnt = fpioc->fp_optcnt;
! 379: fp->fp_wscale = fpioc->fp_wscale;
! 380: fp->fp_ttl = fpioc->fp_ttl;
! 381: SLIST_INIT(&fp->fp_oses);
! 382: if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL) {
! 383: pool_put(&pf_osfp_pl, fp);
! 384: return (ENOMEM);
! 385: }
! 386: pf_osfp_insert(&pf_osfp_list, fp);
! 387: }
! 388: memcpy(entry, &fpioc->fp_os, sizeof(*entry));
! 389:
! 390: /* Make sure the strings are NUL terminated */
! 391: entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0';
! 392: entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0';
! 393: entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0';
! 394:
! 395: SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry);
! 396:
! 397: #ifdef PFDEBUG
! 398: if ((fp = pf_osfp_validate()))
! 399: printf("Invalid fingerprint list\n");
! 400: #endif /* PFDEBUG */
! 401: return (0);
! 402: }
! 403:
! 404:
! 405: /* Find a fingerprint in the list */
! 406: struct pf_os_fingerprint *
! 407: pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find,
! 408: u_int8_t ttldiff)
! 409: {
! 410: struct pf_os_fingerprint *f;
! 411:
! 412: #define MATCH_INT(_MOD, _DC, _field) \
! 413: if ((f->fp_flags & _DC) == 0) { \
! 414: if ((f->fp_flags & _MOD) == 0) { \
! 415: if (f->_field != find->_field) \
! 416: continue; \
! 417: } else { \
! 418: if (f->_field == 0 || find->_field % f->_field) \
! 419: continue; \
! 420: } \
! 421: }
! 422:
! 423: SLIST_FOREACH(f, list, fp_next) {
! 424: if (f->fp_tcpopts != find->fp_tcpopts ||
! 425: f->fp_optcnt != find->fp_optcnt ||
! 426: f->fp_ttl < find->fp_ttl ||
! 427: f->fp_ttl - find->fp_ttl > ttldiff ||
! 428: (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) !=
! 429: (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)))
! 430: continue;
! 431:
! 432: MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize)
! 433: MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss)
! 434: MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale)
! 435: if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) {
! 436: if (f->fp_flags & PF_OSFP_WSIZE_MSS) {
! 437: if (find->fp_mss == 0)
! 438: continue;
! 439:
! 440: /* Some "smart" NAT devices and DSL routers will tweak the MSS size and
! 441: * will set it to whatever is suitable for the link type.
! 442: */
! 443: #define SMART_MSS 1460
! 444: if ((find->fp_wsize % find->fp_mss ||
! 445: find->fp_wsize / find->fp_mss !=
! 446: f->fp_wsize) &&
! 447: (find->fp_wsize % SMART_MSS ||
! 448: find->fp_wsize / SMART_MSS !=
! 449: f->fp_wsize))
! 450: continue;
! 451: } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) {
! 452: if (find->fp_mss == 0)
! 453: continue;
! 454:
! 455: #define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr))
! 456: #define SMART_MTU (SMART_MSS + MTUOFF)
! 457: if ((find->fp_wsize % (find->fp_mss + MTUOFF) ||
! 458: find->fp_wsize / (find->fp_mss + MTUOFF) !=
! 459: f->fp_wsize) &&
! 460: (find->fp_wsize % SMART_MTU ||
! 461: find->fp_wsize / SMART_MTU !=
! 462: f->fp_wsize))
! 463: continue;
! 464: } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) {
! 465: if (f->fp_wsize == 0 || find->fp_wsize %
! 466: f->fp_wsize)
! 467: continue;
! 468: } else {
! 469: if (f->fp_wsize != find->fp_wsize)
! 470: continue;
! 471: }
! 472: }
! 473: return (f);
! 474: }
! 475:
! 476: return (NULL);
! 477: }
! 478:
! 479: /* Find an exact fingerprint in the list */
! 480: struct pf_os_fingerprint *
! 481: pf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find)
! 482: {
! 483: struct pf_os_fingerprint *f;
! 484:
! 485: SLIST_FOREACH(f, list, fp_next) {
! 486: if (f->fp_tcpopts == find->fp_tcpopts &&
! 487: f->fp_wsize == find->fp_wsize &&
! 488: f->fp_psize == find->fp_psize &&
! 489: f->fp_mss == find->fp_mss &&
! 490: f->fp_flags == find->fp_flags &&
! 491: f->fp_optcnt == find->fp_optcnt &&
! 492: f->fp_wscale == find->fp_wscale &&
! 493: f->fp_ttl == find->fp_ttl)
! 494: return (f);
! 495: }
! 496:
! 497: return (NULL);
! 498: }
! 499:
! 500: /* Insert a fingerprint into the list */
! 501: void
! 502: pf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins)
! 503: {
! 504: struct pf_os_fingerprint *f, *prev = NULL;
! 505:
! 506: /* XXX need to go semi tree based. can key on tcp options */
! 507:
! 508: SLIST_FOREACH(f, list, fp_next)
! 509: prev = f;
! 510: if (prev)
! 511: SLIST_INSERT_AFTER(prev, ins, fp_next);
! 512: else
! 513: SLIST_INSERT_HEAD(list, ins, fp_next);
! 514: }
! 515:
! 516: /* Fill a fingerprint by its number (from an ioctl) */
! 517: int
! 518: pf_osfp_get(struct pf_osfp_ioctl *fpioc)
! 519: {
! 520: struct pf_os_fingerprint *fp;
! 521: struct pf_osfp_entry *entry;
! 522: int num = fpioc->fp_getnum;
! 523: int i = 0;
! 524:
! 525:
! 526: memset(fpioc, 0, sizeof(*fpioc));
! 527: SLIST_FOREACH(fp, &pf_osfp_list, fp_next) {
! 528: SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
! 529: if (i++ == num) {
! 530: fpioc->fp_mss = fp->fp_mss;
! 531: fpioc->fp_wsize = fp->fp_wsize;
! 532: fpioc->fp_flags = fp->fp_flags;
! 533: fpioc->fp_psize = fp->fp_psize;
! 534: fpioc->fp_ttl = fp->fp_ttl;
! 535: fpioc->fp_wscale = fp->fp_wscale;
! 536: fpioc->fp_getnum = num;
! 537: memcpy(&fpioc->fp_os, entry,
! 538: sizeof(fpioc->fp_os));
! 539: return (0);
! 540: }
! 541: }
! 542: }
! 543:
! 544: return (EBUSY);
! 545: }
! 546:
! 547:
! 548: /* Validate that each signature is reachable */
! 549: struct pf_os_fingerprint *
! 550: pf_osfp_validate(void)
! 551: {
! 552: struct pf_os_fingerprint *f, *f2, find;
! 553:
! 554: SLIST_FOREACH(f, &pf_osfp_list, fp_next) {
! 555: memcpy(&find, f, sizeof(find));
! 556:
! 557: /* We do a few MSS/th_win percolations to make things unique */
! 558: if (find.fp_mss == 0)
! 559: find.fp_mss = 128;
! 560: if (f->fp_flags & PF_OSFP_WSIZE_MSS)
! 561: find.fp_wsize *= find.fp_mss, 1;
! 562: else if (f->fp_flags & PF_OSFP_WSIZE_MTU)
! 563: find.fp_wsize *= (find.fp_mss + 40);
! 564: else if (f->fp_flags & PF_OSFP_WSIZE_MOD)
! 565: find.fp_wsize *= 2;
! 566: if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) {
! 567: if (f2)
! 568: printf("Found \"%s %s %s\" instead of "
! 569: "\"%s %s %s\"\n",
! 570: SLIST_FIRST(&f2->fp_oses)->fp_class_nm,
! 571: SLIST_FIRST(&f2->fp_oses)->fp_version_nm,
! 572: SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm,
! 573: SLIST_FIRST(&f->fp_oses)->fp_class_nm,
! 574: SLIST_FIRST(&f->fp_oses)->fp_version_nm,
! 575: SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
! 576: else
! 577: printf("Couldn't find \"%s %s %s\"\n",
! 578: SLIST_FIRST(&f->fp_oses)->fp_class_nm,
! 579: SLIST_FIRST(&f->fp_oses)->fp_version_nm,
! 580: SLIST_FIRST(&f->fp_oses)->fp_subtype_nm);
! 581: return (f);
! 582: }
! 583: }
! 584: return (NULL);
! 585: }
CVSweb