pf_osfp.c revision 315026
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: stable/11/sys/netpfil/pf/pf_osfp.c 315026 2017-03-10 20:25:43Z vangyzen $"); 21171168Smlaier 22315026Svangyzen#include "opt_inet6.h" 23315026Svangyzen 24126258Smlaier#include <sys/param.h> 25240233Sglebius#include <sys/kernel.h> 26257176Sglebius#include <sys/lock.h> 27257176Sglebius#include <sys/mbuf.h> 28257176Sglebius#include <sys/rwlock.h> 29126258Smlaier#include <sys/socket.h> 30126258Smlaier 31126258Smlaier#include <netinet/in.h> 32126258Smlaier#include <netinet/ip.h> 33126258Smlaier#include <netinet/tcp.h> 34126258Smlaier 35126258Smlaier#include <net/if.h> 36257176Sglebius#include <net/vnet.h> 37126258Smlaier#include <net/pfvar.h> 38126258Smlaier 39315026Svangyzen#ifdef INET6 40126258Smlaier#include <netinet/ip6.h> 41315026Svangyzen#endif 42126258Smlaier 43240233Sglebiusstatic MALLOC_DEFINE(M_PFOSFP, "pf_osfp", "pf(4) operating system fingerprints"); 44223637Sbz#define DPFPRINTF(format, x...) \ 45223637Sbz if (V_pf_status.debug >= PF_DEBUG_NOISY) \ 46223637Sbz printf(format , ##x) 47126258Smlaier 48223637SbzSLIST_HEAD(pf_osfp_list, pf_os_fingerprint); 49240233Sglebiusstatic VNET_DEFINE(struct pf_osfp_list, pf_osfp_list) = 50240233Sglebius SLIST_HEAD_INITIALIZER(); 51223637Sbz#define V_pf_osfp_list VNET(pf_osfp_list) 52126258Smlaier 53240233Sglebiusstatic struct pf_osfp_enlist *pf_osfp_fingerprint_hdr(const struct ip *, 54240233Sglebius const struct ip6_hdr *, 55240233Sglebius const struct tcphdr *); 56240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *, 57126258Smlaier struct pf_os_fingerprint *, u_int8_t); 58240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *, 59126258Smlaier struct pf_os_fingerprint *); 60240233Sglebiusstatic void pf_osfp_insert(struct pf_osfp_list *, 61126258Smlaier struct pf_os_fingerprint *); 62240233Sglebius#ifdef PFDEBUG 63240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_validate(void); 64240233Sglebius#endif 65126258Smlaier 66126258Smlaier/* 67126258Smlaier * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only) 68126258Smlaier * Returns the list of possible OSes. 69126258Smlaier */ 70126258Smlaierstruct pf_osfp_enlist * 71126258Smlaierpf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off, 72126258Smlaier const struct tcphdr *tcp) 73126258Smlaier{ 74126258Smlaier struct ip *ip; 75171168Smlaier struct ip6_hdr *ip6; 76126258Smlaier char hdr[60]; 77126258Smlaier 78171168Smlaier if ((pd->af != PF_INET && pd->af != PF_INET6) || 79171168Smlaier pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp)) 80126258Smlaier return (NULL); 81126258Smlaier 82171168Smlaier if (pd->af == PF_INET) { 83171168Smlaier ip = mtod(m, struct ip *); 84171168Smlaier ip6 = (struct ip6_hdr *)NULL; 85171168Smlaier } else { 86171168Smlaier ip = (struct ip *)NULL; 87171168Smlaier ip6 = mtod(m, struct ip6_hdr *); 88171168Smlaier } 89171168Smlaier if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, 90171168Smlaier pd->af)) return (NULL); 91126258Smlaier 92171168Smlaier return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr)); 93126258Smlaier} 94126258Smlaier 95240233Sglebiusstatic struct pf_osfp_enlist * 96171168Smlaierpf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) 97126258Smlaier{ 98126258Smlaier struct pf_os_fingerprint fp, *fpresult; 99126258Smlaier int cnt, optlen = 0; 100126261Smlaier const u_int8_t *optp; 101315026Svangyzen#ifdef INET6 102315026Svangyzen char srcname[INET6_ADDRSTRLEN]; 103315026Svangyzen#else 104315026Svangyzen char srcname[INET_ADDRSTRLEN]; 105315026Svangyzen#endif 106126258Smlaier 107171168Smlaier if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN) 108126258Smlaier return (NULL); 109171168Smlaier if (ip) { 110171168Smlaier if ((ip->ip_off & htons(IP_OFFMASK)) != 0) 111171168Smlaier return (NULL); 112171168Smlaier } 113126258Smlaier 114126258Smlaier memset(&fp, 0, sizeof(fp)); 115126258Smlaier 116171168Smlaier if (ip) { 117171168Smlaier fp.fp_psize = ntohs(ip->ip_len); 118171168Smlaier fp.fp_ttl = ip->ip_ttl; 119171168Smlaier if (ip->ip_off & htons(IP_DF)) 120171168Smlaier fp.fp_flags |= PF_OSFP_DF; 121315026Svangyzen inet_ntoa_r(ip->ip_src, srcname); 122171168Smlaier } 123171168Smlaier#ifdef INET6 124171168Smlaier else if (ip6) { 125171168Smlaier /* jumbo payload? */ 126171168Smlaier fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); 127171168Smlaier fp.fp_ttl = ip6->ip6_hlim; 128126258Smlaier fp.fp_flags |= PF_OSFP_DF; 129171168Smlaier fp.fp_flags |= PF_OSFP_INET6; 130315026Svangyzen ip6_sprintf(srcname, (const struct in6_addr *)&ip6->ip6_src); 131171168Smlaier } 132171168Smlaier#endif 133171168Smlaier else 134171168Smlaier return (NULL); 135126258Smlaier fp.fp_wsize = ntohs(tcp->th_win); 136126258Smlaier 137126258Smlaier 138126258Smlaier cnt = (tcp->th_off << 2) - sizeof(*tcp); 139126261Smlaier optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp)); 140126258Smlaier for (; cnt > 0; cnt -= optlen, optp += optlen) { 141126258Smlaier if (*optp == TCPOPT_EOL) 142126258Smlaier break; 143126258Smlaier 144126258Smlaier fp.fp_optcnt++; 145126258Smlaier if (*optp == TCPOPT_NOP) { 146126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) | 147126258Smlaier PF_OSFP_TCPOPT_NOP; 148126258Smlaier optlen = 1; 149126258Smlaier } else { 150126258Smlaier if (cnt < 2) 151126258Smlaier return (NULL); 152126258Smlaier optlen = optp[1]; 153126258Smlaier if (optlen > cnt || optlen < 2) 154126258Smlaier return (NULL); 155126258Smlaier switch (*optp) { 156126258Smlaier case TCPOPT_MAXSEG: 157126258Smlaier if (optlen >= TCPOLEN_MAXSEG) 158126258Smlaier memcpy(&fp.fp_mss, &optp[2], 159126258Smlaier sizeof(fp.fp_mss)); 160126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 161126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS; 162126258Smlaier NTOHS(fp.fp_mss); 163126258Smlaier break; 164126258Smlaier case TCPOPT_WINDOW: 165126258Smlaier if (optlen >= TCPOLEN_WINDOW) 166126258Smlaier memcpy(&fp.fp_wscale, &optp[2], 167126258Smlaier sizeof(fp.fp_wscale)); 168126258Smlaier NTOHS(fp.fp_wscale); 169126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 170126258Smlaier PF_OSFP_TCPOPT_BITS) | 171126258Smlaier PF_OSFP_TCPOPT_WSCALE; 172126258Smlaier break; 173126258Smlaier case TCPOPT_SACK_PERMITTED: 174126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 175126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK; 176126258Smlaier break; 177126258Smlaier case TCPOPT_TIMESTAMP: 178126258Smlaier if (optlen >= TCPOLEN_TIMESTAMP) { 179126258Smlaier u_int32_t ts; 180126258Smlaier memcpy(&ts, &optp[2], sizeof(ts)); 181126258Smlaier if (ts == 0) 182126258Smlaier fp.fp_flags |= PF_OSFP_TS0; 183126258Smlaier 184126258Smlaier } 185126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 186126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS; 187126258Smlaier break; 188126258Smlaier default: 189126258Smlaier return (NULL); 190126258Smlaier } 191126258Smlaier } 192126258Smlaier optlen = MAX(optlen, 1); /* paranoia */ 193126258Smlaier } 194126258Smlaier 195126258Smlaier DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) " 196126258Smlaier "(TS=%s,M=%s%d,W=%s%d)\n", 197171168Smlaier srcname, ntohs(tcp->th_sport), 198126258Smlaier fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0, 199126258Smlaier fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt, 200126258Smlaier (fp.fp_flags & PF_OSFP_TS0) ? "0" : "", 201126258Smlaier (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 202126258Smlaier (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 203126258Smlaier fp.fp_mss, 204126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 205126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 206126258Smlaier fp.fp_wscale); 207126258Smlaier 208223637Sbz if ((fpresult = pf_osfp_find(&V_pf_osfp_list, &fp, 209126258Smlaier PF_OSFP_MAXTTL_OFFSET))) 210126258Smlaier return (&fpresult->fp_oses); 211126258Smlaier return (NULL); 212126258Smlaier} 213126258Smlaier 214126258Smlaier/* Match a fingerprint ID against a list of OSes */ 215126258Smlaierint 216126258Smlaierpf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os) 217126258Smlaier{ 218126258Smlaier struct pf_osfp_entry *entry; 219126258Smlaier int os_class, os_version, os_subtype; 220126258Smlaier int en_class, en_version, en_subtype; 221126258Smlaier 222126258Smlaier if (os == PF_OSFP_ANY) 223126258Smlaier return (1); 224126258Smlaier if (list == NULL) { 225126258Smlaier DPFPRINTF("osfp no match against %x\n", os); 226126258Smlaier return (os == PF_OSFP_UNKNOWN); 227126258Smlaier } 228126258Smlaier PF_OSFP_UNPACK(os, os_class, os_version, os_subtype); 229126258Smlaier SLIST_FOREACH(entry, list, fp_entry) { 230126258Smlaier PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype); 231126258Smlaier if ((os_class == PF_OSFP_ANY || en_class == os_class) && 232126258Smlaier (os_version == PF_OSFP_ANY || en_version == os_version) && 233126258Smlaier (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) { 234126258Smlaier DPFPRINTF("osfp matched %s %s %s %x==%x\n", 235126258Smlaier entry->fp_class_nm, entry->fp_version_nm, 236126258Smlaier entry->fp_subtype_nm, os, entry->fp_os); 237126258Smlaier return (1); 238126258Smlaier } 239126258Smlaier } 240126258Smlaier DPFPRINTF("fingerprint 0x%x didn't match\n", os); 241126258Smlaier return (0); 242126258Smlaier} 243126258Smlaier 244126258Smlaier/* Flush the fingerprint list */ 245126258Smlaiervoid 246126258Smlaierpf_osfp_flush(void) 247126258Smlaier{ 248126258Smlaier struct pf_os_fingerprint *fp; 249126258Smlaier struct pf_osfp_entry *entry; 250126258Smlaier 251223637Sbz while ((fp = SLIST_FIRST(&V_pf_osfp_list))) { 252223637Sbz SLIST_REMOVE_HEAD(&V_pf_osfp_list, fp_next); 253126258Smlaier while ((entry = SLIST_FIRST(&fp->fp_oses))) { 254126258Smlaier SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry); 255240233Sglebius free(entry, M_PFOSFP); 256126258Smlaier } 257240233Sglebius free(fp, M_PFOSFP); 258126258Smlaier } 259126258Smlaier} 260126258Smlaier 261126258Smlaier 262126258Smlaier/* Add a fingerprint */ 263126258Smlaierint 264126258Smlaierpf_osfp_add(struct pf_osfp_ioctl *fpioc) 265126258Smlaier{ 266126258Smlaier struct pf_os_fingerprint *fp, fpadd; 267126258Smlaier struct pf_osfp_entry *entry; 268126258Smlaier 269240233Sglebius PF_RULES_WASSERT(); 270240233Sglebius 271126258Smlaier memset(&fpadd, 0, sizeof(fpadd)); 272126258Smlaier fpadd.fp_tcpopts = fpioc->fp_tcpopts; 273126258Smlaier fpadd.fp_wsize = fpioc->fp_wsize; 274126258Smlaier fpadd.fp_psize = fpioc->fp_psize; 275126258Smlaier fpadd.fp_mss = fpioc->fp_mss; 276126258Smlaier fpadd.fp_flags = fpioc->fp_flags; 277126258Smlaier fpadd.fp_optcnt = fpioc->fp_optcnt; 278126258Smlaier fpadd.fp_wscale = fpioc->fp_wscale; 279126258Smlaier fpadd.fp_ttl = fpioc->fp_ttl; 280126258Smlaier 281223637Sbz#if 0 /* XXX RYAN wants to fix logging */ 282126258Smlaier DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d " 283126258Smlaier "(TS=%s,M=%s%d,W=%s%d) %x\n", 284126258Smlaier fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm, 285126258Smlaier fpioc->fp_os.fp_subtype_nm, 286126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" : 287126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" : 288126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" : 289126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "", 290126258Smlaier fpadd.fp_wsize, 291126258Smlaier fpadd.fp_ttl, 292126258Smlaier (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0, 293126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" : 294126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "", 295126258Smlaier fpadd.fp_psize, 296126258Smlaier (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt, 297126258Smlaier (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "", 298126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 299126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 300126258Smlaier fpadd.fp_mss, 301126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 302126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 303126258Smlaier fpadd.fp_wscale, 304126258Smlaier fpioc->fp_os.fp_os); 305223637Sbz#endif 306126258Smlaier 307223637Sbz if ((fp = pf_osfp_find_exact(&V_pf_osfp_list, &fpadd))) { 308126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 309126258Smlaier if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os)) 310126258Smlaier return (EEXIST); 311126258Smlaier } 312240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 313240233Sglebius == NULL) 314126258Smlaier return (ENOMEM); 315126258Smlaier } else { 316240233Sglebius if ((fp = malloc(sizeof(*fp), M_PFOSFP, M_ZERO | M_NOWAIT)) 317240233Sglebius == NULL) 318126258Smlaier return (ENOMEM); 319126258Smlaier fp->fp_tcpopts = fpioc->fp_tcpopts; 320126258Smlaier fp->fp_wsize = fpioc->fp_wsize; 321126258Smlaier fp->fp_psize = fpioc->fp_psize; 322126258Smlaier fp->fp_mss = fpioc->fp_mss; 323126258Smlaier fp->fp_flags = fpioc->fp_flags; 324126258Smlaier fp->fp_optcnt = fpioc->fp_optcnt; 325126258Smlaier fp->fp_wscale = fpioc->fp_wscale; 326126258Smlaier fp->fp_ttl = fpioc->fp_ttl; 327126258Smlaier SLIST_INIT(&fp->fp_oses); 328240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 329240233Sglebius == NULL) { 330240233Sglebius free(fp, M_PFOSFP); 331126258Smlaier return (ENOMEM); 332126258Smlaier } 333223637Sbz pf_osfp_insert(&V_pf_osfp_list, fp); 334126258Smlaier } 335126258Smlaier memcpy(entry, &fpioc->fp_os, sizeof(*entry)); 336126258Smlaier 337126258Smlaier /* Make sure the strings are NUL terminated */ 338126258Smlaier entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0'; 339126258Smlaier entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0'; 340126258Smlaier entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0'; 341126258Smlaier 342126258Smlaier SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry); 343126258Smlaier 344126258Smlaier#ifdef PFDEBUG 345126258Smlaier if ((fp = pf_osfp_validate())) 346126258Smlaier printf("Invalid fingerprint list\n"); 347126258Smlaier#endif /* PFDEBUG */ 348126258Smlaier return (0); 349126258Smlaier} 350126258Smlaier 351126258Smlaier 352126258Smlaier/* Find a fingerprint in the list */ 353240233Sglebiusstatic struct pf_os_fingerprint * 354126258Smlaierpf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, 355126258Smlaier u_int8_t ttldiff) 356126258Smlaier{ 357126258Smlaier struct pf_os_fingerprint *f; 358126258Smlaier 359223637Sbz#define MATCH_INT(_MOD, _DC, _field) \ 360126258Smlaier if ((f->fp_flags & _DC) == 0) { \ 361126258Smlaier if ((f->fp_flags & _MOD) == 0) { \ 362126258Smlaier if (f->_field != find->_field) \ 363126258Smlaier continue; \ 364126258Smlaier } else { \ 365126258Smlaier if (f->_field == 0 || find->_field % f->_field) \ 366126258Smlaier continue; \ 367126258Smlaier } \ 368126258Smlaier } 369126258Smlaier 370126258Smlaier SLIST_FOREACH(f, list, fp_next) { 371126258Smlaier if (f->fp_tcpopts != find->fp_tcpopts || 372126258Smlaier f->fp_optcnt != find->fp_optcnt || 373126258Smlaier f->fp_ttl < find->fp_ttl || 374126258Smlaier f->fp_ttl - find->fp_ttl > ttldiff || 375126258Smlaier (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) != 376126258Smlaier (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0))) 377126258Smlaier continue; 378126258Smlaier 379126258Smlaier MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize) 380126258Smlaier MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss) 381126258Smlaier MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale) 382126258Smlaier if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) { 383126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) { 384126258Smlaier if (find->fp_mss == 0) 385126258Smlaier continue; 386126258Smlaier 387223637Sbz/* 388223637Sbz * Some "smart" NAT devices and DSL routers will tweak the MSS size and 389126258Smlaier * will set it to whatever is suitable for the link type. 390126258Smlaier */ 391223637Sbz#define SMART_MSS 1460 392126258Smlaier if ((find->fp_wsize % find->fp_mss || 393126258Smlaier find->fp_wsize / find->fp_mss != 394126258Smlaier f->fp_wsize) && 395126258Smlaier (find->fp_wsize % SMART_MSS || 396126258Smlaier find->fp_wsize / SMART_MSS != 397126258Smlaier f->fp_wsize)) 398126258Smlaier continue; 399126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) { 400126258Smlaier if (find->fp_mss == 0) 401126258Smlaier continue; 402126258Smlaier 403223637Sbz#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) 404223637Sbz#define SMART_MTU (SMART_MSS + MTUOFF) 405126258Smlaier if ((find->fp_wsize % (find->fp_mss + MTUOFF) || 406126258Smlaier find->fp_wsize / (find->fp_mss + MTUOFF) != 407126258Smlaier f->fp_wsize) && 408126258Smlaier (find->fp_wsize % SMART_MTU || 409126258Smlaier find->fp_wsize / SMART_MTU != 410126258Smlaier f->fp_wsize)) 411126258Smlaier continue; 412126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) { 413126258Smlaier if (f->fp_wsize == 0 || find->fp_wsize % 414126258Smlaier f->fp_wsize) 415126258Smlaier continue; 416126258Smlaier } else { 417126258Smlaier if (f->fp_wsize != find->fp_wsize) 418126258Smlaier continue; 419126258Smlaier } 420126258Smlaier } 421126258Smlaier return (f); 422126258Smlaier } 423126258Smlaier 424126258Smlaier return (NULL); 425126258Smlaier} 426126258Smlaier 427126258Smlaier/* Find an exact fingerprint in the list */ 428240233Sglebiusstatic struct pf_os_fingerprint * 429126258Smlaierpf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find) 430126258Smlaier{ 431126258Smlaier struct pf_os_fingerprint *f; 432126258Smlaier 433126258Smlaier SLIST_FOREACH(f, list, fp_next) { 434126258Smlaier if (f->fp_tcpopts == find->fp_tcpopts && 435126258Smlaier f->fp_wsize == find->fp_wsize && 436126258Smlaier f->fp_psize == find->fp_psize && 437126258Smlaier f->fp_mss == find->fp_mss && 438126258Smlaier f->fp_flags == find->fp_flags && 439126258Smlaier f->fp_optcnt == find->fp_optcnt && 440126258Smlaier f->fp_wscale == find->fp_wscale && 441126258Smlaier f->fp_ttl == find->fp_ttl) 442126258Smlaier return (f); 443126258Smlaier } 444126258Smlaier 445126258Smlaier return (NULL); 446126258Smlaier} 447126258Smlaier 448126258Smlaier/* Insert a fingerprint into the list */ 449240233Sglebiusstatic void 450126258Smlaierpf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins) 451126258Smlaier{ 452126258Smlaier struct pf_os_fingerprint *f, *prev = NULL; 453126258Smlaier 454126258Smlaier /* XXX need to go semi tree based. can key on tcp options */ 455126258Smlaier 456126258Smlaier SLIST_FOREACH(f, list, fp_next) 457126258Smlaier prev = f; 458126258Smlaier if (prev) 459126258Smlaier SLIST_INSERT_AFTER(prev, ins, fp_next); 460126258Smlaier else 461126258Smlaier SLIST_INSERT_HEAD(list, ins, fp_next); 462126258Smlaier} 463126258Smlaier 464126258Smlaier/* Fill a fingerprint by its number (from an ioctl) */ 465126258Smlaierint 466126258Smlaierpf_osfp_get(struct pf_osfp_ioctl *fpioc) 467126258Smlaier{ 468126258Smlaier struct pf_os_fingerprint *fp; 469126258Smlaier struct pf_osfp_entry *entry; 470126258Smlaier int num = fpioc->fp_getnum; 471126258Smlaier int i = 0; 472126258Smlaier 473126258Smlaier 474126258Smlaier memset(fpioc, 0, sizeof(*fpioc)); 475223637Sbz SLIST_FOREACH(fp, &V_pf_osfp_list, fp_next) { 476126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 477126258Smlaier if (i++ == num) { 478126258Smlaier fpioc->fp_mss = fp->fp_mss; 479126258Smlaier fpioc->fp_wsize = fp->fp_wsize; 480126258Smlaier fpioc->fp_flags = fp->fp_flags; 481126258Smlaier fpioc->fp_psize = fp->fp_psize; 482126258Smlaier fpioc->fp_ttl = fp->fp_ttl; 483126258Smlaier fpioc->fp_wscale = fp->fp_wscale; 484126258Smlaier fpioc->fp_getnum = num; 485126258Smlaier memcpy(&fpioc->fp_os, entry, 486126258Smlaier sizeof(fpioc->fp_os)); 487126258Smlaier return (0); 488126258Smlaier } 489126258Smlaier } 490126258Smlaier } 491126258Smlaier 492126258Smlaier return (EBUSY); 493126258Smlaier} 494126258Smlaier 495126258Smlaier 496240233Sglebius#ifdef PFDEBUG 497126258Smlaier/* Validate that each signature is reachable */ 498240233Sglebiusstatic struct pf_os_fingerprint * 499126258Smlaierpf_osfp_validate(void) 500126258Smlaier{ 501126258Smlaier struct pf_os_fingerprint *f, *f2, find; 502126258Smlaier 503223637Sbz SLIST_FOREACH(f, &V_pf_osfp_list, fp_next) { 504126258Smlaier memcpy(&find, f, sizeof(find)); 505126258Smlaier 506126258Smlaier /* We do a few MSS/th_win percolations to make things unique */ 507126258Smlaier if (find.fp_mss == 0) 508126258Smlaier find.fp_mss = 128; 509126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) 510217388Scsjp find.fp_wsize *= find.fp_mss; 511126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MTU) 512126258Smlaier find.fp_wsize *= (find.fp_mss + 40); 513126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MOD) 514126258Smlaier find.fp_wsize *= 2; 515223637Sbz if (f != (f2 = pf_osfp_find(&V_pf_osfp_list, &find, 0))) { 516126258Smlaier if (f2) 517126258Smlaier printf("Found \"%s %s %s\" instead of " 518126258Smlaier "\"%s %s %s\"\n", 519126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_class_nm, 520126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_version_nm, 521126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm, 522126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 523126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 524126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 525126258Smlaier else 526126258Smlaier printf("Couldn't find \"%s %s %s\"\n", 527126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 528126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 529126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 530126258Smlaier return (f); 531126258Smlaier } 532126258Smlaier } 533126258Smlaier return (NULL); 534126258Smlaier} 535240233Sglebius#endif /* PFDEBUG */ 536