LCOV - code coverage report
Current view: top level - net - pf_osfp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 244 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13