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