pf_osfp.c revision 257176
1244769Sglebius/*- 2126258Smlaier * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> 3126258Smlaier * 4126258Smlaier * Permission to use, copy, modify, and distribute this software for any 5126258Smlaier * purpose with or without fee is hereby granted, provided that the above 6126258Smlaier * copyright notice and this permission notice appear in all copies. 7126258Smlaier * 8126258Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9126258Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10126258Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11126258Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12126258Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13126258Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14126258Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15126258Smlaier * 16244769Sglebius * $OpenBSD: pf_osfp.c,v 1.14 2008/06/12 18:17:01 henning Exp $ 17126258Smlaier */ 18126258Smlaier 19171168Smlaier#include <sys/cdefs.h> 20171168Smlaier__FBSDID("$FreeBSD: head/sys/netpfil/pf/pf_osfp.c 257176 2013-10-26 17:58:36Z glebius $"); 21171168Smlaier 22126258Smlaier#include <sys/param.h> 23240233Sglebius#include <sys/kernel.h> 24257176Sglebius#include <sys/lock.h> 25257176Sglebius#include <sys/mbuf.h> 26257176Sglebius#include <sys/rwlock.h> 27126258Smlaier#include <sys/socket.h> 28126258Smlaier 29126258Smlaier#include <netinet/in.h> 30126258Smlaier#include <netinet/ip.h> 31126258Smlaier#include <netinet/tcp.h> 32126258Smlaier 33126258Smlaier#include <net/if.h> 34257176Sglebius#include <net/vnet.h> 35126258Smlaier#include <net/pfvar.h> 36126258Smlaier 37126258Smlaier#include <netinet/ip6.h> 38126258Smlaier 39240233Sglebiusstatic MALLOC_DEFINE(M_PFOSFP, "pf_osfp", "pf(4) operating system fingerprints"); 40223637Sbz#define DPFPRINTF(format, x...) \ 41223637Sbz if (V_pf_status.debug >= PF_DEBUG_NOISY) \ 42223637Sbz printf(format , ##x) 43126258Smlaier 44223637SbzSLIST_HEAD(pf_osfp_list, pf_os_fingerprint); 45240233Sglebiusstatic VNET_DEFINE(struct pf_osfp_list, pf_osfp_list) = 46240233Sglebius SLIST_HEAD_INITIALIZER(); 47223637Sbz#define V_pf_osfp_list VNET(pf_osfp_list) 48126258Smlaier 49240233Sglebiusstatic struct pf_osfp_enlist *pf_osfp_fingerprint_hdr(const struct ip *, 50240233Sglebius const struct ip6_hdr *, 51240233Sglebius const struct tcphdr *); 52240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *, 53126258Smlaier struct pf_os_fingerprint *, u_int8_t); 54240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *, 55126258Smlaier struct pf_os_fingerprint *); 56240233Sglebiusstatic void pf_osfp_insert(struct pf_osfp_list *, 57126258Smlaier struct pf_os_fingerprint *); 58240233Sglebius#ifdef PFDEBUG 59240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_validate(void); 60240233Sglebius#endif 61126258Smlaier 62126258Smlaier/* 63126258Smlaier * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only) 64126258Smlaier * Returns the list of possible OSes. 65126258Smlaier */ 66126258Smlaierstruct pf_osfp_enlist * 67126258Smlaierpf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off, 68126258Smlaier const struct tcphdr *tcp) 69126258Smlaier{ 70126258Smlaier struct ip *ip; 71171168Smlaier struct ip6_hdr *ip6; 72126258Smlaier char hdr[60]; 73126258Smlaier 74171168Smlaier if ((pd->af != PF_INET && pd->af != PF_INET6) || 75171168Smlaier pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp)) 76126258Smlaier return (NULL); 77126258Smlaier 78171168Smlaier if (pd->af == PF_INET) { 79171168Smlaier ip = mtod(m, struct ip *); 80171168Smlaier ip6 = (struct ip6_hdr *)NULL; 81171168Smlaier } else { 82171168Smlaier ip = (struct ip *)NULL; 83171168Smlaier ip6 = mtod(m, struct ip6_hdr *); 84171168Smlaier } 85171168Smlaier if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, 86171168Smlaier pd->af)) return (NULL); 87126258Smlaier 88171168Smlaier return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr)); 89126258Smlaier} 90126258Smlaier 91240233Sglebiusstatic struct pf_osfp_enlist * 92171168Smlaierpf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) 93126258Smlaier{ 94126258Smlaier struct pf_os_fingerprint fp, *fpresult; 95126258Smlaier int cnt, optlen = 0; 96126261Smlaier const u_int8_t *optp; 97171168Smlaier char srcname[128]; 98126258Smlaier 99171168Smlaier if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN) 100126258Smlaier return (NULL); 101171168Smlaier if (ip) { 102171168Smlaier if ((ip->ip_off & htons(IP_OFFMASK)) != 0) 103171168Smlaier return (NULL); 104171168Smlaier } 105126258Smlaier 106126258Smlaier memset(&fp, 0, sizeof(fp)); 107126258Smlaier 108171168Smlaier if (ip) { 109171168Smlaier fp.fp_psize = ntohs(ip->ip_len); 110171168Smlaier fp.fp_ttl = ip->ip_ttl; 111171168Smlaier if (ip->ip_off & htons(IP_DF)) 112171168Smlaier fp.fp_flags |= PF_OSFP_DF; 113171168Smlaier strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname)); 114171168Smlaier } 115171168Smlaier#ifdef INET6 116171168Smlaier else if (ip6) { 117171168Smlaier /* jumbo payload? */ 118171168Smlaier fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); 119171168Smlaier fp.fp_ttl = ip6->ip6_hlim; 120126258Smlaier fp.fp_flags |= PF_OSFP_DF; 121171168Smlaier fp.fp_flags |= PF_OSFP_INET6; 122171168Smlaier strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src), 123171168Smlaier sizeof(srcname)); 124171168Smlaier } 125171168Smlaier#endif 126171168Smlaier else 127171168Smlaier return (NULL); 128126258Smlaier fp.fp_wsize = ntohs(tcp->th_win); 129126258Smlaier 130126258Smlaier 131126258Smlaier cnt = (tcp->th_off << 2) - sizeof(*tcp); 132126261Smlaier optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp)); 133126258Smlaier for (; cnt > 0; cnt -= optlen, optp += optlen) { 134126258Smlaier if (*optp == TCPOPT_EOL) 135126258Smlaier break; 136126258Smlaier 137126258Smlaier fp.fp_optcnt++; 138126258Smlaier if (*optp == TCPOPT_NOP) { 139126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) | 140126258Smlaier PF_OSFP_TCPOPT_NOP; 141126258Smlaier optlen = 1; 142126258Smlaier } else { 143126258Smlaier if (cnt < 2) 144126258Smlaier return (NULL); 145126258Smlaier optlen = optp[1]; 146126258Smlaier if (optlen > cnt || optlen < 2) 147126258Smlaier return (NULL); 148126258Smlaier switch (*optp) { 149126258Smlaier case TCPOPT_MAXSEG: 150126258Smlaier if (optlen >= TCPOLEN_MAXSEG) 151126258Smlaier memcpy(&fp.fp_mss, &optp[2], 152126258Smlaier sizeof(fp.fp_mss)); 153126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 154126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS; 155126258Smlaier NTOHS(fp.fp_mss); 156126258Smlaier break; 157126258Smlaier case TCPOPT_WINDOW: 158126258Smlaier if (optlen >= TCPOLEN_WINDOW) 159126258Smlaier memcpy(&fp.fp_wscale, &optp[2], 160126258Smlaier sizeof(fp.fp_wscale)); 161126258Smlaier NTOHS(fp.fp_wscale); 162126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 163126258Smlaier PF_OSFP_TCPOPT_BITS) | 164126258Smlaier PF_OSFP_TCPOPT_WSCALE; 165126258Smlaier break; 166126258Smlaier case TCPOPT_SACK_PERMITTED: 167126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 168126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK; 169126258Smlaier break; 170126258Smlaier case TCPOPT_TIMESTAMP: 171126258Smlaier if (optlen >= TCPOLEN_TIMESTAMP) { 172126258Smlaier u_int32_t ts; 173126258Smlaier memcpy(&ts, &optp[2], sizeof(ts)); 174126258Smlaier if (ts == 0) 175126258Smlaier fp.fp_flags |= PF_OSFP_TS0; 176126258Smlaier 177126258Smlaier } 178126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 179126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS; 180126258Smlaier break; 181126258Smlaier default: 182126258Smlaier return (NULL); 183126258Smlaier } 184126258Smlaier } 185126258Smlaier optlen = MAX(optlen, 1); /* paranoia */ 186126258Smlaier } 187126258Smlaier 188126258Smlaier DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) " 189126258Smlaier "(TS=%s,M=%s%d,W=%s%d)\n", 190171168Smlaier srcname, ntohs(tcp->th_sport), 191126258Smlaier fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0, 192126258Smlaier fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt, 193126258Smlaier (fp.fp_flags & PF_OSFP_TS0) ? "0" : "", 194126258Smlaier (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 195126258Smlaier (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 196126258Smlaier fp.fp_mss, 197126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 198126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 199126258Smlaier fp.fp_wscale); 200126258Smlaier 201223637Sbz if ((fpresult = pf_osfp_find(&V_pf_osfp_list, &fp, 202126258Smlaier PF_OSFP_MAXTTL_OFFSET))) 203126258Smlaier return (&fpresult->fp_oses); 204126258Smlaier return (NULL); 205126258Smlaier} 206126258Smlaier 207126258Smlaier/* Match a fingerprint ID against a list of OSes */ 208126258Smlaierint 209126258Smlaierpf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os) 210126258Smlaier{ 211126258Smlaier struct pf_osfp_entry *entry; 212126258Smlaier int os_class, os_version, os_subtype; 213126258Smlaier int en_class, en_version, en_subtype; 214126258Smlaier 215126258Smlaier if (os == PF_OSFP_ANY) 216126258Smlaier return (1); 217126258Smlaier if (list == NULL) { 218126258Smlaier DPFPRINTF("osfp no match against %x\n", os); 219126258Smlaier return (os == PF_OSFP_UNKNOWN); 220126258Smlaier } 221126258Smlaier PF_OSFP_UNPACK(os, os_class, os_version, os_subtype); 222126258Smlaier SLIST_FOREACH(entry, list, fp_entry) { 223126258Smlaier PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype); 224126258Smlaier if ((os_class == PF_OSFP_ANY || en_class == os_class) && 225126258Smlaier (os_version == PF_OSFP_ANY || en_version == os_version) && 226126258Smlaier (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) { 227126258Smlaier DPFPRINTF("osfp matched %s %s %s %x==%x\n", 228126258Smlaier entry->fp_class_nm, entry->fp_version_nm, 229126258Smlaier entry->fp_subtype_nm, os, entry->fp_os); 230126258Smlaier return (1); 231126258Smlaier } 232126258Smlaier } 233126258Smlaier DPFPRINTF("fingerprint 0x%x didn't match\n", os); 234126258Smlaier return (0); 235126258Smlaier} 236126258Smlaier 237126258Smlaier/* Flush the fingerprint list */ 238126258Smlaiervoid 239126258Smlaierpf_osfp_flush(void) 240126258Smlaier{ 241126258Smlaier struct pf_os_fingerprint *fp; 242126258Smlaier struct pf_osfp_entry *entry; 243126258Smlaier 244223637Sbz while ((fp = SLIST_FIRST(&V_pf_osfp_list))) { 245223637Sbz SLIST_REMOVE_HEAD(&V_pf_osfp_list, fp_next); 246126258Smlaier while ((entry = SLIST_FIRST(&fp->fp_oses))) { 247126258Smlaier SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry); 248240233Sglebius free(entry, M_PFOSFP); 249126258Smlaier } 250240233Sglebius free(fp, M_PFOSFP); 251126258Smlaier } 252126258Smlaier} 253126258Smlaier 254126258Smlaier 255126258Smlaier/* Add a fingerprint */ 256126258Smlaierint 257126258Smlaierpf_osfp_add(struct pf_osfp_ioctl *fpioc) 258126258Smlaier{ 259126258Smlaier struct pf_os_fingerprint *fp, fpadd; 260126258Smlaier struct pf_osfp_entry *entry; 261126258Smlaier 262240233Sglebius PF_RULES_WASSERT(); 263240233Sglebius 264126258Smlaier memset(&fpadd, 0, sizeof(fpadd)); 265126258Smlaier fpadd.fp_tcpopts = fpioc->fp_tcpopts; 266126258Smlaier fpadd.fp_wsize = fpioc->fp_wsize; 267126258Smlaier fpadd.fp_psize = fpioc->fp_psize; 268126258Smlaier fpadd.fp_mss = fpioc->fp_mss; 269126258Smlaier fpadd.fp_flags = fpioc->fp_flags; 270126258Smlaier fpadd.fp_optcnt = fpioc->fp_optcnt; 271126258Smlaier fpadd.fp_wscale = fpioc->fp_wscale; 272126258Smlaier fpadd.fp_ttl = fpioc->fp_ttl; 273126258Smlaier 274223637Sbz#if 0 /* XXX RYAN wants to fix logging */ 275126258Smlaier DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d " 276126258Smlaier "(TS=%s,M=%s%d,W=%s%d) %x\n", 277126258Smlaier fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm, 278126258Smlaier fpioc->fp_os.fp_subtype_nm, 279126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" : 280126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" : 281126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" : 282126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "", 283126258Smlaier fpadd.fp_wsize, 284126258Smlaier fpadd.fp_ttl, 285126258Smlaier (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0, 286126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" : 287126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "", 288126258Smlaier fpadd.fp_psize, 289126258Smlaier (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt, 290126258Smlaier (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "", 291126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 292126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 293126258Smlaier fpadd.fp_mss, 294126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 295126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 296126258Smlaier fpadd.fp_wscale, 297126258Smlaier fpioc->fp_os.fp_os); 298223637Sbz#endif 299126258Smlaier 300223637Sbz if ((fp = pf_osfp_find_exact(&V_pf_osfp_list, &fpadd))) { 301126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 302126258Smlaier if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os)) 303126258Smlaier return (EEXIST); 304126258Smlaier } 305240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 306240233Sglebius == NULL) 307126258Smlaier return (ENOMEM); 308126258Smlaier } else { 309240233Sglebius if ((fp = malloc(sizeof(*fp), M_PFOSFP, M_ZERO | M_NOWAIT)) 310240233Sglebius == NULL) 311126258Smlaier return (ENOMEM); 312126258Smlaier fp->fp_tcpopts = fpioc->fp_tcpopts; 313126258Smlaier fp->fp_wsize = fpioc->fp_wsize; 314126258Smlaier fp->fp_psize = fpioc->fp_psize; 315126258Smlaier fp->fp_mss = fpioc->fp_mss; 316126258Smlaier fp->fp_flags = fpioc->fp_flags; 317126258Smlaier fp->fp_optcnt = fpioc->fp_optcnt; 318126258Smlaier fp->fp_wscale = fpioc->fp_wscale; 319126258Smlaier fp->fp_ttl = fpioc->fp_ttl; 320126258Smlaier SLIST_INIT(&fp->fp_oses); 321240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 322240233Sglebius == NULL) { 323240233Sglebius free(fp, M_PFOSFP); 324126258Smlaier return (ENOMEM); 325126258Smlaier } 326223637Sbz pf_osfp_insert(&V_pf_osfp_list, fp); 327126258Smlaier } 328126258Smlaier memcpy(entry, &fpioc->fp_os, sizeof(*entry)); 329126258Smlaier 330126258Smlaier /* Make sure the strings are NUL terminated */ 331126258Smlaier entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0'; 332126258Smlaier entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0'; 333126258Smlaier entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0'; 334126258Smlaier 335126258Smlaier SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry); 336126258Smlaier 337126258Smlaier#ifdef PFDEBUG 338126258Smlaier if ((fp = pf_osfp_validate())) 339126258Smlaier printf("Invalid fingerprint list\n"); 340126258Smlaier#endif /* PFDEBUG */ 341126258Smlaier return (0); 342126258Smlaier} 343126258Smlaier 344126258Smlaier 345126258Smlaier/* Find a fingerprint in the list */ 346240233Sglebiusstatic struct pf_os_fingerprint * 347126258Smlaierpf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, 348126258Smlaier u_int8_t ttldiff) 349126258Smlaier{ 350126258Smlaier struct pf_os_fingerprint *f; 351126258Smlaier 352223637Sbz#define MATCH_INT(_MOD, _DC, _field) \ 353126258Smlaier if ((f->fp_flags & _DC) == 0) { \ 354126258Smlaier if ((f->fp_flags & _MOD) == 0) { \ 355126258Smlaier if (f->_field != find->_field) \ 356126258Smlaier continue; \ 357126258Smlaier } else { \ 358126258Smlaier if (f->_field == 0 || find->_field % f->_field) \ 359126258Smlaier continue; \ 360126258Smlaier } \ 361126258Smlaier } 362126258Smlaier 363126258Smlaier SLIST_FOREACH(f, list, fp_next) { 364126258Smlaier if (f->fp_tcpopts != find->fp_tcpopts || 365126258Smlaier f->fp_optcnt != find->fp_optcnt || 366126258Smlaier f->fp_ttl < find->fp_ttl || 367126258Smlaier f->fp_ttl - find->fp_ttl > ttldiff || 368126258Smlaier (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) != 369126258Smlaier (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0))) 370126258Smlaier continue; 371126258Smlaier 372126258Smlaier MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize) 373126258Smlaier MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss) 374126258Smlaier MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale) 375126258Smlaier if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) { 376126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) { 377126258Smlaier if (find->fp_mss == 0) 378126258Smlaier continue; 379126258Smlaier 380223637Sbz/* 381223637Sbz * Some "smart" NAT devices and DSL routers will tweak the MSS size and 382126258Smlaier * will set it to whatever is suitable for the link type. 383126258Smlaier */ 384223637Sbz#define SMART_MSS 1460 385126258Smlaier if ((find->fp_wsize % find->fp_mss || 386126258Smlaier find->fp_wsize / find->fp_mss != 387126258Smlaier f->fp_wsize) && 388126258Smlaier (find->fp_wsize % SMART_MSS || 389126258Smlaier find->fp_wsize / SMART_MSS != 390126258Smlaier f->fp_wsize)) 391126258Smlaier continue; 392126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) { 393126258Smlaier if (find->fp_mss == 0) 394126258Smlaier continue; 395126258Smlaier 396223637Sbz#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) 397223637Sbz#define SMART_MTU (SMART_MSS + MTUOFF) 398126258Smlaier if ((find->fp_wsize % (find->fp_mss + MTUOFF) || 399126258Smlaier find->fp_wsize / (find->fp_mss + MTUOFF) != 400126258Smlaier f->fp_wsize) && 401126258Smlaier (find->fp_wsize % SMART_MTU || 402126258Smlaier find->fp_wsize / SMART_MTU != 403126258Smlaier f->fp_wsize)) 404126258Smlaier continue; 405126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) { 406126258Smlaier if (f->fp_wsize == 0 || find->fp_wsize % 407126258Smlaier f->fp_wsize) 408126258Smlaier continue; 409126258Smlaier } else { 410126258Smlaier if (f->fp_wsize != find->fp_wsize) 411126258Smlaier continue; 412126258Smlaier } 413126258Smlaier } 414126258Smlaier return (f); 415126258Smlaier } 416126258Smlaier 417126258Smlaier return (NULL); 418126258Smlaier} 419126258Smlaier 420126258Smlaier/* Find an exact fingerprint in the list */ 421240233Sglebiusstatic struct pf_os_fingerprint * 422126258Smlaierpf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find) 423126258Smlaier{ 424126258Smlaier struct pf_os_fingerprint *f; 425126258Smlaier 426126258Smlaier SLIST_FOREACH(f, list, fp_next) { 427126258Smlaier if (f->fp_tcpopts == find->fp_tcpopts && 428126258Smlaier f->fp_wsize == find->fp_wsize && 429126258Smlaier f->fp_psize == find->fp_psize && 430126258Smlaier f->fp_mss == find->fp_mss && 431126258Smlaier f->fp_flags == find->fp_flags && 432126258Smlaier f->fp_optcnt == find->fp_optcnt && 433126258Smlaier f->fp_wscale == find->fp_wscale && 434126258Smlaier f->fp_ttl == find->fp_ttl) 435126258Smlaier return (f); 436126258Smlaier } 437126258Smlaier 438126258Smlaier return (NULL); 439126258Smlaier} 440126258Smlaier 441126258Smlaier/* Insert a fingerprint into the list */ 442240233Sglebiusstatic void 443126258Smlaierpf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins) 444126258Smlaier{ 445126258Smlaier struct pf_os_fingerprint *f, *prev = NULL; 446126258Smlaier 447126258Smlaier /* XXX need to go semi tree based. can key on tcp options */ 448126258Smlaier 449126258Smlaier SLIST_FOREACH(f, list, fp_next) 450126258Smlaier prev = f; 451126258Smlaier if (prev) 452126258Smlaier SLIST_INSERT_AFTER(prev, ins, fp_next); 453126258Smlaier else 454126258Smlaier SLIST_INSERT_HEAD(list, ins, fp_next); 455126258Smlaier} 456126258Smlaier 457126258Smlaier/* Fill a fingerprint by its number (from an ioctl) */ 458126258Smlaierint 459126258Smlaierpf_osfp_get(struct pf_osfp_ioctl *fpioc) 460126258Smlaier{ 461126258Smlaier struct pf_os_fingerprint *fp; 462126258Smlaier struct pf_osfp_entry *entry; 463126258Smlaier int num = fpioc->fp_getnum; 464126258Smlaier int i = 0; 465126258Smlaier 466126258Smlaier 467126258Smlaier memset(fpioc, 0, sizeof(*fpioc)); 468223637Sbz SLIST_FOREACH(fp, &V_pf_osfp_list, fp_next) { 469126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 470126258Smlaier if (i++ == num) { 471126258Smlaier fpioc->fp_mss = fp->fp_mss; 472126258Smlaier fpioc->fp_wsize = fp->fp_wsize; 473126258Smlaier fpioc->fp_flags = fp->fp_flags; 474126258Smlaier fpioc->fp_psize = fp->fp_psize; 475126258Smlaier fpioc->fp_ttl = fp->fp_ttl; 476126258Smlaier fpioc->fp_wscale = fp->fp_wscale; 477126258Smlaier fpioc->fp_getnum = num; 478126258Smlaier memcpy(&fpioc->fp_os, entry, 479126258Smlaier sizeof(fpioc->fp_os)); 480126258Smlaier return (0); 481126258Smlaier } 482126258Smlaier } 483126258Smlaier } 484126258Smlaier 485126258Smlaier return (EBUSY); 486126258Smlaier} 487126258Smlaier 488126258Smlaier 489240233Sglebius#ifdef PFDEBUG 490126258Smlaier/* Validate that each signature is reachable */ 491240233Sglebiusstatic struct pf_os_fingerprint * 492126258Smlaierpf_osfp_validate(void) 493126258Smlaier{ 494126258Smlaier struct pf_os_fingerprint *f, *f2, find; 495126258Smlaier 496223637Sbz SLIST_FOREACH(f, &V_pf_osfp_list, fp_next) { 497126258Smlaier memcpy(&find, f, sizeof(find)); 498126258Smlaier 499126258Smlaier /* We do a few MSS/th_win percolations to make things unique */ 500126258Smlaier if (find.fp_mss == 0) 501126258Smlaier find.fp_mss = 128; 502126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) 503217388Scsjp find.fp_wsize *= find.fp_mss; 504126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MTU) 505126258Smlaier find.fp_wsize *= (find.fp_mss + 40); 506126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MOD) 507126258Smlaier find.fp_wsize *= 2; 508223637Sbz if (f != (f2 = pf_osfp_find(&V_pf_osfp_list, &find, 0))) { 509126258Smlaier if (f2) 510126258Smlaier printf("Found \"%s %s %s\" instead of " 511126258Smlaier "\"%s %s %s\"\n", 512126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_class_nm, 513126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_version_nm, 514126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm, 515126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 516126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 517126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 518126258Smlaier else 519126258Smlaier printf("Couldn't find \"%s %s %s\"\n", 520126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 521126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 522126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 523126258Smlaier return (f); 524126258Smlaier } 525126258Smlaier } 526126258Smlaier return (NULL); 527126258Smlaier} 528240233Sglebius#endif /* PFDEBUG */ 529