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