Line data Source code
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 0 : pf_osfp_fingerprint(struct pf_pdesc *pd)
88 : {
89 0 : struct tcphdr *th = &pd->hdr.tcp;
90 : struct ip *ip = NULL;
91 : struct ip6_hdr *ip6 = NULL;
92 0 : char hdr[60];
93 :
94 0 : if (pd->proto != IPPROTO_TCP)
95 0 : return (NULL);
96 :
97 0 : switch (pd->af) {
98 : case AF_INET:
99 0 : ip = mtod(pd->m, struct ip *);
100 0 : break;
101 : case AF_INET6:
102 0 : ip6 = mtod(pd->m, struct ip6_hdr *);
103 0 : break;
104 : }
105 0 : if (!pf_pull_hdr(pd->m, pd->off, hdr, th->th_off << 2, NULL, NULL,
106 0 : pd->af))
107 0 : return (NULL);
108 :
109 0 : return (pf_osfp_fingerprint_hdr(ip, ip6, (struct tcphdr *)hdr));
110 0 : }
111 : #endif /* _KERNEL */
112 :
113 : struct pf_osfp_enlist *
114 0 : pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6,
115 : const struct tcphdr *tcp)
116 : {
117 0 : struct pf_os_fingerprint fp, *fpresult;
118 : int cnt, optlen = 0;
119 : const u_int8_t *optp;
120 : #ifdef _KERNEL
121 0 : char srcname[128];
122 : #else /* !_KERNEL */
123 : char srcname[NI_MAXHOST];
124 : #endif /* _KERNEL */
125 :
126 0 : if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN)
127 0 : return (NULL);
128 0 : if (ip) {
129 0 : if ((ip->ip_off & htons(IP_OFFMASK)) != 0)
130 0 : return (NULL);
131 : }
132 :
133 0 : memset(&fp, 0, sizeof(fp));
134 :
135 0 : if (ip) {
136 : #ifndef _KERNEL
137 : struct sockaddr_in sin;
138 : #endif /* _KERNEL */
139 :
140 0 : fp.fp_psize = ntohs(ip->ip_len);
141 0 : fp.fp_ttl = ip->ip_ttl;
142 0 : if (ip->ip_off & htons(IP_DF))
143 0 : fp.fp_flags |= PF_OSFP_DF;
144 : #ifdef _KERNEL
145 0 : 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 0 : }
156 : #ifdef INET6
157 0 : else if (ip6) {
158 : #ifndef _KERNEL
159 : struct sockaddr_in6 sin6;
160 : #endif /* !_KERNEL */
161 :
162 : /* jumbo payload? */
163 0 : fp.fp_psize = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
164 0 : fp.fp_ttl = ip6->ip6_hlim;
165 0 : fp.fp_flags |= PF_OSFP_DF;
166 0 : fp.fp_flags |= PF_OSFP_INET6;
167 : #ifdef _KERNEL
168 0 : 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 0 : return (NULL);
182 0 : fp.fp_wsize = ntohs(tcp->th_win);
183 :
184 :
185 0 : cnt = (tcp->th_off << 2) - sizeof(*tcp);
186 0 : optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp));
187 0 : for (; cnt > 0; cnt -= optlen, optp += optlen) {
188 0 : if (*optp == TCPOPT_EOL)
189 : break;
190 :
191 0 : fp.fp_optcnt++;
192 0 : if (*optp == TCPOPT_NOP) {
193 0 : fp.fp_tcpopts = (fp.fp_tcpopts << PF_OSFP_TCPOPT_BITS) |
194 : PF_OSFP_TCPOPT_NOP;
195 : optlen = 1;
196 0 : } else {
197 0 : if (cnt < 2)
198 0 : return (NULL);
199 0 : optlen = optp[1];
200 0 : if (optlen > cnt || optlen < 2)
201 0 : return (NULL);
202 0 : switch (*optp) {
203 : case TCPOPT_MAXSEG:
204 0 : if (optlen >= TCPOLEN_MAXSEG)
205 0 : memcpy(&fp.fp_mss, &optp[2],
206 : sizeof(fp.fp_mss));
207 0 : fp.fp_tcpopts = (fp.fp_tcpopts <<
208 0 : PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_MSS;
209 0 : fp.fp_mss = ntohs(fp.fp_mss);
210 0 : break;
211 : case TCPOPT_WINDOW:
212 0 : if (optlen >= TCPOLEN_WINDOW)
213 0 : memcpy(&fp.fp_wscale, &optp[2],
214 : sizeof(fp.fp_wscale));
215 0 : fp.fp_tcpopts = (fp.fp_tcpopts <<
216 0 : PF_OSFP_TCPOPT_BITS) |
217 : PF_OSFP_TCPOPT_WSCALE;
218 0 : break;
219 : case TCPOPT_SACK_PERMITTED:
220 0 : fp.fp_tcpopts = (fp.fp_tcpopts <<
221 0 : PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_SACK;
222 0 : break;
223 : case TCPOPT_TIMESTAMP:
224 0 : if (optlen >= TCPOLEN_TIMESTAMP) {
225 : u_int32_t ts;
226 0 : memcpy(&ts, &optp[2], sizeof(ts));
227 0 : if (ts == 0)
228 0 : fp.fp_flags |= PF_OSFP_TS0;
229 :
230 0 : }
231 0 : fp.fp_tcpopts = (fp.fp_tcpopts <<
232 0 : PF_OSFP_TCPOPT_BITS) | PF_OSFP_TCPOPT_TS;
233 0 : break;
234 : default:
235 0 : return (NULL);
236 : }
237 : }
238 0 : optlen = MAX(optlen, 1); /* paranoia */
239 : }
240 :
241 0 : 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 0 : if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp,
256 : PF_OSFP_MAXTTL_OFFSET)))
257 0 : return (&fpresult->fp_oses);
258 0 : return (NULL);
259 0 : }
260 :
261 : /* Match a fingerprint ID against a list of OSes */
262 : int
263 0 : 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 0 : if (os == PF_OSFP_ANY)
270 0 : return (1);
271 0 : if (list == NULL) {
272 0 : DPFPRINTF(LOG_INFO, "osfp no match against %x", os);
273 0 : return (os == PF_OSFP_UNKNOWN);
274 : }
275 0 : PF_OSFP_UNPACK(os, os_class, os_version, os_subtype);
276 0 : SLIST_FOREACH(entry, list, fp_entry) {
277 0 : PF_OSFP_UNPACK(entry->fp_os, en_class, en_version, en_subtype);
278 0 : if ((os_class == PF_OSFP_ANY || en_class == os_class) &&
279 0 : (os_version == PF_OSFP_ANY || en_version == os_version) &&
280 0 : (os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) {
281 0 : 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 0 : return (1);
286 : }
287 : }
288 0 : DPFPRINTF(LOG_INFO, "fingerprint 0x%x didn't match", os);
289 0 : return (0);
290 0 : }
291 :
292 : /* Initialize the OS fingerprint system */
293 : void
294 0 : pf_osfp_initialize(void)
295 : {
296 0 : pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0,
297 : IPL_NONE, PR_WAITOK, "pfosfpen", NULL);
298 0 : pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0,
299 : IPL_NONE, PR_WAITOK, "pfosfp", NULL);
300 0 : SLIST_INIT(&pf_osfp_list);
301 0 : }
302 :
303 : /* Flush the fingerprint list */
304 : void
305 0 : pf_osfp_flush(void)
306 : {
307 : struct pf_os_fingerprint *fp;
308 : struct pf_osfp_entry *entry;
309 :
310 0 : while ((fp = SLIST_FIRST(&pf_osfp_list))) {
311 0 : SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next);
312 0 : while ((entry = SLIST_FIRST(&fp->fp_oses))) {
313 0 : SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry);
314 0 : pool_put(&pf_osfp_entry_pl, entry);
315 : }
316 0 : pool_put(&pf_osfp_pl, fp);
317 : }
318 0 : }
319 :
320 :
321 : /* Add a fingerprint */
322 : int
323 0 : pf_osfp_add(struct pf_osfp_ioctl *fpioc)
324 : {
325 0 : struct pf_os_fingerprint *fp, fpadd;
326 : struct pf_osfp_entry *entry;
327 :
328 0 : memset(&fpadd, 0, sizeof(fpadd));
329 0 : fpadd.fp_tcpopts = fpioc->fp_tcpopts;
330 0 : fpadd.fp_wsize = fpioc->fp_wsize;
331 0 : fpadd.fp_psize = fpioc->fp_psize;
332 0 : fpadd.fp_mss = fpioc->fp_mss;
333 0 : fpadd.fp_flags = fpioc->fp_flags;
334 0 : fpadd.fp_optcnt = fpioc->fp_optcnt;
335 0 : fpadd.fp_wscale = fpioc->fp_wscale;
336 0 : fpadd.fp_ttl = fpioc->fp_ttl;
337 :
338 0 : 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 0 : if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) {
364 0 : SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
365 0 : if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os))
366 0 : return (EEXIST);
367 : }
368 0 : if ((entry = pool_get(&pf_osfp_entry_pl,
369 0 : PR_WAITOK|PR_LIMITFAIL)) == NULL)
370 0 : return (ENOMEM);
371 : } else {
372 0 : if ((fp = pool_get(&pf_osfp_pl,
373 0 : PR_WAITOK|PR_ZERO|PR_LIMITFAIL)) == NULL)
374 0 : return (ENOMEM);
375 0 : fp->fp_tcpopts = fpioc->fp_tcpopts;
376 0 : fp->fp_wsize = fpioc->fp_wsize;
377 0 : fp->fp_psize = fpioc->fp_psize;
378 0 : fp->fp_mss = fpioc->fp_mss;
379 0 : fp->fp_flags = fpioc->fp_flags;
380 0 : fp->fp_optcnt = fpioc->fp_optcnt;
381 0 : fp->fp_wscale = fpioc->fp_wscale;
382 0 : fp->fp_ttl = fpioc->fp_ttl;
383 0 : SLIST_INIT(&fp->fp_oses);
384 0 : if ((entry = pool_get(&pf_osfp_entry_pl,
385 0 : PR_WAITOK|PR_LIMITFAIL)) == NULL) {
386 0 : pool_put(&pf_osfp_pl, fp);
387 0 : return (ENOMEM);
388 : }
389 0 : pf_osfp_insert(&pf_osfp_list, fp);
390 : }
391 0 : memcpy(entry, &fpioc->fp_os, sizeof(*entry));
392 :
393 : /* Make sure the strings are NUL terminated */
394 0 : entry->fp_class_nm[sizeof(entry->fp_class_nm)-1] = '\0';
395 0 : entry->fp_version_nm[sizeof(entry->fp_version_nm)-1] = '\0';
396 0 : entry->fp_subtype_nm[sizeof(entry->fp_subtype_nm)-1] = '\0';
397 :
398 0 : 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 0 : return (0);
406 0 : }
407 :
408 :
409 : /* Find a fingerprint in the list */
410 : struct pf_os_fingerprint *
411 0 : 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 0 : SLIST_FOREACH(f, list, fp_next) {
428 0 : if (f->fp_tcpopts != find->fp_tcpopts ||
429 0 : f->fp_optcnt != find->fp_optcnt ||
430 0 : f->fp_ttl < find->fp_ttl ||
431 0 : f->fp_ttl - find->fp_ttl > ttldiff ||
432 0 : (f->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)) !=
433 0 : (find->fp_flags & (PF_OSFP_DF|PF_OSFP_TS0)))
434 : continue;
435 :
436 0 : MATCH_INT(PF_OSFP_PSIZE_MOD, PF_OSFP_PSIZE_DC, fp_psize)
437 0 : MATCH_INT(PF_OSFP_MSS_MOD, PF_OSFP_MSS_DC, fp_mss)
438 0 : MATCH_INT(PF_OSFP_WSCALE_MOD, PF_OSFP_WSCALE_DC, fp_wscale)
439 0 : if ((f->fp_flags & PF_OSFP_WSIZE_DC) == 0) {
440 0 : if (f->fp_flags & PF_OSFP_WSIZE_MSS) {
441 0 : 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 0 : if ((find->fp_wsize % find->fp_mss ||
449 0 : find->fp_wsize / find->fp_mss !=
450 0 : f->fp_wsize) &&
451 0 : (find->fp_wsize % SMART_MSS ||
452 0 : find->fp_wsize / SMART_MSS !=
453 0 : f->fp_wsize))
454 : continue;
455 0 : } else if (f->fp_flags & PF_OSFP_WSIZE_MTU) {
456 0 : 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 0 : if ((find->fp_wsize % (find->fp_mss + MTUOFF) ||
462 0 : find->fp_wsize / (find->fp_mss + MTUOFF) !=
463 0 : f->fp_wsize) &&
464 0 : (find->fp_wsize % SMART_MTU ||
465 0 : find->fp_wsize / SMART_MTU !=
466 0 : f->fp_wsize))
467 : continue;
468 0 : } else if (f->fp_flags & PF_OSFP_WSIZE_MOD) {
469 0 : if (f->fp_wsize == 0 || find->fp_wsize %
470 : f->fp_wsize)
471 : continue;
472 : } else {
473 0 : if (f->fp_wsize != find->fp_wsize)
474 : continue;
475 : }
476 : }
477 0 : return (f);
478 : }
479 :
480 0 : return (NULL);
481 0 : }
482 :
483 : /* Find an exact fingerprint in the list */
484 : struct pf_os_fingerprint *
485 0 : pf_osfp_find_exact(struct pf_osfp_list *list, struct pf_os_fingerprint *find)
486 : {
487 : struct pf_os_fingerprint *f;
488 :
489 0 : SLIST_FOREACH(f, list, fp_next) {
490 0 : if (f->fp_tcpopts == find->fp_tcpopts &&
491 0 : f->fp_wsize == find->fp_wsize &&
492 0 : f->fp_psize == find->fp_psize &&
493 0 : f->fp_mss == find->fp_mss &&
494 0 : f->fp_flags == find->fp_flags &&
495 0 : f->fp_optcnt == find->fp_optcnt &&
496 0 : f->fp_wscale == find->fp_wscale &&
497 0 : f->fp_ttl == find->fp_ttl)
498 0 : return (f);
499 : }
500 :
501 0 : return (NULL);
502 0 : }
503 :
504 : /* Insert a fingerprint into the list */
505 : void
506 0 : 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 0 : SLIST_FOREACH(f, list, fp_next)
513 : prev = f;
514 0 : if (prev)
515 0 : SLIST_INSERT_AFTER(prev, ins, fp_next);
516 : else
517 0 : SLIST_INSERT_HEAD(list, ins, fp_next);
518 0 : }
519 :
520 : /* Fill a fingerprint by its number (from an ioctl) */
521 : int
522 0 : pf_osfp_get(struct pf_osfp_ioctl *fpioc)
523 : {
524 : struct pf_os_fingerprint *fp;
525 : struct pf_osfp_entry *entry;
526 0 : int num = fpioc->fp_getnum;
527 : int i = 0;
528 :
529 :
530 0 : memset(fpioc, 0, sizeof(*fpioc));
531 0 : SLIST_FOREACH(fp, &pf_osfp_list, fp_next) {
532 0 : SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) {
533 0 : if (i++ == num) {
534 0 : fpioc->fp_mss = fp->fp_mss;
535 0 : fpioc->fp_wsize = fp->fp_wsize;
536 0 : fpioc->fp_flags = fp->fp_flags;
537 0 : fpioc->fp_psize = fp->fp_psize;
538 0 : fpioc->fp_ttl = fp->fp_ttl;
539 0 : fpioc->fp_wscale = fp->fp_wscale;
540 0 : fpioc->fp_getnum = num;
541 0 : memcpy(&fpioc->fp_os, entry,
542 : sizeof(fpioc->fp_os));
543 0 : return (0);
544 : }
545 : }
546 : }
547 :
548 0 : return (EBUSY);
549 0 : }
550 :
551 :
552 : /* Validate that each signature is reachable */
553 : struct pf_os_fingerprint *
554 0 : pf_osfp_validate(void)
555 : {
556 0 : struct pf_os_fingerprint *f, *f2, find;
557 :
558 0 : SLIST_FOREACH(f, &pf_osfp_list, fp_next) {
559 0 : memcpy(&find, f, sizeof(find));
560 :
561 : /* We do a few MSS/th_win percolations to make things unique */
562 0 : if (find.fp_mss == 0)
563 0 : find.fp_mss = 128;
564 0 : if (f->fp_flags & PF_OSFP_WSIZE_MSS)
565 0 : find.fp_wsize *= find.fp_mss;
566 0 : else if (f->fp_flags & PF_OSFP_WSIZE_MTU)
567 0 : find.fp_wsize *= (find.fp_mss + 40);
568 0 : else if (f->fp_flags & PF_OSFP_WSIZE_MOD)
569 0 : find.fp_wsize *= 2;
570 0 : if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) {
571 0 : if (f2)
572 0 : 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 0 : 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 0 : return (f);
588 : }
589 : }
590 0 : return (NULL);
591 0 : }
|