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