[BACK]Return to pf_osfp.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/pf_osfp.c, Revision 1.1.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