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