pf_osfp.c revision 240233
1223637Sbz/* $OpenBSD: pf_osfp.c,v 1.14 2008/06/12 18:17:01 henning Exp $ */ 2126258Smlaier 3126258Smlaier/* 4126258Smlaier * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> 5126258Smlaier * 6126258Smlaier * Permission to use, copy, modify, and distribute this software for any 7126258Smlaier * purpose with or without fee is hereby granted, provided that the above 8126258Smlaier * copyright notice and this permission notice appear in all copies. 9126258Smlaier * 10126258Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11126258Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12126258Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13126258Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14126258Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15126258Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16126258Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17126258Smlaier * 18126258Smlaier */ 19126258Smlaier 20171168Smlaier#include <sys/cdefs.h> 21171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/pf_osfp.c 240233 2012-09-08 06:41:54Z glebius $"); 22171168Smlaier 23126258Smlaier#include <sys/param.h> 24240233Sglebius#include <sys/kernel.h> 25126258Smlaier#include <sys/socket.h> 26126258Smlaier 27126258Smlaier#include <netinet/in.h> 28126258Smlaier#include <netinet/ip.h> 29126258Smlaier#include <netinet/tcp.h> 30126258Smlaier 31126258Smlaier#include <net/if.h> 32126258Smlaier#include <net/pfvar.h> 33126258Smlaier 34126258Smlaier#include <netinet/ip6.h> 35171168Smlaier#include <netinet6/in6_var.h> 36126258Smlaier 37240233Sglebiusstatic MALLOC_DEFINE(M_PFOSFP, "pf_osfp", "pf(4) operating system fingerprints"); 38223637Sbz#define DPFPRINTF(format, x...) \ 39223637Sbz if (V_pf_status.debug >= PF_DEBUG_NOISY) \ 40223637Sbz printf(format , ##x) 41126258Smlaier 42223637SbzSLIST_HEAD(pf_osfp_list, pf_os_fingerprint); 43240233Sglebiusstatic VNET_DEFINE(struct pf_osfp_list, pf_osfp_list) = 44240233Sglebius SLIST_HEAD_INITIALIZER(); 45223637Sbz#define V_pf_osfp_list VNET(pf_osfp_list) 46126258Smlaier 47240233Sglebiusstatic struct pf_osfp_enlist *pf_osfp_fingerprint_hdr(const struct ip *, 48240233Sglebius const struct ip6_hdr *, 49240233Sglebius const struct tcphdr *); 50240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *, 51126258Smlaier struct pf_os_fingerprint *, u_int8_t); 52240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *, 53126258Smlaier struct pf_os_fingerprint *); 54240233Sglebiusstatic void pf_osfp_insert(struct pf_osfp_list *, 55126258Smlaier struct pf_os_fingerprint *); 56240233Sglebius#ifdef PFDEBUG 57240233Sglebiusstatic struct pf_os_fingerprint *pf_osfp_validate(void); 58240233Sglebius#endif 59126258Smlaier 60126258Smlaier/* 61126258Smlaier * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only) 62126258Smlaier * Returns the list of possible OSes. 63126258Smlaier */ 64126258Smlaierstruct pf_osfp_enlist * 65126258Smlaierpf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off, 66126258Smlaier const struct tcphdr *tcp) 67126258Smlaier{ 68126258Smlaier struct ip *ip; 69171168Smlaier struct ip6_hdr *ip6; 70126258Smlaier char hdr[60]; 71126258Smlaier 72171168Smlaier if ((pd->af != PF_INET && pd->af != PF_INET6) || 73171168Smlaier pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp)) 74126258Smlaier return (NULL); 75126258Smlaier 76171168Smlaier if (pd->af == PF_INET) { 77171168Smlaier ip = mtod(m, struct ip *); 78171168Smlaier ip6 = (struct ip6_hdr *)NULL; 79171168Smlaier } else { 80171168Smlaier ip = (struct ip *)NULL; 81171168Smlaier ip6 = mtod(m, struct ip6_hdr *); 82171168Smlaier } 83171168Smlaier if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, 84171168Smlaier pd->af)) return (NULL); 85126258Smlaier 86171168Smlaier return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr)); 87126258Smlaier} 88126258Smlaier 89240233Sglebiusstatic struct pf_osfp_enlist * 90171168Smlaierpf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) 91126258Smlaier{ 92126258Smlaier struct pf_os_fingerprint fp, *fpresult; 93126258Smlaier int cnt, optlen = 0; 94126261Smlaier const u_int8_t *optp; 95171168Smlaier char srcname[128]; 96126258Smlaier 97171168Smlaier if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN) 98126258Smlaier return (NULL); 99171168Smlaier if (ip) { 100171168Smlaier if ((ip->ip_off & htons(IP_OFFMASK)) != 0) 101171168Smlaier return (NULL); 102171168Smlaier } 103126258Smlaier 104126258Smlaier memset(&fp, 0, sizeof(fp)); 105126258Smlaier 106171168Smlaier if (ip) { 107171168Smlaier fp.fp_psize = ntohs(ip->ip_len); 108171168Smlaier fp.fp_ttl = ip->ip_ttl; 109171168Smlaier if (ip->ip_off & htons(IP_DF)) 110171168Smlaier fp.fp_flags |= PF_OSFP_DF; 111171168Smlaier strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname)); 112171168Smlaier } 113171168Smlaier#ifdef INET6 114171168Smlaier else if (ip6) { 115171168Smlaier /* jumbo payload? */ 116171168Smlaier fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); 117171168Smlaier fp.fp_ttl = ip6->ip6_hlim; 118126258Smlaier fp.fp_flags |= PF_OSFP_DF; 119171168Smlaier fp.fp_flags |= PF_OSFP_INET6; 120171168Smlaier strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src), 121171168Smlaier sizeof(srcname)); 122171168Smlaier } 123171168Smlaier#endif 124171168Smlaier else 125171168Smlaier return (NULL); 126126258Smlaier fp.fp_wsize = ntohs(tcp->th_win); 127126258Smlaier 128126258Smlaier 129126258Smlaier cnt = (tcp->th_off << 2) - sizeof(*tcp); 130126261Smlaier optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp)); 131126258Smlaier for (; cnt > 0; cnt -= optlen, optp += optlen) { 132126258Smlaier if (*optp == TCPOPT_EOL) 133126258Smlaier break; 134126258Smlaier 135126258Smlaier fp.fp_optcnt++; 136126258Smlaier if (*optp == TCPOPT_NOP) { 137126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) | 138126258Smlaier PF_OSFP_TCPOPT_NOP; 139126258Smlaier optlen = 1; 140126258Smlaier } else { 141126258Smlaier if (cnt < 2) 142126258Smlaier return (NULL); 143126258Smlaier optlen = optp[1]; 144126258Smlaier if (optlen > cnt || optlen < 2) 145126258Smlaier return (NULL); 146126258Smlaier switch (*optp) { 147126258Smlaier case TCPOPT_MAXSEG: 148126258Smlaier if (optlen >= TCPOLEN_MAXSEG) 149126258Smlaier memcpy(&fp.fp_mss, &optp[2], 150126258Smlaier sizeof(fp.fp_mss)); 151126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 152126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS; 153126258Smlaier NTOHS(fp.fp_mss); 154126258Smlaier break; 155126258Smlaier case TCPOPT_WINDOW: 156126258Smlaier if (optlen >= TCPOLEN_WINDOW) 157126258Smlaier memcpy(&fp.fp_wscale, &optp[2], 158126258Smlaier sizeof(fp.fp_wscale)); 159126258Smlaier NTOHS(fp.fp_wscale); 160126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 161126258Smlaier PF_OSFP_TCPOPT_BITS) | 162126258Smlaier PF_OSFP_TCPOPT_WSCALE; 163126258Smlaier break; 164126258Smlaier case TCPOPT_SACK_PERMITTED: 165126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 166126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK; 167126258Smlaier break; 168126258Smlaier case TCPOPT_TIMESTAMP: 169126258Smlaier if (optlen >= TCPOLEN_TIMESTAMP) { 170126258Smlaier u_int32_t ts; 171126258Smlaier memcpy(&ts, &optp[2], sizeof(ts)); 172126258Smlaier if (ts == 0) 173126258Smlaier fp.fp_flags |= PF_OSFP_TS0; 174126258Smlaier 175126258Smlaier } 176126258Smlaier fp.fp_tcpopts = (fp.fp_tcpopts << 177126258Smlaier PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS; 178126258Smlaier break; 179126258Smlaier default: 180126258Smlaier return (NULL); 181126258Smlaier } 182126258Smlaier } 183126258Smlaier optlen = MAX(optlen, 1); /* paranoia */ 184126258Smlaier } 185126258Smlaier 186126258Smlaier DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) " 187126258Smlaier "(TS=%s,M=%s%d,W=%s%d)\n", 188171168Smlaier srcname, ntohs(tcp->th_sport), 189126258Smlaier fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0, 190126258Smlaier fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt, 191126258Smlaier (fp.fp_flags & PF_OSFP_TS0) ? "0" : "", 192126258Smlaier (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 193126258Smlaier (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 194126258Smlaier fp.fp_mss, 195126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 196126258Smlaier (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 197126258Smlaier fp.fp_wscale); 198126258Smlaier 199223637Sbz if ((fpresult = pf_osfp_find(&V_pf_osfp_list, &fp, 200126258Smlaier PF_OSFP_MAXTTL_OFFSET))) 201126258Smlaier return (&fpresult->fp_oses); 202126258Smlaier return (NULL); 203126258Smlaier} 204126258Smlaier 205126258Smlaier/* Match a fingerprint ID against a list of OSes */ 206126258Smlaierint 207126258Smlaierpf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os) 208126258Smlaier{ 209126258Smlaier struct pf_osfp_entry *entry; 210126258Smlaier int os_class, os_version, os_subtype; 211126258Smlaier int en_class, en_version, en_subtype; 212126258Smlaier 213126258Smlaier if (os == PF_OSFP_ANY) 214126258Smlaier return (1); 215126258Smlaier if (list == NULL) { 216126258Smlaier DPFPRINTF("osfp no match against %x\n", os); 217126258Smlaier return (os == PF_OSFP_UNKNOWN); 218126258Smlaier } 219126258Smlaier PF_OSFP_UNPACK(os, os_class, os_version, os_subtype); 220126258Smlaier SLIST_FOREACH(entry, list, fp_entry) { 221126258Smlaier PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype); 222126258Smlaier if ((os_class == PF_OSFP_ANY || en_class == os_class) && 223126258Smlaier (os_version == PF_OSFP_ANY || en_version == os_version) && 224126258Smlaier (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) { 225126258Smlaier DPFPRINTF("osfp matched %s %s %s %x==%x\n", 226126258Smlaier entry->fp_class_nm, entry->fp_version_nm, 227126258Smlaier entry->fp_subtype_nm, os, entry->fp_os); 228126258Smlaier return (1); 229126258Smlaier } 230126258Smlaier } 231126258Smlaier DPFPRINTF("fingerprint 0x%x didn't match\n", os); 232126258Smlaier return (0); 233126258Smlaier} 234126258Smlaier 235126258Smlaier/* Flush the fingerprint list */ 236126258Smlaiervoid 237126258Smlaierpf_osfp_flush(void) 238126258Smlaier{ 239126258Smlaier struct pf_os_fingerprint *fp; 240126258Smlaier struct pf_osfp_entry *entry; 241126258Smlaier 242223637Sbz while ((fp = SLIST_FIRST(&V_pf_osfp_list))) { 243223637Sbz SLIST_REMOVE_HEAD(&V_pf_osfp_list, fp_next); 244126258Smlaier while ((entry = SLIST_FIRST(&fp->fp_oses))) { 245126258Smlaier SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry); 246240233Sglebius free(entry, M_PFOSFP); 247126258Smlaier } 248240233Sglebius free(fp, M_PFOSFP); 249126258Smlaier } 250126258Smlaier} 251126258Smlaier 252126258Smlaier 253126258Smlaier/* Add a fingerprint */ 254126258Smlaierint 255126258Smlaierpf_osfp_add(struct pf_osfp_ioctl *fpioc) 256126258Smlaier{ 257126258Smlaier struct pf_os_fingerprint *fp, fpadd; 258126258Smlaier struct pf_osfp_entry *entry; 259126258Smlaier 260240233Sglebius PF_RULES_WASSERT(); 261240233Sglebius 262126258Smlaier memset(&fpadd, 0, sizeof(fpadd)); 263126258Smlaier fpadd.fp_tcpopts = fpioc->fp_tcpopts; 264126258Smlaier fpadd.fp_wsize = fpioc->fp_wsize; 265126258Smlaier fpadd.fp_psize = fpioc->fp_psize; 266126258Smlaier fpadd.fp_mss = fpioc->fp_mss; 267126258Smlaier fpadd.fp_flags = fpioc->fp_flags; 268126258Smlaier fpadd.fp_optcnt = fpioc->fp_optcnt; 269126258Smlaier fpadd.fp_wscale = fpioc->fp_wscale; 270126258Smlaier fpadd.fp_ttl = fpioc->fp_ttl; 271126258Smlaier 272223637Sbz#if 0 /* XXX RYAN wants to fix logging */ 273126258Smlaier DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d " 274126258Smlaier "(TS=%s,M=%s%d,W=%s%d) %x\n", 275126258Smlaier fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm, 276126258Smlaier fpioc->fp_os.fp_subtype_nm, 277126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" : 278126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" : 279126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" : 280126258Smlaier (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "", 281126258Smlaier fpadd.fp_wsize, 282126258Smlaier fpadd.fp_ttl, 283126258Smlaier (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0, 284126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" : 285126258Smlaier (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "", 286126258Smlaier fpadd.fp_psize, 287126258Smlaier (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt, 288126258Smlaier (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "", 289126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 290126258Smlaier (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 291126258Smlaier fpadd.fp_mss, 292126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 293126258Smlaier (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 294126258Smlaier fpadd.fp_wscale, 295126258Smlaier fpioc->fp_os.fp_os); 296223637Sbz#endif 297126258Smlaier 298223637Sbz if ((fp = pf_osfp_find_exact(&V_pf_osfp_list, &fpadd))) { 299126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 300126258Smlaier if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os)) 301126258Smlaier return (EEXIST); 302126258Smlaier } 303240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 304240233Sglebius == NULL) 305126258Smlaier return (ENOMEM); 306126258Smlaier } else { 307240233Sglebius if ((fp = malloc(sizeof(*fp), M_PFOSFP, M_ZERO | M_NOWAIT)) 308240233Sglebius == NULL) 309126258Smlaier return (ENOMEM); 310126258Smlaier fp->fp_tcpopts = fpioc->fp_tcpopts; 311126258Smlaier fp->fp_wsize = fpioc->fp_wsize; 312126258Smlaier fp->fp_psize = fpioc->fp_psize; 313126258Smlaier fp->fp_mss = fpioc->fp_mss; 314126258Smlaier fp->fp_flags = fpioc->fp_flags; 315126258Smlaier fp->fp_optcnt = fpioc->fp_optcnt; 316126258Smlaier fp->fp_wscale = fpioc->fp_wscale; 317126258Smlaier fp->fp_ttl = fpioc->fp_ttl; 318126258Smlaier SLIST_INIT(&fp->fp_oses); 319240233Sglebius if ((entry = malloc(sizeof(*entry), M_PFOSFP, M_NOWAIT)) 320240233Sglebius == NULL) { 321240233Sglebius free(fp, M_PFOSFP); 322126258Smlaier return (ENOMEM); 323126258Smlaier } 324223637Sbz pf_osfp_insert(&V_pf_osfp_list, fp); 325126258Smlaier } 326126258Smlaier memcpy(entry, &fpioc->fp_os, sizeof(*entry)); 327126258Smlaier 328126258Smlaier /* Make sure the strings are NUL terminated */ 329126258Smlaier entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0'; 330126258Smlaier entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0'; 331126258Smlaier entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0'; 332126258Smlaier 333126258Smlaier SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry); 334126258Smlaier 335126258Smlaier#ifdef PFDEBUG 336126258Smlaier if ((fp = pf_osfp_validate())) 337126258Smlaier printf("Invalid fingerprint list\n"); 338126258Smlaier#endif /* PFDEBUG */ 339126258Smlaier return (0); 340126258Smlaier} 341126258Smlaier 342126258Smlaier 343126258Smlaier/* Find a fingerprint in the list */ 344240233Sglebiusstatic struct pf_os_fingerprint * 345126258Smlaierpf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, 346126258Smlaier u_int8_t ttldiff) 347126258Smlaier{ 348126258Smlaier struct pf_os_fingerprint *f; 349126258Smlaier 350223637Sbz#define MATCH_INT(_MOD, _DC, _field) \ 351126258Smlaier if ((f->fp_flags & _DC) == 0) { \ 352126258Smlaier if ((f->fp_flags & _MOD) == 0) { \ 353126258Smlaier if (f->_field != find->_field) \ 354126258Smlaier continue; \ 355126258Smlaier } else { \ 356126258Smlaier if (f->_field == 0 || find->_field % f->_field) \ 357126258Smlaier continue; \ 358126258Smlaier } \ 359126258Smlaier } 360126258Smlaier 361126258Smlaier SLIST_FOREACH(f, list, fp_next) { 362126258Smlaier if (f->fp_tcpopts != find->fp_tcpopts || 363126258Smlaier f->fp_optcnt != find->fp_optcnt || 364126258Smlaier f->fp_ttl < find->fp_ttl || 365126258Smlaier f->fp_ttl - find->fp_ttl > ttldiff || 366126258Smlaier (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) != 367126258Smlaier (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0))) 368126258Smlaier continue; 369126258Smlaier 370126258Smlaier MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize) 371126258Smlaier MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss) 372126258Smlaier MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale) 373126258Smlaier if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) { 374126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) { 375126258Smlaier if (find->fp_mss == 0) 376126258Smlaier continue; 377126258Smlaier 378223637Sbz/* 379223637Sbz * Some "smart" NAT devices and DSL routers will tweak the MSS size and 380126258Smlaier * will set it to whatever is suitable for the link type. 381126258Smlaier */ 382223637Sbz#define SMART_MSS 1460 383126258Smlaier if ((find->fp_wsize % find->fp_mss || 384126258Smlaier find->fp_wsize / find->fp_mss != 385126258Smlaier f->fp_wsize) && 386126258Smlaier (find->fp_wsize % SMART_MSS || 387126258Smlaier find->fp_wsize / SMART_MSS != 388126258Smlaier f->fp_wsize)) 389126258Smlaier continue; 390126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) { 391126258Smlaier if (find->fp_mss == 0) 392126258Smlaier continue; 393126258Smlaier 394223637Sbz#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) 395223637Sbz#define SMART_MTU (SMART_MSS + MTUOFF) 396126258Smlaier if ((find->fp_wsize % (find->fp_mss + MTUOFF) || 397126258Smlaier find->fp_wsize / (find->fp_mss + MTUOFF) != 398126258Smlaier f->fp_wsize) && 399126258Smlaier (find->fp_wsize % SMART_MTU || 400126258Smlaier find->fp_wsize / SMART_MTU != 401126258Smlaier f->fp_wsize)) 402126258Smlaier continue; 403126258Smlaier } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) { 404126258Smlaier if (f->fp_wsize == 0 || find->fp_wsize % 405126258Smlaier f->fp_wsize) 406126258Smlaier continue; 407126258Smlaier } else { 408126258Smlaier if (f->fp_wsize != find->fp_wsize) 409126258Smlaier continue; 410126258Smlaier } 411126258Smlaier } 412126258Smlaier return (f); 413126258Smlaier } 414126258Smlaier 415126258Smlaier return (NULL); 416126258Smlaier} 417126258Smlaier 418126258Smlaier/* Find an exact fingerprint in the list */ 419240233Sglebiusstatic struct pf_os_fingerprint * 420126258Smlaierpf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find) 421126258Smlaier{ 422126258Smlaier struct pf_os_fingerprint *f; 423126258Smlaier 424126258Smlaier SLIST_FOREACH(f, list, fp_next) { 425126258Smlaier if (f->fp_tcpopts == find->fp_tcpopts && 426126258Smlaier f->fp_wsize == find->fp_wsize && 427126258Smlaier f->fp_psize == find->fp_psize && 428126258Smlaier f->fp_mss == find->fp_mss && 429126258Smlaier f->fp_flags == find->fp_flags && 430126258Smlaier f->fp_optcnt == find->fp_optcnt && 431126258Smlaier f->fp_wscale == find->fp_wscale && 432126258Smlaier f->fp_ttl == find->fp_ttl) 433126258Smlaier return (f); 434126258Smlaier } 435126258Smlaier 436126258Smlaier return (NULL); 437126258Smlaier} 438126258Smlaier 439126258Smlaier/* Insert a fingerprint into the list */ 440240233Sglebiusstatic void 441126258Smlaierpf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins) 442126258Smlaier{ 443126258Smlaier struct pf_os_fingerprint *f, *prev = NULL; 444126258Smlaier 445126258Smlaier /* XXX need to go semi tree based. can key on tcp options */ 446126258Smlaier 447126258Smlaier SLIST_FOREACH(f, list, fp_next) 448126258Smlaier prev = f; 449126258Smlaier if (prev) 450126258Smlaier SLIST_INSERT_AFTER(prev, ins, fp_next); 451126258Smlaier else 452126258Smlaier SLIST_INSERT_HEAD(list, ins, fp_next); 453126258Smlaier} 454126258Smlaier 455126258Smlaier/* Fill a fingerprint by its number (from an ioctl) */ 456126258Smlaierint 457126258Smlaierpf_osfp_get(struct pf_osfp_ioctl *fpioc) 458126258Smlaier{ 459126258Smlaier struct pf_os_fingerprint *fp; 460126258Smlaier struct pf_osfp_entry *entry; 461126258Smlaier int num = fpioc->fp_getnum; 462126258Smlaier int i = 0; 463126258Smlaier 464126258Smlaier 465126258Smlaier memset(fpioc, 0, sizeof(*fpioc)); 466223637Sbz SLIST_FOREACH(fp, &V_pf_osfp_list, fp_next) { 467126258Smlaier SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 468126258Smlaier if (i++ == num) { 469126258Smlaier fpioc->fp_mss = fp->fp_mss; 470126258Smlaier fpioc->fp_wsize = fp->fp_wsize; 471126258Smlaier fpioc->fp_flags = fp->fp_flags; 472126258Smlaier fpioc->fp_psize = fp->fp_psize; 473126258Smlaier fpioc->fp_ttl = fp->fp_ttl; 474126258Smlaier fpioc->fp_wscale = fp->fp_wscale; 475126258Smlaier fpioc->fp_getnum = num; 476126258Smlaier memcpy(&fpioc->fp_os, entry, 477126258Smlaier sizeof(fpioc->fp_os)); 478126258Smlaier return (0); 479126258Smlaier } 480126258Smlaier } 481126258Smlaier } 482126258Smlaier 483126258Smlaier return (EBUSY); 484126258Smlaier} 485126258Smlaier 486126258Smlaier 487240233Sglebius#ifdef PFDEBUG 488126258Smlaier/* Validate that each signature is reachable */ 489240233Sglebiusstatic struct pf_os_fingerprint * 490126258Smlaierpf_osfp_validate(void) 491126258Smlaier{ 492126258Smlaier struct pf_os_fingerprint *f, *f2, find; 493126258Smlaier 494223637Sbz SLIST_FOREACH(f, &V_pf_osfp_list, fp_next) { 495126258Smlaier memcpy(&find, f, sizeof(find)); 496126258Smlaier 497126258Smlaier /* We do a few MSS/th_win percolations to make things unique */ 498126258Smlaier if (find.fp_mss == 0) 499126258Smlaier find.fp_mss = 128; 500126258Smlaier if (f->fp_flags & PF_OSFP_WSIZE_MSS) 501217388Scsjp find.fp_wsize *= find.fp_mss; 502126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MTU) 503126258Smlaier find.fp_wsize *= (find.fp_mss + 40); 504126258Smlaier else if (f->fp_flags & PF_OSFP_WSIZE_MOD) 505126258Smlaier find.fp_wsize *= 2; 506223637Sbz if (f != (f2 = pf_osfp_find(&V_pf_osfp_list, &find, 0))) { 507126258Smlaier if (f2) 508126258Smlaier printf("Found \"%s %s %s\" instead of " 509126258Smlaier "\"%s %s %s\"\n", 510126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_class_nm, 511126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_version_nm, 512126258Smlaier SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm, 513126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 514126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 515126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 516126258Smlaier else 517126258Smlaier printf("Couldn't find \"%s %s %s\"\n", 518126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_class_nm, 519126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_version_nm, 520126258Smlaier SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 521126258Smlaier return (f); 522126258Smlaier } 523126258Smlaier } 524126258Smlaier return (NULL); 525126258Smlaier} 526240233Sglebius#endif /* PFDEBUG */ 527