1223637Sbz/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ 2126353Smlaier 3126353Smlaier/* 4126353Smlaier * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> 5126353Smlaier * 6126353Smlaier * Permission to use, copy, modify, and distribute this software for any 7126353Smlaier * purpose with or without fee is hereby granted, provided that the above 8126353Smlaier * copyright notice and this permission notice appear in all copies. 9126353Smlaier * 10126353Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11126353Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12126353Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13126353Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14126353Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15126353Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16126353Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17126353Smlaier */ 18126353Smlaier 19126353Smlaier#include <sys/types.h> 20126353Smlaier#include <sys/ioctl.h> 21126353Smlaier#include <sys/socket.h> 22126353Smlaier 23126353Smlaier#include <net/if.h> 24126353Smlaier#include <net/pfvar.h> 25126353Smlaier 26171169Smlaier#include <netinet/in_systm.h> 27171169Smlaier#include <netinet/ip.h> 28171169Smlaier#include <netinet/ip6.h> 29171169Smlaier 30126353Smlaier#include <ctype.h> 31126353Smlaier#include <err.h> 32126353Smlaier#include <errno.h> 33126353Smlaier#include <stdio.h> 34126353Smlaier#include <stdlib.h> 35126353Smlaier#include <string.h> 36126353Smlaier 37126353Smlaier#include "pfctl_parser.h" 38130614Smlaier#include "pfctl.h" 39126353Smlaier 40126353Smlaier#ifndef MIN 41126353Smlaier# define MIN(a,b) (((a) < (b)) ? (a) : (b)) 42126353Smlaier#endif /* MIN */ 43126353Smlaier#ifndef MAX 44126353Smlaier# define MAX(a,b) (((a) > (b)) ? (a) : (b)) 45126353Smlaier#endif /* MAX */ 46126353Smlaier 47126353Smlaier 48126353Smlaier#if 0 49126353Smlaier# define DEBUG(fp, str, v...) \ 50126353Smlaier fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \ 51126353Smlaier (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v); 52126353Smlaier#else 53126353Smlaier# define DEBUG(fp, str, v...) ((void)0) 54126353Smlaier#endif 55126353Smlaier 56126353Smlaier 57126353Smlaierstruct name_entry; 58126353SmlaierLIST_HEAD(name_list, name_entry); 59126353Smlaierstruct name_entry { 60126353Smlaier LIST_ENTRY(name_entry) nm_entry; 61126353Smlaier int nm_num; 62126353Smlaier char nm_name[PF_OSFP_LEN]; 63126353Smlaier 64126353Smlaier struct name_list nm_sublist; 65126353Smlaier int nm_sublist_num; 66126353Smlaier}; 67126353Smlaierstruct name_list classes = LIST_HEAD_INITIALIZER(&classes); 68126353Smlaierint class_count; 69126353Smlaierint fingerprint_count; 70126353Smlaier 71126353Smlaiervoid add_fingerprint(int, int, struct pf_osfp_ioctl *); 72126353Smlaierstruct name_entry *fingerprint_name_entry(struct name_list *, char *); 73126353Smlaiervoid pfctl_flush_my_fingerprints(struct name_list *); 74126353Smlaierchar *get_field(char **, size_t *, int *); 75126353Smlaierint get_int(char **, size_t *, int *, int *, const char *, 76126353Smlaier int, int, const char *, int); 77126353Smlaierint get_str(char **, size_t *, char **, const char *, int, 78126353Smlaier const char *, int); 79126353Smlaierint get_tcpopts(const char *, int, const char *, 80126353Smlaier pf_tcpopts_t *, int *, int *, int *, int *, int *, 81126353Smlaier int *); 82126353Smlaiervoid import_fingerprint(struct pf_osfp_ioctl *); 83126353Smlaierconst char *print_ioctl(struct pf_osfp_ioctl *); 84126353Smlaiervoid print_name_list(int, struct name_list *, const char *); 85126353Smlaiervoid sort_name_list(int, struct name_list *); 86126353Smlaierstruct name_entry *lookup_name_list(struct name_list *, const char *); 87126353Smlaier 88126353Smlaier/* Load fingerprints from a file */ 89126353Smlaierint 90126353Smlaierpfctl_file_fingerprints(int dev, int opts, const char *fp_filename) 91126353Smlaier{ 92126353Smlaier FILE *in; 93126353Smlaier char *line; 94126353Smlaier size_t len; 95126353Smlaier int i, lineno = 0; 96126353Smlaier int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale, 97126353Smlaier wscale_mod, optcnt, ts0; 98126353Smlaier pf_tcpopts_t packed_tcpopts; 99126353Smlaier char *class, *version, *subtype, *desc, *tcpopts; 100126353Smlaier struct pf_osfp_ioctl fp; 101126353Smlaier 102126353Smlaier pfctl_flush_my_fingerprints(&classes); 103126353Smlaier 104145837Smlaier if ((in = pfctl_fopen(fp_filename, "r")) == NULL) { 105145837Smlaier warn("%s", fp_filename); 106126353Smlaier return (1); 107126353Smlaier } 108126353Smlaier class = version = subtype = desc = tcpopts = NULL; 109126353Smlaier 110126353Smlaier if ((opts & PF_OPT_NOACTION) == 0) 111126353Smlaier pfctl_clear_fingerprints(dev, opts); 112126353Smlaier 113126353Smlaier while ((line = fgetln(in, &len)) != NULL) { 114126353Smlaier lineno++; 115126353Smlaier if (class) 116126353Smlaier free(class); 117126353Smlaier if (version) 118126353Smlaier free(version); 119126353Smlaier if (subtype) 120126353Smlaier free(subtype); 121126353Smlaier if (desc) 122126353Smlaier free(desc); 123126353Smlaier if (tcpopts) 124126353Smlaier free(tcpopts); 125126353Smlaier class = version = subtype = desc = tcpopts = NULL; 126126353Smlaier memset(&fp, 0, sizeof(fp)); 127126353Smlaier 128126353Smlaier /* Chop off comment */ 129126353Smlaier for (i = 0; i < len; i++) 130126353Smlaier if (line[i] == '#') { 131126353Smlaier len = i; 132126353Smlaier break; 133126353Smlaier } 134126353Smlaier /* Chop off whitespace */ 135126353Smlaier while (len > 0 && isspace(line[len - 1])) 136126353Smlaier len--; 137126353Smlaier while (len > 0 && isspace(line[0])) { 138126353Smlaier len--; 139126353Smlaier line++; 140126353Smlaier } 141126353Smlaier if (len == 0) 142126353Smlaier continue; 143126353Smlaier 144126353Smlaier#define T_DC 0x01 /* Allow don't care */ 145126353Smlaier#define T_MSS 0x02 /* Allow MSS multiple */ 146126353Smlaier#define T_MTU 0x04 /* Allow MTU multiple */ 147126353Smlaier#define T_MOD 0x08 /* Allow modulus */ 148126353Smlaier 149126353Smlaier#define GET_INT(v, mod, n, ty, mx) \ 150126353Smlaier get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno) 151126353Smlaier#define GET_STR(v, n, mn) \ 152126353Smlaier get_str(&line, &len, &v, n, mn, fp_filename, lineno) 153126353Smlaier 154126353Smlaier if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU| 155126353Smlaier T_MOD, 0xffff) || 156126353Smlaier GET_INT(ttl, NULL, "ttl", 0, 0xff) || 157126353Smlaier GET_INT(df, NULL, "don't fragment frag", 0, 1) || 158126353Smlaier GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC, 159126353Smlaier 8192) || 160126353Smlaier GET_STR(tcpopts, "TCP Options", 1) || 161126353Smlaier GET_STR(class, "OS class", 1) || 162126353Smlaier GET_STR(version, "OS version", 0) || 163126353Smlaier GET_STR(subtype, "OS subtype", 0) || 164126353Smlaier GET_STR(desc, "OS description", 2)) 165126353Smlaier continue; 166126353Smlaier if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts, 167126353Smlaier &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0)) 168126353Smlaier continue; 169126353Smlaier if (len != 0) { 170126353Smlaier fprintf(stderr, "%s:%d excess field\n", fp_filename, 171126353Smlaier lineno); 172126353Smlaier continue; 173126353Smlaier } 174126353Smlaier 175126353Smlaier fp.fp_ttl = ttl; 176126353Smlaier if (df) 177126353Smlaier fp.fp_flags |= PF_OSFP_DF; 178126353Smlaier switch (w_mod) { 179126353Smlaier case 0: 180126353Smlaier break; 181126353Smlaier case T_DC: 182126353Smlaier fp.fp_flags |= PF_OSFP_WSIZE_DC; 183126353Smlaier break; 184126353Smlaier case T_MSS: 185126353Smlaier fp.fp_flags |= PF_OSFP_WSIZE_MSS; 186126353Smlaier break; 187126353Smlaier case T_MTU: 188126353Smlaier fp.fp_flags |= PF_OSFP_WSIZE_MTU; 189126353Smlaier break; 190126353Smlaier case T_MOD: 191126353Smlaier fp.fp_flags |= PF_OSFP_WSIZE_MOD; 192126353Smlaier break; 193126353Smlaier } 194126353Smlaier fp.fp_wsize = window; 195126353Smlaier 196126353Smlaier switch (p_mod) { 197126353Smlaier case T_DC: 198126353Smlaier fp.fp_flags |= PF_OSFP_PSIZE_DC; 199126353Smlaier break; 200126353Smlaier case T_MOD: 201126353Smlaier fp.fp_flags |= PF_OSFP_PSIZE_MOD; 202126353Smlaier } 203126353Smlaier fp.fp_psize = psize; 204126353Smlaier 205126353Smlaier 206126353Smlaier switch (wscale_mod) { 207126353Smlaier case T_DC: 208126353Smlaier fp.fp_flags |= PF_OSFP_WSCALE_DC; 209126353Smlaier break; 210126353Smlaier case T_MOD: 211126353Smlaier fp.fp_flags |= PF_OSFP_WSCALE_MOD; 212126353Smlaier } 213126353Smlaier fp.fp_wscale = wscale; 214126353Smlaier 215126353Smlaier switch (mss_mod) { 216126353Smlaier case T_DC: 217126353Smlaier fp.fp_flags |= PF_OSFP_MSS_DC; 218126353Smlaier break; 219126353Smlaier case T_MOD: 220126353Smlaier fp.fp_flags |= PF_OSFP_MSS_MOD; 221126353Smlaier break; 222126353Smlaier } 223126353Smlaier fp.fp_mss = mss; 224126353Smlaier 225126353Smlaier fp.fp_tcpopts = packed_tcpopts; 226126353Smlaier fp.fp_optcnt = optcnt; 227126353Smlaier if (ts0) 228126353Smlaier fp.fp_flags |= PF_OSFP_TS0; 229126353Smlaier 230126353Smlaier if (class[0] == '@') 231126353Smlaier fp.fp_os.fp_enflags |= PF_OSFP_GENERIC; 232126353Smlaier if (class[0] == '*') 233126353Smlaier fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL; 234126353Smlaier 235126353Smlaier if (class[0] == '@' || class[0] == '*') 236126353Smlaier strlcpy(fp.fp_os.fp_class_nm, class + 1, 237126353Smlaier sizeof(fp.fp_os.fp_class_nm)); 238126353Smlaier else 239126353Smlaier strlcpy(fp.fp_os.fp_class_nm, class, 240126353Smlaier sizeof(fp.fp_os.fp_class_nm)); 241126353Smlaier strlcpy(fp.fp_os.fp_version_nm, version, 242126353Smlaier sizeof(fp.fp_os.fp_version_nm)); 243126353Smlaier strlcpy(fp.fp_os.fp_subtype_nm, subtype, 244126353Smlaier sizeof(fp.fp_os.fp_subtype_nm)); 245126353Smlaier 246126353Smlaier add_fingerprint(dev, opts, &fp); 247171169Smlaier 248171169Smlaier fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6); 249171169Smlaier fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip); 250171169Smlaier add_fingerprint(dev, opts, &fp); 251126353Smlaier } 252126353Smlaier 253126353Smlaier if (class) 254126353Smlaier free(class); 255126353Smlaier if (version) 256126353Smlaier free(version); 257126353Smlaier if (subtype) 258126353Smlaier free(subtype); 259126353Smlaier if (desc) 260126353Smlaier free(desc); 261171169Smlaier if (tcpopts) 262171169Smlaier free(tcpopts); 263126353Smlaier 264126353Smlaier fclose(in); 265126353Smlaier 266126353Smlaier if (opts & PF_OPT_VERBOSE2) 267126353Smlaier printf("Loaded %d passive OS fingerprints\n", 268126353Smlaier fingerprint_count); 269126353Smlaier return (0); 270126353Smlaier} 271126353Smlaier 272126353Smlaier/* flush the kernel's fingerprints */ 273126353Smlaiervoid 274126353Smlaierpfctl_clear_fingerprints(int dev, int opts) 275126353Smlaier{ 276126353Smlaier if (ioctl(dev, DIOCOSFPFLUSH)) 277126353Smlaier err(1, "DIOCOSFPFLUSH"); 278126353Smlaier} 279126353Smlaier 280126353Smlaier/* flush pfctl's view of the fingerprints */ 281126353Smlaiervoid 282126353Smlaierpfctl_flush_my_fingerprints(struct name_list *list) 283126353Smlaier{ 284126353Smlaier struct name_entry *nm; 285126353Smlaier 286126353Smlaier while ((nm = LIST_FIRST(list)) != NULL) { 287126353Smlaier LIST_REMOVE(nm, nm_entry); 288126353Smlaier pfctl_flush_my_fingerprints(&nm->nm_sublist); 289126353Smlaier free(nm); 290126353Smlaier } 291145837Smlaier fingerprint_count = 0; 292126353Smlaier class_count = 0; 293126353Smlaier} 294126353Smlaier 295126353Smlaier/* Fetch the active fingerprints from the kernel */ 296126353Smlaierint 297126353Smlaierpfctl_load_fingerprints(int dev, int opts) 298126353Smlaier{ 299126353Smlaier struct pf_osfp_ioctl io; 300126353Smlaier int i; 301126353Smlaier 302126353Smlaier pfctl_flush_my_fingerprints(&classes); 303126353Smlaier 304126353Smlaier for (i = 0; i >= 0; i++) { 305126353Smlaier memset(&io, 0, sizeof(io)); 306126353Smlaier io.fp_getnum = i; 307126353Smlaier if (ioctl(dev, DIOCOSFPGET, &io)) { 308126353Smlaier if (errno == EBUSY) 309126353Smlaier break; 310126353Smlaier warn("DIOCOSFPGET"); 311126353Smlaier return (1); 312126353Smlaier } 313126353Smlaier import_fingerprint(&io); 314126353Smlaier } 315126353Smlaier return (0); 316126353Smlaier} 317126353Smlaier 318126353Smlaier/* List the fingerprints */ 319126353Smlaiervoid 320126353Smlaierpfctl_show_fingerprints(int opts) 321126353Smlaier{ 322130614Smlaier if (LIST_FIRST(&classes) != NULL) { 323130614Smlaier if (opts & PF_OPT_SHOWALL) { 324130614Smlaier pfctl_print_title("OS FINGERPRINTS:"); 325130614Smlaier printf("%u fingerprints loaded\n", fingerprint_count); 326130614Smlaier } else { 327130614Smlaier printf("Class\tVersion\tSubtype(subversion)\n"); 328130614Smlaier printf("-----\t-------\t-------------------\n"); 329130614Smlaier sort_name_list(opts, &classes); 330130614Smlaier print_name_list(opts, &classes, ""); 331130614Smlaier } 332130614Smlaier } 333126353Smlaier} 334126353Smlaier 335126353Smlaier/* Lookup a fingerprint */ 336126353Smlaierpf_osfp_t 337126353Smlaierpfctl_get_fingerprint(const char *name) 338126353Smlaier{ 339126353Smlaier struct name_entry *nm, *class_nm, *version_nm, *subtype_nm; 340126353Smlaier pf_osfp_t ret = PF_OSFP_NOMATCH; 341126353Smlaier int class, version, subtype; 342126353Smlaier int unp_class, unp_version, unp_subtype; 343126353Smlaier int wr_len, version_len, subtype_len; 344126353Smlaier char *ptr, *wr_name; 345126353Smlaier 346126353Smlaier if (strcasecmp(name, "unknown") == 0) 347126353Smlaier return (PF_OSFP_UNKNOWN); 348126353Smlaier 349126353Smlaier /* Try most likely no version and no subtype */ 350126353Smlaier if ((nm = lookup_name_list(&classes, name))) { 351126353Smlaier class = nm->nm_num; 352126353Smlaier version = PF_OSFP_ANY; 353126353Smlaier subtype = PF_OSFP_ANY; 354126353Smlaier goto found; 355126353Smlaier } else { 356126353Smlaier 357126353Smlaier /* Chop it up into class/version/subtype */ 358126353Smlaier 359126353Smlaier if ((wr_name = strdup(name)) == NULL) 360126353Smlaier err(1, "malloc"); 361145837Smlaier if ((ptr = strchr(wr_name, ' ')) == NULL) { 362126353Smlaier free(wr_name); 363126353Smlaier return (PF_OSFP_NOMATCH); 364126353Smlaier } 365126353Smlaier *ptr++ = '\0'; 366126353Smlaier 367126353Smlaier /* The class is easy to find since it is delimited by a space */ 368126353Smlaier if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) { 369126353Smlaier free(wr_name); 370126353Smlaier return (PF_OSFP_NOMATCH); 371126353Smlaier } 372126353Smlaier class = class_nm->nm_num; 373126353Smlaier 374126353Smlaier /* Try no subtype */ 375126353Smlaier if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr))) 376126353Smlaier { 377126353Smlaier version = version_nm->nm_num; 378126353Smlaier subtype = PF_OSFP_ANY; 379126353Smlaier free(wr_name); 380126353Smlaier goto found; 381126353Smlaier } 382126353Smlaier 383126353Smlaier 384126353Smlaier /* 385126353Smlaier * There must be a version and a subtype. 386126353Smlaier * We'll do some fuzzy matching to pick up things like: 387126353Smlaier * Linux 2.2.14 (version=2.2 subtype=14) 388126353Smlaier * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE) 389126353Smlaier * Windows 2000 SP2 (version=2000 subtype=SP2) 390126353Smlaier */ 391126353Smlaier#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-') 392126353Smlaier wr_len = strlen(ptr); 393126353Smlaier LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) { 394126353Smlaier version_len = strlen(version_nm->nm_name); 395126353Smlaier if (wr_len < version_len + 2 || 396126353Smlaier !CONNECTOR(ptr[version_len])) 397126353Smlaier continue; 398126353Smlaier /* first part of the string must be version */ 399126353Smlaier if (strncasecmp(ptr, version_nm->nm_name, 400126353Smlaier version_len)) 401126353Smlaier continue; 402126353Smlaier 403126353Smlaier LIST_FOREACH(subtype_nm, &version_nm->nm_sublist, 404126353Smlaier nm_entry) { 405126353Smlaier subtype_len = strlen(subtype_nm->nm_name); 406126353Smlaier if (wr_len != version_len + subtype_len + 1) 407126353Smlaier continue; 408126353Smlaier 409126353Smlaier /* last part of the string must be subtype */ 410126353Smlaier if (strcasecmp(&ptr[version_len+1], 411126353Smlaier subtype_nm->nm_name) != 0) 412126353Smlaier continue; 413126353Smlaier 414126353Smlaier /* Found it!! */ 415126353Smlaier version = version_nm->nm_num; 416126353Smlaier subtype = subtype_nm->nm_num; 417126353Smlaier free(wr_name); 418126353Smlaier goto found; 419126353Smlaier } 420126353Smlaier } 421126353Smlaier 422126353Smlaier free(wr_name); 423126353Smlaier return (PF_OSFP_NOMATCH); 424126353Smlaier } 425126353Smlaier 426126353Smlaierfound: 427126353Smlaier PF_OSFP_PACK(ret, class, version, subtype); 428126353Smlaier if (ret != PF_OSFP_NOMATCH) { 429126353Smlaier PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype); 430126353Smlaier if (class != unp_class) { 431126353Smlaier fprintf(stderr, "warning: fingerprint table overflowed " 432126353Smlaier "classes\n"); 433126353Smlaier return (PF_OSFP_NOMATCH); 434126353Smlaier } 435126353Smlaier if (version != unp_version) { 436126353Smlaier fprintf(stderr, "warning: fingerprint table overflowed " 437126353Smlaier "versions\n"); 438126353Smlaier return (PF_OSFP_NOMATCH); 439126353Smlaier } 440126353Smlaier if (subtype != unp_subtype) { 441126353Smlaier fprintf(stderr, "warning: fingerprint table overflowed " 442126353Smlaier "subtypes\n"); 443126353Smlaier return (PF_OSFP_NOMATCH); 444126353Smlaier } 445126353Smlaier } 446126353Smlaier if (ret == PF_OSFP_ANY) { 447126353Smlaier /* should never happen */ 448126353Smlaier fprintf(stderr, "warning: fingerprint packed to 'any'\n"); 449126353Smlaier return (PF_OSFP_NOMATCH); 450126353Smlaier } 451126353Smlaier 452126353Smlaier return (ret); 453126353Smlaier} 454126353Smlaier 455126353Smlaier/* Lookup a fingerprint name by ID */ 456126353Smlaierchar * 457126353Smlaierpfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len) 458126353Smlaier{ 459126353Smlaier int class, version, subtype; 460126353Smlaier struct name_list *list; 461126353Smlaier struct name_entry *nm; 462126353Smlaier 463126353Smlaier char *class_name, *version_name, *subtype_name; 464126353Smlaier class_name = version_name = subtype_name = NULL; 465126353Smlaier 466126353Smlaier if (fp == PF_OSFP_UNKNOWN) { 467126353Smlaier strlcpy(buf, "unknown", len); 468126353Smlaier return (buf); 469126353Smlaier } 470126353Smlaier if (fp == PF_OSFP_ANY) { 471126353Smlaier strlcpy(buf, "any", len); 472126353Smlaier return (buf); 473126353Smlaier } 474126353Smlaier 475126353Smlaier PF_OSFP_UNPACK(fp, class, version, subtype); 476126353Smlaier if (class >= (1 << _FP_CLASS_BITS) || 477126353Smlaier version >= (1 << _FP_VERSION_BITS) || 478126353Smlaier subtype >= (1 << _FP_SUBTYPE_BITS)) { 479126353Smlaier warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp); 480126353Smlaier strlcpy(buf, "nomatch", len); 481126353Smlaier return (buf); 482126353Smlaier } 483126353Smlaier 484126353Smlaier LIST_FOREACH(nm, &classes, nm_entry) { 485126353Smlaier if (nm->nm_num == class) { 486126353Smlaier class_name = nm->nm_name; 487126353Smlaier if (version == PF_OSFP_ANY) 488126353Smlaier goto found; 489126353Smlaier list = &nm->nm_sublist; 490126353Smlaier LIST_FOREACH(nm, list, nm_entry) { 491126353Smlaier if (nm->nm_num == version) { 492126353Smlaier version_name = nm->nm_name; 493126353Smlaier if (subtype == PF_OSFP_ANY) 494126353Smlaier goto found; 495126353Smlaier list = &nm->nm_sublist; 496126353Smlaier LIST_FOREACH(nm, list, nm_entry) { 497126353Smlaier if (nm->nm_num == subtype) { 498126353Smlaier subtype_name = 499126353Smlaier nm->nm_name; 500126353Smlaier goto found; 501126353Smlaier } 502126353Smlaier } /* foreach subtype */ 503126353Smlaier strlcpy(buf, "nomatch", len); 504126353Smlaier return (buf); 505126353Smlaier } 506126353Smlaier } /* foreach version */ 507126353Smlaier strlcpy(buf, "nomatch", len); 508126353Smlaier return (buf); 509126353Smlaier } 510126353Smlaier } /* foreach class */ 511126353Smlaier 512126353Smlaier strlcpy(buf, "nomatch", len); 513126353Smlaier return (buf); 514126353Smlaier 515126353Smlaierfound: 516126353Smlaier snprintf(buf, len, "%s", class_name); 517126353Smlaier if (version_name) { 518126353Smlaier strlcat(buf, " ", len); 519126353Smlaier strlcat(buf, version_name, len); 520126353Smlaier if (subtype_name) { 521145837Smlaier if (strchr(version_name, ' ')) 522126353Smlaier strlcat(buf, " ", len); 523145837Smlaier else if (strchr(version_name, '.') && 524126353Smlaier isdigit(*subtype_name)) 525126353Smlaier strlcat(buf, ".", len); 526126353Smlaier else 527126353Smlaier strlcat(buf, " ", len); 528126353Smlaier strlcat(buf, subtype_name, len); 529126353Smlaier } 530126353Smlaier } 531126353Smlaier return (buf); 532126353Smlaier} 533126353Smlaier 534126353Smlaier/* lookup a name in a list */ 535126353Smlaierstruct name_entry * 536126353Smlaierlookup_name_list(struct name_list *list, const char *name) 537126353Smlaier{ 538126353Smlaier struct name_entry *nm; 539126353Smlaier LIST_FOREACH(nm, list, nm_entry) 540126353Smlaier if (strcasecmp(name, nm->nm_name) == 0) 541126353Smlaier return (nm); 542126353Smlaier 543126353Smlaier return (NULL); 544126353Smlaier} 545126353Smlaier 546126353Smlaier 547126353Smlaiervoid 548126353Smlaieradd_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp) 549126353Smlaier{ 550126353Smlaier struct pf_osfp_ioctl fptmp; 551126353Smlaier struct name_entry *nm_class, *nm_version, *nm_subtype; 552126353Smlaier int class, version, subtype; 553126353Smlaier 554126353Smlaier/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */ 555126353Smlaier#define EXPAND(field) do { \ 556126353Smlaier int _dot = -1, _start = -1, _end = -1, _i = 0; \ 557126353Smlaier /* pick major version out of #.# */ \ 558126353Smlaier if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \ 559126353Smlaier _dot = fp->field[_i] - '0'; \ 560126353Smlaier _i += 2; \ 561126353Smlaier } \ 562126353Smlaier if (isdigit(fp->field[_i])) \ 563126353Smlaier _start = fp->field[_i++] - '0'; \ 564126353Smlaier else \ 565126353Smlaier break; \ 566126353Smlaier if (isdigit(fp->field[_i])) \ 567126353Smlaier _start = (_start * 10) + fp->field[_i++] - '0'; \ 568126353Smlaier if (fp->field[_i++] != '-') \ 569126353Smlaier break; \ 570126353Smlaier if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \ 571126353Smlaier fp->field[_i] - '0' == _dot) \ 572126353Smlaier _i += 2; \ 573126353Smlaier else if (_dot != -1) \ 574126353Smlaier break; \ 575126353Smlaier if (isdigit(fp->field[_i])) \ 576126353Smlaier _end = fp->field[_i++] - '0'; \ 577126353Smlaier else \ 578126353Smlaier break; \ 579126353Smlaier if (isdigit(fp->field[_i])) \ 580126353Smlaier _end = (_end * 10) + fp->field[_i++] - '0'; \ 581126353Smlaier if (isdigit(fp->field[_i])) \ 582126353Smlaier _end = (_end * 10) + fp->field[_i++] - '0'; \ 583126353Smlaier if (fp->field[_i] != '\0') \ 584126353Smlaier break; \ 585126353Smlaier memcpy(&fptmp, fp, sizeof(fptmp)); \ 586126353Smlaier for (;_start <= _end; _start++) { \ 587126353Smlaier memset(fptmp.field, 0, sizeof(fptmp.field)); \ 588126353Smlaier fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \ 589126353Smlaier if (_dot == -1) \ 590126353Smlaier snprintf(fptmp.field, sizeof(fptmp.field), \ 591126353Smlaier "%d", _start); \ 592126353Smlaier else \ 593126353Smlaier snprintf(fptmp.field, sizeof(fptmp.field), \ 594126353Smlaier "%d.%d", _dot, _start); \ 595126353Smlaier add_fingerprint(dev, opts, &fptmp); \ 596126353Smlaier } \ 597126353Smlaier} while(0) 598126353Smlaier 599126353Smlaier /* We allow "#-#" as a version or subtype and we'll expand it */ 600126353Smlaier EXPAND(fp_os.fp_version_nm); 601126353Smlaier EXPAND(fp_os.fp_subtype_nm); 602126353Smlaier 603126353Smlaier if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0) 604126353Smlaier errx(1, "fingerprint class \"nomatch\" is reserved"); 605126353Smlaier 606126353Smlaier version = PF_OSFP_ANY; 607126353Smlaier subtype = PF_OSFP_ANY; 608126353Smlaier 609126353Smlaier nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); 610126353Smlaier if (nm_class->nm_num == 0) 611126353Smlaier nm_class->nm_num = ++class_count; 612126353Smlaier class = nm_class->nm_num; 613126353Smlaier 614126353Smlaier nm_version = fingerprint_name_entry(&nm_class->nm_sublist, 615126353Smlaier fp->fp_os.fp_version_nm); 616126353Smlaier if (nm_version) { 617126353Smlaier if (nm_version->nm_num == 0) 618126353Smlaier nm_version->nm_num = ++nm_class->nm_sublist_num; 619126353Smlaier version = nm_version->nm_num; 620126353Smlaier nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, 621126353Smlaier fp->fp_os.fp_subtype_nm); 622126353Smlaier if (nm_subtype) { 623126353Smlaier if (nm_subtype->nm_num == 0) 624126353Smlaier nm_subtype->nm_num = 625126353Smlaier ++nm_version->nm_sublist_num; 626126353Smlaier subtype = nm_subtype->nm_num; 627126353Smlaier } 628126353Smlaier } 629126353Smlaier 630126353Smlaier 631126353Smlaier DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype, 632126353Smlaier print_ioctl(fp)); 633126353Smlaier 634126353Smlaier PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype); 635126353Smlaier fingerprint_count++; 636126353Smlaier 637126353Smlaier#ifdef FAKE_PF_KERNEL 638126353Smlaier /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */ 639126353Smlaier if ((errno = pf_osfp_add(fp))) 640126353Smlaier#else 641126353Smlaier if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp)) 642126353Smlaier#endif /* FAKE_PF_KERNEL */ 643126353Smlaier { 644126353Smlaier if (errno == EEXIST) { 645126353Smlaier warn("Duplicate signature for %s %s %s", 646126353Smlaier fp->fp_os.fp_class_nm, 647126353Smlaier fp->fp_os.fp_version_nm, 648126353Smlaier fp->fp_os.fp_subtype_nm); 649126353Smlaier 650126353Smlaier } else { 651126353Smlaier err(1, "DIOCOSFPADD"); 652126353Smlaier } 653126353Smlaier } 654126353Smlaier} 655126353Smlaier 656126353Smlaier/* import a fingerprint from the kernel */ 657126353Smlaiervoid 658126353Smlaierimport_fingerprint(struct pf_osfp_ioctl *fp) 659126353Smlaier{ 660126353Smlaier struct name_entry *nm_class, *nm_version, *nm_subtype; 661126353Smlaier int class, version, subtype; 662126353Smlaier 663126353Smlaier PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype); 664126353Smlaier 665126353Smlaier nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); 666126353Smlaier if (nm_class->nm_num == 0) { 667126353Smlaier nm_class->nm_num = class; 668126353Smlaier class_count = MAX(class_count, class); 669126353Smlaier } 670126353Smlaier 671126353Smlaier nm_version = fingerprint_name_entry(&nm_class->nm_sublist, 672126353Smlaier fp->fp_os.fp_version_nm); 673126353Smlaier if (nm_version) { 674126353Smlaier if (nm_version->nm_num == 0) { 675126353Smlaier nm_version->nm_num = version; 676126353Smlaier nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num, 677126353Smlaier version); 678126353Smlaier } 679126353Smlaier nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, 680126353Smlaier fp->fp_os.fp_subtype_nm); 681126353Smlaier if (nm_subtype) { 682126353Smlaier if (nm_subtype->nm_num == 0) { 683126353Smlaier nm_subtype->nm_num = subtype; 684126353Smlaier nm_version->nm_sublist_num = 685126353Smlaier MAX(nm_version->nm_sublist_num, subtype); 686126353Smlaier } 687126353Smlaier } 688126353Smlaier } 689126353Smlaier 690126353Smlaier 691126353Smlaier fingerprint_count++; 692126353Smlaier DEBUG(fp, "import signature %d:%d:%d", class, version, subtype); 693126353Smlaier} 694126353Smlaier 695126353Smlaier/* Find an entry for a fingerprints class/version/subtype */ 696126353Smlaierstruct name_entry * 697126353Smlaierfingerprint_name_entry(struct name_list *list, char *name) 698126353Smlaier{ 699126353Smlaier struct name_entry *nm_entry; 700126353Smlaier 701126353Smlaier if (name == NULL || strlen(name) == 0) 702126353Smlaier return (NULL); 703126353Smlaier 704126353Smlaier LIST_FOREACH(nm_entry, list, nm_entry) { 705126353Smlaier if (strcasecmp(nm_entry->nm_name, name) == 0) { 706126353Smlaier /* We'll move this to the front of the list later */ 707126353Smlaier LIST_REMOVE(nm_entry, nm_entry); 708126353Smlaier break; 709126353Smlaier } 710126353Smlaier } 711126353Smlaier if (nm_entry == NULL) { 712126353Smlaier nm_entry = calloc(1, sizeof(*nm_entry)); 713126353Smlaier if (nm_entry == NULL) 714126353Smlaier err(1, "calloc"); 715145837Smlaier LIST_INIT(&nm_entry->nm_sublist); 716145837Smlaier strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name)); 717126353Smlaier } 718126353Smlaier LIST_INSERT_HEAD(list, nm_entry, nm_entry); 719126353Smlaier return (nm_entry); 720126353Smlaier} 721126353Smlaier 722126353Smlaier 723126353Smlaiervoid 724126353Smlaierprint_name_list(int opts, struct name_list *nml, const char *prefix) 725126353Smlaier{ 726126353Smlaier char newprefix[32]; 727126353Smlaier struct name_entry *nm; 728126353Smlaier 729126353Smlaier LIST_FOREACH(nm, nml, nm_entry) { 730126353Smlaier snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix, 731126353Smlaier nm->nm_name); 732126353Smlaier printf("%s\n", newprefix); 733126353Smlaier print_name_list(opts, &nm->nm_sublist, newprefix); 734126353Smlaier } 735126353Smlaier} 736126353Smlaier 737126353Smlaiervoid 738126353Smlaiersort_name_list(int opts, struct name_list *nml) 739126353Smlaier{ 740126353Smlaier struct name_list new; 741126353Smlaier struct name_entry *nm, *nmsearch, *nmlast; 742126353Smlaier 743126353Smlaier /* yes yes, it's a very slow sort. so sue me */ 744126353Smlaier 745126353Smlaier LIST_INIT(&new); 746126353Smlaier 747126353Smlaier while ((nm = LIST_FIRST(nml)) != NULL) { 748126353Smlaier LIST_REMOVE(nm, nm_entry); 749126353Smlaier nmlast = NULL; 750126353Smlaier LIST_FOREACH(nmsearch, &new, nm_entry) { 751126353Smlaier if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) { 752126353Smlaier LIST_INSERT_BEFORE(nmsearch, nm, nm_entry); 753126353Smlaier break; 754126353Smlaier } 755126353Smlaier nmlast = nmsearch; 756126353Smlaier } 757126353Smlaier if (nmsearch == NULL) { 758126353Smlaier if (nmlast) 759126353Smlaier LIST_INSERT_AFTER(nmlast, nm, nm_entry); 760126353Smlaier else 761126353Smlaier LIST_INSERT_HEAD(&new, nm, nm_entry); 762126353Smlaier } 763126353Smlaier 764126353Smlaier sort_name_list(opts, &nm->nm_sublist); 765126353Smlaier } 766126353Smlaier nmlast = NULL; 767126353Smlaier while ((nm = LIST_FIRST(&new)) != NULL) { 768126353Smlaier LIST_REMOVE(nm, nm_entry); 769126353Smlaier if (nmlast == NULL) 770126353Smlaier LIST_INSERT_HEAD(nml, nm, nm_entry); 771126353Smlaier else 772126353Smlaier LIST_INSERT_AFTER(nmlast, nm, nm_entry); 773126353Smlaier nmlast = nm; 774126353Smlaier } 775126353Smlaier} 776126353Smlaier 777126353Smlaier/* parse the next integer in a formatted config file line */ 778126353Smlaierint 779126353Smlaierget_int(char **line, size_t *len, int *var, int *mod, 780126353Smlaier const char *name, int flags, int max, const char *filename, int lineno) 781126353Smlaier{ 782126353Smlaier int fieldlen, i; 783126353Smlaier char *field; 784126353Smlaier long val = 0; 785126353Smlaier 786126353Smlaier if (mod) 787126353Smlaier *mod = 0; 788126353Smlaier *var = 0; 789126353Smlaier 790126353Smlaier field = get_field(line, len, &fieldlen); 791126353Smlaier if (field == NULL) 792126353Smlaier return (1); 793126353Smlaier if (fieldlen == 0) { 794126353Smlaier fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name); 795126353Smlaier return (1); 796126353Smlaier } 797126353Smlaier 798126353Smlaier i = 0; 799126353Smlaier if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*') 800126353Smlaier && fieldlen >= 1) { 801126353Smlaier switch (*field) { 802126353Smlaier case 'S': 803126353Smlaier if (mod && (flags & T_MSS)) 804126353Smlaier *mod = T_MSS; 805126353Smlaier if (fieldlen == 1) 806126353Smlaier return (0); 807126353Smlaier break; 808126353Smlaier case 'T': 809126353Smlaier if (mod && (flags & T_MTU)) 810126353Smlaier *mod = T_MTU; 811126353Smlaier if (fieldlen == 1) 812126353Smlaier return (0); 813126353Smlaier break; 814126353Smlaier case '*': 815126353Smlaier if (fieldlen != 1) { 816126353Smlaier fprintf(stderr, "%s:%d long '%c' %s\n", 817126353Smlaier filename, lineno, *field, name); 818126353Smlaier return (1); 819126353Smlaier } 820126353Smlaier if (mod && (flags & T_DC)) { 821126353Smlaier *mod = T_DC; 822126353Smlaier return (0); 823126353Smlaier } 824126353Smlaier case '%': 825126353Smlaier if (mod && (flags & T_MOD)) 826126353Smlaier *mod = T_MOD; 827126353Smlaier if (fieldlen == 1) { 828126353Smlaier fprintf(stderr, "%s:%d modulus %s must have a " 829126353Smlaier "value\n", filename, lineno, name); 830126353Smlaier return (1); 831126353Smlaier } 832126353Smlaier break; 833126353Smlaier } 834126353Smlaier if (mod == NULL || *mod == 0) { 835126353Smlaier fprintf(stderr, "%s:%d does not allow %c' %s\n", 836126353Smlaier filename, lineno, *field, name); 837126353Smlaier return (1); 838126353Smlaier } 839126353Smlaier i++; 840126353Smlaier } 841126353Smlaier 842126353Smlaier for (; i < fieldlen; i++) { 843130614Smlaier if (field[i] < '0' || field[i] > '9') { 844126353Smlaier fprintf(stderr, "%s:%d non-digit character in %s\n", 845126353Smlaier filename, lineno, name); 846126353Smlaier return (1); 847126353Smlaier } 848126353Smlaier val = val * 10 + field[i] - '0'; 849126353Smlaier if (val < 0) { 850126353Smlaier fprintf(stderr, "%s:%d %s overflowed\n", filename, 851126353Smlaier lineno, name); 852126353Smlaier return (1); 853126353Smlaier } 854126353Smlaier } 855126353Smlaier 856126353Smlaier if (val > max) { 857126353Smlaier fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno, 858126353Smlaier name, val, max); 859126353Smlaier return (1); 860126353Smlaier } 861126353Smlaier *var = (int)val; 862126353Smlaier 863126353Smlaier return (0); 864126353Smlaier} 865126353Smlaier 866126353Smlaier/* parse the next string in a formatted config file line */ 867126353Smlaierint 868126353Smlaierget_str(char **line, size_t *len, char **v, const char *name, int minlen, 869126353Smlaier const char *filename, int lineno) 870126353Smlaier{ 871126353Smlaier int fieldlen; 872126353Smlaier char *ptr; 873126353Smlaier 874126353Smlaier ptr = get_field(line, len, &fieldlen); 875126353Smlaier if (ptr == NULL) 876126353Smlaier return (1); 877126353Smlaier if (fieldlen < minlen) { 878126353Smlaier fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name); 879126353Smlaier return (1); 880126353Smlaier } 881126353Smlaier if ((*v = malloc(fieldlen + 1)) == NULL) { 882126353Smlaier perror("malloc()"); 883126353Smlaier return (1); 884126353Smlaier } 885126353Smlaier memcpy(*v, ptr, fieldlen); 886126353Smlaier (*v)[fieldlen] = '\0'; 887126353Smlaier 888126353Smlaier return (0); 889126353Smlaier} 890126353Smlaier 891126353Smlaier/* Parse out the TCP opts */ 892126353Smlaierint 893126353Smlaierget_tcpopts(const char *filename, int lineno, const char *tcpopts, 894126353Smlaier pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale, 895126353Smlaier int *wscale_mod, int *ts0) 896126353Smlaier{ 897126353Smlaier int i, opt; 898126353Smlaier 899126353Smlaier *packed = 0; 900126353Smlaier *optcnt = 0; 901126353Smlaier *wscale = 0; 902126353Smlaier *wscale_mod = T_DC; 903126353Smlaier *mss = 0; 904126353Smlaier *mss_mod = T_DC; 905126353Smlaier *ts0 = 0; 906126353Smlaier if (strcmp(tcpopts, ".") == 0) 907126353Smlaier return (0); 908126353Smlaier 909126353Smlaier for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) { 910126353Smlaier switch ((opt = toupper(tcpopts[i++]))) { 911126353Smlaier case 'N': /* FALLTHROUGH */ 912126353Smlaier case 'S': 913126353Smlaier *packed = (*packed << PF_OSFP_TCPOPT_BITS) | 914126353Smlaier (opt == 'N' ? PF_OSFP_TCPOPT_NOP : 915126353Smlaier PF_OSFP_TCPOPT_SACK); 916126353Smlaier break; 917126353Smlaier case 'W': /* FALLTHROUGH */ 918126353Smlaier case 'M': { 919126353Smlaier int *this_mod, *this; 920126353Smlaier 921126353Smlaier if (opt == 'W') { 922126353Smlaier this = wscale; 923126353Smlaier this_mod = wscale_mod; 924126353Smlaier } else { 925126353Smlaier this = mss; 926126353Smlaier this_mod = mss_mod; 927126353Smlaier } 928126353Smlaier *this = 0; 929126353Smlaier *this_mod = 0; 930126353Smlaier 931126353Smlaier *packed = (*packed << PF_OSFP_TCPOPT_BITS) | 932126353Smlaier (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE : 933126353Smlaier PF_OSFP_TCPOPT_MSS); 934126353Smlaier if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' || 935126353Smlaier tcpopts[i + 1] == ',')) { 936126353Smlaier *this_mod = T_DC; 937126353Smlaier i++; 938126353Smlaier break; 939126353Smlaier } 940126353Smlaier 941126353Smlaier if (tcpopts[i] == '%') { 942126353Smlaier *this_mod = T_MOD; 943126353Smlaier i++; 944126353Smlaier } 945126353Smlaier do { 946126353Smlaier if (!isdigit(tcpopts[i])) { 947126353Smlaier fprintf(stderr, "%s:%d unknown " 948126353Smlaier "character '%c' in %c TCP opt\n", 949126353Smlaier filename, lineno, tcpopts[i], opt); 950126353Smlaier return (1); 951126353Smlaier } 952126353Smlaier *this = (*this * 10) + tcpopts[i++] - '0'; 953126353Smlaier } while(tcpopts[i] != ',' && tcpopts[i] != '\0'); 954126353Smlaier break; 955126353Smlaier } 956126353Smlaier case 'T': 957126353Smlaier if (tcpopts[i] == '0') { 958126353Smlaier *ts0 = 1; 959126353Smlaier i++; 960126353Smlaier } 961126353Smlaier *packed = (*packed << PF_OSFP_TCPOPT_BITS) | 962126353Smlaier PF_OSFP_TCPOPT_TS; 963126353Smlaier break; 964126353Smlaier } 965126353Smlaier (*optcnt) ++; 966126353Smlaier if (tcpopts[i] == '\0') 967126353Smlaier break; 968126353Smlaier if (tcpopts[i] != ',') { 969126353Smlaier fprintf(stderr, "%s:%d unknown option to %c TCP opt\n", 970126353Smlaier filename, lineno, opt); 971126353Smlaier return (1); 972126353Smlaier } 973126353Smlaier i++; 974126353Smlaier } 975126353Smlaier 976126353Smlaier return (0); 977126353Smlaier} 978126353Smlaier 979126353Smlaier/* rip the next field ouf of a formatted config file line */ 980126353Smlaierchar * 981126353Smlaierget_field(char **line, size_t *len, int *fieldlen) 982126353Smlaier{ 983126353Smlaier char *ret, *ptr = *line; 984126353Smlaier size_t plen = *len; 985126353Smlaier 986126353Smlaier 987126353Smlaier while (plen && isspace(*ptr)) { 988126353Smlaier plen--; 989126353Smlaier ptr++; 990126353Smlaier } 991126353Smlaier ret = ptr; 992126353Smlaier *fieldlen = 0; 993126353Smlaier 994126353Smlaier for (; plen > 0 && *ptr != ':'; plen--, ptr++) 995126353Smlaier (*fieldlen)++; 996126353Smlaier if (plen) { 997126353Smlaier *line = ptr + 1; 998126353Smlaier *len = plen - 1; 999126353Smlaier } else { 1000126353Smlaier *len = 0; 1001126353Smlaier } 1002126353Smlaier while (*fieldlen && isspace(ret[*fieldlen - 1])) 1003126353Smlaier (*fieldlen)--; 1004126353Smlaier return (ret); 1005126353Smlaier} 1006126353Smlaier 1007126353Smlaier 1008126353Smlaierconst char * 1009126353Smlaierprint_ioctl(struct pf_osfp_ioctl *fp) 1010126353Smlaier{ 1011126353Smlaier static char buf[1024]; 1012126353Smlaier char tmp[32]; 1013126353Smlaier int i, opt; 1014126353Smlaier 1015126353Smlaier *buf = '\0'; 1016126353Smlaier if (fp->fp_flags & PF_OSFP_WSIZE_DC) 1017126353Smlaier strlcat(buf, "*", sizeof(buf)); 1018126353Smlaier else if (fp->fp_flags & PF_OSFP_WSIZE_MSS) 1019126353Smlaier strlcat(buf, "S", sizeof(buf)); 1020126353Smlaier else if (fp->fp_flags & PF_OSFP_WSIZE_MTU) 1021126353Smlaier strlcat(buf, "T", sizeof(buf)); 1022126353Smlaier else { 1023126353Smlaier if (fp->fp_flags & PF_OSFP_WSIZE_MOD) 1024126353Smlaier strlcat(buf, "%", sizeof(buf)); 1025126353Smlaier snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize); 1026126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1027126353Smlaier } 1028126353Smlaier strlcat(buf, ":", sizeof(buf)); 1029126353Smlaier 1030126353Smlaier snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl); 1031126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1032126353Smlaier strlcat(buf, ":", sizeof(buf)); 1033126353Smlaier 1034126353Smlaier if (fp->fp_flags & PF_OSFP_DF) 1035126353Smlaier strlcat(buf, "1", sizeof(buf)); 1036126353Smlaier else 1037126353Smlaier strlcat(buf, "0", sizeof(buf)); 1038126353Smlaier strlcat(buf, ":", sizeof(buf)); 1039126353Smlaier 1040126353Smlaier if (fp->fp_flags & PF_OSFP_PSIZE_DC) 1041126353Smlaier strlcat(buf, "*", sizeof(buf)); 1042126353Smlaier else { 1043126353Smlaier if (fp->fp_flags & PF_OSFP_PSIZE_MOD) 1044126353Smlaier strlcat(buf, "%", sizeof(buf)); 1045126353Smlaier snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize); 1046126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1047126353Smlaier } 1048126353Smlaier strlcat(buf, ":", sizeof(buf)); 1049126353Smlaier 1050126353Smlaier if (fp->fp_optcnt == 0) 1051126353Smlaier strlcat(buf, ".", sizeof(buf)); 1052126353Smlaier for (i = fp->fp_optcnt - 1; i >= 0; i--) { 1053126353Smlaier opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS); 1054126353Smlaier opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1; 1055126353Smlaier switch (opt) { 1056126353Smlaier case PF_OSFP_TCPOPT_NOP: 1057126353Smlaier strlcat(buf, "N", sizeof(buf)); 1058126353Smlaier break; 1059126353Smlaier case PF_OSFP_TCPOPT_SACK: 1060126353Smlaier strlcat(buf, "S", sizeof(buf)); 1061126353Smlaier break; 1062126353Smlaier case PF_OSFP_TCPOPT_TS: 1063126353Smlaier strlcat(buf, "T", sizeof(buf)); 1064126353Smlaier if (fp->fp_flags & PF_OSFP_TS0) 1065126353Smlaier strlcat(buf, "0", sizeof(buf)); 1066126353Smlaier break; 1067126353Smlaier case PF_OSFP_TCPOPT_MSS: 1068126353Smlaier strlcat(buf, "M", sizeof(buf)); 1069126353Smlaier if (fp->fp_flags & PF_OSFP_MSS_DC) 1070126353Smlaier strlcat(buf, "*", sizeof(buf)); 1071126353Smlaier else { 1072126353Smlaier if (fp->fp_flags & PF_OSFP_MSS_MOD) 1073126353Smlaier strlcat(buf, "%", sizeof(buf)); 1074126353Smlaier snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss); 1075126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1076126353Smlaier } 1077126353Smlaier break; 1078126353Smlaier case PF_OSFP_TCPOPT_WSCALE: 1079126353Smlaier strlcat(buf, "W", sizeof(buf)); 1080126353Smlaier if (fp->fp_flags & PF_OSFP_WSCALE_DC) 1081126353Smlaier strlcat(buf, "*", sizeof(buf)); 1082126353Smlaier else { 1083126353Smlaier if (fp->fp_flags & PF_OSFP_WSCALE_MOD) 1084126353Smlaier strlcat(buf, "%", sizeof(buf)); 1085126353Smlaier snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale); 1086126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1087126353Smlaier } 1088126353Smlaier break; 1089126353Smlaier } 1090126353Smlaier 1091126353Smlaier if (i != 0) 1092126353Smlaier strlcat(buf, ",", sizeof(buf)); 1093126353Smlaier } 1094126353Smlaier strlcat(buf, ":", sizeof(buf)); 1095126353Smlaier 1096126353Smlaier strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf)); 1097126353Smlaier strlcat(buf, ":", sizeof(buf)); 1098126353Smlaier strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf)); 1099126353Smlaier strlcat(buf, ":", sizeof(buf)); 1100126353Smlaier strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf)); 1101126353Smlaier strlcat(buf, ":", sizeof(buf)); 1102126353Smlaier 1103126353Smlaier snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt, 1104126353Smlaier (long long int)fp->fp_tcpopts); 1105126353Smlaier strlcat(buf, tmp, sizeof(buf)); 1106126353Smlaier 1107126353Smlaier return (buf); 1108126353Smlaier} 1109