source: rtems-libbsd/freebsd/sys/contrib/pf/net/pf_osfp.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

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