154558Sbp/* $OpenBSD: pf_osfp.c,v 1.14 2008/06/12 18:17:01 henning Exp $ */ 254558Sbp 354558Sbp/* 454558Sbp * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> 554558Sbp * 654558Sbp * Permission to use, copy, modify, and distribute this software for any 754558Sbp * purpose with or without fee is hereby granted, provided that the above 854558Sbp * copyright notice and this permission notice appear in all copies. 954558Sbp * 1054558Sbp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1154558Sbp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1254558Sbp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1354558Sbp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1454558Sbp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1554558Sbp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1654558Sbp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1754558Sbp * 1854558Sbp */ 1954558Sbp 2054558Sbp#ifdef __FreeBSD__ 2154558Sbp#include <sys/cdefs.h> 2254558Sbp__FBSDID("$FreeBSD$"); 2354558Sbp#endif 2454558Sbp 2554558Sbp#include <sys/param.h> 2654558Sbp#include <sys/socket.h> 2754558Sbp#ifdef _KERNEL 2854558Sbp#include <sys/systm.h> 2954558Sbp#ifndef __FreeBSD__ 3054558Sbp#include <sys/pool.h> 3156424Sbp#endif 3254558Sbp#endif /* _KERNEL */ 3354558Sbp#include <sys/mbuf.h> 3454558Sbp 3554558Sbp#include <netinet/in.h> 3654558Sbp#include <netinet/in_systm.h> 3754558Sbp#include <netinet/ip.h> 3854558Sbp#include <netinet/tcp.h> 3954558Sbp 4054558Sbp#include <net/if.h> 4154558Sbp#include <net/pfvar.h> 4254558Sbp 4354558Sbp#include <netinet/ip6.h> 4454558Sbp#ifdef _KERNEL 4554558Sbp#include <netinet6/in6_var.h> 4654558Sbp#endif 4754558Sbp 4854558Sbp 4954558Sbp#ifdef _KERNEL 5054558Sbp#ifdef __FreeBSD__ 5154558Sbp#define DPFPRINTF(format, x...) \ 5254558Sbp if (V_pf_status.debug >= PF_DEBUG_NOISY) \ 5354558Sbp printf(format , ##x) 5454558Sbp#else 5554558Sbp#define DPFPRINTF(format, x...) \ 5654558Sbp if (pf_status.debug >= PF_DEBUG_NOISY) \ 5754558Sbp printf(format , ##x) 5854558Sbp#endif 5954558Sbp#ifdef __FreeBSD__ 6054558Sbptypedef uma_zone_t pool_t; 6154558Sbp#else 6254558Sbptypedef struct pool pool_t; 6354558Sbp#endif 6454558Sbp 6554558Sbp#else 6654558Sbp/* Userland equivalents so we can lend code to tcpdump et al. */ 6754558Sbp 6854558Sbp#include <arpa/inet.h> 6954558Sbp#include <errno.h> 7054558Sbp#include <stdio.h> 7154558Sbp#include <stdlib.h> 7254558Sbp#include <string.h> 7354558Sbp#include <netdb.h> 7454558Sbp#define pool_t int 7554558Sbp#define pool_get(pool, flags) malloc(*(pool)) 7654558Sbp#define pool_put(pool, item) free(item) 7754558Sbp#define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size) 7854558Sbp 7954558Sbp#ifdef __FreeBSD__ 8054558Sbp#define NTOHS(x) (x) = ntohs((u_int16_t)(x)) 8154558Sbp#endif 8254558Sbp 8354558Sbp#ifdef PFDEBUG 8454558Sbp#include <sys/stdarg.h> 8560938Sjake#define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) 8654558Sbp#else 8754558Sbp#define DPFPRINTF(format, x...) ((void)0) 8854558Sbp#endif /* PFDEBUG */ 8954558Sbp#endif /* _KERNEL */ 9060938Sjake 9154558Sbp 9254558Sbp#ifdef __FreeBSD__ 9354558SbpSLIST_HEAD(pf_osfp_list, pf_os_fingerprint); 9459681SbpVNET_DEFINE(struct pf_osfp_list, pf_osfp_list); 9554558Sbp#define V_pf_osfp_list VNET(pf_osfp_list) 9654558SbpVNET_DEFINE(pool_t, pf_osfp_entry_pl); 9754558Sbp#define pf_osfp_entry_pl VNET(pf_osfp_entry_pl) 9854558SbpVNET_DEFINE(pool_t, pf_osfp_pl); 9954558Sbp#define pf_osfp_pl VNET(pf_osfp_pl) 10054558Sbp#else 10154558SbpSLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list; 10254558Sbppool_t pf_osfp_entry_pl; 10354558Sbppool_t pf_osfp_pl; 10454558Sbp#endif 10554558Sbp 10659681Sbpstruct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *, 10754558Sbp struct pf_os_fingerprint *, u_int8_t); 10854558Sbpstruct pf_os_fingerprint *pf_osfp_find_exact(struct pf_osfp_list *, 10954558Sbp struct pf_os_fingerprint *); 11054558Sbpvoid pf_osfp_insert(struct pf_osfp_list *, 11154558Sbp struct pf_os_fingerprint *); 11254558Sbp 11354558Sbp 11454558Sbp#ifdef _KERNEL 11554558Sbp/* 11654558Sbp * Passively fingerprint the OS of the host (IPv4 TCP SYN packets only) 11754558Sbp * Returns the list of possible OSes. 11854558Sbp */ 11954558Sbpstruct pf_osfp_enlist * 12054558Sbppf_osfp_fingerprint(struct pf_pdesc *pd, struct mbuf *m, int off, 12154558Sbp const struct tcphdr *tcp) 12254558Sbp{ 12354558Sbp struct ip *ip; 12454558Sbp struct ip6_hdr *ip6; 12554558Sbp char hdr[60]; 12654558Sbp 12754558Sbp if ((pd->af != PF_INET && pd->af != PF_INET6) || 12854558Sbp pd->proto != IPPROTO_TCP || (tcp->th_off << 2) < sizeof(*tcp)) 12954558Sbp return (NULL); 13054558Sbp 13154558Sbp if (pd->af == PF_INET) { 13254558Sbp ip = mtod(m, struct ip *); 13354558Sbp ip6 = (struct ip6_hdr *)NULL; 13454558Sbp } else { 13554558Sbp ip = (struct ip *)NULL; 13654558Sbp ip6 = mtod(m, struct ip6_hdr *); 13754558Sbp } 13854558Sbp if (!pf_pull_hdr(m, off, hdr, tcp->th_off << 2, NULL, NULL, 13954558Sbp pd->af)) return (NULL); 14054558Sbp 14154558Sbp return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr)); 14254558Sbp} 14354558Sbp#endif /* _KERNEL */ 14454558Sbp 14554558Sbpstruct pf_osfp_enlist * 14654558Sbppf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) 14754558Sbp{ 14854558Sbp struct pf_os_fingerprint fp, *fpresult; 14954558Sbp int cnt, optlen = 0; 15054558Sbp const u_int8_t *optp; 15154558Sbp#ifdef _KERNEL 15254558Sbp char srcname[128]; 15354558Sbp#else 15454558Sbp char srcname[NI_MAXHOST]; 15554558Sbp#endif 15654558Sbp 15754558Sbp if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN) 15854558Sbp return (NULL); 15954558Sbp if (ip) { 16054558Sbp if ((ip->ip_off & htons(IP_OFFMASK)) != 0) 16154558Sbp return (NULL); 16254558Sbp } 16354558Sbp 16454558Sbp memset(&fp, 0, sizeof(fp)); 16554558Sbp 16654558Sbp if (ip) { 16754558Sbp#ifndef _KERNEL 16854558Sbp struct sockaddr_in sin; 16954558Sbp#endif 17054558Sbp 17154558Sbp fp.fp_psize = ntohs(ip->ip_len); 17254558Sbp fp.fp_ttl = ip->ip_ttl; 17354558Sbp if (ip->ip_off & htons(IP_DF)) 17454558Sbp fp.fp_flags |= PF_OSFP_DF; 17554558Sbp#ifdef _KERNEL 17654558Sbp strlcpy(srcname, inet_ntoa(ip->ip_src), sizeof(srcname)); 17754558Sbp#else 17854558Sbp memset(&sin, 0, sizeof(sin)); 17954558Sbp sin.sin_family = AF_INET; 18054558Sbp sin.sin_len = sizeof(struct sockaddr_in); 18154558Sbp sin.sin_addr = ip->ip_src; 18254558Sbp (void)getnameinfo((struct sockaddr *)&sin, 18354558Sbp sizeof(struct sockaddr_in), srcname, sizeof(srcname), 18454558Sbp NULL, 0, NI_NUMERICHOST); 18554558Sbp#endif 18654558Sbp } 18754558Sbp#ifdef INET6 18854558Sbp else if (ip6) { 18954558Sbp#ifndef _KERNEL 19054558Sbp struct sockaddr_in6 sin6; 19154558Sbp#endif 19254558Sbp 19354558Sbp /* jumbo payload? */ 19454558Sbp fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); 19554558Sbp fp.fp_ttl = ip6->ip6_hlim; 19654558Sbp fp.fp_flags |= PF_OSFP_DF; 19754558Sbp fp.fp_flags |= PF_OSFP_INET6; 19854558Sbp#ifdef _KERNEL 19954558Sbp strlcpy(srcname, ip6_sprintf((struct in6_addr *)&ip6->ip6_src), 20054558Sbp sizeof(srcname)); 20154558Sbp#else 20254558Sbp memset(&sin6, 0, sizeof(sin6)); 20354558Sbp sin6.sin6_family = AF_INET6; 20454558Sbp sin6.sin6_len = sizeof(struct sockaddr_in6); 20554558Sbp sin6.sin6_addr = ip6->ip6_src; 20654558Sbp (void)getnameinfo((struct sockaddr *)&sin6, 20754558Sbp sizeof(struct sockaddr_in6), srcname, sizeof(srcname), 20854558Sbp NULL, 0, NI_NUMERICHOST); 20954558Sbp#endif 21054558Sbp } 21154558Sbp#endif 21254558Sbp else 21354558Sbp return (NULL); 21454558Sbp fp.fp_wsize = ntohs(tcp->th_win); 21554558Sbp 21654558Sbp 21754558Sbp cnt = (tcp->th_off << 2) - sizeof(*tcp); 21854558Sbp optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp)); 21954558Sbp for (; cnt > 0; cnt -= optlen, optp += optlen) { 22054558Sbp if (*optp == TCPOPT_EOL) 22154558Sbp break; 22254558Sbp 22354558Sbp fp.fp_optcnt++; 22454558Sbp if (*optp == TCPOPT_NOP) { 22554558Sbp fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) | 22654558Sbp PF_OSFP_TCPOPT_NOP; 22754558Sbp optlen = 1; 22854558Sbp } else { 22954558Sbp if (cnt < 2) 23054558Sbp return (NULL); 23154558Sbp optlen = optp[1]; 23254558Sbp if (optlen > cnt || optlen < 2) 23354558Sbp return (NULL); 23454558Sbp switch (*optp) { 23554558Sbp case TCPOPT_MAXSEG: 23654558Sbp if (optlen >= TCPOLEN_MAXSEG) 23754558Sbp memcpy(&fp.fp_mss, &optp[2], 23854558Sbp sizeof(fp.fp_mss)); 23954558Sbp fp.fp_tcpopts = (fp.fp_tcpopts << 24054558Sbp PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS; 24159681Sbp NTOHS(fp.fp_mss); 24259681Sbp break; 24359681Sbp case TCPOPT_WINDOW: 24454558Sbp if (optlen >= TCPOLEN_WINDOW) 24554558Sbp memcpy(&fp.fp_wscale, &optp[2], 24659681Sbp sizeof(fp.fp_wscale)); 24754558Sbp NTOHS(fp.fp_wscale); 24859681Sbp fp.fp_tcpopts = (fp.fp_tcpopts << 24959681Sbp PF_OSFP_TCPOPT_BITS) | 25054558Sbp PF_OSFP_TCPOPT_WSCALE; 25154558Sbp break; 25254558Sbp case TCPOPT_SACK_PERMITTED: 25354558Sbp fp.fp_tcpopts = (fp.fp_tcpopts << 25454558Sbp PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK; 25554558Sbp break; 25654558Sbp case TCPOPT_TIMESTAMP: 25754558Sbp if (optlen >= TCPOLEN_TIMESTAMP) { 25854558Sbp u_int32_t ts; 25954558Sbp memcpy(&ts, &optp[2], sizeof(ts)); 26054558Sbp if (ts == 0) 26154558Sbp fp.fp_flags |= PF_OSFP_TS0; 26254558Sbp 26354558Sbp } 26454558Sbp fp.fp_tcpopts = (fp.fp_tcpopts << 26554558Sbp PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS; 26654558Sbp break; 26754558Sbp default: 26854558Sbp return (NULL); 26954558Sbp } 27054558Sbp } 27154558Sbp optlen = MAX(optlen, 1); /* paranoia */ 27254558Sbp } 27354558Sbp 27454558Sbp DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) " 27554558Sbp "(TS=%s,M=%s%d,W=%s%d)\n", 27654558Sbp srcname, ntohs(tcp->th_sport), 27754558Sbp fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0, 27854558Sbp fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt, 27954558Sbp (fp.fp_flags & PF_OSFP_TS0) ? "0" : "", 28054558Sbp (fp.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 28154558Sbp (fp.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 28254558Sbp fp.fp_mss, 28359681Sbp (fp.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 28459681Sbp (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 28554558Sbp fp.fp_wscale); 28654558Sbp 28754558Sbp#ifdef __FreeBSD__ 28854558Sbp if ((fpresult = pf_osfp_find(&V_pf_osfp_list, &fp, 28954558Sbp#else 29054558Sbp if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp, 29154558Sbp#endif 29254558Sbp PF_OSFP_MAXTTL_OFFSET))) 29354558Sbp return (&fpresult->fp_oses); 29454558Sbp return (NULL); 29554558Sbp} 29654558Sbp 29754558Sbp/* Match a fingerprint ID against a list of OSes */ 29854558Sbpint 29954558Sbppf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os) 30054558Sbp{ 30159681Sbp struct pf_osfp_entry *entry; 30259681Sbp int os_class, os_version, os_subtype; 30354558Sbp int en_class, en_version, en_subtype; 30454558Sbp 30554558Sbp if (os == PF_OSFP_ANY) 30654558Sbp return (1); 30754558Sbp if (list == NULL) { 30854558Sbp DPFPRINTF("osfp no match against %x\n", os); 30954558Sbp return (os == PF_OSFP_UNKNOWN); 31054558Sbp } 31154558Sbp PF_OSFP_UNPACK(os, os_class, os_version, os_subtype); 31254558Sbp SLIST_FOREACH(entry, list, fp_entry) { 31354558Sbp PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype); 31454558Sbp if ((os_class == PF_OSFP_ANY || en_class == os_class) && 31554558Sbp (os_version == PF_OSFP_ANY || en_version == os_version) && 31654558Sbp (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) { 31754558Sbp DPFPRINTF("osfp matched %s %s %s %x==%x\n", 31854558Sbp entry->fp_class_nm, entry->fp_version_nm, 31959681Sbp entry->fp_subtype_nm, os, entry->fp_os); 32059681Sbp return (1); 32154558Sbp } 32254558Sbp } 32354558Sbp DPFPRINTF("fingerprint 0x%x didn't match\n", os); 32454558Sbp return (0); 32554558Sbp} 32654558Sbp 32754558Sbp/* Initialize the OS fingerprint system */ 32854558Sbp#ifdef __FreeBSD__ 32954558Sbpint 33054558Sbp#else 33154558Sbpvoid 33254558Sbp#endif 33354558Sbppf_osfp_initialize(void) 33454558Sbp{ 33554558Sbp#if defined(__FreeBSD__) && defined(_KERNEL) 33654558Sbp int error = ENOMEM; 33754558Sbp 33854558Sbp do { 33954558Sbp pf_osfp_entry_pl = pf_osfp_pl = NULL; 34054558Sbp UMA_CREATE(pf_osfp_entry_pl, struct pf_osfp_entry, "pfospfen"); 34154558Sbp UMA_CREATE(pf_osfp_pl, struct pf_os_fingerprint, "pfosfp"); 34254558Sbp error = 0; 34354558Sbp } while(0); 34454558Sbp 34554558Sbp SLIST_INIT(&V_pf_osfp_list); 34654558Sbp#else 34754558Sbp pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0, 34854558Sbp "pfosfpen", &pool_allocator_nointr); 34954558Sbp pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0, 35054558Sbp "pfosfp", &pool_allocator_nointr); 35154558Sbp SLIST_INIT(&pf_osfp_list); 35254558Sbp#endif 35354558Sbp 35454558Sbp#ifdef __FreeBSD__ 35554558Sbp#ifdef _KERNEL 35654558Sbp return (error); 35754558Sbp#else 35854558Sbp return (0); 35954558Sbp#endif 36054558Sbp#endif 36154558Sbp} 36254558Sbp 36354558Sbp#if defined(__FreeBSD__) && (_KERNEL) 36459681Sbpvoid 36554558Sbppf_osfp_cleanup(void) 36654558Sbp{ 36754558Sbp 36854558Sbp UMA_DESTROY(pf_osfp_entry_pl); 36954558Sbp UMA_DESTROY(pf_osfp_pl); 37054558Sbp} 37154558Sbp#endif 37254558Sbp 37354558Sbp/* Flush the fingerprint list */ 37454558Sbpvoid 37554558Sbppf_osfp_flush(void) 37654558Sbp{ 37754558Sbp struct pf_os_fingerprint *fp; 37854558Sbp struct pf_osfp_entry *entry; 37959681Sbp 38054558Sbp#ifdef __FreeBSD__ 38154558Sbp while ((fp = SLIST_FIRST(&V_pf_osfp_list))) { 38254558Sbp SLIST_REMOVE_HEAD(&V_pf_osfp_list, fp_next); 38359681Sbp#else 38454558Sbp while ((fp = SLIST_FIRST(&pf_osfp_list))) { 38554558Sbp SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next); 38654558Sbp#endif 38754558Sbp while ((entry = SLIST_FIRST(&fp->fp_oses))) { 38854558Sbp SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry); 38954558Sbp pool_put(&pf_osfp_entry_pl, entry); 39054558Sbp } 39154558Sbp pool_put(&pf_osfp_pl, fp); 39254558Sbp } 39354558Sbp} 39454558Sbp 39554558Sbp 39654558Sbp/* Add a fingerprint */ 39754558Sbpint 39854558Sbppf_osfp_add(struct pf_osfp_ioctl *fpioc) 39954558Sbp{ 40059681Sbp struct pf_os_fingerprint *fp, fpadd; 40159681Sbp struct pf_osfp_entry *entry; 40254558Sbp 40354558Sbp memset(&fpadd, 0, sizeof(fpadd)); 40454558Sbp fpadd.fp_tcpopts = fpioc->fp_tcpopts; 40554558Sbp fpadd.fp_wsize = fpioc->fp_wsize; 40654558Sbp fpadd.fp_psize = fpioc->fp_psize; 40754558Sbp fpadd.fp_mss = fpioc->fp_mss; 40854558Sbp fpadd.fp_flags = fpioc->fp_flags; 40954558Sbp fpadd.fp_optcnt = fpioc->fp_optcnt; 41059681Sbp fpadd.fp_wscale = fpioc->fp_wscale; 41159681Sbp fpadd.fp_ttl = fpioc->fp_ttl; 41254558Sbp 41354558Sbp#if 0 /* XXX RYAN wants to fix logging */ 41459681Sbp DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d " 41559681Sbp "(TS=%s,M=%s%d,W=%s%d) %x\n", 41654558Sbp fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm, 41754558Sbp fpioc->fp_os.fp_subtype_nm, 41854558Sbp (fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" : 41954558Sbp (fpadd.fp_flags & PF_OSFP_WSIZE_MSS) ? "S" : 42054558Sbp (fpadd.fp_flags & PF_OSFP_WSIZE_MTU) ? "T" : 42154558Sbp (fpadd.fp_flags & PF_OSFP_WSIZE_DC) ? "*" : "", 42259681Sbp fpadd.fp_wsize, 42354558Sbp fpadd.fp_ttl, 42454558Sbp (fpadd.fp_flags & PF_OSFP_DF) ? 1 : 0, 42554558Sbp (fpadd.fp_flags & PF_OSFP_PSIZE_MOD) ? "%" : 42654558Sbp (fpadd.fp_flags & PF_OSFP_PSIZE_DC) ? "*" : "", 42754558Sbp fpadd.fp_psize, 42854558Sbp (long long int)fpadd.fp_tcpopts, fpadd.fp_optcnt, 42954558Sbp (fpadd.fp_flags & PF_OSFP_TS0) ? "0" : "", 43054558Sbp (fpadd.fp_flags & PF_OSFP_MSS_MOD) ? "%" : 43154558Sbp (fpadd.fp_flags & PF_OSFP_MSS_DC) ? "*" : "", 43254558Sbp fpadd.fp_mss, 43354558Sbp (fpadd.fp_flags & PF_OSFP_WSCALE_MOD) ? "%" : 43454558Sbp (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", 43559681Sbp fpadd.fp_wscale, 43654558Sbp fpioc->fp_os.fp_os); 43759681Sbp#endif 43854558Sbp 43954558Sbp#ifdef __FreeBSD__ 44054558Sbp if ((fp = pf_osfp_find_exact(&V_pf_osfp_list, &fpadd))) { 44154558Sbp#else 44259681Sbp if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) { 44354558Sbp#endif 44454558Sbp SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 44554558Sbp if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os)) 44654558Sbp return (EEXIST); 44754558Sbp } 44859681Sbp if ((entry = pool_get(&pf_osfp_entry_pl, 44954558Sbp#ifdef __FreeBSD__ 45054558Sbp PR_NOWAIT)) == NULL) 45154558Sbp#else 45254558Sbp PR_WAITOK|PR_LIMITFAIL)) == NULL) 45354558Sbp#endif 45454558Sbp return (ENOMEM); 45559681Sbp } else { 45659681Sbp if ((fp = pool_get(&pf_osfp_pl, 45759681Sbp#ifdef __FreeBSD__ 45859681Sbp PR_NOWAIT)) == NULL) 45959681Sbp#else 46059681Sbp PR_WAITOK|PR_LIMITFAIL)) == NULL) 46159681Sbp#endif 46259681Sbp return (ENOMEM); 46359681Sbp memset(fp, 0, sizeof(*fp)); 46459681Sbp fp->fp_tcpopts = fpioc->fp_tcpopts; 46559681Sbp fp->fp_wsize = fpioc->fp_wsize; 46659681Sbp fp->fp_psize = fpioc->fp_psize; 46759681Sbp fp->fp_mss = fpioc->fp_mss; 46859681Sbp fp->fp_flags = fpioc->fp_flags; 46959681Sbp fp->fp_optcnt = fpioc->fp_optcnt; 47054558Sbp fp->fp_wscale = fpioc->fp_wscale; 47154558Sbp fp->fp_ttl = fpioc->fp_ttl; 47254558Sbp SLIST_INIT(&fp->fp_oses); 47354558Sbp if ((entry = pool_get(&pf_osfp_entry_pl, 47454558Sbp#ifdef __FreeBSD__ 47554558Sbp PR_NOWAIT)) == NULL) { 47654558Sbp#else 47754558Sbp PR_WAITOK|PR_LIMITFAIL)) == NULL) { 47859681Sbp#endif 47959681Sbp pool_put(&pf_osfp_pl, fp); 48059681Sbp return (ENOMEM); 48159681Sbp } 48254558Sbp#ifdef __FreeBSD__ 48354558Sbp pf_osfp_insert(&V_pf_osfp_list, fp); 48454558Sbp#else 48554558Sbp pf_osfp_insert(&pf_osfp_list, fp); 48654558Sbp#endif 48759681Sbp } 48854558Sbp memcpy(entry, &fpioc->fp_os, sizeof(*entry)); 48959681Sbp 49054558Sbp /* Make sure the strings are NUL terminated */ 49154558Sbp entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0'; 49254558Sbp entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0'; 49354558Sbp entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0'; 49454558Sbp 49554558Sbp SLIST_INSERT_HEAD(&fp->fp_oses, entry, fp_entry); 49654558Sbp 49754558Sbp#ifdef PFDEBUG 49854558Sbp if ((fp = pf_osfp_validate())) 49954558Sbp printf("Invalid fingerprint list\n"); 50054558Sbp#endif /* PFDEBUG */ 50154558Sbp return (0); 50254558Sbp} 50354558Sbp 50454558Sbp 50554558Sbp/* Find a fingerprint in the list */ 50654558Sbpstruct pf_os_fingerprint * 50754558Sbppf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, 50854558Sbp u_int8_t ttldiff) 50954558Sbp{ 51054558Sbp struct pf_os_fingerprint *f; 51154558Sbp 51254558Sbp#define MATCH_INT(_MOD, _DC, _field) \ 51354558Sbp if ((f->fp_flags & _DC) == 0) { \ 51454558Sbp if ((f->fp_flags & _MOD) == 0) { \ 51554558Sbp if (f->_field != find->_field) \ 51654558Sbp continue; \ 51754558Sbp } else { \ 51854558Sbp if (f->_field == 0 || find->_field % f->_field) \ 51954558Sbp continue; \ 52054558Sbp } \ 52154558Sbp } 52254558Sbp 52354558Sbp SLIST_FOREACH(f, list, fp_next) { 52454558Sbp if (f->fp_tcpopts != find->fp_tcpopts || 52554558Sbp f->fp_optcnt != find->fp_optcnt || 52654558Sbp f->fp_ttl < find->fp_ttl || 52754558Sbp f->fp_ttl - find->fp_ttl > ttldiff || 52854558Sbp (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) != 52954558Sbp (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0))) 53054558Sbp continue; 53154558Sbp 53254558Sbp MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize) 53354558Sbp MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss) 53454558Sbp MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale) 53554558Sbp if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) { 53654558Sbp if (f->fp_flags & PF_OSFP_WSIZE_MSS) { 53754558Sbp if (find->fp_mss == 0) 53854558Sbp continue; 53954558Sbp 54054558Sbp/* 54154558Sbp * Some "smart" NAT devices and DSL routers will tweak the MSS size and 54254558Sbp * will set it to whatever is suitable for the link type. 54354558Sbp */ 54454558Sbp#define SMART_MSS 1460 54554558Sbp if ((find->fp_wsize % find->fp_mss || 54654558Sbp find->fp_wsize / find->fp_mss != 54754558Sbp f->fp_wsize) && 54854558Sbp (find->fp_wsize % SMART_MSS || 54954558Sbp find->fp_wsize / SMART_MSS != 55054558Sbp f->fp_wsize)) 55154558Sbp continue; 55254558Sbp } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) { 55354558Sbp if (find->fp_mss == 0) 55454558Sbp continue; 55554558Sbp 55654558Sbp#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) 55754558Sbp#define SMART_MTU (SMART_MSS + MTUOFF) 55854558Sbp if ((find->fp_wsize % (find->fp_mss + MTUOFF) || 55954558Sbp find->fp_wsize / (find->fp_mss + MTUOFF) != 56054558Sbp f->fp_wsize) && 56154558Sbp (find->fp_wsize % SMART_MTU || 56254558Sbp find->fp_wsize / SMART_MTU != 56354558Sbp f->fp_wsize)) 56454558Sbp continue; 56554558Sbp } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) { 56654558Sbp if (f->fp_wsize == 0 || find->fp_wsize % 56754558Sbp f->fp_wsize) 56854558Sbp continue; 56954558Sbp } else { 57054558Sbp if (f->fp_wsize != find->fp_wsize) 57154558Sbp continue; 57254558Sbp } 57354558Sbp } 57454558Sbp return (f); 57554558Sbp } 57654558Sbp 57754558Sbp return (NULL); 57854558Sbp} 57954558Sbp 58054558Sbp/* Find an exact fingerprint in the list */ 58154558Sbpstruct pf_os_fingerprint * 58254558Sbppf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find) 58354558Sbp{ 58454558Sbp struct pf_os_fingerprint *f; 58554558Sbp 58654558Sbp SLIST_FOREACH(f, list, fp_next) { 58754558Sbp if (f->fp_tcpopts == find->fp_tcpopts && 58854558Sbp f->fp_wsize == find->fp_wsize && 58954558Sbp f->fp_psize == find->fp_psize && 59054558Sbp f->fp_mss == find->fp_mss && 59154558Sbp f->fp_flags == find->fp_flags && 59254558Sbp f->fp_optcnt == find->fp_optcnt && 59354558Sbp f->fp_wscale == find->fp_wscale && 59454558Sbp f->fp_ttl == find->fp_ttl) 59554558Sbp return (f); 59654558Sbp } 59754558Sbp 59854558Sbp return (NULL); 59954558Sbp} 60054558Sbp 60154558Sbp/* Insert a fingerprint into the list */ 60254558Sbpvoid 60354558Sbppf_osfp_insert(struct pf_osfp_list *list, struct pf_os_fingerprint *ins) 60454558Sbp{ 60554558Sbp struct pf_os_fingerprint *f, *prev = NULL; 60654558Sbp 60754558Sbp /* XXX need to go semi tree based. can key on tcp options */ 60854558Sbp 60954558Sbp SLIST_FOREACH(f, list, fp_next) 61054558Sbp prev = f; 61154558Sbp if (prev) 61254558Sbp SLIST_INSERT_AFTER(prev, ins, fp_next); 61354558Sbp else 61454558Sbp SLIST_INSERT_HEAD(list, ins, fp_next); 61554558Sbp} 61654558Sbp 61754558Sbp/* Fill a fingerprint by its number (from an ioctl) */ 61854558Sbpint 61954558Sbppf_osfp_get(struct pf_osfp_ioctl *fpioc) 62054558Sbp{ 62154558Sbp struct pf_os_fingerprint *fp; 62254558Sbp struct pf_osfp_entry *entry; 62354558Sbp int num = fpioc->fp_getnum; 62454558Sbp int i = 0; 62554558Sbp 62654558Sbp 627 memset(fpioc, 0, sizeof(*fpioc)); 628#ifdef __FreeBSD__ 629 SLIST_FOREACH(fp, &V_pf_osfp_list, fp_next) { 630#else 631 SLIST_FOREACH(fp, &pf_osfp_list, fp_next) { 632#endif 633 SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { 634 if (i++ == num) { 635 fpioc->fp_mss = fp->fp_mss; 636 fpioc->fp_wsize = fp->fp_wsize; 637 fpioc->fp_flags = fp->fp_flags; 638 fpioc->fp_psize = fp->fp_psize; 639 fpioc->fp_ttl = fp->fp_ttl; 640 fpioc->fp_wscale = fp->fp_wscale; 641 fpioc->fp_getnum = num; 642 memcpy(&fpioc->fp_os, entry, 643 sizeof(fpioc->fp_os)); 644 return (0); 645 } 646 } 647 } 648 649 return (EBUSY); 650} 651 652 653/* Validate that each signature is reachable */ 654struct pf_os_fingerprint * 655pf_osfp_validate(void) 656{ 657 struct pf_os_fingerprint *f, *f2, find; 658 659#ifdef __FreeBSD__ 660 SLIST_FOREACH(f, &V_pf_osfp_list, fp_next) { 661#else 662 SLIST_FOREACH(f, &pf_osfp_list, fp_next) { 663#endif 664 memcpy(&find, f, sizeof(find)); 665 666 /* We do a few MSS/th_win percolations to make things unique */ 667 if (find.fp_mss == 0) 668 find.fp_mss = 128; 669 if (f->fp_flags & PF_OSFP_WSIZE_MSS) 670 find.fp_wsize *= find.fp_mss; 671 else if (f->fp_flags & PF_OSFP_WSIZE_MTU) 672 find.fp_wsize *= (find.fp_mss + 40); 673 else if (f->fp_flags & PF_OSFP_WSIZE_MOD) 674 find.fp_wsize *= 2; 675#ifdef __FreeBSD__ 676 if (f != (f2 = pf_osfp_find(&V_pf_osfp_list, &find, 0))) { 677#else 678 if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) { 679#endif 680 if (f2) 681 printf("Found \"%s %s %s\" instead of " 682 "\"%s %s %s\"\n", 683 SLIST_FIRST(&f2->fp_oses)->fp_class_nm, 684 SLIST_FIRST(&f2->fp_oses)->fp_version_nm, 685 SLIST_FIRST(&f2->fp_oses)->fp_subtype_nm, 686 SLIST_FIRST(&f->fp_oses)->fp_class_nm, 687 SLIST_FIRST(&f->fp_oses)->fp_version_nm, 688 SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 689 else 690 printf("Couldn't find \"%s %s %s\"\n", 691 SLIST_FIRST(&f->fp_oses)->fp_class_nm, 692 SLIST_FIRST(&f->fp_oses)->fp_version_nm, 693 SLIST_FIRST(&f->fp_oses)->fp_subtype_nm); 694 return (f); 695 } 696 } 697 return (NULL); 698} 699