| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: pfctl_osfp.c,v 1.25 2017/05/28 07:17:53 akfaew Exp $ */  | 
    ||
2  | 
    |||
3  | 
    /*  | 
    ||
4  | 
    * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.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  | 
    #include <sys/types.h>  | 
    ||
20  | 
    #include <sys/ioctl.h>  | 
    ||
21  | 
    #include <sys/socket.h>  | 
    ||
22  | 
    |||
23  | 
    #include <netinet/in.h>  | 
    ||
24  | 
    #include <netinet/ip.h>  | 
    ||
25  | 
    #include <netinet/ip6.h>  | 
    ||
26  | 
    #include <net/if.h>  | 
    ||
27  | 
    #include <net/pfvar.h>  | 
    ||
28  | 
    |||
29  | 
    #include <ctype.h>  | 
    ||
30  | 
    #include <err.h>  | 
    ||
31  | 
    #include <errno.h>  | 
    ||
32  | 
    #include <stdio.h>  | 
    ||
33  | 
    #include <stdlib.h>  | 
    ||
34  | 
    #include <string.h>  | 
    ||
35  | 
    |||
36  | 
    #include "pfctl_parser.h"  | 
    ||
37  | 
    #include "pfctl.h"  | 
    ||
38  | 
    |||
39  | 
    #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))  | 
    ||
40  | 
    |||
41  | 
    /* #define OSFP_DEBUG 1 */  | 
    ||
42  | 
    #ifdef OSFP_DEBUG  | 
    ||
43  | 
    # define DEBUG(fp, str, v...) \  | 
    ||
44  | 
    fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \  | 
    ||
45  | 
    (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v);  | 
    ||
46  | 
    #else  | 
    ||
47  | 
    # define DEBUG(fp, str, v...) ((void)0)  | 
    ||
48  | 
    #endif  | 
    ||
49  | 
    |||
50  | 
    |||
51  | 
    struct name_entry;  | 
    ||
52  | 
    LIST_HEAD(name_list, name_entry);  | 
    ||
53  | 
    struct name_entry { | 
    ||
54  | 
    LIST_ENTRY(name_entry) nm_entry;  | 
    ||
55  | 
    int nm_num;  | 
    ||
56  | 
    char nm_name[PF_OSFP_LEN];  | 
    ||
57  | 
    |||
58  | 
    struct name_list nm_sublist;  | 
    ||
59  | 
    int nm_sublist_num;  | 
    ||
60  | 
    };  | 
    ||
61  | 
    struct name_list classes = LIST_HEAD_INITIALIZER(&classes);  | 
    ||
62  | 
    int class_count;  | 
    ||
63  | 
    int fingerprint_count;  | 
    ||
64  | 
    |||
65  | 
    void add_fingerprint(int, int, struct pf_osfp_ioctl *);  | 
    ||
66  | 
    struct name_entry *fingerprint_name_entry(struct name_list *, char *);  | 
    ||
67  | 
    void pfctl_flush_my_fingerprints(struct name_list *);  | 
    ||
68  | 
    char *get_field(char **, size_t *, int *);  | 
    ||
69  | 
    int get_int(char **, size_t *, int *, int *, const char *,  | 
    ||
70  | 
    int, int, const char *, int);  | 
    ||
71  | 
    int get_str(char **, size_t *, char **, const char *, int,  | 
    ||
72  | 
    const char *, int);  | 
    ||
73  | 
    int get_tcpopts(const char *, int, const char *,  | 
    ||
74  | 
    pf_tcpopts_t *, int *, int *, int *, int *, int *,  | 
    ||
75  | 
    int *);  | 
    ||
76  | 
    void import_fingerprint(struct pf_osfp_ioctl *);  | 
    ||
77  | 
    #ifdef OSFP_DEBUG  | 
    ||
78  | 
    const char *print_ioctl(struct pf_osfp_ioctl *);  | 
    ||
79  | 
    #endif  | 
    ||
80  | 
    void print_name_list(int, struct name_list *, const char *);  | 
    ||
81  | 
    void sort_name_list(int, struct name_list *);  | 
    ||
82  | 
    struct name_entry *lookup_name_list(struct name_list *, const char *);  | 
    ||
83  | 
    |||
84  | 
    /* Load fingerprints from a file */  | 
    ||
85  | 
    int  | 
    ||
86  | 
    pfctl_file_fingerprints(int dev, int opts, const char *fp_filename)  | 
    ||
87  | 
    { | 
    ||
88  | 
    FILE *in;  | 
    ||
89  | 
    558  | 
    char *line;  | 
    |
90  | 
    279  | 
    size_t len;  | 
    |
91  | 
    int i, lineno = 0;  | 
    ||
92  | 
    279  | 
    int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale,  | 
    |
93  | 
    wscale_mod, optcnt, ts0;  | 
    ||
94  | 
    279  | 
    pf_tcpopts_t packed_tcpopts;  | 
    |
95  | 
    279  | 
    char *class, *version, *subtype, *desc, *tcpopts;  | 
    |
96  | 
    279  | 
    struct pf_osfp_ioctl fp;  | 
    |
97  | 
    |||
98  | 
    279  | 
    pfctl_flush_my_fingerprints(&classes);  | 
    |
99  | 
    |||
100  | 
    ✗✓ | 279  | 
    	if ((in = pfctl_fopen(fp_filename, "r")) == NULL) { | 
    
101  | 
    		warn("%s", fp_filename); | 
    ||
102  | 
    return (1);  | 
    ||
103  | 
    }  | 
    ||
104  | 
    279  | 
    class = version = subtype = desc = tcpopts = NULL;  | 
    |
105  | 
    |||
106  | 
    ✗✓ | 279  | 
    if ((opts & PF_OPT_NOACTION) == 0)  | 
    
107  | 
    pfctl_clear_fingerprints(dev, opts);  | 
    ||
108  | 
    |||
109  | 
    ✓✓ | 264213  | 
    	while ((line = fgetln(in, &len)) != NULL) { | 
    
110  | 
    195300  | 
    lineno++;  | 
    |
111  | 
    195300  | 
    free(class);  | 
    |
112  | 
    195300  | 
    free(version);  | 
    |
113  | 
    195300  | 
    free(subtype);  | 
    |
114  | 
    195300  | 
    free(desc);  | 
    |
115  | 
    195300  | 
    free(tcpopts);  | 
    |
116  | 
    195300  | 
    class = version = subtype = desc = tcpopts = NULL;  | 
    |
117  | 
    195300  | 
    memset(&fp, 0, sizeof(fp));  | 
    |
118  | 
    |||
119  | 
    /* Chop off comment */  | 
    ||
120  | 
    ✓✓ | 8887266  | 
    for (i = 0; i < len; i++)  | 
    
121  | 
    ✓✓ | 4331475  | 
    			if (line[i] == '#') { | 
    
122  | 
    83142  | 
    len = i;  | 
    |
123  | 
    83142  | 
    break;  | 
    |
124  | 
    }  | 
    ||
125  | 
    /* Chop off whitespace */  | 
    ||
126  | 
    ✓✓✓✓ | 
    600408  | 
    while (len > 0 && isspace((unsigned char)line[len - 1]))  | 
    
127  | 
    112158  | 
    len--;  | 
    |
128  | 
    ✓✓✗✓ | 
    459234  | 
    		while (len > 0 && isspace((unsigned char)line[0])) { | 
    
129  | 
    len--;  | 
    ||
130  | 
    line++;  | 
    ||
131  | 
    }  | 
    ||
132  | 
    ✓✓ | 195300  | 
    if (len == 0)  | 
    
133  | 
    continue;  | 
    ||
134  | 
    |||
135  | 
    #define T_DC 0x01 /* Allow don't care */  | 
    ||
136  | 
    #define T_MSS 0x02 /* Allow MSS multiple */  | 
    ||
137  | 
    #define T_MTU 0x04 /* Allow MTU multiple */  | 
    ||
138  | 
    #define T_MOD 0x08 /* Allow modulus */  | 
    ||
139  | 
    |||
140  | 
    #define GET_INT(v, mod, n, ty, mx) \  | 
    ||
141  | 
    get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno)  | 
    ||
142  | 
    #define GET_STR(v, n, mn) \  | 
    ||
143  | 
    get_str(&line, &len, &v, n, mn, fp_filename, lineno)  | 
    ||
144  | 
    |||
145  | 
    ✗✓ | 137268  | 
    if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU|  | 
    
146  | 
    ✗✓ | 68634  | 
    T_MOD, 0xffff) ||  | 
    
147  | 
    ✗✓ | 68634  | 
    GET_INT(ttl, NULL, "ttl", 0, 0xff) ||  | 
    
148  | 
    ✗✓ | 68634  | 
    GET_INT(df, NULL, "don't fragment frag", 0, 1) ||  | 
    
149  | 
    68634  | 
    GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC,  | 
    |
150  | 
    ✗✓ | 68634  | 
    8192) ||  | 
    
151  | 
    ✗✓ | 68634  | 
    GET_STR(tcpopts, "TCP Options", 1) ||  | 
    
152  | 
    ✗✓ | 68634  | 
    GET_STR(class, "OS class", 1) ||  | 
    
153  | 
    ✗✓ | 68634  | 
    GET_STR(version, "OS version", 0) ||  | 
    
154  | 
    ✗✓ | 68634  | 
    GET_STR(subtype, "OS subtype", 0) ||  | 
    
155  | 
    68634  | 
    GET_STR(desc, "OS description", 2))  | 
    |
156  | 
    continue;  | 
    ||
157  | 
    ✗✓ | 68634  | 
    if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts,  | 
    
158  | 
    &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0))  | 
    ||
159  | 
    continue;  | 
    ||
160  | 
    ✗✓ | 68634  | 
    		if (len != 0) { | 
    
161  | 
    fprintf(stderr, "%s:%d excess field\n", fp_filename,  | 
    ||
162  | 
    lineno);  | 
    ||
163  | 
    continue;  | 
    ||
164  | 
    }  | 
    ||
165  | 
    |||
166  | 
    68634  | 
    fp.fp_ttl = ttl;  | 
    |
167  | 
    ✓✓ | 68634  | 
    if (df)  | 
    
168  | 
    44640  | 
    fp.fp_flags |= PF_OSFP_DF;  | 
    |
169  | 
    ✓✓✓✗ | 
    122760  | 
    		switch (w_mod) { | 
    
170  | 
    case 0:  | 
    ||
171  | 
    break;  | 
    ||
172  | 
    case T_DC:  | 
    ||
173  | 
    fp.fp_flags |= PF_OSFP_WSIZE_DC;  | 
    ||
174  | 
    break;  | 
    ||
175  | 
    case T_MSS:  | 
    ||
176  | 
    fp.fp_flags |= PF_OSFP_WSIZE_MSS;  | 
    ||
177  | 
    break;  | 
    ||
178  | 
    case T_MTU:  | 
    ||
179  | 
    fp.fp_flags |= PF_OSFP_WSIZE_MTU;  | 
    ||
180  | 
    break;  | 
    ||
181  | 
    case T_MOD:  | 
    ||
182  | 
    fp.fp_flags |= PF_OSFP_WSIZE_MOD;  | 
    ||
183  | 
    break;  | 
    ||
184  | 
    }  | 
    ||
185  | 
    95697  | 
    fp.fp_wsize = window;  | 
    |
186  | 
    |||
187  | 
    ✗✗✓ | 68634  | 
    		switch (p_mod) { | 
    
188  | 
    case T_DC:  | 
    ||
189  | 
    fp.fp_flags |= PF_OSFP_PSIZE_DC;  | 
    ||
190  | 
    break;  | 
    ||
191  | 
    case T_MOD:  | 
    ||
192  | 
    fp.fp_flags |= PF_OSFP_PSIZE_MOD;  | 
    ||
193  | 
    }  | 
    ||
194  | 
    142290  | 
    fp.fp_psize = psize;  | 
    |
195  | 
    |||
196  | 
    |||
197  | 
    ✓✓✓ | 142290  | 
    		switch (wscale_mod) { | 
    
198  | 
    case T_DC:  | 
    ||
199  | 
    fp.fp_flags |= PF_OSFP_WSCALE_DC;  | 
    ||
200  | 
    35991  | 
    break;  | 
    |
201  | 
    case T_MOD:  | 
    ||
202  | 
    fp.fp_flags |= PF_OSFP_WSCALE_MOD;  | 
    ||
203  | 
    }  | 
    ||
204  | 
    190557  | 
    fp.fp_wscale = wscale;  | 
    |
205  | 
    |||
206  | 
    ✓✓✓ | 152892  | 
    		switch (mss_mod) { | 
    
207  | 
    case T_DC:  | 
    ||
208  | 
    fp.fp_flags |= PF_OSFP_MSS_DC;  | 
    ||
209  | 
    42129  | 
    break;  | 
    |
210  | 
    case T_MOD:  | 
    ||
211  | 
    fp.fp_flags |= PF_OSFP_MSS_MOD;  | 
    ||
212  | 
    break;  | 
    ||
213  | 
    }  | 
    ||
214  | 
    110763  | 
    fp.fp_mss = mss;  | 
    |
215  | 
    |||
216  | 
    68634  | 
    fp.fp_tcpopts = packed_tcpopts;  | 
    |
217  | 
    68634  | 
    fp.fp_optcnt = optcnt;  | 
    |
218  | 
    ✓✓ | 68634  | 
    if (ts0)  | 
    
219  | 
    4464  | 
    fp.fp_flags |= PF_OSFP_TS0;  | 
    |
220  | 
    |||
221  | 
    ✓✓ | 68634  | 
    if (class[0] == '@')  | 
    
222  | 
    3348  | 
    fp.fp_os.fp_enflags |= PF_OSFP_GENERIC;  | 
    |
223  | 
    ✓✓ | 68634  | 
    if (class[0] == '*')  | 
    
224  | 
    2511  | 
    fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL;  | 
    |
225  | 
    |||
226  | 
    ✓✓✓✓ | 
    133920  | 
    if (class[0] == '@' || class[0] == '*')  | 
    
227  | 
    5859  | 
    strlcpy(fp.fp_os.fp_class_nm, class + 1,  | 
    |
228  | 
    sizeof(fp.fp_os.fp_class_nm));  | 
    ||
229  | 
    else  | 
    ||
230  | 
    62775  | 
    strlcpy(fp.fp_os.fp_class_nm, class,  | 
    |
231  | 
    sizeof(fp.fp_os.fp_class_nm));  | 
    ||
232  | 
    68634  | 
    strlcpy(fp.fp_os.fp_version_nm, version,  | 
    |
233  | 
    sizeof(fp.fp_os.fp_version_nm));  | 
    ||
234  | 
    68634  | 
    strlcpy(fp.fp_os.fp_subtype_nm, subtype,  | 
    |
235  | 
    sizeof(fp.fp_os.fp_subtype_nm));  | 
    ||
236  | 
    |||
237  | 
    68634  | 
    add_fingerprint(dev, opts, &fp);  | 
    |
238  | 
    |||
239  | 
    68634  | 
    fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6);  | 
    |
240  | 
    68634  | 
    fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip);  | 
    |
241  | 
    68634  | 
    add_fingerprint(dev, opts, &fp);  | 
    |
242  | 
    }  | 
    ||
243  | 
    |||
244  | 
    279  | 
    free(class);  | 
    |
245  | 
    279  | 
    free(version);  | 
    |
246  | 
    279  | 
    free(subtype);  | 
    |
247  | 
    279  | 
    free(desc);  | 
    |
248  | 
    279  | 
    free(tcpopts);  | 
    |
249  | 
    |||
250  | 
    279  | 
    fclose(in);  | 
    |
251  | 
    |||
252  | 
    ✗✓ | 279  | 
    if (opts & PF_OPT_VERBOSE2)  | 
    
253  | 
    		printf("Loaded %d passive OS fingerprints\n", | 
    ||
254  | 
    fingerprint_count);  | 
    ||
255  | 
    279  | 
    return (0);  | 
    |
256  | 
    279  | 
    }  | 
    |
257  | 
    |||
258  | 
    /* flush the kernel's fingerprints */  | 
    ||
259  | 
    void  | 
    ||
260  | 
    pfctl_clear_fingerprints(int dev, int opts)  | 
    ||
261  | 
    { | 
    ||
262  | 
    if (ioctl(dev, DIOCOSFPFLUSH))  | 
    ||
263  | 
    err(1, "DIOCOSFPFLUSH");  | 
    ||
264  | 
    }  | 
    ||
265  | 
    |||
266  | 
    /* flush pfctl's view of the fingerprints */  | 
    ||
267  | 
    void  | 
    ||
268  | 
    pfctl_flush_my_fingerprints(struct name_list *list)  | 
    ||
269  | 
    { | 
    ||
270  | 
    struct name_entry *nm;  | 
    ||
271  | 
    |||
272  | 
    ✗✓ | 1263  | 
    	while ((nm = LIST_FIRST(list)) != NULL) { | 
    
273  | 
    LIST_REMOVE(nm, nm_entry);  | 
    ||
274  | 
    pfctl_flush_my_fingerprints(&nm->nm_sublist);  | 
    ||
275  | 
    free(nm);  | 
    ||
276  | 
    }  | 
    ||
277  | 
    421  | 
    fingerprint_count = 0;  | 
    |
278  | 
    421  | 
    class_count = 0;  | 
    |
279  | 
    421  | 
    }  | 
    |
280  | 
    |||
281  | 
    /* Fetch the active fingerprints from the kernel */  | 
    ||
282  | 
    int  | 
    ||
283  | 
    pfctl_load_fingerprints(int dev, int opts)  | 
    ||
284  | 
    { | 
    ||
285  | 
    284  | 
    struct pf_osfp_ioctl io;  | 
    |
286  | 
    int i;  | 
    ||
287  | 
    |||
288  | 
    142  | 
    pfctl_flush_my_fingerprints(&classes);  | 
    |
289  | 
    |||
290  | 
    ✓✗ | 203060  | 
    	for (i = 0; i >= 0; i++) { | 
    
291  | 
    101530  | 
    memset(&io, 0, sizeof(io));  | 
    |
292  | 
    101530  | 
    io.fp_getnum = i;  | 
    |
293  | 
    ✓✓ | 101530  | 
    		if (ioctl(dev, DIOCOSFPGET, &io)) { | 
    
294  | 
    ✗✓ | 142  | 
    if (errno == EBUSY)  | 
    
295  | 
    break;  | 
    ||
296  | 
    			warn("DIOCOSFPGET"); | 
    ||
297  | 
    return (1);  | 
    ||
298  | 
    }  | 
    ||
299  | 
    101388  | 
    import_fingerprint(&io);  | 
    |
300  | 
    }  | 
    ||
301  | 
    142  | 
    return (0);  | 
    |
302  | 
    142  | 
    }  | 
    |
303  | 
    |||
304  | 
    /* List the fingerprints */  | 
    ||
305  | 
    void  | 
    ||
306  | 
    pfctl_show_fingerprints(int opts)  | 
    ||
307  | 
    { | 
    ||
308  | 
    	if (LIST_FIRST(&classes) != NULL) { | 
    ||
309  | 
    		if (opts & PF_OPT_SHOWALL) { | 
    ||
310  | 
    			pfctl_print_title("OS FINGERPRINTS:"); | 
    ||
311  | 
    			printf("%u fingerprints loaded\n", fingerprint_count); | 
    ||
312  | 
    		} else { | 
    ||
313  | 
    			printf("Class\tVersion\tSubtype(subversion)\n"); | 
    ||
314  | 
    			printf("-----\t-------\t-------------------\n"); | 
    ||
315  | 
    sort_name_list(opts, &classes);  | 
    ||
316  | 
    print_name_list(opts, &classes, "");  | 
    ||
317  | 
    }  | 
    ||
318  | 
    }  | 
    ||
319  | 
    }  | 
    ||
320  | 
    |||
321  | 
    /* Lookup a fingerprint */  | 
    ||
322  | 
    pf_osfp_t  | 
    ||
323  | 
    pfctl_get_fingerprint(const char *name)  | 
    ||
324  | 
    { | 
    ||
325  | 
    struct name_entry *nm, *class_nm, *version_nm, *subtype_nm;  | 
    ||
326  | 
    pf_osfp_t ret = PF_OSFP_NOMATCH;  | 
    ||
327  | 
    int class, version, subtype;  | 
    ||
328  | 
    int unp_class, unp_version, unp_subtype;  | 
    ||
329  | 
    int wr_len, version_len, subtype_len;  | 
    ||
330  | 
    char *ptr, *wr_name;  | 
    ||
331  | 
    |||
332  | 
    if (strcasecmp(name, "unknown") == 0)  | 
    ||
333  | 
    return (PF_OSFP_UNKNOWN);  | 
    ||
334  | 
    |||
335  | 
    /* Try most likely no version and no subtype */  | 
    ||
336  | 
    	if ((nm = lookup_name_list(&classes, name))) { | 
    ||
337  | 
    class = nm->nm_num;  | 
    ||
338  | 
    version = PF_OSFP_ANY;  | 
    ||
339  | 
    subtype = PF_OSFP_ANY;  | 
    ||
340  | 
    goto found;  | 
    ||
341  | 
    	} else { | 
    ||
342  | 
    |||
343  | 
    /* Chop it up into class/version/subtype */  | 
    ||
344  | 
    |||
345  | 
    if ((wr_name = strdup(name)) == NULL)  | 
    ||
346  | 
    err(1, "malloc");  | 
    ||
347  | 
    		if ((ptr = strchr(wr_name, ' ')) == NULL) { | 
    ||
348  | 
    free(wr_name);  | 
    ||
349  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
350  | 
    }  | 
    ||
351  | 
    *ptr++ = '\0';  | 
    ||
352  | 
    |||
353  | 
    /* The class is easy to find since it is delimited by a space */  | 
    ||
354  | 
    		if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) { | 
    ||
355  | 
    free(wr_name);  | 
    ||
356  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
357  | 
    }  | 
    ||
358  | 
    class = class_nm->nm_num;  | 
    ||
359  | 
    |||
360  | 
    /* Try no subtype */  | 
    ||
361  | 
    if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr)))  | 
    ||
362  | 
    		{ | 
    ||
363  | 
    version = version_nm->nm_num;  | 
    ||
364  | 
    subtype = PF_OSFP_ANY;  | 
    ||
365  | 
    free(wr_name);  | 
    ||
366  | 
    goto found;  | 
    ||
367  | 
    }  | 
    ||
368  | 
    |||
369  | 
    |||
370  | 
    /*  | 
    ||
371  | 
    * There must be a version and a subtype.  | 
    ||
372  | 
    * We'll do some fuzzy matching to pick up things like:  | 
    ||
373  | 
    * Linux 2.2.14 (version=2.2 subtype=14)  | 
    ||
374  | 
    * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE)  | 
    ||
375  | 
    * Windows 2000 SP2 (version=2000 subtype=SP2)  | 
    ||
376  | 
    */  | 
    ||
377  | 
    #define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-')  | 
    ||
378  | 
    wr_len = strlen(ptr);  | 
    ||
379  | 
    		LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) { | 
    ||
380  | 
    version_len = strlen(version_nm->nm_name);  | 
    ||
381  | 
    if (wr_len < version_len + 2 ||  | 
    ||
382  | 
    !CONNECTOR(ptr[version_len]))  | 
    ||
383  | 
    continue;  | 
    ||
384  | 
    /* first part of the string must be version */  | 
    ||
385  | 
    if (strncasecmp(ptr, version_nm->nm_name,  | 
    ||
386  | 
    version_len))  | 
    ||
387  | 
    continue;  | 
    ||
388  | 
    |||
389  | 
    LIST_FOREACH(subtype_nm, &version_nm->nm_sublist,  | 
    ||
390  | 
    			    nm_entry) { | 
    ||
391  | 
    subtype_len = strlen(subtype_nm->nm_name);  | 
    ||
392  | 
    if (wr_len != version_len + subtype_len + 1)  | 
    ||
393  | 
    continue;  | 
    ||
394  | 
    |||
395  | 
    /* last part of the string must be subtype */  | 
    ||
396  | 
    if (strcasecmp(&ptr[version_len+1],  | 
    ||
397  | 
    subtype_nm->nm_name) != 0)  | 
    ||
398  | 
    continue;  | 
    ||
399  | 
    |||
400  | 
    /* Found it!! */  | 
    ||
401  | 
    version = version_nm->nm_num;  | 
    ||
402  | 
    subtype = subtype_nm->nm_num;  | 
    ||
403  | 
    free(wr_name);  | 
    ||
404  | 
    goto found;  | 
    ||
405  | 
    }  | 
    ||
406  | 
    }  | 
    ||
407  | 
    |||
408  | 
    free(wr_name);  | 
    ||
409  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
410  | 
    }  | 
    ||
411  | 
    |||
412  | 
    found:  | 
    ||
413  | 
    PF_OSFP_PACK(ret, class, version, subtype);  | 
    ||
414  | 
    	if (ret != PF_OSFP_NOMATCH) { | 
    ||
415  | 
    PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype);  | 
    ||
416  | 
    		if (class != unp_class) { | 
    ||
417  | 
    fprintf(stderr, "warning: fingerprint table overflowed "  | 
    ||
418  | 
    "classes\n");  | 
    ||
419  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
420  | 
    }  | 
    ||
421  | 
    		if (version != unp_version) { | 
    ||
422  | 
    fprintf(stderr, "warning: fingerprint table overflowed "  | 
    ||
423  | 
    "versions\n");  | 
    ||
424  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
425  | 
    }  | 
    ||
426  | 
    		if (subtype != unp_subtype) { | 
    ||
427  | 
    fprintf(stderr, "warning: fingerprint table overflowed "  | 
    ||
428  | 
    "subtypes\n");  | 
    ||
429  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
430  | 
    }  | 
    ||
431  | 
    }  | 
    ||
432  | 
    	if (ret == PF_OSFP_ANY) { | 
    ||
433  | 
    /* should never happen */  | 
    ||
434  | 
    fprintf(stderr, "warning: fingerprint packed to 'any'\n");  | 
    ||
435  | 
    return (PF_OSFP_NOMATCH);  | 
    ||
436  | 
    }  | 
    ||
437  | 
    |||
438  | 
    return (ret);  | 
    ||
439  | 
    }  | 
    ||
440  | 
    |||
441  | 
    /* Lookup a fingerprint name by ID */  | 
    ||
442  | 
    char *  | 
    ||
443  | 
    pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len)  | 
    ||
444  | 
    { | 
    ||
445  | 
    int class, version, subtype;  | 
    ||
446  | 
    struct name_list *list;  | 
    ||
447  | 
    struct name_entry *nm;  | 
    ||
448  | 
    |||
449  | 
    char *class_name, *version_name, *subtype_name;  | 
    ||
450  | 
    class_name = version_name = subtype_name = NULL;  | 
    ||
451  | 
    |||
452  | 
    	if (fp == PF_OSFP_UNKNOWN) { | 
    ||
453  | 
    strlcpy(buf, "unknown", len);  | 
    ||
454  | 
    return (buf);  | 
    ||
455  | 
    }  | 
    ||
456  | 
    	if (fp == PF_OSFP_ANY) { | 
    ||
457  | 
    strlcpy(buf, "any", len);  | 
    ||
458  | 
    return (buf);  | 
    ||
459  | 
    }  | 
    ||
460  | 
    |||
461  | 
    PF_OSFP_UNPACK(fp, class, version, subtype);  | 
    ||
462  | 
    if (class >= (1 << _FP_CLASS_BITS) ||  | 
    ||
463  | 
    version >= (1 << _FP_VERSION_BITS) ||  | 
    ||
464  | 
    	    subtype >= (1 << _FP_SUBTYPE_BITS)) { | 
    ||
465  | 
    		warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp); | 
    ||
466  | 
    strlcpy(buf, "nomatch", len);  | 
    ||
467  | 
    return (buf);  | 
    ||
468  | 
    }  | 
    ||
469  | 
    |||
470  | 
    	LIST_FOREACH(nm, &classes, nm_entry) { | 
    ||
471  | 
    		if (nm->nm_num == class) { | 
    ||
472  | 
    class_name = nm->nm_name;  | 
    ||
473  | 
    if (version == PF_OSFP_ANY)  | 
    ||
474  | 
    goto found;  | 
    ||
475  | 
    list = &nm->nm_sublist;  | 
    ||
476  | 
    			LIST_FOREACH(nm, list, nm_entry) { | 
    ||
477  | 
    				if (nm->nm_num == version) { | 
    ||
478  | 
    version_name = nm->nm_name;  | 
    ||
479  | 
    if (subtype == PF_OSFP_ANY)  | 
    ||
480  | 
    goto found;  | 
    ||
481  | 
    list = &nm->nm_sublist;  | 
    ||
482  | 
    					LIST_FOREACH(nm, list, nm_entry) { | 
    ||
483  | 
    						if (nm->nm_num == subtype) { | 
    ||
484  | 
    subtype_name =  | 
    ||
485  | 
    nm->nm_name;  | 
    ||
486  | 
    goto found;  | 
    ||
487  | 
    }  | 
    ||
488  | 
    } /* foreach subtype */  | 
    ||
489  | 
    strlcpy(buf, "nomatch", len);  | 
    ||
490  | 
    return (buf);  | 
    ||
491  | 
    }  | 
    ||
492  | 
    } /* foreach version */  | 
    ||
493  | 
    strlcpy(buf, "nomatch", len);  | 
    ||
494  | 
    return (buf);  | 
    ||
495  | 
    }  | 
    ||
496  | 
    } /* foreach class */  | 
    ||
497  | 
    |||
498  | 
    strlcpy(buf, "nomatch", len);  | 
    ||
499  | 
    return (buf);  | 
    ||
500  | 
    |||
501  | 
    found:  | 
    ||
502  | 
    snprintf(buf, len, "%s", class_name);  | 
    ||
503  | 
    	if (version_name) { | 
    ||
504  | 
    strlcat(buf, " ", len);  | 
    ||
505  | 
    strlcat(buf, version_name, len);  | 
    ||
506  | 
    		if (subtype_name) { | 
    ||
507  | 
    if (strchr(version_name, ' '))  | 
    ||
508  | 
    strlcat(buf, " ", len);  | 
    ||
509  | 
    else if (strchr(version_name, '.') &&  | 
    ||
510  | 
    isdigit((unsigned char)*subtype_name))  | 
    ||
511  | 
    strlcat(buf, ".", len);  | 
    ||
512  | 
    else  | 
    ||
513  | 
    strlcat(buf, " ", len);  | 
    ||
514  | 
    strlcat(buf, subtype_name, len);  | 
    ||
515  | 
    }  | 
    ||
516  | 
    }  | 
    ||
517  | 
    return (buf);  | 
    ||
518  | 
    }  | 
    ||
519  | 
    |||
520  | 
    /* lookup a name in a list */  | 
    ||
521  | 
    struct name_entry *  | 
    ||
522  | 
    lookup_name_list(struct name_list *list, const char *name)  | 
    ||
523  | 
    { | 
    ||
524  | 
    struct name_entry *nm;  | 
    ||
525  | 
    LIST_FOREACH(nm, list, nm_entry)  | 
    ||
526  | 
    if (strcasecmp(name, nm->nm_name) == 0)  | 
    ||
527  | 
    return (nm);  | 
    ||
528  | 
    |||
529  | 
    return (NULL);  | 
    ||
530  | 
    }  | 
    ||
531  | 
    |||
532  | 
    |||
533  | 
    void  | 
    ||
534  | 
    add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp)  | 
    ||
535  | 
    { | 
    ||
536  | 
    398412  | 
    struct pf_osfp_ioctl fptmp;  | 
    |
537  | 
    struct name_entry *nm_class, *nm_version, *nm_subtype;  | 
    ||
538  | 
    int class, version, subtype;  | 
    ||
539  | 
    |||
540  | 
    /* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */  | 
    ||
541  | 
    #define EXPAND(field) do {						\ | 
    ||
542  | 
    int _dot = -1, _start = -1, _end = -1, _i = 0; \  | 
    ||
543  | 
    /* pick major version out of #.# */ \  | 
    ||
544  | 
    if (isdigit((unsigned char)fp->field[_i]) && \  | 
    ||
545  | 
    	    fp->field[_i+1] == '.') {					\ | 
    ||
546  | 
    _dot = fp->field[_i] - '0'; \  | 
    ||
547  | 
    _i += 2; \  | 
    ||
548  | 
    } \  | 
    ||
549  | 
    if (isdigit((unsigned char)fp->field[_i])) \  | 
    ||
550  | 
    _start = fp->field[_i++] - '0'; \  | 
    ||
551  | 
    else \  | 
    ||
552  | 
    break; \  | 
    ||
553  | 
    if (isdigit((unsigned char)fp->field[_i])) \  | 
    ||
554  | 
    _start = (_start * 10) + fp->field[_i++] - '0'; \  | 
    ||
555  | 
    if (fp->field[_i++] != '-') \  | 
    ||
556  | 
    break; \  | 
    ||
557  | 
    if (isdigit((unsigned char)fp->field[_i]) && \  | 
    ||
558  | 
    fp->field[_i+1] == '.' && fp->field[_i] - '0' == _dot) \  | 
    ||
559  | 
    _i += 2; \  | 
    ||
560  | 
    else if (_dot != -1) \  | 
    ||
561  | 
    break; \  | 
    ||
562  | 
    if (isdigit((unsigned char)fp->field[_i])) \  | 
    ||
563  | 
    _end = fp->field[_i++] - '0'; \  | 
    ||
564  | 
    else \  | 
    ||
565  | 
    break; \  | 
    ||
566  | 
    if (isdigit((unsigned char)fp->field[_i])) \  | 
    ||
567  | 
    _end = (_end * 10) + fp->field[_i++] - '0'; \  | 
    ||
568  | 
    if (isdigit((unsigned char)fp->field[_i])) \  | 
    ||
569  | 
    _end = (_end * 10) + fp->field[_i++] - '0'; \  | 
    ||
570  | 
    if (fp->field[_i] != '\0') \  | 
    ||
571  | 
    break; \  | 
    ||
572  | 
    memcpy(&fptmp, fp, sizeof(fptmp)); \  | 
    ||
573  | 
    	for (;_start <= _end; _start++) {				\ | 
    ||
574  | 
    memset(fptmp.field, 0, sizeof(fptmp.field)); \  | 
    ||
575  | 
    fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \  | 
    ||
576  | 
    if (_dot == -1) \  | 
    ||
577  | 
    snprintf(fptmp.field, sizeof(fptmp.field), \  | 
    ||
578  | 
    "%d", _start); \  | 
    ||
579  | 
    else \  | 
    ||
580  | 
    snprintf(fptmp.field, sizeof(fptmp.field), \  | 
    ||
581  | 
    "%d.%d", _dot, _start); \  | 
    ||
582  | 
    add_fingerprint(dev, opts, &fptmp); \  | 
    ||
583  | 
    } \  | 
    ||
584  | 
    } while(0)  | 
    ||
585  | 
    |||
586  | 
    /* We allow "#-#" as a version or subtype and we'll expand it */  | 
    ||
587  | 
    ✓✓✓✓ ✓✓✓✓ ✓✓✓✗ ✓✗✓✓ ✓✗✓✗ ✓✓✗✓ ✗✓✓✓ ✗✓  | 
    1578024  | 
    EXPAND(fp_os.fp_version_nm);  | 
    
588  | 
    ✓✓✓✓ ✓✓✓✓ ✓✓✓✗ ✗✓✗✗ ✗✓✓✗ ✓✓✗✓ ✗✓✓✓ ✓✗  | 
    809100  | 
    EXPAND(fp_os.fp_subtype_nm);  | 
    
589  | 
    |||
590  | 
    ✗✓ | 199206  | 
    if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0)  | 
    
591  | 
    errx(1, "fingerprint class \"nomatch\" is reserved");  | 
    ||
592  | 
    |||
593  | 
    version = PF_OSFP_ANY;  | 
    ||
594  | 
    subtype = PF_OSFP_ANY;  | 
    ||
595  | 
    |||
596  | 
    199206  | 
    nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);  | 
    |
597  | 
    ✓✓ | 199206  | 
    if (nm_class->nm_num == 0)  | 
    
598  | 
    15624  | 
    nm_class->nm_num = ++class_count;  | 
    |
599  | 
    199206  | 
    class = nm_class->nm_num;  | 
    |
600  | 
    |||
601  | 
    398412  | 
    nm_version = fingerprint_name_entry(&nm_class->nm_sublist,  | 
    |
602  | 
    199206  | 
    fp->fp_os.fp_version_nm);  | 
    |
603  | 
    ✓✓ | 199206  | 
    	if (nm_version) { | 
    
604  | 
    ✓✓ | 194742  | 
    if (nm_version->nm_num == 0)  | 
    
605  | 
    47988  | 
    nm_version->nm_num = ++nm_class->nm_sublist_num;  | 
    |
606  | 
    194742  | 
    version = nm_version->nm_num;  | 
    |
607  | 
    389484  | 
    nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,  | 
    |
608  | 
    194742  | 
    fp->fp_os.fp_subtype_nm);  | 
    |
609  | 
    ✓✓ | 194742  | 
    		if (nm_subtype) { | 
    
610  | 
    ✓✓ | 86490  | 
    if (nm_subtype->nm_num == 0)  | 
    
611  | 
    32085  | 
    nm_subtype->nm_num =  | 
    |
612  | 
    32085  | 
    ++nm_version->nm_sublist_num;  | 
    |
613  | 
    86490  | 
    subtype = nm_subtype->nm_num;  | 
    |
614  | 
    86490  | 
    }  | 
    |
615  | 
    }  | 
    ||
616  | 
    |||
617  | 
    |||
618  | 
    DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype,  | 
    ||
619  | 
    print_ioctl(fp));  | 
    ||
620  | 
    |||
621  | 
    199206  | 
    PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype);  | 
    |
622  | 
    199206  | 
    fingerprint_count++;  | 
    |
623  | 
    |||
624  | 
    #ifdef FAKE_PF_KERNEL  | 
    ||
625  | 
    /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */  | 
    ||
626  | 
    if ((errno = pf_osfp_add(fp)))  | 
    ||
627  | 
    #else  | 
    ||
628  | 
    ✗✓✗✗ | 
    199206  | 
    if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp))  | 
    
629  | 
    #endif /* FAKE_PF_KERNEL */  | 
    ||
630  | 
    	{ | 
    ||
631  | 
    		if (errno == EEXIST) { | 
    ||
632  | 
    			warn("Duplicate signature for %s %s %s", | 
    ||
633  | 
    fp->fp_os.fp_class_nm,  | 
    ||
634  | 
    fp->fp_os.fp_version_nm,  | 
    ||
635  | 
    fp->fp_os.fp_subtype_nm);  | 
    ||
636  | 
    |||
637  | 
    		} else { | 
    ||
638  | 
    err(1, "DIOCOSFPADD");  | 
    ||
639  | 
    }  | 
    ||
640  | 
    }  | 
    ||
641  | 
    199206  | 
    }  | 
    |
642  | 
    |||
643  | 
    /* import a fingerprint from the kernel */  | 
    ||
644  | 
    void  | 
    ||
645  | 
    import_fingerprint(struct pf_osfp_ioctl *fp)  | 
    ||
646  | 
    { | 
    ||
647  | 
    struct name_entry *nm_class, *nm_version, *nm_subtype;  | 
    ||
648  | 
    int class, version, subtype;  | 
    ||
649  | 
    |||
650  | 
    202776  | 
    PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype);  | 
    |
651  | 
    |||
652  | 
    101388  | 
    nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);  | 
    |
653  | 
    ✓✓ | 101388  | 
    	if (nm_class->nm_num == 0) { | 
    
654  | 
    7952  | 
    nm_class->nm_num = class;  | 
    |
655  | 
    7952  | 
    class_count = MAXIMUM(class_count, class);  | 
    |
656  | 
    7952  | 
    }  | 
    |
657  | 
    |||
658  | 
    202776  | 
    nm_version = fingerprint_name_entry(&nm_class->nm_sublist,  | 
    |
659  | 
    101388  | 
    fp->fp_os.fp_version_nm);  | 
    |
660  | 
    ✓✓ | 101388  | 
    	if (nm_version) { | 
    
661  | 
    ✓✓ | 99116  | 
    		if (nm_version->nm_num == 0) { | 
    
662  | 
    24424  | 
    nm_version->nm_num = version;  | 
    |
663  | 
    ✓✓ | 73272  | 
    nm_class->nm_sublist_num = MAXIMUM(nm_class->nm_sublist_num,  | 
    
664  | 
    version);  | 
    ||
665  | 
    24424  | 
    }  | 
    |
666  | 
    198232  | 
    nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,  | 
    |
667  | 
    99116  | 
    fp->fp_os.fp_subtype_nm);  | 
    |
668  | 
    ✓✓ | 99116  | 
    		if (nm_subtype) { | 
    
669  | 
    ✓✓ | 44020  | 
    			if (nm_subtype->nm_num == 0) { | 
    
670  | 
    16330  | 
    nm_subtype->nm_num = subtype;  | 
    |
671  | 
    16330  | 
    nm_version->nm_sublist_num =  | 
    |
672  | 
    ✓✓ | 48990  | 
    MAXIMUM(nm_version->nm_sublist_num, subtype);  | 
    
673  | 
    16330  | 
    }  | 
    |
674  | 
    }  | 
    ||
675  | 
    }  | 
    ||
676  | 
    |||
677  | 
    |||
678  | 
    101388  | 
    fingerprint_count++;  | 
    |
679  | 
    DEBUG(fp, "import signature %d:%d:%d", class, version, subtype);  | 
    ||
680  | 
    101388  | 
    }  | 
    |
681  | 
    |||
682  | 
    /* Find an entry for a fingerprints class/version/subtype */  | 
    ||
683  | 
    struct name_entry *  | 
    ||
684  | 
    fingerprint_name_entry(struct name_list *list, char *name)  | 
    ||
685  | 
    { | 
    ||
686  | 
    struct name_entry *nm_entry;  | 
    ||
687  | 
    |||
688  | 
    ✓✗✓✓ | 
    2685138  | 
    if (name == NULL || strlen(name) == 0)  | 
    
689  | 
    170084  | 
    return (NULL);  | 
    |
690  | 
    |||
691  | 
    ✓✓ | 4661114  | 
    	LIST_FOREACH(nm_entry, list, nm_entry) { | 
    
692  | 
    ✓✓ | 2186154  | 
    		if (strcasecmp(nm_entry->nm_name, name) == 0) { | 
    
693  | 
    /* We'll move this to the front of the list later */  | 
    ||
694  | 
    ✓✓ | 1633420  | 
    LIST_REMOVE(nm_entry, nm_entry);  | 
    
695  | 
    580559  | 
    break;  | 
    |
696  | 
    }  | 
    ||
697  | 
    }  | 
    ||
698  | 
    ✓✓ | 724962  | 
    	if (nm_entry == NULL) { | 
    
699  | 
    144403  | 
    nm_entry = calloc(1, sizeof(*nm_entry));  | 
    |
700  | 
    ✗✓ | 144403  | 
    if (nm_entry == NULL)  | 
    
701  | 
    err(1, "calloc");  | 
    ||
702  | 
    144403  | 
    LIST_INIT(&nm_entry->nm_sublist);  | 
    |
703  | 
    144403  | 
    strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name));  | 
    |
704  | 
    144403  | 
    }  | 
    |
705  | 
    ✓✓ | 2041297  | 
    LIST_INSERT_HEAD(list, nm_entry, nm_entry);  | 
    
706  | 
    724962  | 
    return (nm_entry);  | 
    |
707  | 
    895046  | 
    }  | 
    |
708  | 
    |||
709  | 
    |||
710  | 
    void  | 
    ||
711  | 
    print_name_list(int opts, struct name_list *nml, const char *prefix)  | 
    ||
712  | 
    { | 
    ||
713  | 
    char newprefix[32];  | 
    ||
714  | 
    struct name_entry *nm;  | 
    ||
715  | 
    |||
716  | 
    	LIST_FOREACH(nm, nml, nm_entry) { | 
    ||
717  | 
    snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix,  | 
    ||
718  | 
    nm->nm_name);  | 
    ||
719  | 
    		printf("%s\n", newprefix); | 
    ||
720  | 
    print_name_list(opts, &nm->nm_sublist, newprefix);  | 
    ||
721  | 
    }  | 
    ||
722  | 
    }  | 
    ||
723  | 
    |||
724  | 
    void  | 
    ||
725  | 
    sort_name_list(int opts, struct name_list *nml)  | 
    ||
726  | 
    { | 
    ||
727  | 
    struct name_list new;  | 
    ||
728  | 
    struct name_entry *nm, *nmsearch, *nmlast;  | 
    ||
729  | 
    |||
730  | 
    /* yes yes, it's a very slow sort. so sue me */  | 
    ||
731  | 
    |||
732  | 
    LIST_INIT(&new);  | 
    ||
733  | 
    |||
734  | 
    	while ((nm = LIST_FIRST(nml)) != NULL) { | 
    ||
735  | 
    LIST_REMOVE(nm, nm_entry);  | 
    ||
736  | 
    nmlast = NULL;  | 
    ||
737  | 
    		LIST_FOREACH(nmsearch, &new, nm_entry) { | 
    ||
738  | 
    			if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) { | 
    ||
739  | 
    LIST_INSERT_BEFORE(nmsearch, nm, nm_entry);  | 
    ||
740  | 
    break;  | 
    ||
741  | 
    }  | 
    ||
742  | 
    nmlast = nmsearch;  | 
    ||
743  | 
    }  | 
    ||
744  | 
    		if (nmsearch == NULL) { | 
    ||
745  | 
    if (nmlast)  | 
    ||
746  | 
    LIST_INSERT_AFTER(nmlast, nm, nm_entry);  | 
    ||
747  | 
    else  | 
    ||
748  | 
    LIST_INSERT_HEAD(&new, nm, nm_entry);  | 
    ||
749  | 
    }  | 
    ||
750  | 
    |||
751  | 
    sort_name_list(opts, &nm->nm_sublist);  | 
    ||
752  | 
    }  | 
    ||
753  | 
    nmlast = NULL;  | 
    ||
754  | 
    	while ((nm = LIST_FIRST(&new)) != NULL) { | 
    ||
755  | 
    LIST_REMOVE(nm, nm_entry);  | 
    ||
756  | 
    if (nmlast == NULL)  | 
    ||
757  | 
    LIST_INSERT_HEAD(nml, nm, nm_entry);  | 
    ||
758  | 
    else  | 
    ||
759  | 
    LIST_INSERT_AFTER(nmlast, nm, nm_entry);  | 
    ||
760  | 
    nmlast = nm;  | 
    ||
761  | 
    }  | 
    ||
762  | 
    }  | 
    ||
763  | 
    |||
764  | 
    /* parse the next integer in a formatted config file line */  | 
    ||
765  | 
    int  | 
    ||
766  | 
    get_int(char **line, size_t *len, int *var, int *mod,  | 
    ||
767  | 
    const char *name, int flags, int max, const char *filename, int lineno)  | 
    ||
768  | 
    { | 
    ||
769  | 
    549072  | 
    int fieldlen, i;  | 
    |
770  | 
    char *field;  | 
    ||
771  | 
    long val = 0;  | 
    ||
772  | 
    |||
773  | 
    ✓✓ | 274536  | 
    if (mod)  | 
    
774  | 
    137268  | 
    *mod = 0;  | 
    |
775  | 
    274536  | 
    *var = 0;  | 
    |
776  | 
    |||
777  | 
    274536  | 
    field = get_field(line, len, &fieldlen);  | 
    |
778  | 
    ✗✓ | 274536  | 
    if (field == NULL)  | 
    
779  | 
    return (1);  | 
    ||
780  | 
    ✗✓ | 274536  | 
    	if (fieldlen == 0) { | 
    
781  | 
    fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name);  | 
    ||
782  | 
    return (1);  | 
    ||
783  | 
    }  | 
    ||
784  | 
    |||
785  | 
    i = 0;  | 
    ||
786  | 
    ✓✓✓✓ ✓✓✓✗  | 
    1074708  | 
    if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*')  | 
    
787  | 
    ✓✓ | 274536  | 
    	    && fieldlen >= 1) { | 
    
788  | 
    ✓✓✓✓ ✓  | 
    51336  | 
    		switch (*field) { | 
    
789  | 
    case 'S':  | 
    ||
790  | 
    ✓✗✓✗ | 
    42408  | 
    if (mod && (flags & T_MSS))  | 
    
791  | 
    21204  | 
    *mod = T_MSS;  | 
    |
792  | 
    ✗✓ | 21204  | 
    if (fieldlen == 1)  | 
    
793  | 
    return (0);  | 
    ||
794  | 
    break;  | 
    ||
795  | 
    case 'T':  | 
    ||
796  | 
    ✓✗✓✗ | 
    3906  | 
    if (mod && (flags & T_MTU))  | 
    
797  | 
    1953  | 
    *mod = T_MTU;  | 
    |
798  | 
    ✗✓ | 1953  | 
    if (fieldlen == 1)  | 
    
799  | 
    return (0);  | 
    ||
800  | 
    break;  | 
    ||
801  | 
    case '*':  | 
    ||
802  | 
    ✗✓ | 2790  | 
    			if (fieldlen != 1) { | 
    
803  | 
    fprintf(stderr, "%s:%d long '%c' %s\n",  | 
    ||
804  | 
    filename, lineno, *field, name);  | 
    ||
805  | 
    return (1);  | 
    ||
806  | 
    }  | 
    ||
807  | 
    ✓✗✓✗ | 
    5580  | 
    			if (mod && (flags & T_DC)) { | 
    
808  | 
    2790  | 
    *mod = T_DC;  | 
    |
809  | 
    2790  | 
    return (0);  | 
    |
810  | 
    }  | 
    ||
811  | 
    case '%':  | 
    ||
812  | 
    ✓✗✓✗ | 
    2232  | 
    if (mod && (flags & T_MOD))  | 
    
813  | 
    1116  | 
    *mod = T_MOD;  | 
    |
814  | 
    ✗✓ | 1116  | 
    			if (fieldlen == 1) { | 
    
815  | 
    fprintf(stderr, "%s:%d modulus %s must have a "  | 
    ||
816  | 
    "value\n", filename, lineno, name);  | 
    ||
817  | 
    return (1);  | 
    ||
818  | 
    }  | 
    ||
819  | 
    break;  | 
    ||
820  | 
    }  | 
    ||
821  | 
    ✓✗✗✓ | 
    48546  | 
    		if (mod == NULL || *mod == 0) { | 
    
822  | 
    fprintf(stderr, "%s:%d does not allow %c' %s\n",  | 
    ||
823  | 
    filename, lineno, *field, name);  | 
    ||
824  | 
    return (1);  | 
    ||
825  | 
    }  | 
    ||
826  | 
    i++;  | 
    ||
827  | 
    24273  | 
    }  | 
    |
828  | 
    |||
829  | 
    ✓✓ | 1472562  | 
    	for (; i < fieldlen; i++) { | 
    
830  | 
    ✓✗✗✓ | 
    1200816  | 
    		if (field[i] < '0' || field[i] > '9') { | 
    
831  | 
    fprintf(stderr, "%s:%d non-digit character in %s\n",  | 
    ||
832  | 
    filename, lineno, name);  | 
    ||
833  | 
    return (1);  | 
    ||
834  | 
    }  | 
    ||
835  | 
    600408  | 
    val = val * 10 + field[i] - '0';  | 
    |
836  | 
    ✗✓ | 600408  | 
    		if (val < 0) { | 
    
837  | 
    fprintf(stderr, "%s:%d %s overflowed\n", filename,  | 
    ||
838  | 
    lineno, name);  | 
    ||
839  | 
    return (1);  | 
    ||
840  | 
    }  | 
    ||
841  | 
    }  | 
    ||
842  | 
    |||
843  | 
    ✗✓ | 271746  | 
    	if (val > max) { | 
    
844  | 
    fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno,  | 
    ||
845  | 
    name, val, max);  | 
    ||
846  | 
    return (1);  | 
    ||
847  | 
    }  | 
    ||
848  | 
    271746  | 
    *var = (int)val;  | 
    |
849  | 
    |||
850  | 
    271746  | 
    return (0);  | 
    |
851  | 
    274536  | 
    }  | 
    |
852  | 
    |||
853  | 
    /* parse the next string in a formatted config file line */  | 
    ||
854  | 
    int  | 
    ||
855  | 
    get_str(char **line, size_t *len, char **v, const char *name, int minlen,  | 
    ||
856  | 
    const char *filename, int lineno)  | 
    ||
857  | 
    { | 
    ||
858  | 
    686340  | 
    int fieldlen;  | 
    |
859  | 
    char *ptr;  | 
    ||
860  | 
    |||
861  | 
    343170  | 
    ptr = get_field(line, len, &fieldlen);  | 
    |
862  | 
    ✗✓ | 343170  | 
    if (ptr == NULL)  | 
    
863  | 
    return (1);  | 
    ||
864  | 
    ✗✓ | 343170  | 
    	if (fieldlen < minlen) { | 
    
865  | 
    fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name);  | 
    ||
866  | 
    return (1);  | 
    ||
867  | 
    }  | 
    ||
868  | 
    ✗✓ | 343170  | 
    	if ((*v = malloc(fieldlen + 1)) == NULL) { | 
    
869  | 
    		perror("malloc()"); | 
    ||
870  | 
    return (1);  | 
    ||
871  | 
    }  | 
    ||
872  | 
    343170  | 
    memcpy(*v, ptr, fieldlen);  | 
    |
873  | 
    343170  | 
    (*v)[fieldlen] = '\0';  | 
    |
874  | 
    |||
875  | 
    343170  | 
    return (0);  | 
    |
876  | 
    343170  | 
    }  | 
    |
877  | 
    |||
878  | 
    /* Parse out the TCP opts */  | 
    ||
879  | 
    int  | 
    ||
880  | 
    get_tcpopts(const char *filename, int lineno, const char *tcpopts,  | 
    ||
881  | 
    pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale,  | 
    ||
882  | 
    int *wscale_mod, int *ts0)  | 
    ||
883  | 
    { | 
    ||
884  | 
    int i, opt;  | 
    ||
885  | 
    |||
886  | 
    137268  | 
    *packed = 0;  | 
    |
887  | 
    68634  | 
    *optcnt = 0;  | 
    |
888  | 
    68634  | 
    *wscale = 0;  | 
    |
889  | 
    68634  | 
    *wscale_mod = T_DC;  | 
    |
890  | 
    68634  | 
    *mss = 0;  | 
    |
891  | 
    68634  | 
    *mss_mod = T_DC;  | 
    |
892  | 
    68634  | 
    *ts0 = 0;  | 
    |
893  | 
    ✓✓ | 68634  | 
    if (strcmp(tcpopts, ".") == 0)  | 
    
894  | 
    2511  | 
    return (0);  | 
    |
895  | 
    |||
896  | 
    ✓✗✓✗ | 
    847881  | 
    	for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) { | 
    
897  | 
    ✗✓✗✓ ✓✓  | 
    565254  | 
    		switch ((opt = toupper((unsigned char)tcpopts[i++]))) { | 
    
898  | 
    case 'N': /* FALLTHROUGH */  | 
    ||
899  | 
    case 'S':  | 
    ||
900  | 
    313596  | 
    *packed = (*packed << PF_OSFP_TCPOPT_BITS) |  | 
    |
901  | 
    156798  | 
    (opt == 'N' ? PF_OSFP_TCPOPT_NOP :  | 
    |
902  | 
    PF_OSFP_TCPOPT_SACK);  | 
    ||
903  | 
    156798  | 
    break;  | 
    |
904  | 
    case 'W': /* FALLTHROUGH */  | 
    ||
905  | 
    		case 'M': { | 
    ||
906  | 
    int *this_mod, *this;  | 
    ||
907  | 
    |||
908  | 
    ✓✓ | 99882  | 
    			if (opt == 'W') { | 
    
909  | 
    this = wscale;  | 
    ||
910  | 
    this_mod = wscale_mod;  | 
    ||
911  | 
    33759  | 
    			} else { | 
    |
912  | 
    this = mss;  | 
    ||
913  | 
    this_mod = mss_mod;  | 
    ||
914  | 
    }  | 
    ||
915  | 
    99882  | 
    *this = 0;  | 
    |
916  | 
    99882  | 
    *this_mod = 0;  | 
    |
917  | 
    |||
918  | 
    199764  | 
    *packed = (*packed << PF_OSFP_TCPOPT_BITS) |  | 
    |
919  | 
    99882  | 
    (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE :  | 
    |
920  | 
    PF_OSFP_TCPOPT_MSS);  | 
    ||
921  | 
    ✓✓✓✓ ✓✗  | 
    174654  | 
    if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' ||  | 
    
922  | 
    34038  | 
    			    tcpopts[i + 1] == ',')) { | 
    |
923  | 
    40734  | 
    *this_mod = T_DC;  | 
    |
924  | 
    i++;  | 
    ||
925  | 
    40734  | 
    break;  | 
    |
926  | 
    }  | 
    ||
927  | 
    |||
928  | 
    ✓✓ | 59148  | 
    			if (tcpopts[i] == '%') { | 
    
929  | 
    1674  | 
    *this_mod = T_MOD;  | 
    |
930  | 
    1674  | 
    i++;  | 
    |
931  | 
    1674  | 
    }  | 
    |
932  | 
    			do { | 
    ||
933  | 
    ✗✓ | 131130  | 
    				if (!isdigit((unsigned char)tcpopts[i])) { | 
    
934  | 
    fprintf(stderr, "%s:%d unknown "  | 
    ||
935  | 
    "character '%c' in %c TCP opt\n",  | 
    ||
936  | 
    filename, lineno, tcpopts[i], opt);  | 
    ||
937  | 
    return (1);  | 
    ||
938  | 
    }  | 
    ||
939  | 
    131130  | 
    *this = (*this * 10) + tcpopts[i++] - '0';  | 
    |
940  | 
    ✓✓✓✓ | 
    225432  | 
    } while(tcpopts[i] != ',' && tcpopts[i] != '\0');  | 
    
941  | 
    ✓✗ | 59148  | 
    break;  | 
    
942  | 
    }  | 
    ||
943  | 
    case 'T':  | 
    ||
944  | 
    ✓✓ | 25947  | 
    			if (tcpopts[i] == '0') { | 
    
945  | 
    4464  | 
    *ts0 = 1;  | 
    |
946  | 
    4464  | 
    i++;  | 
    |
947  | 
    4464  | 
    }  | 
    |
948  | 
    25947  | 
    *packed = (*packed << PF_OSFP_TCPOPT_BITS) |  | 
    |
949  | 
    PF_OSFP_TCPOPT_TS;  | 
    ||
950  | 
    25947  | 
    break;  | 
    |
951  | 
    }  | 
    ||
952  | 
    282627  | 
    (*optcnt) ++;  | 
    |
953  | 
    ✓✓ | 282627  | 
    if (tcpopts[i] == '\0')  | 
    
954  | 
    break;  | 
    ||
955  | 
    ✗✓ | 216504  | 
    		if (tcpopts[i] != ',') { | 
    
956  | 
    fprintf(stderr, "%s:%d unknown option to %c TCP opt\n",  | 
    ||
957  | 
    filename, lineno, opt);  | 
    ||
958  | 
    return (1);  | 
    ||
959  | 
    }  | 
    ||
960  | 
    216504  | 
    i++;  | 
    |
961  | 
    }  | 
    ||
962  | 
    |||
963  | 
    66123  | 
    return (0);  | 
    |
964  | 
    68634  | 
    }  | 
    |
965  | 
    |||
966  | 
    /* rip the next field out of a formatted config file line */  | 
    ||
967  | 
    char *  | 
    ||
968  | 
    get_field(char **line, size_t *len, int *fieldlen)  | 
    ||
969  | 
    { | 
    ||
970  | 
    1235412  | 
    char *ret, *ptr = *line;  | 
    |
971  | 
    617706  | 
    size_t plen = *len;  | 
    |
972  | 
    |||
973  | 
    |||
974  | 
    ✓✗✓✓ | 
    2299239  | 
    	while (plen && isspace((unsigned char)*ptr)) { | 
    
975  | 
    148707  | 
    plen--;  | 
    |
976  | 
    148707  | 
    ptr++;  | 
    |
977  | 
    }  | 
    ||
978  | 
    ret = ptr;  | 
    ||
979  | 
    617706  | 
    *fieldlen = 0;  | 
    |
980  | 
    |||
981  | 
    ✓✓✓✓ | 
    12099672  | 
    for (; plen > 0 && *ptr != ':'; plen--, ptr++)  | 
    
982  | 
    3438396  | 
    (*fieldlen)++;  | 
    |
983  | 
    ✓✓ | 617706  | 
    	if (plen) { | 
    
984  | 
    549072  | 
    *line = ptr + 1;  | 
    |
985  | 
    549072  | 
    *len = plen - 1;  | 
    |
986  | 
    549072  | 
    	} else { | 
    |
987  | 
    68634  | 
    *len = 0;  | 
    |
988  | 
    }  | 
    ||
989  | 
    ✓✓✗✓ | 
    1195236  | 
    while (*fieldlen && isspace((unsigned char)ret[*fieldlen - 1]))  | 
    
990  | 
    (*fieldlen)--;  | 
    ||
991  | 
    617706  | 
    return (ret);  | 
    |
992  | 
    }  | 
    ||
993  | 
    |||
994  | 
    |||
995  | 
    #ifdef OSFP_DEBUG  | 
    ||
996  | 
    const char *  | 
    ||
997  | 
    print_ioctl(struct pf_osfp_ioctl *fp)  | 
    ||
998  | 
    { | 
    ||
999  | 
    static char buf[1024];  | 
    ||
1000  | 
    char tmp[32];  | 
    ||
1001  | 
    int i, opt;  | 
    ||
1002  | 
    |||
1003  | 
    *buf = '\0';  | 
    ||
1004  | 
    if (fp->fp_flags & PF_OSFP_WSIZE_DC)  | 
    ||
1005  | 
    strlcat(buf, "*", sizeof(buf));  | 
    ||
1006  | 
    else if (fp->fp_flags & PF_OSFP_WSIZE_MSS)  | 
    ||
1007  | 
    strlcat(buf, "S", sizeof(buf));  | 
    ||
1008  | 
    else if (fp->fp_flags & PF_OSFP_WSIZE_MTU)  | 
    ||
1009  | 
    strlcat(buf, "T", sizeof(buf));  | 
    ||
1010  | 
    	else { | 
    ||
1011  | 
    if (fp->fp_flags & PF_OSFP_WSIZE_MOD)  | 
    ||
1012  | 
    strlcat(buf, "%", sizeof(buf));  | 
    ||
1013  | 
    snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize);  | 
    ||
1014  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1015  | 
    }  | 
    ||
1016  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1017  | 
    |||
1018  | 
    snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl);  | 
    ||
1019  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1020  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1021  | 
    |||
1022  | 
    if (fp->fp_flags & PF_OSFP_DF)  | 
    ||
1023  | 
    strlcat(buf, "1", sizeof(buf));  | 
    ||
1024  | 
    else  | 
    ||
1025  | 
    strlcat(buf, "0", sizeof(buf));  | 
    ||
1026  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1027  | 
    |||
1028  | 
    if (fp->fp_flags & PF_OSFP_PSIZE_DC)  | 
    ||
1029  | 
    strlcat(buf, "*", sizeof(buf));  | 
    ||
1030  | 
    	else { | 
    ||
1031  | 
    if (fp->fp_flags & PF_OSFP_PSIZE_MOD)  | 
    ||
1032  | 
    strlcat(buf, "%", sizeof(buf));  | 
    ||
1033  | 
    snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize);  | 
    ||
1034  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1035  | 
    }  | 
    ||
1036  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1037  | 
    |||
1038  | 
    if (fp->fp_optcnt == 0)  | 
    ||
1039  | 
    strlcat(buf, ".", sizeof(buf));  | 
    ||
1040  | 
    	for (i = fp->fp_optcnt - 1; i >= 0; i--) { | 
    ||
1041  | 
    opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS);  | 
    ||
1042  | 
    opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1;  | 
    ||
1043  | 
    		switch (opt) { | 
    ||
1044  | 
    case PF_OSFP_TCPOPT_NOP:  | 
    ||
1045  | 
    strlcat(buf, "N", sizeof(buf));  | 
    ||
1046  | 
    break;  | 
    ||
1047  | 
    case PF_OSFP_TCPOPT_SACK:  | 
    ||
1048  | 
    strlcat(buf, "S", sizeof(buf));  | 
    ||
1049  | 
    break;  | 
    ||
1050  | 
    case PF_OSFP_TCPOPT_TS:  | 
    ||
1051  | 
    strlcat(buf, "T", sizeof(buf));  | 
    ||
1052  | 
    if (fp->fp_flags & PF_OSFP_TS0)  | 
    ||
1053  | 
    strlcat(buf, "0", sizeof(buf));  | 
    ||
1054  | 
    break;  | 
    ||
1055  | 
    case PF_OSFP_TCPOPT_MSS:  | 
    ||
1056  | 
    strlcat(buf, "M", sizeof(buf));  | 
    ||
1057  | 
    if (fp->fp_flags & PF_OSFP_MSS_DC)  | 
    ||
1058  | 
    strlcat(buf, "*", sizeof(buf));  | 
    ||
1059  | 
    			else { | 
    ||
1060  | 
    if (fp->fp_flags & PF_OSFP_MSS_MOD)  | 
    ||
1061  | 
    strlcat(buf, "%", sizeof(buf));  | 
    ||
1062  | 
    snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss);  | 
    ||
1063  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1064  | 
    }  | 
    ||
1065  | 
    break;  | 
    ||
1066  | 
    case PF_OSFP_TCPOPT_WSCALE:  | 
    ||
1067  | 
    strlcat(buf, "W", sizeof(buf));  | 
    ||
1068  | 
    if (fp->fp_flags & PF_OSFP_WSCALE_DC)  | 
    ||
1069  | 
    strlcat(buf, "*", sizeof(buf));  | 
    ||
1070  | 
    			else { | 
    ||
1071  | 
    if (fp->fp_flags & PF_OSFP_WSCALE_MOD)  | 
    ||
1072  | 
    strlcat(buf, "%", sizeof(buf));  | 
    ||
1073  | 
    snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale);  | 
    ||
1074  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1075  | 
    }  | 
    ||
1076  | 
    break;  | 
    ||
1077  | 
    }  | 
    ||
1078  | 
    |||
1079  | 
    if (i != 0)  | 
    ||
1080  | 
    strlcat(buf, ",", sizeof(buf));  | 
    ||
1081  | 
    }  | 
    ||
1082  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1083  | 
    |||
1084  | 
    strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf));  | 
    ||
1085  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1086  | 
    strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf));  | 
    ||
1087  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1088  | 
    strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf));  | 
    ||
1089  | 
    strlcat(buf, ":", sizeof(buf));  | 
    ||
1090  | 
    |||
1091  | 
    snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt,  | 
    ||
1092  | 
    (long long int)fp->fp_tcpopts);  | 
    ||
1093  | 
    strlcat(buf, tmp, sizeof(buf));  | 
    ||
1094  | 
    |||
1095  | 
    return (buf);  | 
    ||
1096  | 
    }  | 
    ||
1097  | 
    #endif  | 
    
| Generated by: GCOVR (Version 3.3) |