[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     ! 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