The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/pf_osfp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ec26de46060aec58482a7a23f8bf7868


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.