diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-10-07 15:10:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-01-10 09:53:31 +0100 |
commit | c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch) | |
tree | ad4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/contrib | |
parent | userspace-header-gen.py: Simplify program ports (diff) | |
download | rtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2 |
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/contrib')
29 files changed, 10191 insertions, 26213 deletions
diff --git a/freebsd/contrib/libxo/libxo/libxo.c b/freebsd/contrib/libxo/libxo/libxo.c new file mode 100644 index 00000000..fc7c3209 --- /dev/null +++ b/freebsd/contrib/libxo/libxo/libxo.c @@ -0,0 +1,8080 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 2014-2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, July 2014 + * + * This is the implementation of libxo, the formatting library that + * generates multiple styles of output from a single code path. + * Command line utilities can have their normal text output while + * automation tools can see XML or JSON output, and web tools can use + * HTML output that encodes the text output annotated with additional + * information. Specialized encoders can be built that allow custom + * encoding including binary ones like CBOR, thrift, protobufs, etc. + * + * Full documentation is available in ./doc/libxo.txt or online at: + * http://juniper.github.io/libxo/libxo-manual.html + * + * For first time readers, the core bits of code to start looking at are: + * - xo_do_emit() -- parse and emit a set of fields + * - xo_do_emit_fields -- the central function of the library + * - xo_do_format_field() -- handles formatting a single field + * - xo_transiton() -- the state machine that keeps things sane + * and of course the "xo_handle_t" data structure, which carries all + * configuration and state. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <stddef.h> +#include <wchar.h> +#include <locale.h> +#include <sys/types.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <ctype.h> +#include <wctype.h> +#include <getopt.h> + +#include "xo_config.h" +#include "xo.h" +#include "xo_encoder.h" +#include "xo_buf.h" + +/* + * We ask wcwidth() to do an impossible job, really. It's supposed to + * need to tell us the number of columns consumed to display a unicode + * character. It returns that number without any sort of context, but + * we know they are characters whose glyph differs based on placement + * (end of word, middle of word, etc) and many that affect characters + * previously emitted. Without content, it can't hope to tell us. + * But it's the only standard tool we've got, so we use it. We would + * use wcswidth() but it typically just loops through adding the results + * of wcwidth() calls in an entirely unhelpful way. + * + * Even then, there are many poor implementations (macosx), so we have + * to carry our own. We could have configure.ac test this (with + * something like 'assert(wcwidth(0x200d) == 0)'), but it would have + * to run a binary, which breaks cross-compilation. Hmm... I could + * run this test at init time and make a warning for our dear user. + * + * Anyhow, it remains a best-effort sort of thing. And it's all made + * more hopeless because we assume the display code doing the rendering is + * playing by the same rules we are. If it display 0x200d as a square + * box or a funky question mark, the output will be hosed. + */ +#ifdef LIBXO_WCWIDTH +#include "xo_wcwidth.h" +#else /* LIBXO_WCWIDTH */ +#define xo_wcwidth(_x) wcwidth(_x) +#endif /* LIBXO_WCWIDTH */ + +#ifdef HAVE_STDIO_EXT_H +#include <stdio_ext.h> +#endif /* HAVE_STDIO_EXT_H */ + +/* + * humanize_number is a great function, unless you don't have it. So + * we carry one in our pocket. + */ +#ifdef HAVE_HUMANIZE_NUMBER +#include <libutil.h> +#define xo_humanize_number humanize_number +#else /* HAVE_HUMANIZE_NUMBER */ +#include "xo_humanize.h" +#endif /* HAVE_HUMANIZE_NUMBER */ + +#ifdef HAVE_GETTEXT +#include <libintl.h> +#endif /* HAVE_GETTEXT */ + +/* + * Three styles of specifying thread-local variables are supported. + * configure.ac has the brains to run each possibility through the + * compiler and see what works; we are left to define the THREAD_LOCAL + * macro to the right value. Most toolchains (clang, gcc) use + * "before", but some (borland) use "after" and I've heard of some + * (ms) that use __declspec. Any others out there? + */ +#define THREAD_LOCAL_before 1 +#define THREAD_LOCAL_after 2 +#define THREAD_LOCAL_declspec 3 + +#ifndef HAVE_THREAD_LOCAL +#define THREAD_LOCAL(_x) _x +#elif HAVE_THREAD_LOCAL == THREAD_LOCAL_before +#define THREAD_LOCAL(_x) __thread _x +#elif HAVE_THREAD_LOCAL == THREAD_LOCAL_after +#define THREAD_LOCAL(_x) _x __thread +#elif HAVE_THREAD_LOCAL == THREAD_LOCAL_declspec +#define THREAD_LOCAL(_x) __declspec(_x) +#else +#error unknown thread-local setting +#endif /* HAVE_THREADS_H */ + +const char xo_version[] = LIBXO_VERSION; +const char xo_version_extra[] = LIBXO_VERSION_EXTRA; +static const char xo_default_format[] = "%s"; + +#ifndef UNUSED +#define UNUSED __attribute__ ((__unused__)) +#endif /* UNUSED */ + +#define XO_INDENT_BY 2 /* Amount to indent when pretty printing */ +#define XO_DEPTH 128 /* Default stack depth */ +#define XO_MAX_ANCHOR_WIDTH (8*1024) /* Anything wider is just sillyb */ + +#define XO_FAILURE_NAME "failure" + +/* Flags for the stack frame */ +typedef unsigned xo_xsf_flags_t; /* XSF_* flags */ +#define XSF_NOT_FIRST (1<<0) /* Not the first element */ +#define XSF_LIST (1<<1) /* Frame is a list */ +#define XSF_INSTANCE (1<<2) /* Frame is an instance */ +#define XSF_DTRT (1<<3) /* Save the name for DTRT mode */ + +#define XSF_CONTENT (1<<4) /* Some content has been emitted */ +#define XSF_EMIT (1<<5) /* Some field has been emitted */ +#define XSF_EMIT_KEY (1<<6) /* A key has been emitted */ +#define XSF_EMIT_LEAF_LIST (1<<7) /* A leaf-list field has been emitted */ + +/* These are the flags we propagate between markers and their parents */ +#define XSF_MARKER_FLAGS \ + (XSF_NOT_FIRST | XSF_CONTENT | XSF_EMIT | XSF_EMIT_KEY | XSF_EMIT_LEAF_LIST ) + +/* + * A word about states: We use a finite state machine (FMS) approach + * to help remove fragility from the caller's code. Instead of + * requiring a specific order of calls, we'll allow the caller more + * flexibility and make the library responsible for recovering from + * missed steps. The goal is that the library should not be capable + * of emitting invalid xml or json, but the developer shouldn't need + * to know or understand all the details about these encodings. + * + * You can think of states as either states or events, since they + * function rather like both. None of the XO_CLOSE_* events will + * persist as states, since the matching stack frame will be popped. + * Same is true of XSS_EMIT, which is an event that asks us to + * prep for emitting output fields. + */ + +/* Stack frame states */ +typedef unsigned xo_state_t; +#define XSS_INIT 0 /* Initial stack state */ +#define XSS_OPEN_CONTAINER 1 +#define XSS_CLOSE_CONTAINER 2 +#define XSS_OPEN_LIST 3 +#define XSS_CLOSE_LIST 4 +#define XSS_OPEN_INSTANCE 5 +#define XSS_CLOSE_INSTANCE 6 +#define XSS_OPEN_LEAF_LIST 7 +#define XSS_CLOSE_LEAF_LIST 8 +#define XSS_DISCARDING 9 /* Discarding data until recovered */ +#define XSS_MARKER 10 /* xo_open_marker's marker */ +#define XSS_EMIT 11 /* xo_emit has a leaf field */ +#define XSS_EMIT_LEAF_LIST 12 /* xo_emit has a leaf-list ({l:}) */ +#define XSS_FINISH 13 /* xo_finish was called */ + +#define XSS_MAX 13 + +#define XSS_TRANSITION(_old, _new) ((_old) << 8 | (_new)) + +/* + * xo_stack_t: As we open and close containers and levels, we + * create a stack of frames to track them. This is needed for + * XOF_WARN and XOF_XPATH. + */ +typedef struct xo_stack_s { + xo_xsf_flags_t xs_flags; /* Flags for this frame */ + xo_state_t xs_state; /* State for this stack frame */ + char *xs_name; /* Name (for XPath value) */ + char *xs_keys; /* XPath predicate for any key fields */ +} xo_stack_t; + +/* + * libxo supports colors and effects, for those who like them. + * XO_COL_* ("colors") refers to fancy ansi codes, while X__EFF_* + * ("effects") are bits since we need to maintain state. + */ +#define XO_COL_DEFAULT 0 +#define XO_COL_BLACK 1 +#define XO_COL_RED 2 +#define XO_COL_GREEN 3 +#define XO_COL_YELLOW 4 +#define XO_COL_BLUE 5 +#define XO_COL_MAGENTA 6 +#define XO_COL_CYAN 7 +#define XO_COL_WHITE 8 + +#define XO_NUM_COLORS 9 + +/* + * Yes, there's no blink. We're civilized. We like users. Blink + * isn't something one does to someone you like. Friends don't let + * friends use blink. On friends. You know what I mean. Blink is + * like, well, it's like bursting into show tunes at a funeral. It's + * just not done. Not something anyone wants. And on those rare + * instances where it might actually be appropriate, it's still wrong, + * since it's likely done by the wrong person for the wrong reason. + * Just like blink. And if I implemented blink, I'd be like a funeral + * director who adds "Would you like us to burst into show tunes?" on + * the list of questions asked while making funeral arrangements. + * It's formalizing wrongness in the wrong way. And we're just too + * civilized to do that. Hhhmph! + */ +#define XO_EFF_RESET (1<<0) +#define XO_EFF_NORMAL (1<<1) +#define XO_EFF_BOLD (1<<2) +#define XO_EFF_UNDERLINE (1<<3) +#define XO_EFF_INVERSE (1<<4) + +#define XO_EFF_CLEAR_BITS XO_EFF_RESET /* Reset gets reset, surprisingly */ + +typedef uint8_t xo_effect_t; +typedef uint8_t xo_color_t; +typedef struct xo_colors_s { + xo_effect_t xoc_effects; /* Current effect set */ + xo_color_t xoc_col_fg; /* Foreground color */ + xo_color_t xoc_col_bg; /* Background color */ +} xo_colors_t; + +/* + * xo_handle_t: this is the principle data structure for libxo. + * It's used as a store for state, options, content, and all manor + * of other information. + */ +struct xo_handle_s { + xo_xof_flags_t xo_flags; /* Flags (XOF_*) from the user*/ + xo_xof_flags_t xo_iflags; /* Internal flags (XOIF_*) */ + xo_style_t xo_style; /* XO_STYLE_* value */ + unsigned short xo_indent; /* Indent level (if pretty) */ + unsigned short xo_indent_by; /* Indent amount (tab stop) */ + xo_write_func_t xo_write; /* Write callback */ + xo_close_func_t xo_close; /* Close callback */ + xo_flush_func_t xo_flush; /* Flush callback */ + xo_formatter_t xo_formatter; /* Custom formating function */ + xo_checkpointer_t xo_checkpointer; /* Custom formating support function */ + void *xo_opaque; /* Opaque data for write function */ + xo_buffer_t xo_data; /* Output data */ + xo_buffer_t xo_fmt; /* Work area for building format strings */ + xo_buffer_t xo_attrs; /* Work area for building XML attributes */ + xo_buffer_t xo_predicate; /* Work area for building XPath predicates */ + xo_stack_t *xo_stack; /* Stack pointer */ + int xo_depth; /* Depth of stack */ + int xo_stack_size; /* Size of the stack */ + xo_info_t *xo_info; /* Info fields for all elements */ + int xo_info_count; /* Number of info entries */ + va_list xo_vap; /* Variable arguments (stdargs) */ + char *xo_leading_xpath; /* A leading XPath expression */ + mbstate_t xo_mbstate; /* Multi-byte character conversion state */ + unsigned xo_anchor_offset; /* Start of anchored text */ + unsigned xo_anchor_columns; /* Number of columns since the start anchor */ + int xo_anchor_min_width; /* Desired width of anchored text */ + unsigned xo_units_offset; /* Start of units insertion point */ + unsigned xo_columns; /* Columns emitted during this xo_emit call */ + uint8_t xo_color_map_fg[XO_NUM_COLORS]; /* Foreground color mappings */ + uint8_t xo_color_map_bg[XO_NUM_COLORS]; /* Background color mappings */ + xo_colors_t xo_colors; /* Current color and effect values */ + xo_buffer_t xo_color_buf; /* HTML: buffer of colors and effects */ + char *xo_version; /* Version string */ + int xo_errno; /* Saved errno for "%m" */ + char *xo_gt_domain; /* Gettext domain, suitable for dgettext(3) */ + xo_encoder_func_t xo_encoder; /* Encoding function */ + void *xo_private; /* Private data for external encoders */ +}; + +/* Flag operations */ +#define XOF_BIT_ISSET(_flag, _bit) (((_flag) & (_bit)) ? 1 : 0) +#define XOF_BIT_SET(_flag, _bit) do { (_flag) |= (_bit); } while (0) +#define XOF_BIT_CLEAR(_flag, _bit) do { (_flag) &= ~(_bit); } while (0) + +#define XOF_ISSET(_xop, _bit) XOF_BIT_ISSET(_xop->xo_flags, _bit) +#define XOF_SET(_xop, _bit) XOF_BIT_SET(_xop->xo_flags, _bit) +#define XOF_CLEAR(_xop, _bit) XOF_BIT_CLEAR(_xop->xo_flags, _bit) + +#define XOIF_ISSET(_xop, _bit) XOF_BIT_ISSET(_xop->xo_iflags, _bit) +#define XOIF_SET(_xop, _bit) XOF_BIT_SET(_xop->xo_iflags, _bit) +#define XOIF_CLEAR(_xop, _bit) XOF_BIT_CLEAR(_xop->xo_iflags, _bit) + +/* Internal flags */ +#define XOIF_REORDER XOF_BIT(0) /* Reordering fields; record field info */ +#define XOIF_DIV_OPEN XOF_BIT(1) /* A <div> is open */ +#define XOIF_TOP_EMITTED XOF_BIT(2) /* The top JSON braces have been emitted */ +#define XOIF_ANCHOR XOF_BIT(3) /* An anchor is in place */ + +#define XOIF_UNITS_PENDING XOF_BIT(4) /* We have a units-insertion pending */ +#define XOIF_INIT_IN_PROGRESS XOF_BIT(5) /* Init of handle is in progress */ + +/* Flags for formatting functions */ +typedef unsigned long xo_xff_flags_t; +#define XFF_COLON (1<<0) /* Append a ":" */ +#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */ +#define XFF_WS (1<<2) /* Append a blank */ +#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding styles (XML, JSON) */ + +#define XFF_QUOTE (1<<4) /* Force quotes */ +#define XFF_NOQUOTE (1<<5) /* Force no quotes */ +#define XFF_DISPLAY_ONLY (1<<6) /* Only emit for display styles (text, html) */ +#define XFF_KEY (1<<7) /* Field is a key (for XPath) */ + +#define XFF_XML (1<<8) /* Force XML encoding style (for XPath) */ +#define XFF_ATTR (1<<9) /* Escape value using attribute rules (XML) */ +#define XFF_BLANK_LINE (1<<10) /* Emit a blank line */ +#define XFF_NO_OUTPUT (1<<11) /* Do not make any output */ + +#define XFF_TRIM_WS (1<<12) /* Trim whitespace off encoded values */ +#define XFF_LEAF_LIST (1<<13) /* A leaf-list (list of values) */ +#define XFF_UNESCAPE (1<<14) /* Need to printf-style unescape the value */ +#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */ + +#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */ +#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */ +#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */ +#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */ + +#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */ +#define XFF_ARGUMENT (1<<21) /* Content provided via argument */ + +/* Flags to turn off when we don't want i18n processing */ +#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL) + +/* + * Normal printf has width and precision, which for strings operate as + * min and max number of columns. But this depends on the idea that + * one byte means one column, which UTF-8 and multi-byte characters + * pitches on its ear. It may take 40 bytes of data to populate 14 + * columns, but we can't go off looking at 40 bytes of data without the + * caller's permission for fear/knowledge that we'll generate core files. + * + * So we make three values, distinguishing between "max column" and + * "number of bytes that we will inspect inspect safely" We call the + * later "size", and make the format "%[[<min>].[[<size>].<max>]]s". + * + * Under the "first do no harm" theory, we default "max" to "size". + * This is a reasonable assumption for folks that don't grok the + * MBS/WCS/UTF-8 world, and while it will be annoying, it will never + * be evil. + * + * For example, xo_emit("{:tag/%-14.14s}", buf) will make 14 + * columns of output, but will never look at more than 14 bytes of the + * input buffer. This is mostly compatible with printf and caller's + * expectations. + * + * In contrast xo_emit("{:tag/%-14..14s}", buf) will look at however + * many bytes (or until a NUL is seen) are needed to fill 14 columns + * of output. xo_emit("{:tag/%-14.*.14s}", xx, buf) will look at up + * to xx bytes (or until a NUL is seen) in order to fill 14 columns + * of output. + * + * It's fairly amazing how a good idea (handle all languages of the + * world) blows such a big hole in the bottom of the fairly weak boat + * that is C string handling. The simplicity and completenesss are + * sunk in ways we haven't even begun to understand. + */ +#define XF_WIDTH_MIN 0 /* Minimal width */ +#define XF_WIDTH_SIZE 1 /* Maximum number of bytes to examine */ +#define XF_WIDTH_MAX 2 /* Maximum width */ +#define XF_WIDTH_NUM 3 /* Numeric fields in printf (min.size.max) */ + +/* Input and output string encodings */ +#define XF_ENC_WIDE 1 /* Wide characters (wchar_t) */ +#define XF_ENC_UTF8 2 /* UTF-8 */ +#define XF_ENC_LOCALE 3 /* Current locale */ + +/* + * A place to parse printf-style format flags for each field + */ +typedef struct xo_format_s { + unsigned char xf_fc; /* Format character */ + unsigned char xf_enc; /* Encoding of the string (XF_ENC_*) */ + unsigned char xf_skip; /* Skip this field */ + unsigned char xf_lflag; /* 'l' (long) */ + unsigned char xf_hflag;; /* 'h' (half) */ + unsigned char xf_jflag; /* 'j' (intmax_t) */ + unsigned char xf_tflag; /* 't' (ptrdiff_t) */ + unsigned char xf_zflag; /* 'z' (size_t) */ + unsigned char xf_qflag; /* 'q' (quad_t) */ + unsigned char xf_seen_minus; /* Seen a minus */ + int xf_leading_zero; /* Seen a leading zero (zero fill) */ + unsigned xf_dots; /* Seen one or more '.'s */ + int xf_width[XF_WIDTH_NUM]; /* Width/precision/size numeric fields */ + unsigned xf_stars; /* Seen one or more '*'s */ + unsigned char xf_star[XF_WIDTH_NUM]; /* Seen one or more '*'s */ +} xo_format_t; + +/* + * This structure represents the parsed field information, suitable for + * processing by xo_do_emit and anything else that needs to parse fields. + * Note that all pointers point to the main format string. + * + * XXX This is a first step toward compilable or cachable format + * strings. We can also cache the results of dgettext when no format + * is used, assuming the 'p' modifier has _not_ been set. + */ +typedef struct xo_field_info_s { + xo_xff_flags_t xfi_flags; /* Flags for this field */ + unsigned xfi_ftype; /* Field type, as character (e.g. 'V') */ + const char *xfi_start; /* Start of field in the format string */ + const char *xfi_content; /* Field's content */ + const char *xfi_format; /* Field's Format */ + const char *xfi_encoding; /* Field's encoding format */ + const char *xfi_next; /* Next character in format string */ + unsigned xfi_len; /* Length of field */ + unsigned xfi_clen; /* Content length */ + unsigned xfi_flen; /* Format length */ + unsigned xfi_elen; /* Encoding length */ + unsigned xfi_fnum; /* Field number (if used; 0 otherwise) */ + unsigned xfi_renum; /* Reordered number (0 == no renumbering) */ +} xo_field_info_t; + +/* + * We keep a 'default' handle to allow callers to avoid having to + * allocate one. Passing NULL to any of our functions will use + * this default handle. Most functions have a variant that doesn't + * require a handle at all, since most output is to stdout, which + * the default handle handles handily. + */ +static THREAD_LOCAL(xo_handle_t) xo_default_handle; +static THREAD_LOCAL(int) xo_default_inited; +static int xo_locale_inited; +static const char *xo_program; + +/* + * To allow libxo to be used in diverse environment, we allow the + * caller to give callbacks for memory allocation. + */ +xo_realloc_func_t xo_realloc = realloc; +xo_free_func_t xo_free = free; + +/* Forward declarations */ +static void +xo_failure (xo_handle_t *xop, const char *fmt, ...); + +static int +xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name, + xo_state_t new_state); + +static void +xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags, + const char *name, int nlen, + const char *value, int vlen, + const char *encoding, int elen); + +static void +xo_anchor_clear (xo_handle_t *xop); + +/* + * xo_style is used to retrieve the current style. When we're built + * for "text only" mode, we use this function to drive the removal + * of most of the code in libxo. We return a constant and the compiler + * happily removes the non-text code that is not longer executed. This + * trims our code nicely without needing to trampel perfectly readable + * code with ifdefs. + */ +static inline xo_style_t +xo_style (xo_handle_t *xop UNUSED) +{ +#ifdef LIBXO_TEXT_ONLY + return XO_STYLE_TEXT; +#else /* LIBXO_TEXT_ONLY */ + return xop->xo_style; +#endif /* LIBXO_TEXT_ONLY */ +} + +/* + * Callback to write data to a FILE pointer + */ +static int +xo_write_to_file (void *opaque, const char *data) +{ + FILE *fp = (FILE *) opaque; + + return fprintf(fp, "%s", data); +} + +/* + * Callback to close a file + */ +static void +xo_close_file (void *opaque) +{ + FILE *fp = (FILE *) opaque; + + fclose(fp); +} + +/* + * Callback to flush a FILE pointer + */ +static int +xo_flush_file (void *opaque) +{ + FILE *fp = (FILE *) opaque; + + return fflush(fp); +} + +/* + * Use a rotating stock of buffers to make a printable string + */ +#define XO_NUMBUFS 8 +#define XO_SMBUFSZ 128 + +static const char * +xo_printable (const char *str) +{ + static THREAD_LOCAL(char) bufset[XO_NUMBUFS][XO_SMBUFSZ]; + static THREAD_LOCAL(int) bufnum = 0; + + if (str == NULL) + return ""; + + if (++bufnum == XO_NUMBUFS) + bufnum = 0; + + char *res = bufset[bufnum], *cp, *ep; + + for (cp = res, ep = res + XO_SMBUFSZ - 1; *str && cp < ep; cp++, str++) { + if (*str == '\n') { + *cp++ = '\\'; + *cp = 'n'; + } else if (*str == '\r') { + *cp++ = '\\'; + *cp = 'r'; + } else if (*str == '\"') { + *cp++ = '\\'; + *cp = '"'; + } else + *cp = *str; + } + + *cp = '\0'; + return res; +} + +static int +xo_depth_check (xo_handle_t *xop, int depth) +{ + xo_stack_t *xsp; + + if (depth >= xop->xo_stack_size) { + depth += XO_DEPTH; /* Extra room */ + + xsp = xo_realloc(xop->xo_stack, sizeof(xop->xo_stack[0]) * depth); + if (xsp == NULL) { + xo_failure(xop, "xo_depth_check: out of memory (%d)", depth); + return -1; + } + + int count = depth - xop->xo_stack_size; + + bzero(xsp + xop->xo_stack_size, count * sizeof(*xsp)); + xop->xo_stack_size = depth; + xop->xo_stack = xsp; + } + + return 0; +} + +void +xo_no_setlocale (void) +{ + xo_locale_inited = 1; /* Skip initialization */ +} + +/* + * We need to decide if stdout is line buffered (_IOLBF). Lacking a + * standard way to decide this (e.g. getlinebuf()), we have configure + * look to find __flbf, which glibc supported. If not, we'll rely on + * isatty, with the assumption that terminals are the only thing + * that's line buffered. We _could_ test for "steam._flags & _IOLBF", + * which is all __flbf does, but that's even tackier. Like a + * bedazzled Elvis outfit on an ugly lap dog sort of tacky. Not + * something we're willing to do. + */ +static int +xo_is_line_buffered (FILE *stream) +{ +#if HAVE___FLBF + if (__flbf(stream)) + return 1; +#else /* HAVE___FLBF */ + if (isatty(fileno(stream))) + return 1; +#endif /* HAVE___FLBF */ + return 0; +} + +/* + * Initialize an xo_handle_t, using both static defaults and + * the global settings from the LIBXO_OPTIONS environment + * variable. + */ +static void +xo_init_handle (xo_handle_t *xop) +{ + xop->xo_opaque = stdout; + xop->xo_write = xo_write_to_file; + xop->xo_flush = xo_flush_file; + + if (xo_is_line_buffered(stdout)) + XOF_SET(xop, XOF_FLUSH_LINE); + + /* + * We only want to do color output on terminals, but we only want + * to do this if the user has asked for color. + */ + if (XOF_ISSET(xop, XOF_COLOR_ALLOWED) && isatty(1)) + XOF_SET(xop, XOF_COLOR); + + /* + * We need to initialize the locale, which isn't really pretty. + * Libraries should depend on their caller to set up the + * environment. But we really can't count on the caller to do + * this, because well, they won't. Trust me. + */ + if (!xo_locale_inited) { + xo_locale_inited = 1; /* Only do this once */ + + const char *cp = getenv("LC_CTYPE"); + if (cp == NULL) + cp = getenv("LANG"); + if (cp == NULL) + cp = getenv("LC_ALL"); + if (cp == NULL) + cp = "C"; /* Default for C programs */ + (void) setlocale(LC_CTYPE, cp); + } + + /* + * Initialize only the xo_buffers we know we'll need; the others + * can be allocated as needed. + */ + xo_buf_init(&xop->xo_data); + xo_buf_init(&xop->xo_fmt); + + if (XOIF_ISSET(xop, XOIF_INIT_IN_PROGRESS)) + return; + XOIF_SET(xop, XOIF_INIT_IN_PROGRESS); + + xop->xo_indent_by = XO_INDENT_BY; + xo_depth_check(xop, XO_DEPTH); + +#if !defined(NO_LIBXO_OPTIONS) + if (!XOF_ISSET(xop, XOF_NO_ENV)) { + char *env = getenv("LIBXO_OPTIONS"); + if (env) + xo_set_options(xop, env); + + } +#endif /* NO_GETENV */ + + XOIF_CLEAR(xop, XOIF_INIT_IN_PROGRESS); +} + +/* + * Initialize the default handle. + */ +static void +xo_default_init (void) +{ + xo_handle_t *xop = &xo_default_handle; + + xo_init_handle(xop); + + xo_default_inited = 1; +} + +/* + * Cheap convenience function to return either the argument, or + * the internal handle, after it has been initialized. The usage + * is: + * xop = xo_default(xop); + */ +static xo_handle_t * +xo_default (xo_handle_t *xop) +{ + if (xop == NULL) { + if (xo_default_inited == 0) + xo_default_init(); + xop = &xo_default_handle; + } + + return xop; +} + +/* + * Return the number of spaces we should be indenting. If + * we are pretty-printing, this is indent * indent_by. + */ +static int +xo_indent (xo_handle_t *xop) +{ + int rc = 0; + + xop = xo_default(xop); + + if (XOF_ISSET(xop, XOF_PRETTY)) { + rc = xop->xo_indent * xop->xo_indent_by; + if (XOIF_ISSET(xop, XOIF_TOP_EMITTED)) + rc += xop->xo_indent_by; + } + + return (rc > 0) ? rc : 0; +} + +static void +xo_buf_indent (xo_handle_t *xop, int indent) +{ + xo_buffer_t *xbp = &xop->xo_data; + + if (indent <= 0) + indent = xo_indent(xop); + + if (!xo_buf_has_room(xbp, indent)) + return; + + memset(xbp->xb_curp, ' ', indent); + xbp->xb_curp += indent; +} + +static char xo_xml_amp[] = "&"; +static char xo_xml_lt[] = "<"; +static char xo_xml_gt[] = ">"; +static char xo_xml_quot[] = """; + +static int +xo_escape_xml (xo_buffer_t *xbp, int len, xo_xff_flags_t flags) +{ + int slen; + unsigned delta = 0; + char *cp, *ep, *ip; + const char *sp; + int attr = (flags & XFF_ATTR); + + for (cp = xbp->xb_curp, ep = cp + len; cp < ep; cp++) { + /* We're subtracting 2: 1 for the NUL, 1 for the char we replace */ + if (*cp == '<') + delta += sizeof(xo_xml_lt) - 2; + else if (*cp == '>') + delta += sizeof(xo_xml_gt) - 2; + else if (*cp == '&') + delta += sizeof(xo_xml_amp) - 2; + else if (attr && *cp == '"') + delta += sizeof(xo_xml_quot) - 2; + } + + if (delta == 0) /* Nothing to escape; bail */ + return len; + + if (!xo_buf_has_room(xbp, delta)) /* No room; bail, but don't append */ + return 0; + + ep = xbp->xb_curp; + cp = ep + len; + ip = cp + delta; + do { + cp -= 1; + ip -= 1; + + if (*cp == '<') + sp = xo_xml_lt; + else if (*cp == '>') + sp = xo_xml_gt; + else if (*cp == '&') + sp = xo_xml_amp; + else if (attr && *cp == '"') + sp = xo_xml_quot; + else { + *ip = *cp; + continue; + } + + slen = strlen(sp); + ip -= slen - 1; + memcpy(ip, sp, slen); + + } while (cp > ep && cp != ip); + + return len + delta; +} + +static int +xo_escape_json (xo_buffer_t *xbp, int len, xo_xff_flags_t flags UNUSED) +{ + unsigned delta = 0; + char *cp, *ep, *ip; + + for (cp = xbp->xb_curp, ep = cp + len; cp < ep; cp++) { + if (*cp == '\\' || *cp == '"') + delta += 1; + else if (*cp == '\n' || *cp == '\r') + delta += 1; + } + + if (delta == 0) /* Nothing to escape; bail */ + return len; + + if (!xo_buf_has_room(xbp, delta)) /* No room; bail, but don't append */ + return 0; + + ep = xbp->xb_curp; + cp = ep + len; + ip = cp + delta; + do { + cp -= 1; + ip -= 1; + + if (*cp == '\\' || *cp == '"') { + *ip-- = *cp; + *ip = '\\'; + } else if (*cp == '\n') { + *ip-- = 'n'; + *ip = '\\'; + } else if (*cp == '\r') { + *ip-- = 'r'; + *ip = '\\'; + } else { + *ip = *cp; + } + + } while (cp > ep && cp != ip); + + return len + delta; +} + +/* + * PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and + * ; ']' MUST be escaped. + */ +static int +xo_escape_sdparams (xo_buffer_t *xbp, int len, xo_xff_flags_t flags UNUSED) +{ + unsigned delta = 0; + char *cp, *ep, *ip; + + for (cp = xbp->xb_curp, ep = cp + len; cp < ep; cp++) { + if (*cp == '\\' || *cp == '"' || *cp == ']') + delta += 1; + } + + if (delta == 0) /* Nothing to escape; bail */ + return len; + + if (!xo_buf_has_room(xbp, delta)) /* No room; bail, but don't append */ + return 0; + + ep = xbp->xb_curp; + cp = ep + len; + ip = cp + delta; + do { + cp -= 1; + ip -= 1; + + if (*cp == '\\' || *cp == '"' || *cp == ']') { + *ip-- = *cp; + *ip = '\\'; + } else { + *ip = *cp; + } + + } while (cp > ep && cp != ip); + + return len + delta; +} + +static void +xo_buf_escape (xo_handle_t *xop, xo_buffer_t *xbp, + const char *str, int len, xo_xff_flags_t flags) +{ + if (!xo_buf_has_room(xbp, len)) + return; + + memcpy(xbp->xb_curp, str, len); + + switch (xo_style(xop)) { + case XO_STYLE_XML: + case XO_STYLE_HTML: + len = xo_escape_xml(xbp, len, flags); + break; + + case XO_STYLE_JSON: + len = xo_escape_json(xbp, len, flags); + break; + + case XO_STYLE_SDPARAMS: + len = xo_escape_sdparams(xbp, len, flags); + break; + } + + xbp->xb_curp += len; +} + +/* + * Write the current contents of the data buffer using the handle's + * xo_write function. + */ +static int +xo_write (xo_handle_t *xop) +{ + int rc = 0; + xo_buffer_t *xbp = &xop->xo_data; + + if (xbp->xb_curp != xbp->xb_bufp) { + xo_buf_append(xbp, "", 1); /* Append ending NUL */ + xo_anchor_clear(xop); + if (xop->xo_write) + rc = xop->xo_write(xop->xo_opaque, xbp->xb_bufp); + xbp->xb_curp = xbp->xb_bufp; + } + + /* Turn off the flags that don't survive across writes */ + XOIF_CLEAR(xop, XOIF_UNITS_PENDING); + + return rc; +} + +/* + * Format arguments into our buffer. If a custom formatter has been set, + * we use that to do the work; otherwise we vsnprintf(). + */ +static int +xo_vsnprintf (xo_handle_t *xop, xo_buffer_t *xbp, const char *fmt, va_list vap) +{ + va_list va_local; + int rc; + int left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + + va_copy(va_local, vap); + + if (xop->xo_formatter) + rc = xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local); + else + rc = vsnprintf(xbp->xb_curp, left, fmt, va_local); + + if (rc >= left) { + if (!xo_buf_has_room(xbp, rc)) { + va_end(va_local); + return -1; + } + + /* + * After we call vsnprintf(), the stage of vap is not defined. + * We need to copy it before we pass. Then we have to do our + * own logic below to move it along. This is because the + * implementation can have va_list be a pointer (bsd) or a + * structure (macosx) or anything in between. + */ + + va_end(va_local); /* Reset vap to the start */ + va_copy(va_local, vap); + + left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + if (xop->xo_formatter) + rc = xop->xo_formatter(xop, xbp->xb_curp, left, fmt, va_local); + else + rc = vsnprintf(xbp->xb_curp, left, fmt, va_local); + } + va_end(va_local); + + return rc; +} + +/* + * Print some data through the handle. + */ +static int +xo_printf_v (xo_handle_t *xop, const char *fmt, va_list vap) +{ + xo_buffer_t *xbp = &xop->xo_data; + int left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + int rc; + va_list va_local; + + va_copy(va_local, vap); + + rc = vsnprintf(xbp->xb_curp, left, fmt, va_local); + + if (rc >= left) { + if (!xo_buf_has_room(xbp, rc)) { + va_end(va_local); + return -1; + } + + va_end(va_local); /* Reset vap to the start */ + va_copy(va_local, vap); + + left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + rc = vsnprintf(xbp->xb_curp, left, fmt, va_local); + } + + va_end(va_local); + + if (rc > 0) + xbp->xb_curp += rc; + + return rc; +} + +static int +xo_printf (xo_handle_t *xop, const char *fmt, ...) +{ + int rc; + va_list vap; + + va_start(vap, fmt); + + rc = xo_printf_v(xop, fmt, vap); + + va_end(vap); + return rc; +} + +/* + * These next few function are make The Essential UTF-8 Ginsu Knife. + * Identify an input and output character, and convert it. + */ +static int xo_utf8_bits[7] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + +static int +xo_is_utf8 (char ch) +{ + return (ch & 0x80); +} + +static inline int +xo_utf8_to_wc_len (const char *buf) +{ + unsigned b = (unsigned char) *buf; + int len; + + if ((b & 0x80) == 0x0) + len = 1; + else if ((b & 0xe0) == 0xc0) + len = 2; + else if ((b & 0xf0) == 0xe0) + len = 3; + else if ((b & 0xf8) == 0xf0) + len = 4; + else if ((b & 0xfc) == 0xf8) + len = 5; + else if ((b & 0xfe) == 0xfc) + len = 6; + else + len = -1; + + return len; +} + +static int +xo_buf_utf8_len (xo_handle_t *xop, const char *buf, int bufsiz) +{ + + unsigned b = (unsigned char) *buf; + int len, i; + + len = xo_utf8_to_wc_len(buf); + if (len == -1) { + xo_failure(xop, "invalid UTF-8 data: %02hhx", b); + return -1; + } + + if (len > bufsiz) { + xo_failure(xop, "invalid UTF-8 data (short): %02hhx (%d/%d)", + b, len, bufsiz); + return -1; + } + + for (i = 2; i < len; i++) { + b = (unsigned char ) buf[i]; + if ((b & 0xc0) != 0x80) { + xo_failure(xop, "invalid UTF-8 data (byte %d): %x", i, b); + return -1; + } + } + + return len; +} + +/* + * Build a wide character from the input buffer; the number of + * bits we pull off the first character is dependent on the length, + * but we put 6 bits off all other bytes. + */ +static inline wchar_t +xo_utf8_char (const char *buf, int len) +{ + /* Most common case: singleton byte */ + if (len == 1) + return (unsigned char) buf[0]; + + int i; + wchar_t wc; + const unsigned char *cp = (const unsigned char *) buf; + + wc = *cp & xo_utf8_bits[len]; + for (i = 1; i < len; i++) { + wc <<= 6; + wc |= cp[i] & 0x3f; + if ((cp[i] & 0xc0) != 0x80) + return (wchar_t) -1; + } + + return wc; +} + +/* + * Determine the number of bytes needed to encode a wide character. + */ +static int +xo_utf8_emit_len (wchar_t wc) +{ + int len; + + if ((wc & ((1<<7) - 1)) == wc) /* Simple case */ + len = 1; + else if ((wc & ((1<<11) - 1)) == wc) + len = 2; + else if ((wc & ((1<<16) - 1)) == wc) + len = 3; + else if ((wc & ((1<<21) - 1)) == wc) + len = 4; + else if ((wc & ((1<<26) - 1)) == wc) + len = 5; + else + len = 6; + + return len; +} + +static void +xo_utf8_emit_char (char *buf, int len, wchar_t wc) +{ + int i; + + if (len == 1) { /* Simple case */ + buf[0] = wc & 0x7f; + return; + } + + for (i = len - 1; i >= 0; i--) { + buf[i] = 0x80 | (wc & 0x3f); + wc >>= 6; + } + + buf[0] &= xo_utf8_bits[len]; + buf[0] |= ~xo_utf8_bits[len] << 1; +} + +static int +xo_buf_append_locale_from_utf8 (xo_handle_t *xop, xo_buffer_t *xbp, + const char *ibuf, int ilen) +{ + wchar_t wc; + int len; + + /* + * Build our wide character from the input buffer; the number of + * bits we pull off the first character is dependent on the length, + * but we put 6 bits off all other bytes. + */ + wc = xo_utf8_char(ibuf, ilen); + if (wc == (wchar_t) -1) { + xo_failure(xop, "invalid utf-8 byte sequence"); + return 0; + } + + if (XOF_ISSET(xop, XOF_NO_LOCALE)) { + if (!xo_buf_has_room(xbp, ilen)) + return 0; + + memcpy(xbp->xb_curp, ibuf, ilen); + xbp->xb_curp += ilen; + + } else { + if (!xo_buf_has_room(xbp, MB_LEN_MAX + 1)) + return 0; + + bzero(&xop->xo_mbstate, sizeof(xop->xo_mbstate)); + len = wcrtomb(xbp->xb_curp, wc, &xop->xo_mbstate); + + if (len <= 0) { + xo_failure(xop, "could not convert wide char: %lx", + (unsigned long) wc); + return 0; + } + xbp->xb_curp += len; + } + + return xo_wcwidth(wc); +} + +static void +xo_buf_append_locale (xo_handle_t *xop, xo_buffer_t *xbp, + const char *cp, int len) +{ + const char *sp = cp, *ep = cp + len; + unsigned save_off = xbp->xb_bufp - xbp->xb_curp; + int slen; + int cols = 0; + + for ( ; cp < ep; cp++) { + if (!xo_is_utf8(*cp)) { + cols += 1; + continue; + } + + /* + * We're looking at a non-ascii UTF-8 character. + * First we copy the previous data. + * Then we need find the length and validate it. + * Then we turn it into a wide string. + * Then we turn it into a localized string. + * Then we repeat. Isn't i18n fun? + */ + if (sp != cp) + xo_buf_append(xbp, sp, cp - sp); /* Append previous data */ + + slen = xo_buf_utf8_len(xop, cp, ep - cp); + if (slen <= 0) { + /* Bad data; back it all out */ + xbp->xb_curp = xbp->xb_bufp + save_off; + return; + } + + cols += xo_buf_append_locale_from_utf8(xop, xbp, cp, slen); + + /* Next time through, we'll start at the next character */ + cp += slen - 1; + sp = cp + 1; + } + + /* Update column values */ + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += cols; + + /* Before we fall into the basic logic below, we need reset len */ + len = ep - sp; + if (len != 0) /* Append trailing data */ + xo_buf_append(xbp, sp, len); +} + +/* + * Append the given string to the given buffer, without escaping or + * character set conversion. This is the straight copy to the data + * buffer with no fanciness. + */ +static void +xo_data_append (xo_handle_t *xop, const char *str, int len) +{ + xo_buf_append(&xop->xo_data, str, len); +} + +/* + * Append the given string to the given buffer + */ +static void +xo_data_escape (xo_handle_t *xop, const char *str, int len) +{ + xo_buf_escape(xop, &xop->xo_data, str, len, 0); +} + +#ifdef LIBXO_NO_RETAIN +/* + * Empty implementations of the retain logic + */ + +void +xo_retain_clear_all (void) +{ + return; +} + +void +xo_retain_clear (const char *fmt UNUSED) +{ + return; +} +static void +xo_retain_add (const char *fmt UNUSED, xo_field_info_t *fields UNUSED, + unsigned num_fields UNUSED) +{ + return; +} + +static int +xo_retain_find (const char *fmt UNUSED, xo_field_info_t **valp UNUSED, + unsigned *nump UNUSED) +{ + return -1; +} + +#else /* !LIBXO_NO_RETAIN */ +/* + * Retain: We retain parsed field definitions to enhance performance, + * especially inside loops. We depend on the caller treating the format + * strings as immutable, so that we can retain pointers into them. We + * hold the pointers in a hash table, so allow quick access. Retained + * information is retained until xo_retain_clear is called. + */ + +/* + * xo_retain_entry_t holds information about one retained set of + * parsed fields. + */ +typedef struct xo_retain_entry_s { + struct xo_retain_entry_s *xre_next; /* Pointer to next (older) entry */ + unsigned long xre_hits; /* Number of times we've hit */ + const char *xre_format; /* Pointer to format string */ + unsigned xre_num_fields; /* Number of fields saved */ + xo_field_info_t *xre_fields; /* Pointer to fields */ +} xo_retain_entry_t; + +/* + * xo_retain_t holds a complete set of parsed fields as a hash table. + */ +#ifndef XO_RETAIN_SIZE +#define XO_RETAIN_SIZE 6 +#endif /* XO_RETAIN_SIZE */ +#define RETAIN_HASH_SIZE (1<<XO_RETAIN_SIZE) + +typedef struct xo_retain_s { + xo_retain_entry_t *xr_bucket[RETAIN_HASH_SIZE]; +} xo_retain_t; + +static THREAD_LOCAL(xo_retain_t) xo_retain; +static THREAD_LOCAL(unsigned) xo_retain_count; + +/* + * Simple hash function based on Thomas Wang's paper. The original is + * gone, but an archive is available on the Way Back Machine: + * + * http://web.archive.org/web/20071223173210/\ + * http://www.concentric.net/~Ttwang/tech/inthash.htm + * + * For our purposes, we can assume the low four bits are uninteresting + * since any string less that 16 bytes wouldn't be worthy of + * retaining. We toss the high bits also, since these bits are likely + * to be common among constant format strings. We then run Wang's + * algorithm, and cap the result at RETAIN_HASH_SIZE. + */ +static unsigned +xo_retain_hash (const char *fmt) +{ + volatile uintptr_t iptr = (uintptr_t) (const void *) fmt; + + /* Discard low four bits and high bits; they aren't interesting */ + uint32_t val = (uint32_t) ((iptr >> 4) & (((1 << 24) - 1))); + + val = (val ^ 61) ^ (val >> 16); + val = val + (val << 3); + val = val ^ (val >> 4); + val = val * 0x3a8f05c5; /* My large prime number */ + val = val ^ (val >> 15); + val &= RETAIN_HASH_SIZE - 1; + + return val; +} + +/* + * Walk all buckets, clearing all retained entries + */ +void +xo_retain_clear_all (void) +{ + int i; + xo_retain_entry_t *xrep, *next; + + for (i = 0; i < RETAIN_HASH_SIZE; i++) { + for (xrep = xo_retain.xr_bucket[i]; xrep; xrep = next) { + next = xrep->xre_next; + xo_free(xrep); + } + xo_retain.xr_bucket[i] = NULL; + } + xo_retain_count = 0; +} + +/* + * Walk all buckets, clearing all retained entries + */ +void +xo_retain_clear (const char *fmt) +{ + xo_retain_entry_t **xrepp; + unsigned hash = xo_retain_hash(fmt); + + for (xrepp = &xo_retain.xr_bucket[hash]; *xrepp; + xrepp = &(*xrepp)->xre_next) { + if ((*xrepp)->xre_format == fmt) { + *xrepp = (*xrepp)->xre_next; + xo_retain_count -= 1; + return; + } + } +} + +/* + * Search the hash for an entry matching 'fmt'; return it's fields. + */ +static int +xo_retain_find (const char *fmt, xo_field_info_t **valp, unsigned *nump) +{ + if (xo_retain_count == 0) + return -1; + + unsigned hash = xo_retain_hash(fmt); + xo_retain_entry_t *xrep; + + for (xrep = xo_retain.xr_bucket[hash]; xrep != NULL; + xrep = xrep->xre_next) { + if (xrep->xre_format == fmt) { + *valp = xrep->xre_fields; + *nump = xrep->xre_num_fields; + xrep->xre_hits += 1; + return 0; + } + } + + return -1; +} + +static void +xo_retain_add (const char *fmt, xo_field_info_t *fields, unsigned num_fields) +{ + unsigned hash = xo_retain_hash(fmt); + xo_retain_entry_t *xrep; + unsigned sz = sizeof(*xrep) + (num_fields + 1) * sizeof(*fields); + xo_field_info_t *xfip; + + xrep = xo_realloc(NULL, sz); + if (xrep == NULL) + return; + + xfip = (xo_field_info_t *) &xrep[1]; + memcpy(xfip, fields, num_fields * sizeof(*fields)); + + bzero(xrep, sizeof(*xrep)); + + xrep->xre_format = fmt; + xrep->xre_fields = xfip; + xrep->xre_num_fields = num_fields; + + /* Record the field info in the retain bucket */ + xrep->xre_next = xo_retain.xr_bucket[hash]; + xo_retain.xr_bucket[hash] = xrep; + xo_retain_count += 1; +} + +#endif /* !LIBXO_NO_RETAIN */ + +/* + * Generate a warning. Normally, this is a text message written to + * standard error. If the XOF_WARN_XML flag is set, then we generate + * XMLified content on standard output. + */ +static void +xo_warn_hcv (xo_handle_t *xop, int code, int check_warn, + const char *fmt, va_list vap) +{ + xop = xo_default(xop); + if (check_warn && !XOF_ISSET(xop, XOF_WARN)) + return; + + if (fmt == NULL) + return; + + int len = strlen(fmt); + int plen = xo_program ? strlen(xo_program) : 0; + char *newfmt = alloca(len + 1 + plen + 2); /* NUL, and ": " */ + + if (plen) { + memcpy(newfmt, xo_program, plen); + newfmt[plen++] = ':'; + newfmt[plen++] = ' '; + } + memcpy(newfmt + plen, fmt, len); + newfmt[len + plen] = '\0'; + + if (XOF_ISSET(xop, XOF_WARN_XML)) { + static char err_open[] = "<error>"; + static char err_close[] = "</error>"; + static char msg_open[] = "<message>"; + static char msg_close[] = "</message>"; + + xo_buffer_t *xbp = &xop->xo_data; + + xo_buf_append(xbp, err_open, sizeof(err_open) - 1); + xo_buf_append(xbp, msg_open, sizeof(msg_open) - 1); + + va_list va_local; + va_copy(va_local, vap); + + int left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + int rc = vsnprintf(xbp->xb_curp, left, newfmt, vap); + if (rc >= left) { + if (!xo_buf_has_room(xbp, rc)) { + va_end(va_local); + return; + } + + va_end(vap); /* Reset vap to the start */ + va_copy(vap, va_local); + + left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + rc = vsnprintf(xbp->xb_curp, left, fmt, vap); + } + va_end(va_local); + + rc = xo_escape_xml(xbp, rc, 1); + xbp->xb_curp += rc; + + xo_buf_append(xbp, msg_close, sizeof(msg_close) - 1); + xo_buf_append(xbp, err_close, sizeof(err_close) - 1); + + if (code >= 0) { + const char *msg = strerror(code); + if (msg) { + xo_buf_append(xbp, ": ", 2); + xo_buf_append(xbp, msg, strlen(msg)); + } + } + + xo_buf_append(xbp, "\n", 1); /* Append newline and NUL to string */ + (void) xo_write(xop); + + } else { + vfprintf(stderr, newfmt, vap); + if (code >= 0) { + const char *msg = strerror(code); + if (msg) + fprintf(stderr, ": %s", msg); + } + fprintf(stderr, "\n"); + } +} + +void +xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(xop, code, 0, fmt, vap); + va_end(vap); +} + +void +xo_warn_c (int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, code, 0, fmt, vap); + va_end(vap); +} + +void +xo_warn (const char *fmt, ...) +{ + int code = errno; + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, code, 0, fmt, vap); + va_end(vap); +} + +void +xo_warnx (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, -1, 0, fmt, vap); + va_end(vap); +} + +void +xo_err (int eval, const char *fmt, ...) +{ + int code = errno; + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, code, 0, fmt, vap); + va_end(vap); + xo_finish(); + exit(eval); +} + +void +xo_errx (int eval, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, -1, 0, fmt, vap); + va_end(vap); + xo_finish(); + exit(eval); +} + +void +xo_errc (int eval, int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(NULL, code, 0, fmt, vap); + va_end(vap); + xo_finish(); + exit(eval); +} + +/* + * Generate a warning. Normally, this is a text message written to + * standard error. If the XOF_WARN_XML flag is set, then we generate + * XMLified content on standard output. + */ +void +xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) +{ + static char msg_open[] = "<message>"; + static char msg_close[] = "</message>"; + xo_buffer_t *xbp; + int rc; + va_list va_local; + + xop = xo_default(xop); + + if (fmt == NULL || *fmt == '\0') + return; + + int need_nl = (fmt[strlen(fmt) - 1] != '\n'); + + switch (xo_style(xop)) { + case XO_STYLE_XML: + xbp = &xop->xo_data; + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_buf_indent(xop, xop->xo_indent_by); + xo_buf_append(xbp, msg_open, sizeof(msg_open) - 1); + + va_copy(va_local, vap); + + int left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + rc = vsnprintf(xbp->xb_curp, left, fmt, vap); + if (rc >= left) { + if (!xo_buf_has_room(xbp, rc)) { + va_end(va_local); + return; + } + + va_end(vap); /* Reset vap to the start */ + va_copy(vap, va_local); + + left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + rc = vsnprintf(xbp->xb_curp, left, fmt, vap); + } + va_end(va_local); + + rc = xo_escape_xml(xbp, rc, 0); + xbp->xb_curp += rc; + + if (need_nl && code > 0) { + const char *msg = strerror(code); + if (msg) { + xo_buf_append(xbp, ": ", 2); + xo_buf_append(xbp, msg, strlen(msg)); + } + } + + if (need_nl) + xo_buf_append(xbp, "\n", 1); /* Append newline and NUL to string */ + + xo_buf_append(xbp, msg_close, sizeof(msg_close) - 1); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_buf_append(xbp, "\n", 1); /* Append newline and NUL to string */ + + (void) xo_write(xop); + break; + + case XO_STYLE_HTML: + { + char buf[BUFSIZ], *bp = buf, *cp; + int bufsiz = sizeof(buf); + int rc2; + + va_copy(va_local, vap); + + rc = vsnprintf(bp, bufsiz, fmt, va_local); + if (rc > bufsiz) { + bufsiz = rc + BUFSIZ; + bp = alloca(bufsiz); + va_end(va_local); + va_copy(va_local, vap); + rc = vsnprintf(bp, bufsiz, fmt, va_local); + } + va_end(va_local); + cp = bp + rc; + + if (need_nl) { + rc2 = snprintf(cp, bufsiz - rc, "%s%s\n", + (code > 0) ? ": " : "", + (code > 0) ? strerror(code) : ""); + if (rc2 > 0) + rc += rc2; + } + + xo_buf_append_div(xop, "message", 0, NULL, 0, bp, rc, NULL, 0); + } + break; + + case XO_STYLE_JSON: + case XO_STYLE_SDPARAMS: + case XO_STYLE_ENCODER: + /* No means of representing messages */ + return; + + case XO_STYLE_TEXT: + rc = xo_printf_v(xop, fmt, vap); + /* + * XXX need to handle UTF-8 widths + */ + if (rc > 0) { + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += rc; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += rc; + } + + if (need_nl && code > 0) { + const char *msg = strerror(code); + if (msg) { + xo_printf(xop, ": %s", msg); + } + } + if (need_nl) + xo_printf(xop, "\n"); + + break; + } + + switch (xo_style(xop)) { + case XO_STYLE_HTML: + if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) { + static char div_close[] = "</div>"; + XOIF_CLEAR(xop, XOIF_DIV_OPEN); + xo_data_append(xop, div_close, sizeof(div_close) - 1); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); + } + break; + } + + (void) xo_flush_h(xop); +} + +void +xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_message_hcv(xop, code, fmt, vap); + va_end(vap); +} + +void +xo_message_c (int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_message_hcv(NULL, code, fmt, vap); + va_end(vap); +} + +void +xo_message_e (const char *fmt, ...) +{ + int code = errno; + va_list vap; + + va_start(vap, fmt); + xo_message_hcv(NULL, code, fmt, vap); + va_end(vap); +} + +void +xo_message (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_message_hcv(NULL, 0, fmt, vap); + va_end(vap); +} + +static void +xo_failure (xo_handle_t *xop, const char *fmt, ...) +{ + if (!XOF_ISSET(xop, XOF_WARN)) + return; + + va_list vap; + + va_start(vap, fmt); + xo_warn_hcv(xop, -1, 1, fmt, vap); + va_end(vap); +} + +/** + * Create a handle for use by later libxo functions. + * + * Note: normal use of libxo does not require a distinct handle, since + * the default handle (used when NULL is passed) generates text on stdout. + * + * @style Style of output desired (XO_STYLE_* value) + * @flags Set of XOF_* flags in use with this handle + */ +xo_handle_t * +xo_create (xo_style_t style, xo_xof_flags_t flags) +{ + xo_handle_t *xop = xo_realloc(NULL, sizeof(*xop)); + + if (xop) { + bzero(xop, sizeof(*xop)); + + xop->xo_style = style; + XOF_SET(xop, flags); + xo_init_handle(xop); + xop->xo_style = style; /* Reset style (see LIBXO_OPTIONS) */ + } + + return xop; +} + +/** + * Create a handle that will write to the given file. Use + * the XOF_CLOSE_FP flag to have the file closed on xo_destroy(). + * @fp FILE pointer to use + * @style Style of output desired (XO_STYLE_* value) + * @flags Set of XOF_* flags to use with this handle + */ +xo_handle_t * +xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags) +{ + xo_handle_t *xop = xo_create(style, flags); + + if (xop) { + xop->xo_opaque = fp; + xop->xo_write = xo_write_to_file; + xop->xo_close = xo_close_file; + xop->xo_flush = xo_flush_file; + } + + return xop; +} + +/** + * Set the default handler to output to a file. + * @xop libxo handle + * @fp FILE pointer to use + */ +int +xo_set_file_h (xo_handle_t *xop, FILE *fp) +{ + xop = xo_default(xop); + + if (fp == NULL) { + xo_failure(xop, "xo_set_file: NULL fp"); + return -1; + } + + xop->xo_opaque = fp; + xop->xo_write = xo_write_to_file; + xop->xo_close = xo_close_file; + xop->xo_flush = xo_flush_file; + + return 0; +} + +/** + * Set the default handler to output to a file. + * @fp FILE pointer to use + */ +int +xo_set_file (FILE *fp) +{ + return xo_set_file_h(NULL, fp); +} + +/** + * Release any resources held by the handle. + * @xop XO handle to alter (or NULL for default handle) + */ +void +xo_destroy (xo_handle_t *xop_arg) +{ + xo_handle_t *xop = xo_default(xop_arg); + + xo_flush_h(xop); + + if (xop->xo_close && XOF_ISSET(xop, XOF_CLOSE_FP)) + xop->xo_close(xop->xo_opaque); + + xo_free(xop->xo_stack); + xo_buf_cleanup(&xop->xo_data); + xo_buf_cleanup(&xop->xo_fmt); + xo_buf_cleanup(&xop->xo_predicate); + xo_buf_cleanup(&xop->xo_attrs); + xo_buf_cleanup(&xop->xo_color_buf); + + if (xop->xo_version) + xo_free(xop->xo_version); + + if (xop_arg == NULL) { + bzero(&xo_default_handle, sizeof(xo_default_handle)); + xo_default_inited = 0; + } else + xo_free(xop); +} + +/** + * Record a new output style to use for the given handle (or default if + * handle is NULL). This output style will be used for any future output. + * + * @xop XO handle to alter (or NULL for default handle) + * @style new output style (XO_STYLE_*) + */ +void +xo_set_style (xo_handle_t *xop, xo_style_t style) +{ + xop = xo_default(xop); + xop->xo_style = style; +} + +xo_style_t +xo_get_style (xo_handle_t *xop) +{ + xop = xo_default(xop); + return xo_style(xop); +} + +static int +xo_name_to_style (const char *name) +{ + if (strcmp(name, "xml") == 0) + return XO_STYLE_XML; + else if (strcmp(name, "json") == 0) + return XO_STYLE_JSON; + else if (strcmp(name, "encoder") == 0) + return XO_STYLE_ENCODER; + else if (strcmp(name, "text") == 0) + return XO_STYLE_TEXT; + else if (strcmp(name, "html") == 0) + return XO_STYLE_HTML; + else if (strcmp(name, "sdparams") == 0) + return XO_STYLE_SDPARAMS; + + return -1; +} + +/* + * Indicate if the style is an "encoding" one as opposed to a "display" one. + */ +static int +xo_style_is_encoding (xo_handle_t *xop) +{ + if (xo_style(xop) == XO_STYLE_JSON + || xo_style(xop) == XO_STYLE_XML + || xo_style(xop) == XO_STYLE_SDPARAMS + || xo_style(xop) == XO_STYLE_ENCODER) + return 1; + return 0; +} + +/* Simple name-value mapping */ +typedef struct xo_mapping_s { + xo_xff_flags_t xm_value; + const char *xm_name; +} xo_mapping_t; + +static xo_xff_flags_t +xo_name_lookup (xo_mapping_t *map, const char *value, int len) +{ + if (len == 0) + return 0; + + if (len < 0) + len = strlen(value); + + while (isspace((int) *value)) { + value += 1; + len -= 1; + } + + while (isspace((int) value[len])) + len -= 1; + + if (*value == '\0') + return 0; + + for ( ; map->xm_name; map++) + if (strncmp(map->xm_name, value, len) == 0) + return map->xm_value; + + return 0; +} + +#ifdef NOT_NEEDED_YET +static const char * +xo_value_lookup (xo_mapping_t *map, xo_xff_flags_t value) +{ + if (value == 0) + return NULL; + + for ( ; map->xm_name; map++) + if (map->xm_value == value) + return map->xm_name; + + return NULL; +} +#endif /* NOT_NEEDED_YET */ + +static xo_mapping_t xo_xof_names[] = { + { XOF_COLOR_ALLOWED, "color" }, + { XOF_COLUMNS, "columns" }, + { XOF_DTRT, "dtrt" }, + { XOF_FLUSH, "flush" }, + { XOF_IGNORE_CLOSE, "ignore-close" }, + { XOF_INFO, "info" }, + { XOF_KEYS, "keys" }, + { XOF_LOG_GETTEXT, "log-gettext" }, + { XOF_LOG_SYSLOG, "log-syslog" }, + { XOF_NO_HUMANIZE, "no-humanize" }, + { XOF_NO_LOCALE, "no-locale" }, + { XOF_RETAIN_NONE, "no-retain" }, + { XOF_NO_TOP, "no-top" }, + { XOF_NOT_FIRST, "not-first" }, + { XOF_PRETTY, "pretty" }, + { XOF_RETAIN_ALL, "retain" }, + { XOF_UNDERSCORES, "underscores" }, + { XOF_UNITS, "units" }, + { XOF_WARN, "warn" }, + { XOF_WARN_XML, "warn-xml" }, + { XOF_XPATH, "xpath" }, + { 0, NULL } +}; + +/* + * Convert string name to XOF_* flag value. + * Not all are useful. Or safe. Or sane. + */ +static unsigned +xo_name_to_flag (const char *name) +{ + return (unsigned) xo_name_lookup(xo_xof_names, name, -1); +} + +int +xo_set_style_name (xo_handle_t *xop, const char *name) +{ + if (name == NULL) + return -1; + + int style = xo_name_to_style(name); + if (style < 0) + return -1; + + xo_set_style(xop, style); + return 0; +} + +/* + * Set the options for a handle using a string of options + * passed in. The input is a comma-separated set of names + * and optional values: "xml,pretty,indent=4" + */ +int +xo_set_options (xo_handle_t *xop, const char *input) +{ + char *cp, *ep, *vp, *np, *bp; + int style = -1, new_style, len, rc = 0; + xo_xof_flags_t new_flag; + + if (input == NULL) + return 0; + + xop = xo_default(xop); + +#ifdef LIBXO_COLOR_ON_BY_DEFAULT + /* If the installer used --enable-color-on-by-default, then we allow it */ + XOF_SET(xop, XOF_COLOR_ALLOWED); +#endif /* LIBXO_COLOR_ON_BY_DEFAULT */ + + /* + * We support a simpler, old-school style of giving option + * also, using a single character for each option. It's + * ideal for lazy people, such as myself. + */ + if (*input == ':') { + int sz; + + for (input++ ; *input; input++) { + switch (*input) { + case 'c': + XOF_SET(xop, XOF_COLOR_ALLOWED); + break; + + case 'f': + XOF_SET(xop, XOF_FLUSH); + break; + + case 'F': + XOF_SET(xop, XOF_FLUSH_LINE); + break; + + case 'g': + XOF_SET(xop, XOF_LOG_GETTEXT); + break; + + case 'H': + xop->xo_style = XO_STYLE_HTML; + break; + + case 'I': + XOF_SET(xop, XOF_INFO); + break; + + case 'i': + sz = strspn(input + 1, "0123456789"); + if (sz > 0) { + xop->xo_indent_by = atoi(input + 1); + input += sz - 1; /* Skip value */ + } + break; + + case 'J': + xop->xo_style = XO_STYLE_JSON; + break; + + case 'k': + XOF_SET(xop, XOF_KEYS); + break; + + case 'n': + XOF_SET(xop, XOF_NO_HUMANIZE); + break; + + case 'P': + XOF_SET(xop, XOF_PRETTY); + break; + + case 'T': + xop->xo_style = XO_STYLE_TEXT; + break; + + case 'U': + XOF_SET(xop, XOF_UNITS); + break; + + case 'u': + XOF_SET(xop, XOF_UNDERSCORES); + break; + + case 'W': + XOF_SET(xop, XOF_WARN); + break; + + case 'X': + xop->xo_style = XO_STYLE_XML; + break; + + case 'x': + XOF_SET(xop, XOF_XPATH); + break; + } + } + return 0; + } + + len = strlen(input) + 1; + bp = alloca(len); + memcpy(bp, input, len); + + for (cp = bp, ep = cp + len - 1; cp && cp < ep; cp = np) { + np = strchr(cp, ','); + if (np) + *np++ = '\0'; + + vp = strchr(cp, '='); + if (vp) + *vp++ = '\0'; + + if (strcmp("colors", cp) == 0) { + /* XXX Look for colors=red-blue+green-yellow */ + continue; + } + + /* + * For options, we don't allow "encoder" since we want to + * handle it explicitly below as "encoder=xxx". + */ + new_style = xo_name_to_style(cp); + if (new_style >= 0 && new_style != XO_STYLE_ENCODER) { + if (style >= 0) + xo_warnx("ignoring multiple styles: '%s'", cp); + else + style = new_style; + } else { + new_flag = xo_name_to_flag(cp); + if (new_flag != 0) + XOF_SET(xop, new_flag); + else { + if (strcmp(cp, "no-color") == 0) { + XOF_CLEAR(xop, XOF_COLOR_ALLOWED); + } else if (strcmp(cp, "indent") == 0) { + if (vp) + xop->xo_indent_by = atoi(vp); + else + xo_failure(xop, "missing value for indent option"); + } else if (strcmp(cp, "encoder") == 0) { + if (vp == NULL) + xo_failure(xop, "missing value for encoder option"); + else { + if (xo_encoder_init(xop, vp)) { + xo_failure(xop, "encoder not found: %s", vp); + rc = -1; + } + } + + } else { + xo_warnx("unknown libxo option value: '%s'", cp); + rc = -1; + } + } + } + } + + if (style > 0) + xop->xo_style= style; + + return rc; +} + +/** + * Set one or more flags for a given handle (or default if handle is NULL). + * These flags will affect future output. + * + * @xop XO handle to alter (or NULL for default handle) + * @flags Flags to be set (XOF_*) + */ +void +xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags) +{ + xop = xo_default(xop); + + XOF_SET(xop, flags); +} + +xo_xof_flags_t +xo_get_flags (xo_handle_t *xop) +{ + xop = xo_default(xop); + + return xop->xo_flags; +} + +/* + * strndup with a twist: len < 0 means strlen + */ +static char * +xo_strndup (const char *str, int len) +{ + if (len < 0) + len = strlen(str); + + char *cp = xo_realloc(NULL, len + 1); + if (cp) { + memcpy(cp, str, len); + cp[len] = '\0'; + } + + return cp; +} + +/** + * Record a leading prefix for the XPath we generate. This allows the + * generated data to be placed within an XML hierarchy but still have + * accurate XPath expressions. + * + * @xop XO handle to alter (or NULL for default handle) + * @path The XPath expression + */ +void +xo_set_leading_xpath (xo_handle_t *xop, const char *path) +{ + xop = xo_default(xop); + + if (xop->xo_leading_xpath) { + xo_free(xop->xo_leading_xpath); + xop->xo_leading_xpath = NULL; + } + + if (path == NULL) + return; + + xop->xo_leading_xpath = xo_strndup(path, -1); +} + +/** + * Record the info data for a set of tags + * + * @xop XO handle to alter (or NULL for default handle) + * @info Info data (xo_info_t) to be recorded (or NULL) (MUST BE SORTED) + * @count Number of entries in info (or -1 to count them ourselves) + */ +void +xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count) +{ + xop = xo_default(xop); + + if (count < 0 && infop) { + xo_info_t *xip; + + for (xip = infop, count = 0; xip->xi_name; xip++, count++) + continue; + } + + xop->xo_info = infop; + xop->xo_info_count = count; +} + +/** + * Set the formatter callback for a handle. The callback should + * return a newly formatting contents of a formatting instruction, + * meaning the bits inside the braces. + */ +void +xo_set_formatter (xo_handle_t *xop, xo_formatter_t func, + xo_checkpointer_t cfunc) +{ + xop = xo_default(xop); + + xop->xo_formatter = func; + xop->xo_checkpointer = cfunc; +} + +/** + * Clear one or more flags for a given handle (or default if handle is NULL). + * These flags will affect future output. + * + * @xop XO handle to alter (or NULL for default handle) + * @flags Flags to be cleared (XOF_*) + */ +void +xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags) +{ + xop = xo_default(xop); + + XOF_CLEAR(xop, flags); +} + +static const char * +xo_state_name (xo_state_t state) +{ + static const char *names[] = { + "init", + "open_container", + "close_container", + "open_list", + "close_list", + "open_instance", + "close_instance", + "open_leaf_list", + "close_leaf_list", + "discarding", + "marker", + "emit", + "emit_leaf_list", + "finish", + NULL + }; + + if (state < (sizeof(names) / sizeof(names[0]))) + return names[state]; + + return "unknown"; +} + +static void +xo_line_ensure_open (xo_handle_t *xop, xo_xff_flags_t flags UNUSED) +{ + static char div_open[] = "<div class=\"line\">"; + static char div_open_blank[] = "<div class=\"blank-line\">"; + + if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) + return; + + if (xo_style(xop) != XO_STYLE_HTML) + return; + + XOIF_SET(xop, XOIF_DIV_OPEN); + if (flags & XFF_BLANK_LINE) + xo_data_append(xop, div_open_blank, sizeof(div_open_blank) - 1); + else + xo_data_append(xop, div_open, sizeof(div_open) - 1); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); +} + +static void +xo_line_close (xo_handle_t *xop) +{ + static char div_close[] = "</div>"; + + switch (xo_style(xop)) { + case XO_STYLE_HTML: + if (!XOIF_ISSET(xop, XOIF_DIV_OPEN)) + xo_line_ensure_open(xop, 0); + + XOIF_CLEAR(xop, XOIF_DIV_OPEN); + xo_data_append(xop, div_close, sizeof(div_close) - 1); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); + break; + + case XO_STYLE_TEXT: + xo_data_append(xop, "\n", 1); + break; + } +} + +static int +xo_info_compare (const void *key, const void *data) +{ + const char *name = key; + const xo_info_t *xip = data; + + return strcmp(name, xip->xi_name); +} + + +static xo_info_t * +xo_info_find (xo_handle_t *xop, const char *name, int nlen) +{ + xo_info_t *xip; + char *cp = alloca(nlen + 1); /* Need local copy for NUL termination */ + + memcpy(cp, name, nlen); + cp[nlen] = '\0'; + + xip = bsearch(cp, xop->xo_info, xop->xo_info_count, + sizeof(xop->xo_info[0]), xo_info_compare); + return xip; +} + +#define CONVERT(_have, _need) (((_have) << 8) | (_need)) + +/* + * Check to see that the conversion is safe and sane. + */ +static int +xo_check_conversion (xo_handle_t *xop, int have_enc, int need_enc) +{ + switch (CONVERT(have_enc, need_enc)) { + case CONVERT(XF_ENC_UTF8, XF_ENC_UTF8): + case CONVERT(XF_ENC_UTF8, XF_ENC_LOCALE): + case CONVERT(XF_ENC_WIDE, XF_ENC_UTF8): + case CONVERT(XF_ENC_WIDE, XF_ENC_LOCALE): + case CONVERT(XF_ENC_LOCALE, XF_ENC_LOCALE): + case CONVERT(XF_ENC_LOCALE, XF_ENC_UTF8): + return 0; + + default: + xo_failure(xop, "invalid conversion (%c:%c)", have_enc, need_enc); + return 1; + } +} + +static int +xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp, + xo_xff_flags_t flags, + const wchar_t *wcp, const char *cp, int len, int max, + int need_enc, int have_enc) +{ + int cols = 0; + wchar_t wc = 0; + int ilen, olen, width; + int attr = (flags & XFF_ATTR); + const char *sp; + + if (len > 0 && !xo_buf_has_room(xbp, len)) + return 0; + + for (;;) { + if (len == 0) + break; + + if (cp) { + if (*cp == '\0') + break; + if ((flags & XFF_UNESCAPE) && (*cp == '\\' || *cp == '%')) { + cp += 1; + len -= 1; + } + } + + if (wcp && *wcp == L'\0') + break; + + ilen = 0; + + switch (have_enc) { + case XF_ENC_WIDE: /* Wide character */ + wc = *wcp++; + ilen = 1; + break; + + case XF_ENC_UTF8: /* UTF-8 */ + ilen = xo_utf8_to_wc_len(cp); + if (ilen < 0) { + xo_failure(xop, "invalid UTF-8 character: %02hhx", *cp); + return -1; /* Can't continue; we can't find the end */ + } + + if (len > 0 && len < ilen) { + len = 0; /* Break out of the loop */ + continue; + } + + wc = xo_utf8_char(cp, ilen); + if (wc == (wchar_t) -1) { + xo_failure(xop, "invalid UTF-8 character: %02hhx/%d", + *cp, ilen); + return -1; /* Can't continue; we can't find the end */ + } + cp += ilen; + break; + + case XF_ENC_LOCALE: /* Native locale */ + ilen = (len > 0) ? len : MB_LEN_MAX; + ilen = mbrtowc(&wc, cp, ilen, &xop->xo_mbstate); + if (ilen < 0) { /* Invalid data; skip */ + xo_failure(xop, "invalid mbs char: %02hhx", *cp); + wc = L'?'; + ilen = 1; + } + + if (ilen == 0) { /* Hit a wide NUL character */ + len = 0; + continue; + } + + cp += ilen; + break; + } + + /* Reduce len, but not below zero */ + if (len > 0) { + len -= ilen; + if (len < 0) + len = 0; + } + + /* + * Find the width-in-columns of this character, which must be done + * in wide characters, since we lack a mbswidth() function. If + * it doesn't fit + */ + width = xo_wcwidth(wc); + if (width < 0) + width = iswcntrl(wc) ? 0 : 1; + + if (xo_style(xop) == XO_STYLE_TEXT || xo_style(xop) == XO_STYLE_HTML) { + if (max > 0 && cols + width > max) + break; + } + + switch (need_enc) { + case XF_ENC_UTF8: + + /* Output in UTF-8 needs to be escaped, based on the style */ + switch (xo_style(xop)) { + case XO_STYLE_XML: + case XO_STYLE_HTML: + if (wc == '<') + sp = xo_xml_lt; + else if (wc == '>') + sp = xo_xml_gt; + else if (wc == '&') + sp = xo_xml_amp; + else if (attr && wc == '"') + sp = xo_xml_quot; + else + break; + + int slen = strlen(sp); + if (!xo_buf_has_room(xbp, slen - 1)) + return -1; + + memcpy(xbp->xb_curp, sp, slen); + xbp->xb_curp += slen; + goto done_with_encoding; /* Need multi-level 'break' */ + + case XO_STYLE_JSON: + if (wc != '\\' && wc != '"' && wc != '\n' && wc != '\r') + break; + + if (!xo_buf_has_room(xbp, 2)) + return -1; + + *xbp->xb_curp++ = '\\'; + if (wc == '\n') + wc = 'n'; + else if (wc == '\r') + wc = 'r'; + else wc = wc & 0x7f; + + *xbp->xb_curp++ = wc; + goto done_with_encoding; + + case XO_STYLE_SDPARAMS: + if (wc != '\\' && wc != '"' && wc != ']') + break; + + if (!xo_buf_has_room(xbp, 2)) + return -1; + + *xbp->xb_curp++ = '\\'; + wc = wc & 0x7f; + *xbp->xb_curp++ = wc; + goto done_with_encoding; + } + + olen = xo_utf8_emit_len(wc); + if (olen < 0) { + xo_failure(xop, "ignoring bad length"); + continue; + } + + if (!xo_buf_has_room(xbp, olen)) + return -1; + + xo_utf8_emit_char(xbp->xb_curp, olen, wc); + xbp->xb_curp += olen; + break; + + case XF_ENC_LOCALE: + if (!xo_buf_has_room(xbp, MB_LEN_MAX + 1)) + return -1; + + olen = wcrtomb(xbp->xb_curp, wc, &xop->xo_mbstate); + if (olen <= 0) { + xo_failure(xop, "could not convert wide char: %lx", + (unsigned long) wc); + width = 1; + *xbp->xb_curp++ = '?'; + } else + xbp->xb_curp += olen; + break; + } + + done_with_encoding: + cols += width; + } + + return cols; +} + +static int +xo_needed_encoding (xo_handle_t *xop) +{ + if (XOF_ISSET(xop, XOF_UTF8)) /* Check the override flag */ + return XF_ENC_UTF8; + + if (xo_style(xop) == XO_STYLE_TEXT) /* Text means locale */ + return XF_ENC_LOCALE; + + return XF_ENC_UTF8; /* Otherwise, we love UTF-8 */ +} + +static int +xo_format_string (xo_handle_t *xop, xo_buffer_t *xbp, xo_xff_flags_t flags, + xo_format_t *xfp) +{ + static char null[] = "(null)"; + static char null_no_quotes[] = "null"; + + char *cp = NULL; + wchar_t *wcp = NULL; + int len, cols = 0, rc = 0; + int off = xbp->xb_curp - xbp->xb_bufp, off2; + int need_enc = xo_needed_encoding(xop); + + if (xo_check_conversion(xop, xfp->xf_enc, need_enc)) + return 0; + + len = xfp->xf_width[XF_WIDTH_SIZE]; + + if (xfp->xf_fc == 'm') { + cp = strerror(xop->xo_errno); + if (len < 0) + len = cp ? strlen(cp) : 0; + goto normal_string; + + } else if (xfp->xf_enc == XF_ENC_WIDE) { + wcp = va_arg(xop->xo_vap, wchar_t *); + if (xfp->xf_skip) + return 0; + + /* + * Dont' deref NULL; use the traditional "(null)" instead + * of the more accurate "who's been a naughty boy, then?". + */ + if (wcp == NULL) { + cp = null; + len = sizeof(null) - 1; + } + + } else { + cp = va_arg(xop->xo_vap, char *); /* UTF-8 or native */ + + normal_string: + if (xfp->xf_skip) + return 0; + + /* Echo "Dont' deref NULL" logic */ + if (cp == NULL) { + if ((flags & XFF_NOQUOTE) && xo_style_is_encoding(xop)) { + cp = null_no_quotes; + len = sizeof(null_no_quotes) - 1; + } else { + cp = null; + len = sizeof(null) - 1; + } + } + + /* + * Optimize the most common case, which is "%s". We just + * need to copy the complete string to the output buffer. + */ + if (xfp->xf_enc == need_enc + && xfp->xf_width[XF_WIDTH_MIN] < 0 + && xfp->xf_width[XF_WIDTH_SIZE] < 0 + && xfp->xf_width[XF_WIDTH_MAX] < 0 + && !(XOIF_ISSET(xop, XOIF_ANCHOR) + || XOF_ISSET(xop, XOF_COLUMNS))) { + len = strlen(cp); + xo_buf_escape(xop, xbp, cp, len, flags); + + /* + * Our caller expects xb_curp left untouched, so we have + * to reset it and return the number of bytes written to + * the buffer. + */ + off2 = xbp->xb_curp - xbp->xb_bufp; + rc = off2 - off; + xbp->xb_curp = xbp->xb_bufp + off; + + return rc; + } + } + + cols = xo_format_string_direct(xop, xbp, flags, wcp, cp, len, + xfp->xf_width[XF_WIDTH_MAX], + need_enc, xfp->xf_enc); + if (cols < 0) + goto bail; + + /* + * xo_buf_append* will move xb_curp, so we save/restore it. + */ + off2 = xbp->xb_curp - xbp->xb_bufp; + rc = off2 - off; + xbp->xb_curp = xbp->xb_bufp + off; + + if (cols < xfp->xf_width[XF_WIDTH_MIN]) { + /* + * Find the number of columns needed to display the string. + * If we have the original wide string, we just call wcswidth, + * but if we did the work ourselves, then we need to do it. + */ + int delta = xfp->xf_width[XF_WIDTH_MIN] - cols; + if (!xo_buf_has_room(xbp, xfp->xf_width[XF_WIDTH_MIN])) + goto bail; + + /* + * If seen_minus, then pad on the right; otherwise move it so + * we can pad on the left. + */ + if (xfp->xf_seen_minus) { + cp = xbp->xb_curp + rc; + } else { + cp = xbp->xb_curp; + memmove(xbp->xb_curp + delta, xbp->xb_curp, rc); + } + + /* Set the padding */ + memset(cp, (xfp->xf_leading_zero > 0) ? '0' : ' ', delta); + rc += delta; + cols += delta; + } + + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += cols; + + return rc; + + bail: + xbp->xb_curp = xbp->xb_bufp + off; + return 0; +} + +/* + * Look backwards in a buffer to find a numeric value + */ +static int +xo_buf_find_last_number (xo_buffer_t *xbp, int start_offset) +{ + int rc = 0; /* Fail with zero */ + int digit = 1; + char *sp = xbp->xb_bufp; + char *cp = sp + start_offset; + + while (--cp >= sp) + if (isdigit((int) *cp)) + break; + + for ( ; cp >= sp; cp--) { + if (!isdigit((int) *cp)) + break; + rc += (*cp - '0') * digit; + digit *= 10; + } + + return rc; +} + +static int +xo_count_utf8_cols (const char *str, int len) +{ + int tlen; + wchar_t wc; + int cols = 0; + const char *ep = str + len; + + while (str < ep) { + tlen = xo_utf8_to_wc_len(str); + if (tlen < 0) /* Broken input is very bad */ + return cols; + + wc = xo_utf8_char(str, tlen); + if (wc == (wchar_t) -1) + return cols; + + /* We only print printable characters */ + if (iswprint((wint_t) wc)) { + /* + * Find the width-in-columns of this character, which must be done + * in wide characters, since we lack a mbswidth() function. + */ + int width = xo_wcwidth(wc); + if (width < 0) + width = iswcntrl(wc) ? 0 : 1; + + cols += width; + } + + str += tlen; + } + + return cols; +} + +#ifdef HAVE_GETTEXT +static inline const char * +xo_dgettext (xo_handle_t *xop, const char *str) +{ + const char *domainname = xop->xo_gt_domain; + const char *res; + + res = dgettext(domainname, str); + + if (XOF_ISSET(xop, XOF_LOG_GETTEXT)) + fprintf(stderr, "xo: gettext: %s%s%smsgid \"%s\" returns \"%s\"\n", + domainname ? "domain \"" : "", xo_printable(domainname), + domainname ? "\", " : "", xo_printable(str), xo_printable(res)); + + return res; +} + +static inline const char * +xo_dngettext (xo_handle_t *xop, const char *sing, const char *plural, + unsigned long int n) +{ + const char *domainname = xop->xo_gt_domain; + const char *res; + + res = dngettext(domainname, sing, plural, n); + if (XOF_ISSET(xop, XOF_LOG_GETTEXT)) + fprintf(stderr, "xo: gettext: %s%s%s" + "msgid \"%s\", msgid_plural \"%s\" (%lu) returns \"%s\"\n", + domainname ? "domain \"" : "", + xo_printable(domainname), domainname ? "\", " : "", + xo_printable(sing), + xo_printable(plural), n, xo_printable(res)); + + return res; +} +#else /* HAVE_GETTEXT */ +static inline const char * +xo_dgettext (xo_handle_t *xop UNUSED, const char *str) +{ + return str; +} + +static inline const char * +xo_dngettext (xo_handle_t *xop UNUSED, const char *singular, + const char *plural, unsigned long int n) +{ + return (n == 1) ? singular : plural; +} +#endif /* HAVE_GETTEXT */ + +/* + * This is really _re_formatting, since the normal format code has + * generated a beautiful string into xo_data, starting at + * start_offset. We need to see if it's plural, which means + * comma-separated options, or singular. Then we make the appropriate + * call to d[n]gettext() to get the locale-based version. Note that + * both input and output of gettext() this should be UTF-8. + */ +static int +xo_format_gettext (xo_handle_t *xop, xo_xff_flags_t flags, + int start_offset, int cols, int need_enc) +{ + xo_buffer_t *xbp = &xop->xo_data; + + if (!xo_buf_has_room(xbp, 1)) + return cols; + + xbp->xb_curp[0] = '\0'; /* NUL-terminate the input string */ + + char *cp = xbp->xb_bufp + start_offset; + int len = xbp->xb_curp - cp; + const char *newstr = NULL; + + /* + * The plural flag asks us to look backwards at the last numeric + * value rendered and disect the string into two pieces. + */ + if (flags & XFF_GT_PLURAL) { + int n = xo_buf_find_last_number(xbp, start_offset); + char *two = memchr(cp, (int) ',', len); + if (two == NULL) { + xo_failure(xop, "no comma in plural gettext field: '%s'", cp); + return cols; + } + + if (two == cp) { + xo_failure(xop, "nothing before comma in plural gettext " + "field: '%s'", cp); + return cols; + } + + if (two == xbp->xb_curp) { + xo_failure(xop, "nothing after comma in plural gettext " + "field: '%s'", cp); + return cols; + } + + *two++ = '\0'; + if (flags & XFF_GT_FIELD) { + newstr = xo_dngettext(xop, cp, two, n); + } else { + /* Don't do a gettext() look up, just get the plural form */ + newstr = (n == 1) ? cp : two; + } + + /* + * If we returned the first string, optimize a bit by + * backing up over comma + */ + if (newstr == cp) { + xbp->xb_curp = two - 1; /* One for comma */ + /* + * If the caller wanted UTF8, we're done; nothing changed, + * but we need to count the columns used. + */ + if (need_enc == XF_ENC_UTF8) + return xo_count_utf8_cols(cp, xbp->xb_curp - cp); + } + + } else { + /* The simple case (singular) */ + newstr = xo_dgettext(xop, cp); + + if (newstr == cp) { + /* If the caller wanted UTF8, we're done; nothing changed */ + if (need_enc == XF_ENC_UTF8) + return cols; + } + } + + /* + * Since the new string string might be in gettext's buffer or + * in the buffer (as the plural form), we make a copy. + */ + int nlen = strlen(newstr); + char *newcopy = alloca(nlen + 1); + memcpy(newcopy, newstr, nlen + 1); + + xbp->xb_curp = xbp->xb_bufp + start_offset; /* Reset the buffer */ + return xo_format_string_direct(xop, xbp, flags, NULL, newcopy, nlen, 0, + need_enc, XF_ENC_UTF8); +} + +static void +xo_data_append_content (xo_handle_t *xop, const char *str, int len, + xo_xff_flags_t flags) +{ + int cols; + int need_enc = xo_needed_encoding(xop); + int start_offset = xo_buf_offset(&xop->xo_data); + + cols = xo_format_string_direct(xop, &xop->xo_data, XFF_UNESCAPE | flags, + NULL, str, len, -1, + need_enc, XF_ENC_UTF8); + if (flags & XFF_GT_FLAGS) + cols = xo_format_gettext(xop, flags, start_offset, cols, need_enc); + + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += cols; +} + +static void +xo_bump_width (xo_format_t *xfp, int digit) +{ + int *ip = &xfp->xf_width[xfp->xf_dots]; + + *ip = ((*ip > 0) ? *ip : 0) * 10 + digit; +} + +static int +xo_trim_ws (xo_buffer_t *xbp, int len) +{ + char *cp, *sp, *ep; + int delta; + + /* First trim leading space */ + for (cp = sp = xbp->xb_curp, ep = cp + len; cp < ep; cp++) { + if (*cp != ' ') + break; + } + + delta = cp - sp; + if (delta) { + len -= delta; + memmove(sp, cp, len); + } + + /* Then trim off the end */ + for (cp = xbp->xb_curp, sp = ep = cp + len; cp < ep; ep--) { + if (ep[-1] != ' ') + break; + } + + delta = sp - ep; + if (delta) { + len -= delta; + cp[len] = '\0'; + } + + return len; +} + +/* + * Interface to format a single field. The arguments are in xo_vap, + * and the format is in 'fmt'. If 'xbp' is null, we use xop->xo_data; + * this is the most common case. + */ +static int +xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp, + const char *fmt, int flen, xo_xff_flags_t flags) +{ + xo_format_t xf; + const char *cp, *ep, *sp, *xp = NULL; + int rc, cols; + int style = (flags & XFF_XML) ? XO_STYLE_XML : xo_style(xop); + unsigned make_output = !(flags & XFF_NO_OUTPUT); + int need_enc = xo_needed_encoding(xop); + int real_need_enc = need_enc; + int old_cols = xop->xo_columns; + + /* The gettext interface is UTF-8, so we'll need that for now */ + if (flags & XFF_GT_FIELD) + need_enc = XF_ENC_UTF8; + + if (xbp == NULL) + xbp = &xop->xo_data; + + unsigned start_offset = xo_buf_offset(xbp); + + for (cp = fmt, ep = fmt + flen; cp < ep; cp++) { + /* + * Since we're starting a new field, save the starting offset. + * We'll need this later for field-related operations. + */ + + if (*cp != '%') { + add_one: + if (xp == NULL) + xp = cp; + + if (*cp == '\\' && cp[1] != '\0') + cp += 1; + continue; + + } if (cp + 1 < ep && cp[1] == '%') { + cp += 1; + goto add_one; + } + + if (xp) { + if (make_output) { + cols = xo_format_string_direct(xop, xbp, flags | XFF_UNESCAPE, + NULL, xp, cp - xp, -1, + need_enc, XF_ENC_UTF8); + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += cols; + } + + xp = NULL; + } + + bzero(&xf, sizeof(xf)); + xf.xf_leading_zero = -1; + xf.xf_width[0] = xf.xf_width[1] = xf.xf_width[2] = -1; + + /* + * "%@" starts an XO-specific set of flags: + * @X@ - XML-only field; ignored if style isn't XML + */ + if (cp[1] == '@') { + for (cp += 2; cp < ep; cp++) { + if (*cp == '@') { + break; + } + if (*cp == '*') { + /* + * '*' means there's a "%*.*s" value in vap that + * we want to ignore + */ + if (!XOF_ISSET(xop, XOF_NO_VA_ARG)) + va_arg(xop->xo_vap, int); + } + } + } + + /* Hidden fields are only visible to JSON and XML */ + if (XOF_ISSET(xop, XFF_ENCODE_ONLY)) { + if (style != XO_STYLE_XML + && !xo_style_is_encoding(xop)) + xf.xf_skip = 1; + } else if (XOF_ISSET(xop, XFF_DISPLAY_ONLY)) { + if (style != XO_STYLE_TEXT + && xo_style(xop) != XO_STYLE_HTML) + xf.xf_skip = 1; + } + + if (!make_output) + xf.xf_skip = 1; + + /* + * Looking at one piece of a format; find the end and + * call snprintf. Then advance xo_vap on our own. + * + * Note that 'n', 'v', and '$' are not supported. + */ + sp = cp; /* Save start pointer */ + for (cp += 1; cp < ep; cp++) { + if (*cp == 'l') + xf.xf_lflag += 1; + else if (*cp == 'h') + xf.xf_hflag += 1; + else if (*cp == 'j') + xf.xf_jflag += 1; + else if (*cp == 't') + xf.xf_tflag += 1; + else if (*cp == 'z') + xf.xf_zflag += 1; + else if (*cp == 'q') + xf.xf_qflag += 1; + else if (*cp == '.') { + if (++xf.xf_dots >= XF_WIDTH_NUM) { + xo_failure(xop, "Too many dots in format: '%s'", fmt); + return -1; + } + } else if (*cp == '-') + xf.xf_seen_minus = 1; + else if (isdigit((int) *cp)) { + if (xf.xf_leading_zero < 0) + xf.xf_leading_zero = (*cp == '0'); + xo_bump_width(&xf, *cp - '0'); + } else if (*cp == '*') { + xf.xf_stars += 1; + xf.xf_star[xf.xf_dots] = 1; + } else if (strchr("diouxXDOUeEfFgGaAcCsSpm", *cp) != NULL) + break; + else if (*cp == 'n' || *cp == 'v') { + xo_failure(xop, "unsupported format: '%s'", fmt); + return -1; + } + } + + if (cp == ep) + xo_failure(xop, "field format missing format character: %s", + fmt); + + xf.xf_fc = *cp; + + if (!XOF_ISSET(xop, XOF_NO_VA_ARG)) { + if (*cp == 's' || *cp == 'S') { + /* Handle "%*.*.*s" */ + int s; + for (s = 0; s < XF_WIDTH_NUM; s++) { + if (xf.xf_star[s]) { + xf.xf_width[s] = va_arg(xop->xo_vap, int); + + /* Normalize a negative width value */ + if (xf.xf_width[s] < 0) { + if (s == 0) { + xf.xf_width[0] = -xf.xf_width[0]; + xf.xf_seen_minus = 1; + } else + xf.xf_width[s] = -1; /* Ignore negative values */ + } + } + } + } + } + + /* If no max is given, it defaults to size */ + if (xf.xf_width[XF_WIDTH_MAX] < 0 && xf.xf_width[XF_WIDTH_SIZE] >= 0) + xf.xf_width[XF_WIDTH_MAX] = xf.xf_width[XF_WIDTH_SIZE]; + + if (xf.xf_fc == 'D' || xf.xf_fc == 'O' || xf.xf_fc == 'U') + xf.xf_lflag = 1; + + if (!xf.xf_skip) { + xo_buffer_t *fbp = &xop->xo_fmt; + int len = cp - sp + 1; + if (!xo_buf_has_room(fbp, len + 1)) + return -1; + + char *newfmt = fbp->xb_curp; + memcpy(newfmt, sp, len); + newfmt[0] = '%'; /* If we skipped over a "%@...@s" format */ + newfmt[len] = '\0'; + + /* + * Bad news: our strings are UTF-8, but the stock printf + * functions won't handle field widths for wide characters + * correctly. So we have to handle this ourselves. + */ + if (xop->xo_formatter == NULL + && (xf.xf_fc == 's' || xf.xf_fc == 'S' + || xf.xf_fc == 'm')) { + + xf.xf_enc = (xf.xf_fc == 'm') ? XF_ENC_UTF8 + : (xf.xf_lflag || (xf.xf_fc == 'S')) ? XF_ENC_WIDE + : xf.xf_hflag ? XF_ENC_LOCALE : XF_ENC_UTF8; + + rc = xo_format_string(xop, xbp, flags, &xf); + + if ((flags & XFF_TRIM_WS) && xo_style_is_encoding(xop)) + rc = xo_trim_ws(xbp, rc); + + } else { + int columns = rc = xo_vsnprintf(xop, xbp, newfmt, xop->xo_vap); + + /* + * For XML and HTML, we need "&<>" processing; for JSON, + * it's quotes. Text gets nothing. + */ + switch (style) { + case XO_STYLE_XML: + if (flags & XFF_TRIM_WS) + columns = rc = xo_trim_ws(xbp, rc); + /* FALLTHRU */ + case XO_STYLE_HTML: + rc = xo_escape_xml(xbp, rc, (flags & XFF_ATTR)); + break; + + case XO_STYLE_JSON: + if (flags & XFF_TRIM_WS) + columns = rc = xo_trim_ws(xbp, rc); + rc = xo_escape_json(xbp, rc, 0); + break; + + case XO_STYLE_SDPARAMS: + if (flags & XFF_TRIM_WS) + columns = rc = xo_trim_ws(xbp, rc); + rc = xo_escape_sdparams(xbp, rc, 0); + break; + + case XO_STYLE_ENCODER: + if (flags & XFF_TRIM_WS) + columns = rc = xo_trim_ws(xbp, rc); + break; + } + + /* + * We can assume all the non-%s data we've + * added is ASCII, so the columns and bytes are the + * same. xo_format_string handles all the fancy + * string conversions and updates xo_anchor_columns + * accordingly. + */ + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += columns; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += columns; + } + + xbp->xb_curp += rc; + } + + /* + * Now for the tricky part: we need to move the argument pointer + * along by the amount needed. + */ + if (!XOF_ISSET(xop, XOF_NO_VA_ARG)) { + + if (xf.xf_fc == 's' ||xf.xf_fc == 'S') { + /* + * The 'S' and 's' formats are normally handled in + * xo_format_string, but if we skipped it, then we + * need to pop it. + */ + if (xf.xf_skip) + va_arg(xop->xo_vap, char *); + + } else if (xf.xf_fc == 'm') { + /* Nothing on the stack for "%m" */ + + } else { + int s; + for (s = 0; s < XF_WIDTH_NUM; s++) { + if (xf.xf_star[s]) + va_arg(xop->xo_vap, int); + } + + if (strchr("diouxXDOU", xf.xf_fc) != NULL) { + if (xf.xf_hflag > 1) { + va_arg(xop->xo_vap, int); + + } else if (xf.xf_hflag > 0) { + va_arg(xop->xo_vap, int); + + } else if (xf.xf_lflag > 1) { + va_arg(xop->xo_vap, unsigned long long); + + } else if (xf.xf_lflag > 0) { + va_arg(xop->xo_vap, unsigned long); + + } else if (xf.xf_jflag > 0) { + va_arg(xop->xo_vap, intmax_t); + + } else if (xf.xf_tflag > 0) { + va_arg(xop->xo_vap, ptrdiff_t); + + } else if (xf.xf_zflag > 0) { + va_arg(xop->xo_vap, size_t); + + } else if (xf.xf_qflag > 0) { + va_arg(xop->xo_vap, quad_t); + + } else { + va_arg(xop->xo_vap, int); + } + } else if (strchr("eEfFgGaA", xf.xf_fc) != NULL) + if (xf.xf_lflag) + va_arg(xop->xo_vap, long double); + else + va_arg(xop->xo_vap, double); + + else if (xf.xf_fc == 'C' || (xf.xf_fc == 'c' && xf.xf_lflag)) + va_arg(xop->xo_vap, wint_t); + + else if (xf.xf_fc == 'c') + va_arg(xop->xo_vap, int); + + else if (xf.xf_fc == 'p') + va_arg(xop->xo_vap, void *); + } + } + } + + if (xp) { + if (make_output) { + cols = xo_format_string_direct(xop, xbp, flags | XFF_UNESCAPE, + NULL, xp, cp - xp, -1, + need_enc, XF_ENC_UTF8); + + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += cols; + } + + xp = NULL; + } + + if (flags & XFF_GT_FLAGS) { + /* + * Handle gettext()ing the field by looking up the value + * and then copying it in, while converting to locale, if + * needed. + */ + int new_cols = xo_format_gettext(xop, flags, start_offset, + old_cols, real_need_enc); + + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += new_cols - old_cols; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += new_cols - old_cols; + } + + return 0; +} + +static char * +xo_fix_encoding (xo_handle_t *xop UNUSED, char *encoding) +{ + char *cp = encoding; + + if (cp[0] != '%' || !isdigit((int) cp[1])) + return encoding; + + for (cp += 2; *cp; cp++) { + if (!isdigit((int) *cp)) + break; + } + + cp -= 1; + *cp = '%'; + + return cp; +} + +static void +xo_color_append_html (xo_handle_t *xop) +{ + /* + * If the color buffer has content, we add it now. It's already + * prebuilt and ready, since we want to add it to every <div>. + */ + if (!xo_buf_is_empty(&xop->xo_color_buf)) { + xo_buffer_t *xbp = &xop->xo_color_buf; + + xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp); + } +} + +/* + * A wrapper for humanize_number that autoscales, since the + * HN_AUTOSCALE flag scales as needed based on the size of + * the output buffer, not the size of the value. I also + * wish HN_DECIMAL was more imperative, without the <10 + * test. But the boat only goes where we want when we hold + * the rudder, so xo_humanize fixes part of the problem. + */ +static int +xo_humanize (char *buf, int len, uint64_t value, int flags) +{ + int scale = 0; + + if (value) { + uint64_t left = value; + + if (flags & HN_DIVISOR_1000) { + for ( ; left; scale++) + left /= 1000; + } else { + for ( ; left; scale++) + left /= 1024; + } + scale -= 1; + } + + return xo_humanize_number(buf, len, value, "", scale, flags); +} + +/* + * This is an area where we can save information from the handle for + * later restoration. We need to know what data was rendered to know + * what needs cleaned up. + */ +typedef struct xo_humanize_save_s { + unsigned xhs_offset; /* Saved xo_offset */ + unsigned xhs_columns; /* Saved xo_columns */ + unsigned xhs_anchor_columns; /* Saved xo_anchor_columns */ +} xo_humanize_save_t; + +/* + * Format a "humanized" value for a numeric, meaning something nice + * like "44M" instead of "44470272". We autoscale, choosing the + * most appropriate value for K/M/G/T/P/E based on the value given. + */ +static void +xo_format_humanize (xo_handle_t *xop, xo_buffer_t *xbp, + xo_humanize_save_t *savep, xo_xff_flags_t flags) +{ + if (XOF_ISSET(xop, XOF_NO_HUMANIZE)) + return; + + unsigned end_offset = xbp->xb_curp - xbp->xb_bufp; + if (end_offset == savep->xhs_offset) /* Huh? Nothing to render */ + return; + + /* + * We have a string that's allegedly a number. We want to + * humanize it, which means turning it back into a number + * and calling xo_humanize_number on it. + */ + uint64_t value; + char *ep; + + xo_buf_append(xbp, "", 1); /* NUL-terminate it */ + + value = strtoull(xbp->xb_bufp + savep->xhs_offset, &ep, 0); + if (!(value == ULLONG_MAX && errno == ERANGE) + && (ep != xbp->xb_bufp + savep->xhs_offset)) { + /* + * There are few values where humanize_number needs + * more bytes than the original value. I've used + * 10 as a rectal number to cover those scenarios. + */ + if (xo_buf_has_room(xbp, 10)) { + xbp->xb_curp = xbp->xb_bufp + savep->xhs_offset; + + int rc; + int left = (xbp->xb_bufp + xbp->xb_size) - xbp->xb_curp; + int hn_flags = HN_NOSPACE; /* On by default */ + + if (flags & XFF_HN_SPACE) + hn_flags &= ~HN_NOSPACE; + + if (flags & XFF_HN_DECIMAL) + hn_flags |= HN_DECIMAL; + + if (flags & XFF_HN_1000) + hn_flags |= HN_DIVISOR_1000; + + rc = xo_humanize(xbp->xb_curp, + left, value, hn_flags); + if (rc > 0) { + xbp->xb_curp += rc; + xop->xo_columns = savep->xhs_columns + rc; + xop->xo_anchor_columns = savep->xhs_anchor_columns + rc; + } + } + } +} + +static void +xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags, + const char *name, int nlen, + const char *value, int vlen, + const char *encoding, int elen) +{ + static char div_start[] = "<div class=\""; + static char div_tag[] = "\" data-tag=\""; + static char div_xpath[] = "\" data-xpath=\""; + static char div_key[] = "\" data-key=\"key"; + static char div_end[] = "\">"; + static char div_close[] = "</div>"; + + /* The encoding format defaults to the normal format */ + if (encoding == NULL) { + char *enc = alloca(vlen + 1); + memcpy(enc, value, vlen); + enc[vlen] = '\0'; + encoding = xo_fix_encoding(xop, enc); + elen = strlen(encoding); + } + + /* + * To build our XPath predicate, we need to save the va_list before + * we format our data, and then restore it before we format the + * xpath expression. + * Display-only keys implies that we've got an encode-only key + * elsewhere, so we don't use them from making predicates. + */ + int need_predidate = + (name && (flags & XFF_KEY) && !(flags & XFF_DISPLAY_ONLY) + && XOF_ISSET(xop, XOF_XPATH)); + + if (need_predidate) { + va_list va_local; + + va_copy(va_local, xop->xo_vap); + if (xop->xo_checkpointer) + xop->xo_checkpointer(xop, xop->xo_vap, 0); + + /* + * Build an XPath predicate expression to match this key. + * We use the format buffer. + */ + xo_buffer_t *pbp = &xop->xo_predicate; + pbp->xb_curp = pbp->xb_bufp; /* Restart buffer */ + + xo_buf_append(pbp, "[", 1); + xo_buf_escape(xop, pbp, name, nlen, 0); + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_buf_append(pbp, " = '", 4); + else + xo_buf_append(pbp, "='", 2); + + xo_xff_flags_t pflags = flags | XFF_XML | XFF_ATTR; + pflags &= ~(XFF_NO_OUTPUT | XFF_ENCODE_ONLY); + xo_do_format_field(xop, pbp, encoding, elen, pflags); + + xo_buf_append(pbp, "']", 2); + + /* Now we record this predicate expression in the stack */ + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + int olen = xsp->xs_keys ? strlen(xsp->xs_keys) : 0; + int dlen = pbp->xb_curp - pbp->xb_bufp; + + char *cp = xo_realloc(xsp->xs_keys, olen + dlen + 1); + if (cp) { + memcpy(cp + olen, pbp->xb_bufp, dlen); + cp[olen + dlen] = '\0'; + xsp->xs_keys = cp; + } + + /* Now we reset the xo_vap as if we were never here */ + va_end(xop->xo_vap); + va_copy(xop->xo_vap, va_local); + va_end(va_local); + if (xop->xo_checkpointer) + xop->xo_checkpointer(xop, xop->xo_vap, 1); + } + + if (flags & XFF_ENCODE_ONLY) { + /* + * Even if this is encode-only, we need to go through the + * work of formatting it to make sure the args are cleared + * from xo_vap. + */ + xo_do_format_field(xop, NULL, encoding, elen, + flags | XFF_NO_OUTPUT); + return; + } + + xo_line_ensure_open(xop, 0); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_buf_indent(xop, xop->xo_indent_by); + + xo_data_append(xop, div_start, sizeof(div_start) - 1); + xo_data_append(xop, class, strlen(class)); + + /* + * If the color buffer has content, we add it now. It's already + * prebuilt and ready, since we want to add it to every <div>. + */ + if (!xo_buf_is_empty(&xop->xo_color_buf)) { + xo_buffer_t *xbp = &xop->xo_color_buf; + + xo_data_append(xop, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp); + } + + if (name) { + xo_data_append(xop, div_tag, sizeof(div_tag) - 1); + xo_data_escape(xop, name, nlen); + + /* + * Save the offset at which we'd place units. See xo_format_units. + */ + if (XOF_ISSET(xop, XOF_UNITS)) { + XOIF_SET(xop, XOIF_UNITS_PENDING); + /* + * Note: We need the '+1' here because we know we've not + * added the closing quote. We add one, knowing the quote + * will be added shortly. + */ + xop->xo_units_offset = + xop->xo_data.xb_curp -xop->xo_data.xb_bufp + 1; + } + + if (XOF_ISSET(xop, XOF_XPATH)) { + int i; + xo_stack_t *xsp; + + xo_data_append(xop, div_xpath, sizeof(div_xpath) - 1); + if (xop->xo_leading_xpath) + xo_data_append(xop, xop->xo_leading_xpath, + strlen(xop->xo_leading_xpath)); + + for (i = 0; i <= xop->xo_depth; i++) { + xsp = &xop->xo_stack[i]; + if (xsp->xs_name == NULL) + continue; + + /* + * XSS_OPEN_LIST and XSS_OPEN_LEAF_LIST stack frames + * are directly under XSS_OPEN_INSTANCE frames so we + * don't need to put these in our XPath expressions. + */ + if (xsp->xs_state == XSS_OPEN_LIST + || xsp->xs_state == XSS_OPEN_LEAF_LIST) + continue; + + xo_data_append(xop, "/", 1); + xo_data_escape(xop, xsp->xs_name, strlen(xsp->xs_name)); + if (xsp->xs_keys) { + /* Don't show keys for the key field */ + if (i != xop->xo_depth || !(flags & XFF_KEY)) + xo_data_append(xop, xsp->xs_keys, strlen(xsp->xs_keys)); + } + } + + xo_data_append(xop, "/", 1); + xo_data_escape(xop, name, nlen); + } + + if (XOF_ISSET(xop, XOF_INFO) && xop->xo_info) { + static char in_type[] = "\" data-type=\""; + static char in_help[] = "\" data-help=\""; + + xo_info_t *xip = xo_info_find(xop, name, nlen); + if (xip) { + if (xip->xi_type) { + xo_data_append(xop, in_type, sizeof(in_type) - 1); + xo_data_escape(xop, xip->xi_type, strlen(xip->xi_type)); + } + if (xip->xi_help) { + xo_data_append(xop, in_help, sizeof(in_help) - 1); + xo_data_escape(xop, xip->xi_help, strlen(xip->xi_help)); + } + } + } + + if ((flags & XFF_KEY) && XOF_ISSET(xop, XOF_KEYS)) + xo_data_append(xop, div_key, sizeof(div_key) - 1); + } + + xo_buffer_t *xbp = &xop->xo_data; + unsigned base_offset = xbp->xb_curp - xbp->xb_bufp; + + xo_data_append(xop, div_end, sizeof(div_end) - 1); + + xo_humanize_save_t save; /* Save values for humanizing logic */ + + save.xhs_offset = xbp->xb_curp - xbp->xb_bufp; + save.xhs_columns = xop->xo_columns; + save.xhs_anchor_columns = xop->xo_anchor_columns; + + xo_do_format_field(xop, NULL, value, vlen, flags); + + if (flags & XFF_HUMANIZE) { + /* + * Unlike text style, we want to retain the original value and + * stuff it into the "data-number" attribute. + */ + static const char div_number[] = "\" data-number=\""; + int div_len = sizeof(div_number) - 1; + + unsigned end_offset = xbp->xb_curp - xbp->xb_bufp; + int olen = end_offset - save.xhs_offset; + + char *cp = alloca(olen + 1); + memcpy(cp, xbp->xb_bufp + save.xhs_offset, olen); + cp[olen] = '\0'; + + xo_format_humanize(xop, xbp, &save, flags); + + if (xo_buf_has_room(xbp, div_len + olen)) { + unsigned new_offset = xbp->xb_curp - xbp->xb_bufp; + + + /* Move the humanized string off to the left */ + memmove(xbp->xb_bufp + base_offset + div_len + olen, + xbp->xb_bufp + base_offset, new_offset - base_offset); + + /* Copy the data_number attribute name */ + memcpy(xbp->xb_bufp + base_offset, div_number, div_len); + + /* Copy the original long value */ + memcpy(xbp->xb_bufp + base_offset + div_len, cp, olen); + xbp->xb_curp += div_len + olen; + } + } + + xo_data_append(xop, div_close, sizeof(div_close) - 1); + + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); +} + +static void +xo_format_text (xo_handle_t *xop, const char *str, int len) +{ + switch (xo_style(xop)) { + case XO_STYLE_TEXT: + xo_buf_append_locale(xop, &xop->xo_data, str, len); + break; + + case XO_STYLE_HTML: + xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0); + break; + } +} + +static void +xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + const char *fmt = xfip->xfi_format; + unsigned flen = xfip->xfi_flen; + xo_xff_flags_t flags = xfip->xfi_flags; + + static char div_open[] = "<div class=\"title"; + static char div_middle[] = "\">"; + static char div_close[] = "</div>"; + + if (flen == 0) { + fmt = "%s"; + flen = 2; + } + + switch (xo_style(xop)) { + case XO_STYLE_XML: + case XO_STYLE_JSON: + case XO_STYLE_SDPARAMS: + case XO_STYLE_ENCODER: + /* + * Even though we don't care about text, we need to do + * enough parsing work to skip over the right bits of xo_vap. + */ + if (len == 0) + xo_do_format_field(xop, NULL, fmt, flen, flags | XFF_NO_OUTPUT); + return; + } + + xo_buffer_t *xbp = &xop->xo_data; + int start = xbp->xb_curp - xbp->xb_bufp; + int left = xbp->xb_size - start; + int rc; + + if (xo_style(xop) == XO_STYLE_HTML) { + xo_line_ensure_open(xop, 0); + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_buf_indent(xop, xop->xo_indent_by); + xo_buf_append(&xop->xo_data, div_open, sizeof(div_open) - 1); + xo_color_append_html(xop); + xo_buf_append(&xop->xo_data, div_middle, sizeof(div_middle) - 1); + } + + start = xbp->xb_curp - xbp->xb_bufp; /* Reset start */ + if (len) { + char *newfmt = alloca(flen + 1); + memcpy(newfmt, fmt, flen); + newfmt[flen] = '\0'; + + /* If len is non-zero, the format string apply to the name */ + char *newstr = alloca(len + 1); + memcpy(newstr, str, len); + newstr[len] = '\0'; + + if (newstr[len - 1] == 's') { + char *bp; + + rc = snprintf(NULL, 0, newfmt, newstr); + if (rc > 0) { + /* + * We have to do this the hard way, since we might need + * the columns. + */ + bp = alloca(rc + 1); + rc = snprintf(bp, rc + 1, newfmt, newstr); + + xo_data_append_content(xop, bp, rc, flags); + } + goto move_along; + + } else { + rc = snprintf(xbp->xb_curp, left, newfmt, newstr); + if (rc >= left) { + if (!xo_buf_has_room(xbp, rc)) + return; + left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); + rc = snprintf(xbp->xb_curp, left, newfmt, newstr); + } + + if (rc > 0) { + if (XOF_ISSET(xop, XOF_COLUMNS)) + xop->xo_columns += rc; + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xop->xo_anchor_columns += rc; + } + } + + } else { + xo_do_format_field(xop, NULL, fmt, flen, flags); + + /* xo_do_format_field moved curp, so we need to reset it */ + rc = xbp->xb_curp - (xbp->xb_bufp + start); + xbp->xb_curp = xbp->xb_bufp + start; + } + + /* If we're styling HTML, then we need to escape it */ + if (xo_style(xop) == XO_STYLE_HTML) { + rc = xo_escape_xml(xbp, rc, 0); + } + + if (rc > 0) + xbp->xb_curp += rc; + + move_along: + if (xo_style(xop) == XO_STYLE_HTML) { + xo_data_append(xop, div_close, sizeof(div_close) - 1); + if (XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); + } +} + +static void +xo_format_prep (xo_handle_t *xop, xo_xff_flags_t flags) +{ + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) { + xo_data_append(xop, ",", 1); + if (!(flags & XFF_LEAF_LIST) && XOF_ISSET(xop, XOF_PRETTY)) + xo_data_append(xop, "\n", 1); + } else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; +} + +#if 0 +/* Useful debugging function */ +void +xo_arg (xo_handle_t *xop); +void +xo_arg (xo_handle_t *xop) +{ + xop = xo_default(xop); + fprintf(stderr, "0x%x", va_arg(xop->xo_vap, unsigned)); +} +#endif /* 0 */ + +static void +xo_format_value (xo_handle_t *xop, const char *name, int nlen, + const char *format, int flen, + const char *encoding, int elen, xo_xff_flags_t flags) +{ + int pretty = XOF_ISSET(xop, XOF_PRETTY); + int quote; + + /* + * Before we emit a value, we need to know that the frame is ready. + */ + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + if (flags & XFF_LEAF_LIST) { + /* + * Check if we've already started to emit normal leafs + * or if we're not in a leaf list. + */ + if ((xsp->xs_flags & (XSF_EMIT | XSF_EMIT_KEY)) + || !(xsp->xs_flags & XSF_EMIT_LEAF_LIST)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT_LEAF_LIST); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_LEAF_LIST; + } + + xsp = &xop->xo_stack[xop->xo_depth]; + if (xsp->xs_name) { + name = xsp->xs_name; + nlen = strlen(name); + } + + } else if (flags & XFF_KEY) { + /* Emitting a 'k' (key) field */ + if ((xsp->xs_flags & XSF_EMIT) && !(flags & XFF_DISPLAY_ONLY)) { + xo_failure(xop, "key field emitted after normal value field: '%.*s'", + nlen, name); + + } else if (!(xsp->xs_flags & XSF_EMIT_KEY)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT_KEY; + + xsp = &xop->xo_stack[xop->xo_depth]; + xsp->xs_flags |= XSF_EMIT_KEY; + } + + } else { + /* Emitting a normal value field */ + if ((xsp->xs_flags & XSF_EMIT_LEAF_LIST) + || !(xsp->xs_flags & XSF_EMIT)) { + char nbuf[nlen + 1]; + memcpy(nbuf, name, nlen); + nbuf[nlen] = '\0'; + + int rc = xo_transition(xop, 0, nbuf, XSS_EMIT); + if (rc < 0) + flags |= XFF_DISPLAY_ONLY | XFF_ENCODE_ONLY; + else + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_EMIT; + + xsp = &xop->xo_stack[xop->xo_depth]; + xsp->xs_flags |= XSF_EMIT; + } + } + + xo_buffer_t *xbp = &xop->xo_data; + xo_humanize_save_t save; /* Save values for humanizing logic */ + + switch (xo_style(xop)) { + case XO_STYLE_TEXT: + if (flags & XFF_ENCODE_ONLY) + flags |= XFF_NO_OUTPUT; + + save.xhs_offset = xbp->xb_curp - xbp->xb_bufp; + save.xhs_columns = xop->xo_columns; + save.xhs_anchor_columns = xop->xo_anchor_columns; + + xo_do_format_field(xop, NULL, format, flen, flags); + + if (flags & XFF_HUMANIZE) + xo_format_humanize(xop, xbp, &save, flags); + break; + + case XO_STYLE_HTML: + if (flags & XFF_ENCODE_ONLY) + flags |= XFF_NO_OUTPUT; + + xo_buf_append_div(xop, "data", flags, name, nlen, + format, flen, encoding, elen); + break; + + case XO_STYLE_XML: + /* + * Even though we're not making output, we still need to + * let the formatting code handle the va_arg popping. + */ + if (flags & XFF_DISPLAY_ONLY) { + flags |= XFF_NO_OUTPUT; + xo_do_format_field(xop, NULL, format, flen, flags); + break; + } + + if (encoding) { + format = encoding; + flen = elen; + } else { + char *enc = alloca(flen + 1); + memcpy(enc, format, flen); + enc[flen] = '\0'; + format = xo_fix_encoding(xop, enc); + flen = strlen(format); + } + + if (nlen == 0) { + static char missing[] = "missing-field-name"; + xo_failure(xop, "missing field name: %s", format); + name = missing; + nlen = sizeof(missing) - 1; + } + + if (pretty) + xo_buf_indent(xop, -1); + xo_data_append(xop, "<", 1); + xo_data_escape(xop, name, nlen); + + if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) { + xo_data_append(xop, xop->xo_attrs.xb_bufp, + xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp); + xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp; + } + + /* + * We indicate 'key' fields using the 'key' attribute. While + * this is really committing the crime of mixing meta-data with + * data, it's often useful. Especially when format meta-data is + * difficult to come by. + */ + if ((flags & XFF_KEY) && XOF_ISSET(xop, XOF_KEYS)) { + static char attr[] = " key=\"key\""; + xo_data_append(xop, attr, sizeof(attr) - 1); + } + + /* + * Save the offset at which we'd place units. See xo_format_units. + */ + if (XOF_ISSET(xop, XOF_UNITS)) { + XOIF_SET(xop, XOIF_UNITS_PENDING); + xop->xo_units_offset = xop->xo_data.xb_curp -xop->xo_data.xb_bufp; + } + + xo_data_append(xop, ">", 1); + xo_do_format_field(xop, NULL, format, flen, flags); + xo_data_append(xop, "</", 2); + xo_data_escape(xop, name, nlen); + xo_data_append(xop, ">", 1); + if (pretty) + xo_data_append(xop, "\n", 1); + break; + + case XO_STYLE_JSON: + if (flags & XFF_DISPLAY_ONLY) { + flags |= XFF_NO_OUTPUT; + xo_do_format_field(xop, NULL, format, flen, flags); + break; + } + + if (encoding) { + format = encoding; + flen = elen; + } else { + char *enc = alloca(flen + 1); + memcpy(enc, format, flen); + enc[flen] = '\0'; + format = xo_fix_encoding(xop, enc); + flen = strlen(format); + } + + int first = !(xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST); + + xo_format_prep(xop, flags); + + if (flags & XFF_QUOTE) + quote = 1; + else if (flags & XFF_NOQUOTE) + quote = 0; + else if (flen == 0) { + quote = 0; + format = "true"; /* JSON encodes empty tags as a boolean true */ + flen = 4; + } else if (strchr("diouxXDOUeEfFgGaAcCp", format[flen - 1]) == NULL) + quote = 1; + else + quote = 0; + + if (nlen == 0) { + static char missing[] = "missing-field-name"; + xo_failure(xop, "missing field name: %s", format); + name = missing; + nlen = sizeof(missing) - 1; + } + + if (flags & XFF_LEAF_LIST) { + if (!first && pretty) + xo_data_append(xop, "\n", 1); + if (pretty) + xo_buf_indent(xop, -1); + } else { + if (pretty) + xo_buf_indent(xop, -1); + xo_data_append(xop, "\"", 1); + + xbp = &xop->xo_data; + int off = xbp->xb_curp - xbp->xb_bufp; + + xo_data_escape(xop, name, nlen); + + if (XOF_ISSET(xop, XOF_UNDERSCORES)) { + int now = xbp->xb_curp - xbp->xb_bufp; + for ( ; off < now; off++) + if (xbp->xb_bufp[off] == '-') + xbp->xb_bufp[off] = '_'; + } + xo_data_append(xop, "\":", 2); + if (pretty) + xo_data_append(xop, " ", 1); + } + + if (quote) + xo_data_append(xop, "\"", 1); + + xo_do_format_field(xop, NULL, format, flen, flags); + + if (quote) + xo_data_append(xop, "\"", 1); + break; + + case XO_STYLE_SDPARAMS: + if (flags & XFF_DISPLAY_ONLY) { + flags |= XFF_NO_OUTPUT; + xo_do_format_field(xop, NULL, format, flen, flags); + break; + } + + if (encoding) { + format = encoding; + flen = elen; + } else { + char *enc = alloca(flen + 1); + memcpy(enc, format, flen); + enc[flen] = '\0'; + format = xo_fix_encoding(xop, enc); + flen = strlen(format); + } + + if (nlen == 0) { + static char missing[] = "missing-field-name"; + xo_failure(xop, "missing field name: %s", format); + name = missing; + nlen = sizeof(missing) - 1; + } + + xo_data_escape(xop, name, nlen); + xo_data_append(xop, "=\"", 2); + xo_do_format_field(xop, NULL, format, flen, flags); + xo_data_append(xop, "\" ", 2); + break; + + case XO_STYLE_ENCODER: + if (flags & XFF_DISPLAY_ONLY) { + flags |= XFF_NO_OUTPUT; + xo_do_format_field(xop, NULL, format, flen, flags); + break; + } + + if (flags & XFF_QUOTE) + quote = 1; + else if (flags & XFF_NOQUOTE) + quote = 0; + else if (flen == 0) { + quote = 0; + format = "true"; /* JSON encodes empty tags as a boolean true */ + flen = 4; + } else if (strchr("diouxXDOUeEfFgGaAcCp", format[flen - 1]) == NULL) + quote = 1; + else + quote = 0; + + if (encoding) { + format = encoding; + flen = elen; + } else { + char *enc = alloca(flen + 1); + memcpy(enc, format, flen); + enc[flen] = '\0'; + format = xo_fix_encoding(xop, enc); + flen = strlen(format); + } + + if (nlen == 0) { + static char missing[] = "missing-field-name"; + xo_failure(xop, "missing field name: %s", format); + name = missing; + nlen = sizeof(missing) - 1; + } + + unsigned name_offset = xo_buf_offset(&xop->xo_data); + xo_data_append(xop, name, nlen); + xo_data_append(xop, "", 1); + + unsigned value_offset = xo_buf_offset(&xop->xo_data); + xo_do_format_field(xop, NULL, format, flen, flags); + xo_data_append(xop, "", 1); + + xo_encoder_handle(xop, quote ? XO_OP_STRING : XO_OP_CONTENT, + xo_buf_data(&xop->xo_data, name_offset), + xo_buf_data(&xop->xo_data, value_offset)); + xo_buf_reset(&xop->xo_data); + break; + } +} + +static void +xo_set_gettext_domain (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + const char *fmt = xfip->xfi_format; + unsigned flen = xfip->xfi_flen; + + /* Start by discarding previous domain */ + if (xop->xo_gt_domain) { + xo_free(xop->xo_gt_domain); + xop->xo_gt_domain = NULL; + } + + /* An empty {G:} means no domainname */ + if (len == 0 && flen == 0) + return; + + int start_offset = -1; + if (len == 0 && flen != 0) { + /* Need to do format the data to get the domainname from args */ + start_offset = xop->xo_data.xb_curp - xop->xo_data.xb_bufp; + xo_do_format_field(xop, NULL, fmt, flen, 0); + + int end_offset = xop->xo_data.xb_curp - xop->xo_data.xb_bufp; + len = end_offset - start_offset; + str = xop->xo_data.xb_bufp + start_offset; + } + + xop->xo_gt_domain = xo_strndup(str, len); + + /* Reset the current buffer point to avoid emitting the name as output */ + if (start_offset >= 0) + xop->xo_data.xb_curp = xop->xo_data.xb_bufp + start_offset; +} + +static void +xo_format_content (xo_handle_t *xop, const char *class_name, + const char *tag_name, + const char *str, int len, const char *fmt, int flen, + xo_xff_flags_t flags) +{ + switch (xo_style(xop)) { + case XO_STYLE_TEXT: + if (len) + xo_data_append_content(xop, str, len, flags); + else + xo_do_format_field(xop, NULL, fmt, flen, flags); + break; + + case XO_STYLE_HTML: + if (len == 0) { + str = fmt; + len = flen; + } + + xo_buf_append_div(xop, class_name, flags, NULL, 0, str, len, NULL, 0); + break; + + case XO_STYLE_XML: + case XO_STYLE_JSON: + case XO_STYLE_SDPARAMS: + if (tag_name) { + if (len == 0) { + str = fmt; + len = flen; + } + + xo_open_container_h(xop, tag_name); + xo_format_value(xop, "message", 7, str, len, NULL, 0, flags); + xo_close_container_h(xop, tag_name); + + } else { + /* + * Even though we don't care about labels, we need to do + * enough parsing work to skip over the right bits of xo_vap. + */ + if (len == 0) + xo_do_format_field(xop, NULL, fmt, flen, + flags | XFF_NO_OUTPUT); + } + break; + + case XO_STYLE_ENCODER: + if (len == 0) + xo_do_format_field(xop, NULL, fmt, flen, + flags | XFF_NO_OUTPUT); + break; + } +} + +static const char *xo_color_names[] = { + "default", /* XO_COL_DEFAULT */ + "black", /* XO_COL_BLACK */ + "red", /* XO_CLOR_RED */ + "green", /* XO_COL_GREEN */ + "yellow", /* XO_COL_YELLOW */ + "blue", /* XO_COL_BLUE */ + "magenta", /* XO_COL_MAGENTA */ + "cyan", /* XO_COL_CYAN */ + "white", /* XO_COL_WHITE */ + NULL +}; + +static int +xo_color_find (const char *str) +{ + int i; + + for (i = 0; xo_color_names[i]; i++) { + if (strcmp(xo_color_names[i], str) == 0) + return i; + } + + return -1; +} + +static const char *xo_effect_names[] = { + "reset", /* XO_EFF_RESET */ + "normal", /* XO_EFF_NORMAL */ + "bold", /* XO_EFF_BOLD */ + "underline", /* XO_EFF_UNDERLINE */ + "inverse", /* XO_EFF_INVERSE */ + NULL +}; + +static const char *xo_effect_on_codes[] = { + "0", /* XO_EFF_RESET */ + "0", /* XO_EFF_NORMAL */ + "1", /* XO_EFF_BOLD */ + "4", /* XO_EFF_UNDERLINE */ + "7", /* XO_EFF_INVERSE */ + NULL +}; + +#if 0 +/* + * See comment below re: joy of terminal standards. These can + * be use by just adding: + * + if (newp->xoc_effects & bit) + * code = xo_effect_on_codes[i]; + * + else + * + code = xo_effect_off_codes[i]; + * in xo_color_handle_text. + */ +static const char *xo_effect_off_codes[] = { + "0", /* XO_EFF_RESET */ + "0", /* XO_EFF_NORMAL */ + "21", /* XO_EFF_BOLD */ + "24", /* XO_EFF_UNDERLINE */ + "27", /* XO_EFF_INVERSE */ + NULL +}; +#endif /* 0 */ + +static int +xo_effect_find (const char *str) +{ + int i; + + for (i = 0; xo_effect_names[i]; i++) { + if (strcmp(xo_effect_names[i], str) == 0) + return i; + } + + return -1; +} + +static void +xo_colors_parse (xo_handle_t *xop, xo_colors_t *xocp, char *str) +{ +#ifdef LIBXO_TEXT_ONLY + return; +#endif /* LIBXO_TEXT_ONLY */ + + char *cp, *ep, *np, *xp; + int len = strlen(str); + int rc; + + /* + * Possible tokens: colors, bg-colors, effects, no-effects, "reset". + */ + for (cp = str, ep = cp + len - 1; cp && cp < ep; cp = np) { + /* Trim leading whitespace */ + while (isspace((int) *cp)) + cp += 1; + + np = strchr(cp, ','); + if (np) + *np++ = '\0'; + + /* Trim trailing whitespace */ + xp = cp + strlen(cp) - 1; + while (isspace(*xp) && xp > cp) + *xp-- = '\0'; + + if (cp[0] == 'f' && cp[1] == 'g' && cp[2] == '-') { + rc = xo_color_find(cp + 3); + if (rc < 0) + goto unknown; + + xocp->xoc_col_fg = rc; + + } else if (cp[0] == 'b' && cp[1] == 'g' && cp[2] == '-') { + rc = xo_color_find(cp + 3); + if (rc < 0) + goto unknown; + xocp->xoc_col_bg = rc; + + } else if (cp[0] == 'n' && cp[1] == 'o' && cp[2] == '-') { + rc = xo_effect_find(cp + 3); + if (rc < 0) + goto unknown; + xocp->xoc_effects &= ~(1 << rc); + + } else { + rc = xo_effect_find(cp); + if (rc < 0) + goto unknown; + xocp->xoc_effects |= 1 << rc; + + switch (1 << rc) { + case XO_EFF_RESET: + xocp->xoc_col_fg = xocp->xoc_col_bg = 0; + /* Note: not "|=" since we want to wipe out the old value */ + xocp->xoc_effects = XO_EFF_RESET; + break; + + case XO_EFF_NORMAL: + xocp->xoc_effects &= ~(XO_EFF_BOLD | XO_EFF_UNDERLINE + | XO_EFF_INVERSE | XO_EFF_NORMAL); + break; + } + } + continue; + + unknown: + if (XOF_ISSET(xop, XOF_WARN)) + xo_failure(xop, "unknown color/effect string detected: '%s'", cp); + } +} + +static inline int +xo_colors_enabled (xo_handle_t *xop UNUSED) +{ +#ifdef LIBXO_TEXT_ONLY + return 0; +#else /* LIBXO_TEXT_ONLY */ + return XOF_ISSET(xop, XOF_COLOR); +#endif /* LIBXO_TEXT_ONLY */ +} + +static void +xo_colors_handle_text (xo_handle_t *xop, xo_colors_t *newp) +{ + char buf[BUFSIZ]; + char *cp = buf, *ep = buf + sizeof(buf); + unsigned i, bit; + xo_colors_t *oldp = &xop->xo_colors; + const char *code = NULL; + + /* + * Start the buffer with an escape. We don't want to add the '[' + * now, since we let xo_effect_text_add unconditionally add the ';'. + * We'll replace the first ';' with a '[' when we're done. + */ + *cp++ = 0x1b; /* Escape */ + + /* + * Terminals were designed back in the age before "certainty" was + * invented, when standards were more what you'd call "guidelines" + * than actual rules. Anyway we can't depend on them to operate + * correctly. So when display attributes are changed, we punt, + * reseting them all and turning back on the ones we want to keep. + * Longer, but should be completely reliable. Savvy? + */ + if (oldp->xoc_effects != (newp->xoc_effects & oldp->xoc_effects)) { + newp->xoc_effects |= XO_EFF_RESET; + oldp->xoc_effects = 0; + } + + for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) { + if ((newp->xoc_effects & bit) == (oldp->xoc_effects & bit)) + continue; + + code = xo_effect_on_codes[i]; + + cp += snprintf(cp, ep - cp, ";%s", code); + if (cp >= ep) + return; /* Should not occur */ + + if (bit == XO_EFF_RESET) { + /* Mark up the old value so we can detect current values as new */ + oldp->xoc_effects = 0; + oldp->xoc_col_fg = oldp->xoc_col_bg = XO_COL_DEFAULT; + } + } + + if (newp->xoc_col_fg != oldp->xoc_col_fg) { + cp += snprintf(cp, ep - cp, ";3%u", + (newp->xoc_col_fg != XO_COL_DEFAULT) + ? newp->xoc_col_fg - 1 : 9); + } + + if (newp->xoc_col_bg != oldp->xoc_col_bg) { + cp += snprintf(cp, ep - cp, ";4%u", + (newp->xoc_col_bg != XO_COL_DEFAULT) + ? newp->xoc_col_bg - 1 : 9); + } + + if (cp - buf != 1 && cp < ep - 3) { + buf[1] = '['; /* Overwrite leading ';' */ + *cp++ = 'm'; + *cp = '\0'; + xo_buf_append(&xop->xo_data, buf, cp - buf); + } +} + +static void +xo_colors_handle_html (xo_handle_t *xop, xo_colors_t *newp) +{ + xo_colors_t *oldp = &xop->xo_colors; + + /* + * HTML colors are mostly trivial: fill in xo_color_buf with + * a set of class tags representing the colors and effects. + */ + + /* If nothing changed, then do nothing */ + if (oldp->xoc_effects == newp->xoc_effects + && oldp->xoc_col_fg == newp->xoc_col_fg + && oldp->xoc_col_bg == newp->xoc_col_bg) + return; + + unsigned i, bit; + xo_buffer_t *xbp = &xop->xo_color_buf; + + xo_buf_reset(xbp); /* We rebuild content after each change */ + + for (i = 0, bit = 1; xo_effect_names[i]; i++, bit <<= 1) { + if (!(newp->xoc_effects & bit)) + continue; + + xo_buf_append_str(xbp, " effect-"); + xo_buf_append_str(xbp, xo_effect_names[i]); + } + + const char *fg = NULL; + const char *bg = NULL; + + if (newp->xoc_col_fg != XO_COL_DEFAULT) + fg = xo_color_names[newp->xoc_col_fg]; + if (newp->xoc_col_bg != XO_COL_DEFAULT) + bg = xo_color_names[newp->xoc_col_bg]; + + if (newp->xoc_effects & XO_EFF_INVERSE) { + const char *tmp = fg; + fg = bg; + bg = tmp; + if (fg == NULL) + fg = "inverse"; + if (bg == NULL) + bg = "inverse"; + + } + + if (fg) { + xo_buf_append_str(xbp, " color-fg-"); + xo_buf_append_str(xbp, fg); + } + + if (bg) { + xo_buf_append_str(xbp, " color-bg-"); + xo_buf_append_str(xbp, bg); + } +} + +static void +xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + const char *fmt = xfip->xfi_format; + unsigned flen = xfip->xfi_flen; + + xo_buffer_t xb; + + /* If the string is static and we've in an encoding style, bail */ + if (len != 0 && xo_style_is_encoding(xop)) + return; + + xo_buf_init(&xb); + + if (len) + xo_buf_append(&xb, str, len); + else if (flen) + xo_do_format_field(xop, &xb, fmt, flen, 0); + else + xo_buf_append(&xb, "reset", 6); /* Default if empty */ + + if (xo_colors_enabled(xop)) { + switch (xo_style(xop)) { + case XO_STYLE_TEXT: + case XO_STYLE_HTML: + xo_buf_append(&xb, "", 1); + + xo_colors_t xoc = xop->xo_colors; + xo_colors_parse(xop, &xoc, xb.xb_bufp); + + if (xo_style(xop) == XO_STYLE_TEXT) { + /* + * Text mode means emitting the colors as ANSI character + * codes. This will allow people who like colors to have + * colors. The issue is, of course conflicting with the + * user's perfectly reasonable color scheme. Which leads + * to the hell of LSCOLORS, where even app need to have + * customization hooks for adjusting colors. Instead we + * provide a simpler-but-still-annoying answer where one + * can map colors to other colors. + */ + xo_colors_handle_text(xop, &xoc); + xoc.xoc_effects &= ~XO_EFF_RESET; /* After handling it */ + + } else { + /* + * HTML output is wrapped in divs, so the color information + * must appear in every div until cleared. Most pathetic. + * Most unavoidable. + */ + xoc.xoc_effects &= ~XO_EFF_RESET; /* Before handling effects */ + xo_colors_handle_html(xop, &xoc); + } + + xop->xo_colors = xoc; + break; + + case XO_STYLE_XML: + case XO_STYLE_JSON: + case XO_STYLE_SDPARAMS: + case XO_STYLE_ENCODER: + /* + * Nothing to do; we did all that work just to clear the stack of + * formatting arguments. + */ + break; + } + } + + xo_buf_cleanup(&xb); +} + +static void +xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + const char *fmt = xfip->xfi_format; + unsigned flen = xfip->xfi_flen; + xo_xff_flags_t flags = xfip->xfi_flags; + + static char units_start_xml[] = " units=\""; + static char units_start_html[] = " data-units=\""; + + if (!XOIF_ISSET(xop, XOIF_UNITS_PENDING)) { + xo_format_content(xop, "units", NULL, str, len, fmt, flen, flags); + return; + } + + xo_buffer_t *xbp = &xop->xo_data; + int start = xop->xo_units_offset; + int stop = xbp->xb_curp - xbp->xb_bufp; + + if (xo_style(xop) == XO_STYLE_XML) + xo_buf_append(xbp, units_start_xml, sizeof(units_start_xml) - 1); + else if (xo_style(xop) == XO_STYLE_HTML) + xo_buf_append(xbp, units_start_html, sizeof(units_start_html) - 1); + else + return; + + if (len) + xo_data_escape(xop, str, len); + else + xo_do_format_field(xop, NULL, fmt, flen, flags); + + xo_buf_append(xbp, "\"", 1); + + int now = xbp->xb_curp - xbp->xb_bufp; + int delta = now - stop; + if (delta <= 0) { /* Strange; no output to move */ + xbp->xb_curp = xbp->xb_bufp + stop; /* Reset buffer to prior state */ + return; + } + + /* + * Now we're in it alright. We've need to insert the unit value + * we just created into the right spot. We make a local copy, + * move it and then insert our copy. We know there's room in the + * buffer, since we're just moving this around. + */ + char *buf = alloca(delta); + + memcpy(buf, xbp->xb_bufp + stop, delta); + memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start); + memmove(xbp->xb_bufp + start, buf, delta); +} + +static int +xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + const char *fmt = xfip->xfi_format; + unsigned flen = xfip->xfi_flen; + + long width = 0; + char *bp; + char *cp; + + if (len) { + bp = alloca(len + 1); /* Make local NUL-terminated copy of str */ + memcpy(bp, str, len); + bp[len] = '\0'; + + width = strtol(bp, &cp, 0); + if (width == LONG_MIN || width == LONG_MAX + || bp == cp || *cp != '\0' ) { + width = 0; + xo_failure(xop, "invalid width for anchor: '%s'", bp); + } + } else if (flen) { + if (flen != 2 || strncmp("%d", fmt, flen) != 0) + xo_failure(xop, "invalid width format: '%*.*s'", flen, flen, fmt); + if (!XOF_ISSET(xop, XOF_NO_VA_ARG)) + width = va_arg(xop->xo_vap, int); + } + + return width; +} + +static void +xo_anchor_clear (xo_handle_t *xop) +{ + XOIF_CLEAR(xop, XOIF_ANCHOR); + xop->xo_anchor_offset = 0; + xop->xo_anchor_columns = 0; + xop->xo_anchor_min_width = 0; +} + +/* + * An anchor is a marker used to delay field width implications. + * Imagine the format string "{[:10}{min:%d}/{cur:%d}/{max:%d}{:]}". + * We are looking for output like " 1/4/5" + * + * To make this work, we record the anchor and then return to + * format it when the end anchor tag is seen. + */ +static void +xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML) + return; + + if (XOIF_ISSET(xop, XOIF_ANCHOR)) + xo_failure(xop, "the anchor already recording is discarded"); + + XOIF_SET(xop, XOIF_ANCHOR); + xo_buffer_t *xbp = &xop->xo_data; + xop->xo_anchor_offset = xbp->xb_curp - xbp->xb_bufp; + xop->xo_anchor_columns = 0; + + /* + * Now we find the width, if possible. If it's not there, + * we'll get it on the end anchor. + */ + xop->xo_anchor_min_width = xo_find_width(xop, xfip, str, len); +} + +static void +xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip, + const char *str, unsigned len) +{ + if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML) + return; + + if (!XOIF_ISSET(xop, XOIF_ANCHOR)) { + xo_failure(xop, "no start anchor"); + return; + } + + XOIF_CLEAR(xop, XOIF_UNITS_PENDING); + + int width = xo_find_width(xop, xfip, str, len); + if (width == 0) + width = xop->xo_anchor_min_width; + + if (width == 0) /* No width given; nothing to do */ + goto done; + + xo_buffer_t *xbp = &xop->xo_data; + int start = xop->xo_anchor_offset; + int stop = xbp->xb_curp - xbp->xb_bufp; + int abswidth = (width > 0) ? width : -width; + int blen = abswidth - xop->xo_anchor_columns; + + if (blen <= 0) /* Already over width */ + goto done; + + if (abswidth > XO_MAX_ANCHOR_WIDTH) { + xo_failure(xop, "width over %u are not supported", + XO_MAX_ANCHOR_WIDTH); + goto done; + } + + /* Make a suitable padding field and emit it */ + char *buf = alloca(blen); + memset(buf, ' ', blen); + xo_format_content(xop, "padding", NULL, buf, blen, NULL, 0, 0); + + if (width < 0) /* Already left justified */ + goto done; + + int now = xbp->xb_curp - xbp->xb_bufp; + int delta = now - stop; + if (delta <= 0) /* Strange; no output to move */ + goto done; + + /* + * Now we're in it alright. We've need to insert the padding data + * we just created (which might be an HTML <div> or text) before + * the formatted data. We make a local copy, move it and then + * insert our copy. We know there's room in the buffer, since + * we're just moving this around. + */ + if (delta > blen) + buf = alloca(delta); /* Expand buffer if needed */ + + memcpy(buf, xbp->xb_bufp + stop, delta); + memmove(xbp->xb_bufp + start + delta, xbp->xb_bufp + start, stop - start); + memmove(xbp->xb_bufp + start, buf, delta); + + done: + xo_anchor_clear(xop); +} + +static const char * +xo_class_name (int ftype) +{ + switch (ftype) { + case 'D': return "decoration"; + case 'E': return "error"; + case 'L': return "label"; + case 'N': return "note"; + case 'P': return "padding"; + case 'W': return "warning"; + } + + return NULL; +} + +static const char * +xo_tag_name (int ftype) +{ + switch (ftype) { + case 'E': return "__error"; + case 'W': return "__warning"; + } + + return NULL; +} + +static int +xo_role_wants_default_format (int ftype) +{ + switch (ftype) { + /* These roles can be completely empty and/or without formatting */ + case 'C': + case 'G': + case '[': + case ']': + return 0; + } + + return 1; +} + +static xo_mapping_t xo_role_names[] = { + { 'C', "color" }, + { 'D', "decoration" }, + { 'E', "error" }, + { 'L', "label" }, + { 'N', "note" }, + { 'P', "padding" }, + { 'T', "title" }, + { 'U', "units" }, + { 'V', "value" }, + { 'W', "warning" }, + { '[', "start-anchor" }, + { ']', "stop-anchor" }, + { 0, NULL } +}; + +#define XO_ROLE_EBRACE '{' /* Escaped braces */ +#define XO_ROLE_TEXT '+' +#define XO_ROLE_NEWLINE '\n' + +static xo_mapping_t xo_modifier_names[] = { + { XFF_ARGUMENT, "argument" }, + { XFF_COLON, "colon" }, + { XFF_COMMA, "comma" }, + { XFF_DISPLAY_ONLY, "display" }, + { XFF_ENCODE_ONLY, "encoding" }, + { XFF_GT_FIELD, "gettext" }, + { XFF_HUMANIZE, "humanize" }, + { XFF_HUMANIZE, "hn" }, + { XFF_HN_SPACE, "hn-space" }, + { XFF_HN_DECIMAL, "hn-decimal" }, + { XFF_HN_1000, "hn-1000" }, + { XFF_KEY, "key" }, + { XFF_LEAF_LIST, "leaf-list" }, + { XFF_LEAF_LIST, "list" }, + { XFF_NOQUOTE, "no-quotes" }, + { XFF_NOQUOTE, "no-quote" }, + { XFF_GT_PLURAL, "plural" }, + { XFF_QUOTE, "quotes" }, + { XFF_QUOTE, "quote" }, + { XFF_TRIM_WS, "trim" }, + { XFF_WS, "white" }, + { 0, NULL } +}; + +#ifdef NOT_NEEDED_YET +static xo_mapping_t xo_modifier_short_names[] = { + { XFF_COLON, "c" }, + { XFF_DISPLAY_ONLY, "d" }, + { XFF_ENCODE_ONLY, "e" }, + { XFF_GT_FIELD, "g" }, + { XFF_HUMANIZE, "h" }, + { XFF_KEY, "k" }, + { XFF_LEAF_LIST, "l" }, + { XFF_NOQUOTE, "n" }, + { XFF_GT_PLURAL, "p" }, + { XFF_QUOTE, "q" }, + { XFF_TRIM_WS, "t" }, + { XFF_WS, "w" }, + { 0, NULL } +}; +#endif /* NOT_NEEDED_YET */ + +static int +xo_count_fields (xo_handle_t *xop UNUSED, const char *fmt) +{ + int rc = 1; + const char *cp; + + for (cp = fmt; *cp; cp++) + if (*cp == '{' || *cp == '\n') + rc += 1; + + return rc * 2 + 1; +} + +/* + * The field format is: + * '{' modifiers ':' content [ '/' print-fmt [ '/' encode-fmt ]] '}' + * Roles are optional and include the following field types: + * 'D': decoration; something non-text and non-data (colons, commmas) + * 'E': error message + * 'G': gettext() the entire string; optional domainname as content + * 'L': label; text preceding data + * 'N': note; text following data + * 'P': padding; whitespace + * 'T': Title, where 'content' is a column title + * 'U': Units, where 'content' is the unit label + * 'V': value, where 'content' is the name of the field (the default) + * 'W': warning message + * '[': start a section of anchored text + * ']': end a section of anchored text + * The following modifiers are also supported: + * 'a': content is provided via argument (const char *), not descriptor + * 'c': flag: emit a colon after the label + * 'd': field is only emitted for display styles (text and html) + * 'e': field is only emitted for encoding styles (xml and json) + * 'g': gettext() the field + * 'h': humanize a numeric value (only for display styles) + * 'k': this field is a key, suitable for XPath predicates + * 'l': a leaf-list, a simple list of values + * 'n': no quotes around this field + * 'p': the field has plural gettext semantics (ngettext) + * 'q': add quotes around this field + * 't': trim whitespace around the value + * 'w': emit a blank after the label + * The print-fmt and encode-fmt strings is the printf-style formating + * for this data. JSON and XML will use the encoding-fmt, if present. + * If the encode-fmt is not provided, it defaults to the print-fmt. + * If the print-fmt is not provided, it defaults to 's'. + */ +static const char * +xo_parse_roles (xo_handle_t *xop, const char *fmt, + const char *basep, xo_field_info_t *xfip) +{ + const char *sp; + unsigned ftype = 0; + xo_xff_flags_t flags = 0; + uint8_t fnum = 0; + + for (sp = basep; sp && *sp; sp++) { + if (*sp == ':' || *sp == '/' || *sp == '}') + break; + + if (*sp == '\\') { + if (sp[1] == '\0') { + xo_failure(xop, "backslash at the end of string"); + return NULL; + } + + /* Anything backslashed is ignored */ + sp += 1; + continue; + } + + if (*sp == ',') { + const char *np; + for (np = ++sp; *np; np++) + if (*np == ':' || *np == '/' || *np == '}' || *np == ',') + break; + + int slen = np - sp; + if (slen > 0) { + xo_xff_flags_t value; + + value = xo_name_lookup(xo_role_names, sp, slen); + if (value) + ftype = value; + else { + value = xo_name_lookup(xo_modifier_names, sp, slen); + if (value) + flags |= value; + else + xo_failure(xop, "unknown keyword ignored: '%.*s'", + slen, sp); + } + } + + sp = np - 1; + continue; + } + + switch (*sp) { + case 'C': + case 'D': + case 'E': + case 'G': + case 'L': + case 'N': + case 'P': + case 'T': + case 'U': + case 'V': + case 'W': + case '[': + case ']': + if (ftype != 0) { + xo_failure(xop, "field descriptor uses multiple types: '%s'", + xo_printable(fmt)); + return NULL; + } + ftype = *sp; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fnum = (fnum * 10) + (*sp - '0'); + break; + + case 'a': + flags |= XFF_ARGUMENT; + break; + + case 'c': + flags |= XFF_COLON; + break; + + case 'd': + flags |= XFF_DISPLAY_ONLY; + break; + + case 'e': + flags |= XFF_ENCODE_ONLY; + break; + + case 'g': + flags |= XFF_GT_FIELD; + break; + + case 'h': + flags |= XFF_HUMANIZE; + break; + + case 'k': + flags |= XFF_KEY; + break; + + case 'l': + flags |= XFF_LEAF_LIST; + break; + + case 'n': + flags |= XFF_NOQUOTE; + break; + + case 'p': + flags |= XFF_GT_PLURAL; + break; + + case 'q': + flags |= XFF_QUOTE; + break; + + case 't': + flags |= XFF_TRIM_WS; + break; + + case 'w': + flags |= XFF_WS; + break; + + default: + xo_failure(xop, "field descriptor uses unknown modifier: '%s'", + xo_printable(fmt)); + /* + * No good answer here; a bad format will likely + * mean a core file. We just return and hope + * the caller notices there's no output, and while + * that seems, well, bad, there's nothing better. + */ + return NULL; + } + + if (ftype == 'N' || ftype == 'U') { + if (flags & XFF_COLON) { + xo_failure(xop, "colon modifier on 'N' or 'U' field ignored: " + "'%s'", xo_printable(fmt)); + flags &= ~XFF_COLON; + } + } + } + + xfip->xfi_flags = flags; + xfip->xfi_ftype = ftype ?: 'V'; + xfip->xfi_fnum = fnum; + + return sp; +} + +/* + * Number any remaining fields that need numbers. Note that some + * field types (text, newline, escaped braces) never get numbers. + */ +static void +xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED, + const char *fmt UNUSED, + xo_field_info_t *fields) +{ + xo_field_info_t *xfip; + unsigned fnum, max_fields; + uint64_t bits = 0; + + /* First make a list of add the explicitly used bits */ + for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) { + switch (xfip->xfi_ftype) { + case XO_ROLE_NEWLINE: /* Don't get numbered */ + case XO_ROLE_TEXT: + case XO_ROLE_EBRACE: + case 'G': + continue; + } + + fnum += 1; + if (fnum >= 63) + break; + + if (xfip->xfi_fnum) + bits |= 1 << xfip->xfi_fnum; + } + + max_fields = fnum; + + for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) { + switch (xfip->xfi_ftype) { + case XO_ROLE_NEWLINE: /* Don't get numbered */ + case XO_ROLE_TEXT: + case XO_ROLE_EBRACE: + case 'G': + continue; + } + + if (xfip->xfi_fnum != 0) + continue; + + /* Find the next unassigned field */ + for (fnum++; bits & (1 << fnum); fnum++) + continue; + + if (fnum > max_fields) + break; + + xfip->xfi_fnum = fnum; /* Mark the field number */ + bits |= 1 << fnum; /* Mark it used */ + } +} + +/* + * The format string uses field numbers, so we need to whiffle through it + * and make sure everything's sane and lovely. + */ +static int +xo_parse_field_numbers (xo_handle_t *xop, const char *fmt, + xo_field_info_t *fields, unsigned num_fields) +{ + xo_field_info_t *xfip; + unsigned field, fnum; + uint64_t bits = 0; + + for (xfip = fields, field = 0; field < num_fields; xfip++, field++) { + /* Fields default to 1:1 with natural position */ + if (xfip->xfi_fnum == 0) + xfip->xfi_fnum = field + 1; + else if (xfip->xfi_fnum > num_fields) { + xo_failure(xop, "field number exceeds number of fields: '%s'", fmt); + return -1; + } + + fnum = xfip->xfi_fnum - 1; /* Move to zero origin */ + if (fnum < 64) { /* Only test what fits */ + if (bits & (1 << fnum)) { + xo_failure(xop, "field number %u reused: '%s'", + xfip->xfi_fnum, fmt); + return -1; + } + bits |= 1 << fnum; + } + } + + return 0; +} + +static int +xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields, + unsigned num_fields, const char *fmt) +{ + const char *cp, *sp, *ep, *basep; + unsigned field = 0; + xo_field_info_t *xfip = fields; + unsigned seen_fnum = 0; + + for (cp = fmt; *cp && field < num_fields; field++, xfip++) { + xfip->xfi_start = cp; + + if (*cp == '\n') { + xfip->xfi_ftype = XO_ROLE_NEWLINE; + xfip->xfi_len = 1; + cp += 1; + continue; + } + + if (*cp != '{') { + /* Normal text */ + for (sp = cp; *sp; sp++) { + if (*sp == '{' || *sp == '\n') + break; + } + + xfip->xfi_ftype = XO_ROLE_TEXT; + xfip->xfi_content = cp; + xfip->xfi_clen = sp - cp; + xfip->xfi_next = sp; + + cp = sp; + continue; + } + + if (cp[1] == '{') { /* Start of {{escaped braces}} */ + xfip->xfi_start = cp + 1; /* Start at second brace */ + xfip->xfi_ftype = XO_ROLE_EBRACE; + + cp += 2; /* Skip over _both_ characters */ + for (sp = cp; *sp; sp++) { + if (*sp == '}' && sp[1] == '}') + break; + } + if (*sp == '\0') { + xo_failure(xop, "missing closing '}}': '%s'", + xo_printable(fmt)); + return -1; + } + + xfip->xfi_len = sp - xfip->xfi_start + 1; + + /* Move along the string, but don't run off the end */ + if (*sp == '}' && sp[1] == '}') + sp += 2; + cp = *sp ? sp : sp; + xfip->xfi_next = cp; + continue; + } + + /* We are looking at the start of a field definition */ + xfip->xfi_start = basep = cp + 1; + + const char *format = NULL; + int flen = 0; + + /* Looking at roles and modifiers */ + sp = xo_parse_roles(xop, fmt, basep, xfip); + if (sp == NULL) { + /* xo_failure has already been called */ + return -1; + } + + if (xfip->xfi_fnum) + seen_fnum = 1; + + /* Looking at content */ + if (*sp == ':') { + for (ep = ++sp; *sp; sp++) { + if (*sp == '}' || *sp == '/') + break; + if (*sp == '\\') { + if (sp[1] == '\0') { + xo_failure(xop, "backslash at the end of string"); + return -1; + } + sp += 1; + continue; + } + } + if (ep != sp) { + xfip->xfi_clen = sp - ep; + xfip->xfi_content = ep; + } + } else { + xo_failure(xop, "missing content (':'): '%s'", xo_printable(fmt)); + return -1; + } + + /* Looking at main (display) format */ + if (*sp == '/') { + for (ep = ++sp; *sp; sp++) { + if (*sp == '}' || *sp == '/') + break; + if (*sp == '\\') { + if (sp[1] == '\0') { + xo_failure(xop, "backslash at the end of string"); + return -1; + } + sp += 1; + continue; + } + } + flen = sp - ep; + format = ep; + } + + /* Looking at encoding format */ + if (*sp == '/') { + for (ep = ++sp; *sp; sp++) { + if (*sp == '}') + break; + } + + xfip->xfi_encoding = ep; + xfip->xfi_elen = sp - ep; + } + + if (*sp != '}') { + xo_failure(xop, "missing closing '}': %s", xo_printable(fmt)); + return -1; + } + + xfip->xfi_len = sp - xfip->xfi_start; + xfip->xfi_next = ++sp; + + /* If we have content, then we have a default format */ + if (xfip->xfi_clen || format || (xfip->xfi_flags & XFF_ARGUMENT)) { + if (format) { + xfip->xfi_format = format; + xfip->xfi_flen = flen; + } else if (xo_role_wants_default_format(xfip->xfi_ftype)) { + xfip->xfi_format = xo_default_format; + xfip->xfi_flen = 2; + } + } + + cp = sp; + } + + int rc = 0; + + /* + * If we saw a field number on at least one field, then we need + * to enforce some rules and/or guidelines. + */ + if (seen_fnum) + rc = xo_parse_field_numbers(xop, fmt, fields, field); + + return rc; +} + +/* + * We are passed a pointer to a format string just past the "{G:}" + * field. We build a simplified version of the format string. + */ +static int +xo_gettext_simplify_format (xo_handle_t *xop UNUSED, + xo_buffer_t *xbp, + xo_field_info_t *fields, + int this_field, + const char *fmt UNUSED, + xo_simplify_field_func_t field_cb) +{ + unsigned ftype; + xo_xff_flags_t flags; + int field = this_field + 1; + xo_field_info_t *xfip; + char ch; + + for (xfip = &fields[field]; xfip->xfi_ftype; xfip++, field++) { + ftype = xfip->xfi_ftype; + flags = xfip->xfi_flags; + + if ((flags & XFF_GT_FIELD) && xfip->xfi_content && ftype != 'V') { + if (field_cb) + field_cb(xfip->xfi_content, xfip->xfi_clen, + (flags & XFF_GT_PLURAL) ? 1 : 0); + } + + switch (ftype) { + case 'G': + /* Ignore gettext roles */ + break; + + case XO_ROLE_NEWLINE: + xo_buf_append(xbp, "\n", 1); + break; + + case XO_ROLE_EBRACE: + xo_buf_append(xbp, "{", 1); + xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen); + xo_buf_append(xbp, "}", 1); + break; + + case XO_ROLE_TEXT: + xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen); + break; + + default: + xo_buf_append(xbp, "{", 1); + if (ftype != 'V') { + ch = ftype; + xo_buf_append(xbp, &ch, 1); + } + + unsigned fnum = xfip->xfi_fnum ?: 0; + if (fnum) { + char num[12]; + /* Field numbers are origin 1, not 0, following printf(3) */ + snprintf(num, sizeof(num), "%u", fnum); + xo_buf_append(xbp, num, strlen(num)); + } + + xo_buf_append(xbp, ":", 1); + xo_buf_append(xbp, xfip->xfi_content, xfip->xfi_clen); + xo_buf_append(xbp, "}", 1); + } + } + + xo_buf_append(xbp, "", 1); + return 0; +} + +void +xo_dump_fields (xo_field_info_t *); /* Fake prototype for debug function */ +void +xo_dump_fields (xo_field_info_t *fields) +{ + xo_field_info_t *xfip; + + for (xfip = fields; xfip->xfi_ftype; xfip++) { + printf("%lu(%u): %lx [%c/%u] [%.*s] [%.*s] [%.*s]\n", + (unsigned long) (xfip - fields), xfip->xfi_fnum, + (unsigned long) xfip->xfi_flags, + isprint((int) xfip->xfi_ftype) ? xfip->xfi_ftype : ' ', + xfip->xfi_ftype, + xfip->xfi_clen, xfip->xfi_content ?: "", + xfip->xfi_flen, xfip->xfi_format ?: "", + xfip->xfi_elen, xfip->xfi_encoding ?: ""); + } +} + +#ifdef HAVE_GETTEXT +/* + * Find the field that matches the given field number + */ +static xo_field_info_t * +xo_gettext_find_field (xo_field_info_t *fields, unsigned fnum) +{ + xo_field_info_t *xfip; + + for (xfip = fields; xfip->xfi_ftype; xfip++) + if (xfip->xfi_fnum == fnum) + return xfip; + + return NULL; +} + +/* + * At this point, we need to consider if the fields have been reordered, + * such as "The {:adjective} {:noun}" to "La {:noun} {:adjective}". + * + * We need to rewrite the new_fields using the old fields order, + * so that we can render the message using the arguments as they + * appear on the stack. It's a lot of work, but we don't really + * want to (eventually) fall into the standard printf code which + * means using the arguments straight (and in order) from the + * varargs we were originally passed. + */ +static void +xo_gettext_rewrite_fields (xo_handle_t *xop UNUSED, + xo_field_info_t *fields, unsigned max_fields) +{ + xo_field_info_t tmp[max_fields]; + bzero(tmp, max_fields * sizeof(tmp[0])); + + unsigned fnum = 0; + xo_field_info_t *newp, *outp, *zp; + for (newp = fields, outp = tmp; newp->xfi_ftype; newp++, outp++) { + switch (newp->xfi_ftype) { + case XO_ROLE_NEWLINE: /* Don't get numbered */ + case XO_ROLE_TEXT: + case XO_ROLE_EBRACE: + case 'G': + *outp = *newp; + outp->xfi_renum = 0; + continue; + } + + zp = xo_gettext_find_field(fields, ++fnum); + if (zp == NULL) { /* Should not occur */ + *outp = *newp; + outp->xfi_renum = 0; + continue; + } + + *outp = *zp; + outp->xfi_renum = newp->xfi_fnum; + } + + memcpy(fields, tmp, max_fields * sizeof(tmp[0])); +} + +/* + * We've got two lists of fields, the old list from the original + * format string and the new one from the parsed gettext reply. The + * new list has the localized words, where the old list has the + * formatting information. We need to combine them into a single list + * (the new list). + * + * If the list needs to be reordered, then we've got more serious work + * to do. + */ +static int +xo_gettext_combine_formats (xo_handle_t *xop, const char *fmt UNUSED, + const char *gtfmt, xo_field_info_t *old_fields, + xo_field_info_t *new_fields, unsigned new_max_fields, + int *reorderedp) +{ + int reordered = 0; + xo_field_info_t *newp, *oldp, *startp = old_fields; + + xo_gettext_finish_numbering_fields(xop, fmt, old_fields); + + for (newp = new_fields; newp->xfi_ftype; newp++) { + switch (newp->xfi_ftype) { + case XO_ROLE_NEWLINE: + case XO_ROLE_TEXT: + case XO_ROLE_EBRACE: + continue; + + case 'V': + for (oldp = startp; oldp->xfi_ftype; oldp++) { + if (oldp->xfi_ftype != 'V') + continue; + if (newp->xfi_clen != oldp->xfi_clen + || strncmp(newp->xfi_content, oldp->xfi_content, + oldp->xfi_clen) != 0) { + reordered = 1; + continue; + } + startp = oldp + 1; + break; + } + + /* Didn't find it on the first pass (starting from start) */ + if (oldp->xfi_ftype == 0) { + for (oldp = old_fields; oldp < startp; oldp++) { + if (oldp->xfi_ftype != 'V') + continue; + if (newp->xfi_clen != oldp->xfi_clen) + continue; + if (strncmp(newp->xfi_content, oldp->xfi_content, + oldp->xfi_clen) != 0) + continue; + reordered = 1; + break; + } + if (oldp == startp) { + /* Field not found */ + xo_failure(xop, "post-gettext format can't find field " + "'%.*s' in format '%s'", + newp->xfi_clen, newp->xfi_content, + xo_printable(gtfmt)); + return -1; + } + } + break; + + default: + /* + * Other fields don't have names for us to use, so if + * the types aren't the same, then we'll have to assume + * the original field is a match. + */ + for (oldp = startp; oldp->xfi_ftype; oldp++) { + if (oldp->xfi_ftype == 'V') /* Can't go past these */ + break; + if (oldp->xfi_ftype == newp->xfi_ftype) + goto copy_it; /* Assumably we have a match */ + } + continue; + } + + /* + * Found a match; copy over appropriate fields + */ + copy_it: + newp->xfi_flags = oldp->xfi_flags; + newp->xfi_fnum = oldp->xfi_fnum; + newp->xfi_format = oldp->xfi_format; + newp->xfi_flen = oldp->xfi_flen; + newp->xfi_encoding = oldp->xfi_encoding; + newp->xfi_elen = oldp->xfi_elen; + } + + *reorderedp = reordered; + if (reordered) { + xo_gettext_finish_numbering_fields(xop, fmt, new_fields); + xo_gettext_rewrite_fields(xop, new_fields, new_max_fields); + } + + return 0; +} + +/* + * We don't want to make gettext() calls here with a complete format + * string, since that means changing a flag would mean a + * labor-intensive re-translation expense. Instead we build a + * simplified form with a reduced level of detail, perform a lookup on + * that string and then re-insert the formating info. + * + * So something like: + * xo_emit("{G:}close {:fd/%ld} returned {g:error/%m} {:test/%6.6s}\n", ...) + * would have a lookup string of: + * "close {:fd} returned {:error} {:test}\n" + * + * We also need to handling reordering of fields, where the gettext() + * reply string uses fields in a different order than the original + * format string: + * "cluse-a {:fd} retoorned {:test}. Bork {:error} Bork. Bork.\n" + * If we have to reorder fields within the message, then things get + * complicated. See xo_gettext_rewrite_fields. + * + * Summary: i18n aighn't cheap. + */ +static const char * +xo_gettext_build_format (xo_handle_t *xop, + xo_field_info_t *fields, int this_field, + const char *fmt, char **new_fmtp) +{ + if (xo_style_is_encoding(xop)) + goto bail; + + xo_buffer_t xb; + xo_buf_init(&xb); + + if (xo_gettext_simplify_format(xop, &xb, fields, + this_field, fmt, NULL)) + goto bail2; + + const char *gtfmt = xo_dgettext(xop, xb.xb_bufp); + if (gtfmt == NULL || gtfmt == fmt || strcmp(gtfmt, fmt) == 0) + goto bail2; + + xo_buf_cleanup(&xb); + + char *new_fmt = xo_strndup(gtfmt, -1); + if (new_fmt == NULL) + goto bail2; + + *new_fmtp = new_fmt; + return new_fmt; + + bail2: + xo_buf_cleanup(&xb); + bail: + *new_fmtp = NULL; + return fmt; +} + +static void +xo_gettext_rebuild_content (xo_handle_t *xop, xo_field_info_t *fields, + unsigned *fstart, unsigned min_fstart, + unsigned *fend, unsigned max_fend) +{ + xo_field_info_t *xfip; + char *buf; + unsigned base = fstart[min_fstart]; + unsigned blen = fend[max_fend] - base; + xo_buffer_t *xbp = &xop->xo_data; + + if (blen == 0) + return; + + buf = xo_realloc(NULL, blen); + if (buf == NULL) + return; + + memcpy(buf, xbp->xb_bufp + fstart[min_fstart], blen); /* Copy our data */ + + unsigned field = min_fstart, soff, doff = base, len, fnum; + xo_field_info_t *zp; + + /* + * Be aware there are two competing views of "field number": we + * want the user to thing in terms of "The {1:size}" where {G:}, + * newlines, escaped braces, and text don't have numbers. But is + * also the internal view, where we have an array of + * xo_field_info_t and every field have an index. fnum, fstart[] + * and fend[] are the latter, but xfi_renum is the former. + */ + for (xfip = fields + field; xfip->xfi_ftype; xfip++, field++) { + fnum = field; + if (xfip->xfi_renum) { + zp = xo_gettext_find_field(fields, xfip->xfi_renum); + fnum = zp ? zp - fields : field; + } + + soff = fstart[fnum]; + len = fend[fnum] - soff; + + if (len > 0) { + soff -= base; + memcpy(xbp->xb_bufp + doff, buf + soff, len); + doff += len; + } + } + + xo_free(buf); +} +#else /* HAVE_GETTEXT */ +static const char * +xo_gettext_build_format (xo_handle_t *xop UNUSED, + xo_field_info_t *fields UNUSED, + int this_field UNUSED, + const char *fmt UNUSED, char **new_fmtp) +{ + *new_fmtp = NULL; + return fmt; +} + +static int +xo_gettext_combine_formats (xo_handle_t *xop UNUSED, const char *fmt UNUSED, + const char *gtfmt UNUSED, + xo_field_info_t *old_fields UNUSED, + xo_field_info_t *new_fields UNUSED, + unsigned new_max_fields UNUSED, + int *reorderedp UNUSED) +{ + return -1; +} + +static void +xo_gettext_rebuild_content (xo_handle_t *xop UNUSED, + xo_field_info_t *fields UNUSED, + unsigned *fstart UNUSED, unsigned min_fstart UNUSED, + unsigned *fend UNUSED, unsigned max_fend UNUSED) +{ + return; +} +#endif /* HAVE_GETTEXT */ + +/* + * Emit a set of fields. This is really the core of libxo. + */ +static int +xo_do_emit_fields (xo_handle_t *xop, xo_field_info_t *fields, + unsigned max_fields, const char *fmt) +{ + int gettext_inuse = 0; + int gettext_changed = 0; + int gettext_reordered = 0; + unsigned ftype; + xo_xff_flags_t flags; + xo_field_info_t *new_fields = NULL; + xo_field_info_t *xfip; + unsigned field; + int rc = 0; + + int flush = XOF_ISSET(xop, XOF_FLUSH); + int flush_line = XOF_ISSET(xop, XOF_FLUSH_LINE); + char *new_fmt = NULL; + + if (XOIF_ISSET(xop, XOIF_REORDER) || xo_style(xop) == XO_STYLE_ENCODER) + flush_line = 0; + + /* + * Some overhead for gettext; if the fields in the msgstr returned + * by gettext are reordered, then we need to record start and end + * for each field. We'll go ahead and render the fields in the + * normal order, but later we can then reconstruct the reordered + * fields using these fstart/fend values. + */ + unsigned flimit = max_fields * 2; /* Pessimistic limit */ + unsigned min_fstart = flimit - 1; + unsigned max_fend = 0; /* Highest recorded fend[] entry */ + unsigned fstart[flimit]; + bzero(fstart, flimit * sizeof(fstart[0])); + unsigned fend[flimit]; + bzero(fend, flimit * sizeof(fend[0])); + + for (xfip = fields, field = 0; xfip->xfi_ftype && field < max_fields; + xfip++, field++) { + ftype = xfip->xfi_ftype; + flags = xfip->xfi_flags; + + /* Record field start offset */ + if (gettext_reordered) { + fstart[field] = xo_buf_offset(&xop->xo_data); + if (min_fstart > field) + min_fstart = field; + } + + const char *content = xfip->xfi_content; + int clen = xfip->xfi_clen; + + if (flags & XFF_ARGUMENT) { + /* + * Argument flag means the content isn't given in the descriptor, + * but as a UTF-8 string ('const char *') argument in xo_vap. + */ + content = va_arg(xop->xo_vap, char *); + clen = content ? strlen(content) : 0; + } + + if (ftype == XO_ROLE_NEWLINE) { + xo_line_close(xop); + if (flush_line && xo_flush_h(xop) < 0) + return -1; + goto bottom; + + } else if (ftype == XO_ROLE_EBRACE) { + xo_format_text(xop, xfip->xfi_start, xfip->xfi_len); + goto bottom; + + } else if (ftype == XO_ROLE_TEXT) { + /* Normal text */ + xo_format_text(xop, xfip->xfi_content, xfip->xfi_clen); + goto bottom; + } + + /* + * Notes and units need the 'w' flag handled before the content. + */ + if (ftype == 'N' || ftype == 'U') { + if (flags & XFF_WS) { + xo_format_content(xop, "padding", NULL, " ", 1, + NULL, 0, flags); + flags &= ~XFF_WS; /* Block later handling of this */ + } + } + + if (ftype == 'V') + xo_format_value(xop, content, clen, + xfip->xfi_format, xfip->xfi_flen, + xfip->xfi_encoding, xfip->xfi_elen, flags); + else if (ftype == '[') + xo_anchor_start(xop, xfip, content, clen); + else if (ftype == ']') + xo_anchor_stop(xop, xfip, content, clen); + else if (ftype == 'C') + xo_format_colors(xop, xfip, content, clen); + + else if (ftype == 'G') { + /* + * A {G:domain} field; disect the domain name and translate + * the remaining portion of the input string. If the user + * didn't put the {G:} at the start of the format string, then + * assumably they just want us to translate the rest of it. + * Since gettext returns strings in a static buffer, we make + * a copy in new_fmt. + */ + xo_set_gettext_domain(xop, xfip, content, clen); + + if (!gettext_inuse) { /* Only translate once */ + gettext_inuse = 1; + if (new_fmt) { + xo_free(new_fmt); + new_fmt = NULL; + } + + xo_gettext_build_format(xop, fields, field, + xfip->xfi_next, &new_fmt); + if (new_fmt) { + gettext_changed = 1; + + unsigned new_max_fields = xo_count_fields(xop, new_fmt); + + if (++new_max_fields < max_fields) + new_max_fields = max_fields; + + /* Leave a blank slot at the beginning */ + int sz = (new_max_fields + 1) * sizeof(xo_field_info_t); + new_fields = alloca(sz); + bzero(new_fields, sz); + + if (!xo_parse_fields(xop, new_fields + 1, + new_max_fields, new_fmt)) { + gettext_reordered = 0; + + if (!xo_gettext_combine_formats(xop, fmt, new_fmt, + fields, new_fields + 1, + new_max_fields, &gettext_reordered)) { + + if (gettext_reordered) { + if (XOF_ISSET(xop, XOF_LOG_GETTEXT)) + xo_failure(xop, "gettext finds reordered " + "fields in '%s' and '%s'", + xo_printable(fmt), + xo_printable(new_fmt)); + flush_line = 0; /* Must keep at content */ + XOIF_SET(xop, XOIF_REORDER); + } + + field = -1; /* Will be incremented at top of loop */ + xfip = new_fields; + max_fields = new_max_fields; + } + } + } + } + continue; + + } else if (clen || xfip->xfi_format) { + + const char *class_name = xo_class_name(ftype); + if (class_name) + xo_format_content(xop, class_name, xo_tag_name(ftype), + content, clen, + xfip->xfi_format, xfip->xfi_flen, flags); + else if (ftype == 'T') + xo_format_title(xop, xfip, content, clen); + else if (ftype == 'U') + xo_format_units(xop, xfip, content, clen); + else + xo_failure(xop, "unknown field type: '%c'", ftype); + } + + if (flags & XFF_COLON) + xo_format_content(xop, "decoration", NULL, ":", 1, NULL, 0, 0); + + if (flags & XFF_WS) + xo_format_content(xop, "padding", NULL, " ", 1, NULL, 0, 0); + + bottom: + /* Record the end-of-field offset */ + if (gettext_reordered) { + fend[field] = xo_buf_offset(&xop->xo_data); + max_fend = field; + } + } + + if (gettext_changed && gettext_reordered) { + /* Final step: rebuild the content using the rendered fields */ + xo_gettext_rebuild_content(xop, new_fields + 1, fstart, min_fstart, + fend, max_fend); + } + + XOIF_CLEAR(xop, XOIF_REORDER); + + /* + * If we've got enough data, flush it. + */ + if (xo_buf_offset(&xop->xo_data) > XO_BUF_HIGH_WATER) + flush = 1; + + /* If we don't have an anchor, write the text out */ + if (flush && !XOIF_ISSET(xop, XOIF_ANCHOR)) { + if (xo_write(xop) < 0) + rc = -1; /* Report failure */ + else if (xo_flush_h(xop) < 0) + rc = -1; + } + + if (new_fmt) + xo_free(new_fmt); + + /* + * We've carried the gettext domainname inside our handle just for + * convenience, but we need to ensure it doesn't survive across + * xo_emit calls. + */ + if (xop->xo_gt_domain) { + xo_free(xop->xo_gt_domain); + xop->xo_gt_domain = NULL; + } + + return (rc < 0) ? rc : (int) xop->xo_columns; +} + +/* + * Parse and emit a set of fields + */ +static int +xo_do_emit (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt) +{ + xop->xo_columns = 0; /* Always reset it */ + xop->xo_errno = errno; /* Save for "%m" */ + + if (fmt == NULL) + return 0; + + unsigned max_fields; + xo_field_info_t *fields = NULL; + + /* Adjust XOEF_RETAIN based on global flags */ + if (XOF_ISSET(xop, XOF_RETAIN_ALL)) + flags |= XOEF_RETAIN; + if (XOF_ISSET(xop, XOF_RETAIN_NONE)) + flags &= ~XOEF_RETAIN; + + /* + * Check for 'retain' flag, telling us to retain the field + * information. If we've already saved it, then we can avoid + * re-parsing the format string. + */ + if (!(flags & XOEF_RETAIN) + || xo_retain_find(fmt, &fields, &max_fields) != 0 + || fields == NULL) { + + /* Nothing retained; parse the format string */ + max_fields = xo_count_fields(xop, fmt); + fields = alloca(max_fields * sizeof(fields[0])); + bzero(fields, max_fields * sizeof(fields[0])); + + if (xo_parse_fields(xop, fields, max_fields, fmt)) + return -1; /* Warning already displayed */ + + if (flags & XOEF_RETAIN) { + /* Retain the info */ + xo_retain_add(fmt, fields, max_fields); + } + } + + return xo_do_emit_fields(xop, fields, max_fields, fmt); +} + +/* + * Rebuild a format string in a gettext-friendly format. This function + * is exposed to tools can perform this function. See xo(1). + */ +char * +xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers, + xo_simplify_field_func_t field_cb) +{ + xop = xo_default(xop); + + xop->xo_columns = 0; /* Always reset it */ + xop->xo_errno = errno; /* Save for "%m" */ + + unsigned max_fields = xo_count_fields(xop, fmt); + xo_field_info_t fields[max_fields]; + + bzero(fields, max_fields * sizeof(fields[0])); + + if (xo_parse_fields(xop, fields, max_fields, fmt)) + return NULL; /* Warning already displayed */ + + xo_buffer_t xb; + xo_buf_init(&xb); + + if (with_numbers) + xo_gettext_finish_numbering_fields(xop, fmt, fields); + + if (xo_gettext_simplify_format(xop, &xb, fields, -1, fmt, field_cb)) + return NULL; + + return xb.xb_bufp; +} + +int +xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap) +{ + int rc; + + xop = xo_default(xop); + va_copy(xop->xo_vap, vap); + rc = xo_do_emit(xop, 0, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +int +xo_emit_h (xo_handle_t *xop, const char *fmt, ...) +{ + int rc; + + xop = xo_default(xop); + va_start(xop->xo_vap, fmt); + rc = xo_do_emit(xop, 0, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +int +xo_emit (const char *fmt, ...) +{ + xo_handle_t *xop = xo_default(NULL); + int rc; + + va_start(xop->xo_vap, fmt); + rc = xo_do_emit(xop, 0, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +int +xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags, + const char *fmt, va_list vap) +{ + int rc; + + xop = xo_default(xop); + va_copy(xop->xo_vap, vap); + rc = xo_do_emit(xop, flags, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +int +xo_emit_hf (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...) +{ + int rc; + + xop = xo_default(xop); + va_start(xop->xo_vap, fmt); + rc = xo_do_emit(xop, flags, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +int +xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...) +{ + xo_handle_t *xop = xo_default(NULL); + int rc; + + va_start(xop->xo_vap, fmt); + rc = xo_do_emit(xop, flags, fmt); + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + + return rc; +} + +/* + * Emit a single field by providing the info information typically provided + * inside the field description (role, modifiers, and formats). This is + * a convenience function to avoid callers using snprintf to build field + * descriptions. + */ +int +xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents, + const char *fmt, const char *efmt, + va_list vap) +{ + int rc; + + xop = xo_default(xop); + + if (rolmod == NULL) + rolmod = "V"; + + xo_field_info_t xfi; + + bzero(&xfi, sizeof(xfi)); + + const char *cp; + cp = xo_parse_roles(xop, rolmod, rolmod, &xfi); + if (cp == NULL) + return -1; + + xfi.xfi_start = fmt; + xfi.xfi_content = contents; + xfi.xfi_format = fmt; + xfi.xfi_encoding = efmt; + xfi.xfi_clen = contents ? strlen(contents) : 0; + xfi.xfi_flen = fmt ? strlen(fmt) : 0; + xfi.xfi_elen = efmt ? strlen(efmt) : 0; + + /* If we have content, then we have a default format */ + if (contents && fmt == NULL + && xo_role_wants_default_format(xfi.xfi_ftype)) { + xfi.xfi_format = xo_default_format; + xfi.xfi_flen = 2; + } + + + + va_copy(xop->xo_vap, vap); + + rc = xo_do_emit_fields(xop, &xfi, 1, fmt ?: contents ?: "field"); + + va_end(xop->xo_vap); + + return rc; +} + +int +xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, + const char *fmt, const char *efmt, ...) +{ + int rc; + va_list vap; + + va_start(vap, efmt); + rc = xo_emit_field_hv(xop, rolmod, contents, fmt, efmt, vap); + va_end(vap); + + return rc; +} + +int +xo_emit_field (const char *rolmod, const char *contents, + const char *fmt, const char *efmt, ...) +{ + int rc; + va_list vap; + + va_start(vap, efmt); + rc = xo_emit_field_hv(NULL, rolmod, contents, fmt, efmt, vap); + va_end(vap); + + return rc; +} + +int +xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap) +{ + const int extra = 5; /* space, equals, quote, quote, and nul */ + xop = xo_default(xop); + + int rc = 0; + int nlen = strlen(name); + xo_buffer_t *xbp = &xop->xo_attrs; + unsigned name_offset, value_offset; + + switch (xo_style(xop)) { + case XO_STYLE_XML: + if (!xo_buf_has_room(xbp, nlen + extra)) + return -1; + + *xbp->xb_curp++ = ' '; + memcpy(xbp->xb_curp, name, nlen); + xbp->xb_curp += nlen; + *xbp->xb_curp++ = '='; + *xbp->xb_curp++ = '"'; + + rc = xo_vsnprintf(xop, xbp, fmt, vap); + + if (rc >= 0) { + rc = xo_escape_xml(xbp, rc, 1); + xbp->xb_curp += rc; + } + + if (!xo_buf_has_room(xbp, 2)) + return -1; + + *xbp->xb_curp++ = '"'; + *xbp->xb_curp = '\0'; + + rc += nlen + extra; + break; + + case XO_STYLE_ENCODER: + name_offset = xo_buf_offset(xbp); + xo_buf_append(xbp, name, nlen); + xo_buf_append(xbp, "", 1); + + value_offset = xo_buf_offset(xbp); + rc = xo_vsnprintf(xop, xbp, fmt, vap); + if (rc >= 0) { + xbp->xb_curp += rc; + *xbp->xb_curp = '\0'; + rc = xo_encoder_handle(xop, XO_OP_ATTRIBUTE, + xo_buf_data(xbp, name_offset), + xo_buf_data(xbp, value_offset)); + } + } + + return rc; +} + +int +xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...) +{ + int rc; + va_list vap; + + va_start(vap, fmt); + rc = xo_attr_hv(xop, name, fmt, vap); + va_end(vap); + + return rc; +} + +int +xo_attr (const char *name, const char *fmt, ...) +{ + int rc; + va_list vap; + + va_start(vap, fmt); + rc = xo_attr_hv(NULL, name, fmt, vap); + va_end(vap); + + return rc; +} + +static void +xo_stack_set_flags (xo_handle_t *xop) +{ + if (XOF_ISSET(xop, XOF_NOT_FIRST)) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + xsp->xs_flags |= XSF_NOT_FIRST; + XOF_CLEAR(xop, XOF_NOT_FIRST); + } +} + +static void +xo_depth_change (xo_handle_t *xop, const char *name, + int delta, int indent, xo_state_t state, xo_xsf_flags_t flags) +{ + if (xo_style(xop) == XO_STYLE_HTML || xo_style(xop) == XO_STYLE_TEXT) + indent = 0; + + if (XOF_ISSET(xop, XOF_DTRT)) + flags |= XSF_DTRT; + + if (delta >= 0) { /* Push operation */ + if (xo_depth_check(xop, xop->xo_depth + delta)) + return; + + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth + delta]; + xsp->xs_flags = flags; + xsp->xs_state = state; + xo_stack_set_flags(xop); + + if (name == NULL) + name = XO_FAILURE_NAME; + + xsp->xs_name = xo_strndup(name, -1); + + } else { /* Pop operation */ + if (xop->xo_depth == 0) { + if (!XOF_ISSET(xop, XOF_IGNORE_CLOSE)) + xo_failure(xop, "close with empty stack: '%s'", name); + return; + } + + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + if (XOF_ISSET(xop, XOF_WARN)) { + const char *top = xsp->xs_name; + if (top && strcmp(name, top) != 0) { + xo_failure(xop, "incorrect close: '%s' .vs. '%s'", + name, top); + return; + } + if ((xsp->xs_flags & XSF_LIST) != (flags & XSF_LIST)) { + xo_failure(xop, "list close on list confict: '%s'", + name); + return; + } + if ((xsp->xs_flags & XSF_INSTANCE) != (flags & XSF_INSTANCE)) { + xo_failure(xop, "list close on instance confict: '%s'", + name); + return; + } + } + + if (xsp->xs_name) { + xo_free(xsp->xs_name); + xsp->xs_name = NULL; + } + if (xsp->xs_keys) { + xo_free(xsp->xs_keys); + xsp->xs_keys = NULL; + } + } + + xop->xo_depth += delta; /* Record new depth */ + xop->xo_indent += indent; +} + +void +xo_set_depth (xo_handle_t *xop, int depth) +{ + xop = xo_default(xop); + + if (xo_depth_check(xop, depth)) + return; + + xop->xo_depth += depth; + xop->xo_indent += depth; +} + +static xo_xsf_flags_t +xo_stack_flags (unsigned xflags) +{ + if (xflags & XOF_DTRT) + return XSF_DTRT; + return 0; +} + +static void +xo_emit_top (xo_handle_t *xop, const char *ppn) +{ + xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn); + XOIF_SET(xop, XOIF_TOP_EMITTED); + + if (xop->xo_version) { + xo_printf(xop, "%*s\"__version\": \"%s\", %s", + xo_indent(xop), "", xop->xo_version, ppn); + xo_free(xop->xo_version); + xop->xo_version = NULL; + } +} + +static int +xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) +{ + int rc = 0; + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + if (name == NULL) { + xo_failure(xop, "NULL passed for container name"); + name = XO_FAILURE_NAME; + } + + flags |= xop->xo_flags; /* Pick up handle flags */ + + switch (xo_style(xop)) { + case XO_STYLE_XML: + rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name); + + if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) { + rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp; + xo_data_append(xop, xop->xo_attrs.xb_bufp, + xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp); + xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp; + } + + rc += xo_printf(xop, ">%s", ppn); + break; + + case XO_STYLE_JSON: + xo_stack_set_flags(xop); + + if (!XOF_ISSET(xop, XOF_NO_TOP) + && !XOIF_ISSET(xop, XOIF_TOP_EMITTED)) + xo_emit_top(xop, ppn); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s\"%s\": {%s", + pre_nl, xo_indent(xop), "", name, ppn); + break; + + case XO_STYLE_SDPARAMS: + break; + + case XO_STYLE_ENCODER: + rc = xo_encoder_handle(xop, XO_OP_OPEN_CONTAINER, name, NULL); + break; + } + + xo_depth_change(xop, name, 1, 1, XSS_OPEN_CONTAINER, + xo_stack_flags(flags)); + + return rc; +} + +static int +xo_open_container_hf (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_CONTAINER); +} + +int +xo_open_container_h (xo_handle_t *xop, const char *name) +{ + return xo_open_container_hf(xop, 0, name); +} + +int +xo_open_container (const char *name) +{ + return xo_open_container_hf(NULL, 0, name); +} + +int +xo_open_container_hd (xo_handle_t *xop, const char *name) +{ + return xo_open_container_hf(xop, XOF_DTRT, name); +} + +int +xo_open_container_d (const char *name) +{ + return xo_open_container_hf(NULL, XOF_DTRT, name); +} + +static int +xo_do_close_container (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + int rc = 0; + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + if (name == NULL) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + name = xsp->xs_name; + if (name) { + int len = strlen(name) + 1; + /* We need to make a local copy; xo_depth_change will free it */ + char *cp = alloca(len); + memcpy(cp, name, len); + name = cp; + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); + name = XO_FAILURE_NAME; + } + } + + switch (xo_style(xop)) { + case XO_STYLE_XML: + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0); + rc = xo_printf(xop, "%*s</%s>%s", xo_indent(xop), "", name, ppn); + break; + + case XO_STYLE_JSON: + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + ppn = (xop->xo_depth <= 1) ? "\n" : ""; + + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0); + rc = xo_printf(xop, "%s%*s}%s", pre_nl, xo_indent(xop), "", ppn); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + + case XO_STYLE_HTML: + case XO_STYLE_TEXT: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0); + break; + + case XO_STYLE_SDPARAMS: + break; + + case XO_STYLE_ENCODER: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0); + rc = xo_encoder_handle(xop, XO_OP_CLOSE_CONTAINER, name, NULL); + break; + } + + return rc; +} + +int +xo_close_container_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_CONTAINER); +} + +int +xo_close_container (const char *name) +{ + return xo_close_container_h(NULL, name); +} + +int +xo_close_container_hd (xo_handle_t *xop) +{ + return xo_close_container_h(xop, NULL); +} + +int +xo_close_container_d (void) +{ + return xo_close_container_h(NULL, NULL); +} + +static int +xo_do_open_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + int rc = 0; + int indent = 0; + + xop = xo_default(xop); + + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + switch (xo_style(xop)) { + case XO_STYLE_JSON: + + indent = 1; + if (!XOF_ISSET(xop, XOF_NO_TOP) + && !XOIF_ISSET(xop, XOIF_TOP_EMITTED)) + xo_emit_top(xop, ppn); + + if (name == NULL) { + xo_failure(xop, "NULL passed for list name"); + name = XO_FAILURE_NAME; + } + + xo_stack_set_flags(xop); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s\"%s\": [%s", + pre_nl, xo_indent(xop), "", name, ppn); + break; + + case XO_STYLE_ENCODER: + rc = xo_encoder_handle(xop, XO_OP_OPEN_LIST, name, NULL); + break; + } + + xo_depth_change(xop, name, 1, indent, XSS_OPEN_LIST, + XSF_LIST | xo_stack_flags(flags)); + + return rc; +} + +static int +xo_open_list_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_LIST); +} + +int +xo_open_list_h (xo_handle_t *xop, const char *name) +{ + return xo_open_list_hf(xop, 0, name); +} + +int +xo_open_list (const char *name) +{ + return xo_open_list_hf(NULL, 0, name); +} + +int +xo_open_list_hd (xo_handle_t *xop, const char *name) +{ + return xo_open_list_hf(xop, XOF_DTRT, name); +} + +int +xo_open_list_d (const char *name) +{ + return xo_open_list_hf(NULL, XOF_DTRT, name); +} + +static int +xo_do_close_list (xo_handle_t *xop, const char *name) +{ + int rc = 0; + const char *pre_nl = ""; + + if (name == NULL) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + name = xsp->xs_name; + if (name) { + int len = strlen(name) + 1; + /* We need to make a local copy; xo_depth_change will free it */ + char *cp = alloca(len); + memcpy(cp, name, len); + name = cp; + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); + name = XO_FAILURE_NAME; + } + } + + switch (xo_style(xop)) { + case XO_STYLE_JSON: + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LIST, XSF_LIST); + rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), ""); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + + case XO_STYLE_ENCODER: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST); + rc = xo_encoder_handle(xop, XO_OP_CLOSE_LIST, name, NULL); + break; + + default: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + } + + return rc; +} + +int +xo_close_list_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_LIST); +} + +int +xo_close_list (const char *name) +{ + return xo_close_list_h(NULL, name); +} + +int +xo_close_list_hd (xo_handle_t *xop) +{ + return xo_close_list_h(xop, NULL); +} + +int +xo_close_list_d (void) +{ + return xo_close_list_h(NULL, NULL); +} + +static int +xo_do_open_leaf_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + int rc = 0; + int indent = 0; + + xop = xo_default(xop); + + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + switch (xo_style(xop)) { + case XO_STYLE_JSON: + indent = 1; + + if (!XOF_ISSET(xop, XOF_NO_TOP)) { + if (!XOIF_ISSET(xop, XOIF_TOP_EMITTED)) { + xo_printf(xop, "%*s{%s", xo_indent(xop), "", ppn); + XOIF_SET(xop, XOIF_TOP_EMITTED); + } + } + + if (name == NULL) { + xo_failure(xop, "NULL passed for list name"); + name = XO_FAILURE_NAME; + } + + xo_stack_set_flags(xop); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s\"%s\": [%s", + pre_nl, xo_indent(xop), "", name, ppn); + break; + + case XO_STYLE_ENCODER: + rc = xo_encoder_handle(xop, XO_OP_OPEN_LEAF_LIST, name, NULL); + break; + } + + xo_depth_change(xop, name, 1, indent, XSS_OPEN_LEAF_LIST, + XSF_LIST | xo_stack_flags(flags)); + + return rc; +} + +static int +xo_do_close_leaf_list (xo_handle_t *xop, const char *name) +{ + int rc = 0; + const char *pre_nl = ""; + + if (name == NULL) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + name = xsp->xs_name; + if (name) { + int len = strlen(name) + 1; + /* We need to make a local copy; xo_depth_change will free it */ + char *cp = alloca(len); + memcpy(cp, name, len); + name = cp; + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); + name = XO_FAILURE_NAME; + } + } + + switch (xo_style(xop)) { + case XO_STYLE_JSON: + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_LEAF_LIST, XSF_LIST); + rc = xo_printf(xop, "%s%*s]", pre_nl, xo_indent(xop), ""); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + + case XO_STYLE_ENCODER: + rc = xo_encoder_handle(xop, XO_OP_CLOSE_LEAF_LIST, name, NULL); + /* FALLTHRU */ + + default: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LEAF_LIST, XSF_LIST); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + } + + return rc; +} + +static int +xo_do_open_instance (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + xop = xo_default(xop); + + int rc = 0; + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + flags |= xop->xo_flags; + + if (name == NULL) { + xo_failure(xop, "NULL passed for instance name"); + name = XO_FAILURE_NAME; + } + + switch (xo_style(xop)) { + case XO_STYLE_XML: + rc = xo_printf(xop, "%*s<%s", xo_indent(xop), "", name); + + if (xop->xo_attrs.xb_curp != xop->xo_attrs.xb_bufp) { + rc += xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp; + xo_data_append(xop, xop->xo_attrs.xb_bufp, + xop->xo_attrs.xb_curp - xop->xo_attrs.xb_bufp); + xop->xo_attrs.xb_curp = xop->xo_attrs.xb_bufp; + } + + rc += xo_printf(xop, ">%s", ppn); + break; + + case XO_STYLE_JSON: + xo_stack_set_flags(xop); + + if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST) + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + + rc = xo_printf(xop, "%s%*s{%s", + pre_nl, xo_indent(xop), "", ppn); + break; + + case XO_STYLE_SDPARAMS: + break; + + case XO_STYLE_ENCODER: + rc = xo_encoder_handle(xop, XO_OP_OPEN_INSTANCE, name, NULL); + break; + } + + xo_depth_change(xop, name, 1, 1, XSS_OPEN_INSTANCE, xo_stack_flags(flags)); + + return rc; +} + +static int +xo_open_instance_hf (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name) +{ + return xo_transition(xop, flags, name, XSS_OPEN_INSTANCE); +} + +int +xo_open_instance_h (xo_handle_t *xop, const char *name) +{ + return xo_open_instance_hf(xop, 0, name); +} + +int +xo_open_instance (const char *name) +{ + return xo_open_instance_hf(NULL, 0, name); +} + +int +xo_open_instance_hd (xo_handle_t *xop, const char *name) +{ + return xo_open_instance_hf(xop, XOF_DTRT, name); +} + +int +xo_open_instance_d (const char *name) +{ + return xo_open_instance_hf(NULL, XOF_DTRT, name); +} + +static int +xo_do_close_instance (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + int rc = 0; + const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + const char *pre_nl = ""; + + if (name == NULL) { + xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; + + name = xsp->xs_name; + if (name) { + int len = strlen(name) + 1; + /* We need to make a local copy; xo_depth_change will free it */ + char *cp = alloca(len); + memcpy(cp, name, len); + name = cp; + } else if (!(xsp->xs_flags & XSF_DTRT)) { + xo_failure(xop, "missing name without 'dtrt' mode"); + name = XO_FAILURE_NAME; + } + } + + switch (xo_style(xop)) { + case XO_STYLE_XML: + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0); + rc = xo_printf(xop, "%*s</%s>%s", xo_indent(xop), "", name, ppn); + break; + + case XO_STYLE_JSON: + pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; + + xo_depth_change(xop, name, -1, -1, XSS_CLOSE_INSTANCE, 0); + rc = xo_printf(xop, "%s%*s}", pre_nl, xo_indent(xop), ""); + xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + break; + + case XO_STYLE_HTML: + case XO_STYLE_TEXT: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0); + break; + + case XO_STYLE_SDPARAMS: + break; + + case XO_STYLE_ENCODER: + xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0); + rc = xo_encoder_handle(xop, XO_OP_CLOSE_INSTANCE, name, NULL); + break; + } + + return rc; +} + +int +xo_close_instance_h (xo_handle_t *xop, const char *name) +{ + return xo_transition(xop, 0, name, XSS_CLOSE_INSTANCE); +} + +int +xo_close_instance (const char *name) +{ + return xo_close_instance_h(NULL, name); +} + +int +xo_close_instance_hd (xo_handle_t *xop) +{ + return xo_close_instance_h(xop, NULL); +} + +int +xo_close_instance_d (void) +{ + return xo_close_instance_h(NULL, NULL); +} + +static int +xo_do_close_all (xo_handle_t *xop, xo_stack_t *limit) +{ + xo_stack_t *xsp; + int rc = 0; + xo_xsf_flags_t flags; + + for (xsp = &xop->xo_stack[xop->xo_depth]; xsp >= limit; xsp--) { + switch (xsp->xs_state) { + case XSS_INIT: + /* Nothing */ + rc = 0; + break; + + case XSS_OPEN_CONTAINER: + rc = xo_do_close_container(xop, NULL); + break; + + case XSS_OPEN_LIST: + rc = xo_do_close_list(xop, NULL); + break; + + case XSS_OPEN_INSTANCE: + rc = xo_do_close_instance(xop, NULL); + break; + + case XSS_OPEN_LEAF_LIST: + rc = xo_do_close_leaf_list(xop, NULL); + break; + + case XSS_MARKER: + flags = xsp->xs_flags & XSF_MARKER_FLAGS; + xo_depth_change(xop, xsp->xs_name, -1, 0, XSS_MARKER, 0); + xop->xo_stack[xop->xo_depth].xs_flags |= flags; + rc = 0; + break; + } + + if (rc < 0) + xo_failure(xop, "close %d failed: %d", xsp->xs_state, rc); + } + + return 0; +} + +/* + * This function is responsible for clearing out whatever is needed + * to get to the desired state, if possible. + */ +static int +xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state) +{ + xo_stack_t *xsp, *limit = NULL; + int rc; + xo_state_t need_state = new_state; + + if (new_state == XSS_CLOSE_CONTAINER) + need_state = XSS_OPEN_CONTAINER; + else if (new_state == XSS_CLOSE_LIST) + need_state = XSS_OPEN_LIST; + else if (new_state == XSS_CLOSE_INSTANCE) + need_state = XSS_OPEN_INSTANCE; + else if (new_state == XSS_CLOSE_LEAF_LIST) + need_state = XSS_OPEN_LEAF_LIST; + else if (new_state == XSS_MARKER) + need_state = XSS_MARKER; + else + return 0; /* Unknown or useless new states are ignored */ + + for (xsp = &xop->xo_stack[xop->xo_depth]; xsp > xop->xo_stack; xsp--) { + /* + * Marker's normally stop us from going any further, unless + * we are popping a marker (new_state == XSS_MARKER). + */ + if (xsp->xs_state == XSS_MARKER && need_state != XSS_MARKER) { + if (name) { + xo_failure(xop, "close (xo_%s) fails at marker '%s'; " + "not found '%s'", + xo_state_name(new_state), + xsp->xs_name, name); + return 0; + + } else { + limit = xsp; + xo_failure(xop, "close stops at marker '%s'", xsp->xs_name); + } + break; + } + + if (xsp->xs_state != need_state) + continue; + + if (name && xsp->xs_name && strcmp(name, xsp->xs_name) != 0) + continue; + + limit = xsp; + break; + } + + if (limit == NULL) { + xo_failure(xop, "xo_%s can't find match for '%s'", + xo_state_name(new_state), name); + return 0; + } + + rc = xo_do_close_all(xop, limit); + + return rc; +} + +/* + * We are in a given state and need to transition to the new state. + */ +static int +xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name, + xo_state_t new_state) +{ + xo_stack_t *xsp; + int rc; + int old_state, on_marker; + + xop = xo_default(xop); + + rc = 0; + xsp = &xop->xo_stack[xop->xo_depth]; + old_state = xsp->xs_state; + on_marker = (old_state == XSS_MARKER); + + /* If there's a marker on top of the stack, we need to find a real state */ + while (old_state == XSS_MARKER) { + if (xsp == xop->xo_stack) + break; + xsp -= 1; + old_state = xsp->xs_state; + } + + /* + * At this point, the list of possible states are: + * XSS_INIT, XSS_OPEN_CONTAINER, XSS_OPEN_LIST, + * XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST, XSS_DISCARDING + */ + switch (XSS_TRANSITION(old_state, new_state)) { + + open_container: + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_CONTAINER): + rc = xo_do_open_container(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_container; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_container; + break; + + /*close_container:*/ + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_CONTAINER): + /* This is an exception for "xo --close" */ + rc = xo_do_close_container(xop, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_CONTAINER): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_CONTAINER): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + rc = xo_do_close(xop, name, new_state); + break; + + open_list: + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LIST): + rc = xo_do_open_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_list; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_list; + break; + + /*close_list:*/ + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LIST): + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LIST): + rc = xo_do_close(xop, name, new_state); + break; + + open_instance: + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_INSTANCE): + rc = xo_do_open_instance(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_INSTANCE): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_INSTANCE): + rc = xo_do_open_list(xop, flags, name); + if (rc >= 0) + goto open_instance; + break; + + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_INSTANCE): + if (on_marker) { + rc = xo_do_open_list(xop, flags, name); + } else { + rc = xo_do_close_instance(xop, NULL); + } + if (rc >= 0) + goto open_instance; + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + goto open_instance; + break; + + /*close_instance:*/ + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_instance(xop, name); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_INSTANCE): + /* This one makes no sense; ignore it */ + xo_failure(xop, "xo_close_instance ignored when called from " + "initial state ('%s')", name ?: "(unknown)"); + break; + + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_INSTANCE): + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_INSTANCE): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + if (rc >= 0) + rc = xo_do_close(xop, name, new_state); + break; + + open_leaf_list: + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_INIT, XSS_OPEN_LEAF_LIST): + rc = xo_do_open_leaf_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_list(xop, NULL); + if (rc >= 0) + goto open_leaf_list; + break; + + /*close_leaf_list:*/ + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_CLOSE_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, name); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_LEAF_LIST): + /* Makes no sense; ignore */ + xo_failure(xop, "xo_close_leaf_list ignored when called from " + "initial state ('%s')", name ?: "(unknown)"); + break; + + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_LEAF_LIST): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, name, new_state); + break; + + /*emit:*/ + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT): + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close(xop, NULL, XSS_CLOSE_LIST); + break; + + case XSS_TRANSITION(XSS_INIT, XSS_EMIT): + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT): + if (on_marker) + goto marker_prevents_close; + rc = xo_do_close_leaf_list(xop, NULL); + break; + + /*emit_leaf_list:*/ + case XSS_TRANSITION(XSS_INIT, XSS_EMIT_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_EMIT_LEAF_LIST): + case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_EMIT_LEAF_LIST): + rc = xo_do_open_leaf_list(xop, flags, name); + break; + + case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_EMIT_LEAF_LIST): + break; + + case XSS_TRANSITION(XSS_OPEN_LIST, XSS_EMIT_LEAF_LIST): + /* + * We need to be backward compatible with the pre-xo_open_leaf_list + * API, where both lists and leaf-lists were opened as lists. So + * if we find an open list that hasn't had anything written to it, + * we'll accept it. + */ + break; + + default: + xo_failure(xop, "unknown transition: (%u -> %u)", + xsp->xs_state, new_state); + } + + /* Handle the flush flag */ + if (rc >= 0 && XOF_ISSET(xop, XOF_FLUSH)) + if (xo_flush_h(xop)) + rc = -1; + + return rc; + + marker_prevents_close: + xo_failure(xop, "marker '%s' prevents transition from %s to %s", + xop->xo_stack[xop->xo_depth].xs_name, + xo_state_name(old_state), xo_state_name(new_state)); + return -1; +} + +int +xo_open_marker_h (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + xo_depth_change(xop, name, 1, 0, XSS_MARKER, + xop->xo_stack[xop->xo_depth].xs_flags & XSF_MARKER_FLAGS); + + return 0; +} + +int +xo_open_marker (const char *name) +{ + return xo_open_marker_h(NULL, name); +} + +int +xo_close_marker_h (xo_handle_t *xop, const char *name) +{ + xop = xo_default(xop); + + return xo_do_close(xop, name, XSS_MARKER); +} + +int +xo_close_marker (const char *name) +{ + return xo_close_marker_h(NULL, name); +} + +/* + * Record custom output functions into the xo handle, allowing + * integration with a variety of output frameworks. + */ +void +xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func, + xo_close_func_t close_func, xo_flush_func_t flush_func) +{ + xop = xo_default(xop); + + xop->xo_opaque = opaque; + xop->xo_write = write_func; + xop->xo_close = close_func; + xop->xo_flush = flush_func; +} + +void +xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func) +{ + xo_realloc = realloc_func; + xo_free = free_func; +} + +int +xo_flush_h (xo_handle_t *xop) +{ + int rc; + + xop = xo_default(xop); + + switch (xo_style(xop)) { + case XO_STYLE_ENCODER: + xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL); + } + + rc = xo_write(xop); + if (rc >= 0 && xop->xo_flush) + if (xop->xo_flush(xop->xo_opaque) < 0) + return -1; + + return rc; +} + +int +xo_flush (void) +{ + return xo_flush_h(NULL); +} + +int +xo_finish_h (xo_handle_t *xop) +{ + const char *cp = ""; + xop = xo_default(xop); + + if (!XOF_ISSET(xop, XOF_NO_CLOSE)) + xo_do_close_all(xop, xop->xo_stack); + + switch (xo_style(xop)) { + case XO_STYLE_JSON: + if (!XOF_ISSET(xop, XOF_NO_TOP)) { + if (XOIF_ISSET(xop, XOIF_TOP_EMITTED)) + XOIF_CLEAR(xop, XOIF_TOP_EMITTED); /* Turn off before output */ + else + cp = "{ "; + xo_printf(xop, "%*s%s}\n",xo_indent(xop), "", cp); + } + break; + + case XO_STYLE_ENCODER: + xo_encoder_handle(xop, XO_OP_FINISH, NULL, NULL); + break; + } + + return xo_flush_h(xop); +} + +int +xo_finish (void) +{ + return xo_finish_h(NULL); +} + +/* + * xo_finish_atexit is suitable for atexit() calls, to force clear up + * and finalizing output. + */ +void +xo_finish_atexit (void) +{ + (void) xo_finish_h(NULL); +} + +/* + * Generate an error message, such as would be displayed on stderr + */ +void +xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) +{ + xop = xo_default(xop); + + /* + * If the format string doesn't end with a newline, we pop + * one on ourselves. + */ + int len = strlen(fmt); + if (len > 0 && fmt[len - 1] != '\n') { + char *newfmt = alloca(len + 2); + memcpy(newfmt, fmt, len); + newfmt[len] = '\n'; + newfmt[len] = '\0'; + fmt = newfmt; + } + + switch (xo_style(xop)) { + case XO_STYLE_TEXT: + vfprintf(stderr, fmt, vap); + break; + + case XO_STYLE_HTML: + va_copy(xop->xo_vap, vap); + + xo_buf_append_div(xop, "error", 0, NULL, 0, fmt, strlen(fmt), NULL, 0); + + if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) + xo_line_close(xop); + + xo_write(xop); + + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + break; + + case XO_STYLE_XML: + case XO_STYLE_JSON: + va_copy(xop->xo_vap, vap); + + xo_open_container_h(xop, "error"); + xo_format_value(xop, "message", 7, fmt, strlen(fmt), NULL, 0, 0); + xo_close_container_h(xop, "error"); + + va_end(xop->xo_vap); + bzero(&xop->xo_vap, sizeof(xop->xo_vap)); + break; + + case XO_STYLE_SDPARAMS: + case XO_STYLE_ENCODER: + break; + } +} + +void +xo_error_h (xo_handle_t *xop, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_error_hv(xop, fmt, vap); + va_end(vap); +} + +/* + * Generate an error message, such as would be displayed on stderr + */ +void +xo_error (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_error_hv(NULL, fmt, vap); + va_end(vap); +} + +/* + * Parse any libxo-specific options from the command line, removing them + * so the main() argument parsing won't see them. We return the new value + * for argc or -1 for error. If an error occurred, the program should + * exit. A suitable error message has already been displayed. + */ +int +xo_parse_args (int argc, char **argv) +{ + static char libxo_opt[] = "--libxo"; + char *cp; + int i, save; + + /* Save our program name for xo_err and friends */ + xo_program = argv[0]; + cp = strrchr(xo_program, '/'); + if (cp) + xo_program = cp + 1; + + for (save = i = 1; i < argc; i++) { + if (argv[i] == NULL + || strncmp(argv[i], libxo_opt, sizeof(libxo_opt) - 1) != 0) { + if (save != i) + argv[save] = argv[i]; + save += 1; + continue; + } + + cp = argv[i] + sizeof(libxo_opt) - 1; + if (*cp == '\0') { + cp = argv[++i]; + if (cp == NULL) { + xo_warnx("missing libxo option"); + return -1; + } + + if (xo_set_options(NULL, cp) < 0) + return -1; + } else if (*cp == ':') { + if (xo_set_options(NULL, cp) < 0) + return -1; + + } else if (*cp == '=') { + if (xo_set_options(NULL, ++cp) < 0) + return -1; + + } else if (*cp == '-') { + cp += 1; + if (strcmp(cp, "check") == 0) { + exit(XO_HAS_LIBXO); + + } else { + xo_warnx("unknown libxo option: '%s'", argv[i]); + return -1; + } + } else { + xo_warnx("unknown libxo option: '%s'", argv[i]); + return -1; + } + } + + argv[save] = NULL; + return save; +} + +/* + * Debugging function that dumps the current stack of open libxo constructs, + * suitable for calling from the debugger. + */ +void +xo_dump_stack (xo_handle_t *xop) +{ + int i; + xo_stack_t *xsp; + + xop = xo_default(xop); + + fprintf(stderr, "Stack dump:\n"); + + xsp = xop->xo_stack; + for (i = 1, xsp++; i <= xop->xo_depth; i++, xsp++) { + fprintf(stderr, " [%d] %s '%s' [%x]\n", + i, xo_state_name(xsp->xs_state), + xsp->xs_name ?: "--", xsp->xs_flags); + } +} + +/* + * Record the program name used for error messages + */ +void +xo_set_program (const char *name) +{ + xo_program = name; +} + +void +xo_set_version_h (xo_handle_t *xop, const char *version) +{ + xop = xo_default(xop); + + if (version == NULL || strchr(version, '"') != NULL) + return; + + if (!xo_style_is_encoding(xop)) + return; + + switch (xo_style(xop)) { + case XO_STYLE_XML: + /* For XML, we record this as an attribute for the first tag */ + xo_attr_h(xop, "__version", "%s", version); + break; + + case XO_STYLE_JSON: + /* + * For JSON, we record the version string in our handle, and emit + * it in xo_emit_top. + */ + xop->xo_version = xo_strndup(version, -1); + break; + + case XO_STYLE_ENCODER: + xo_encoder_handle(xop, XO_OP_VERSION, NULL, version); + break; + } +} + +/* + * Set the version number for the API content being carried through + * the xo handle. + */ +void +xo_set_version (const char *version) +{ + xo_set_version_h(NULL, version); +} + +/* + * Generate a warning. Normally, this is a text message written to + * standard error. If the XOF_WARN_XML flag is set, then we generate + * XMLified content on standard output. + */ +void +xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code, + const char *fmt, va_list vap) +{ + xop = xo_default(xop); + + if (fmt == NULL) + return; + + xo_open_marker_h(xop, "xo_emit_warn_hcv"); + xo_open_container_h(xop, as_warning ? "__warning" : "__error"); + + if (xo_program) + xo_emit("{wc:program}", xo_program); + + if (xo_style(xop) == XO_STYLE_XML || xo_style(xop) == XO_STYLE_JSON) { + va_list ap; + xo_handle_t temp; + + bzero(&temp, sizeof(temp)); + temp.xo_style = XO_STYLE_TEXT; + xo_buf_init(&temp.xo_data); + xo_depth_check(&temp, XO_DEPTH); + + va_copy(ap, vap); + (void) xo_emit_hv(&temp, fmt, ap); + va_end(ap); + + xo_buffer_t *src = &temp.xo_data; + xo_format_value(xop, "message", 7, src->xb_bufp, + src->xb_curp - src->xb_bufp, NULL, 0, 0); + + xo_free(temp.xo_stack); + xo_buf_cleanup(src); + } + + (void) xo_emit_hv(xop, fmt, vap); + + int len = strlen(fmt); + if (len > 0 && fmt[len - 1] != '\n') { + if (code > 0) { + const char *msg = strerror(code); + if (msg) + xo_emit_h(xop, ": {G:strerror}{g:error/%s}", msg); + } + xo_emit("\n"); + } + + xo_close_marker_h(xop, "xo_emit_warn_hcv"); + xo_flush_h(xop); +} + +void +xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_emit_warn_hcv(xop, 1, code, fmt, vap); + va_end(vap); +} + +void +xo_emit_warn_c (int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, code, fmt, vap); + va_end(vap); +} + +void +xo_emit_warn (const char *fmt, ...) +{ + int code = errno; + va_list vap; + + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, code, fmt, vap); + va_end(vap); +} + +void +xo_emit_warnx (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, -1, fmt, vap); + va_end(vap); +} + +void +xo_emit_err_v (int eval, int code, const char *fmt, va_list vap) +{ + xo_emit_warn_hcv(NULL, 0, code, fmt, vap); + xo_finish(); + exit(eval); +} + +void +xo_emit_err (int eval, const char *fmt, ...) +{ + int code = errno; + va_list vap; + va_start(vap, fmt); + xo_emit_err_v(0, code, fmt, vap); + va_end(vap); + exit(eval); +} + +void +xo_emit_errx (int eval, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_emit_err_v(0, -1, fmt, vap); + va_end(vap); + xo_finish(); + exit(eval); +} + +void +xo_emit_errc (int eval, int code, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 0, code, fmt, vap); + va_end(vap); + xo_finish(); + exit(eval); +} + +/* + * Get the opaque private pointer for an xo handle + */ +void * +xo_get_private (xo_handle_t *xop) +{ + xop = xo_default(xop); + return xop->xo_private; +} + +/* + * Set the opaque private pointer for an xo handle. + */ +void +xo_set_private (xo_handle_t *xop, void *opaque) +{ + xop = xo_default(xop); + xop->xo_private = opaque; +} + +/* + * Get the encoder function + */ +xo_encoder_func_t +xo_get_encoder (xo_handle_t *xop) +{ + xop = xo_default(xop); + return xop->xo_encoder; +} + +/* + * Record an encoder callback function in an xo handle. + */ +void +xo_set_encoder (xo_handle_t *xop, xo_encoder_func_t encoder) +{ + xop = xo_default(xop); + + xop->xo_style = XO_STYLE_ENCODER; + xop->xo_encoder = encoder; +} diff --git a/freebsd/contrib/libxo/libxo/xo.h b/freebsd/contrib/libxo/libxo/xo.h new file mode 100644 index 00000000..310b21ca --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo.h @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2014-2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, July 2014 + */ + +/** + * libxo provides a means of generating text, XML, JSON, and HTML output + * using a single set of function calls, maximizing the value of output + * while minimizing the cost/impact on the code. + * + * Full documentation is available in ./doc/libxo.txt or online at: + * http://juniper.github.io/libxo/libxo-manual.html + */ + +#ifndef INCLUDE_XO_H +#define INCLUDE_XO_H + +#include <stdio.h> +#include <sys/types.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> + +#ifdef __dead2 +#define NORETURN __dead2 +#else +#define NORETURN +#endif /* __dead2 */ + +/* + * Normally we'd use the HAVE_PRINTFLIKE define triggered by the + * --enable-printflike option to configure, but we don't install + * our internal "xoconfig.h", and I'd rather not. Taking the + * coward's path, we'll turn it on inside a #if that allows + * others to turn it off where needed. Not ideal, but functional. + */ +#if !defined(NO_PRINTFLIKE) && !defined(__linux__) +#define PRINTFLIKE(_x, _y) __printflike(_x, _y) +#else +#define PRINTFLIKE(_x, _y) +#endif /* NO_PRINTFLIKE */ + +/** Formatting types */ +typedef unsigned short xo_style_t; +#define XO_STYLE_TEXT 0 /** Generate text output */ +#define XO_STYLE_XML 1 /** Generate XML output */ +#define XO_STYLE_JSON 2 /** Generate JSON output */ +#define XO_STYLE_HTML 3 /** Generate HTML output */ +#define XO_STYLE_SDPARAMS 4 /* Generate syslog structured data params */ +#define XO_STYLE_ENCODER 5 /* Generate calls to external encoder */ + +/** Flags for libxo */ +typedef unsigned long long xo_xof_flags_t; +#define XOF_BIT(_n) ((xo_xof_flags_t) 1 << (_n)) +#define XOF_CLOSE_FP XOF_BIT(0) /** Close file pointer on xo_close() */ +#define XOF_PRETTY XOF_BIT(1) /** Make 'pretty printed' output */ +#define XOF_LOG_SYSLOG XOF_BIT(2) /** Log (on stderr) our syslog content */ +#define XOF_RESV3 XOF_BIT(3) /* Unused */ + +#define XOF_WARN XOF_BIT(4) /** Generate warnings for broken calls */ +#define XOF_XPATH XOF_BIT(5) /** Emit XPath attributes in HTML */ +#define XOF_INFO XOF_BIT(6) /** Emit additional info fields (HTML) */ +#define XOF_WARN_XML XOF_BIT(7) /** Emit warnings in XML (on stdout) */ + +#define XOF_NO_ENV XOF_BIT(8) /** Don't look at LIBXO_OPTIONS env var */ +#define XOF_NO_VA_ARG XOF_BIT(9) /** Don't advance va_list w/ va_arg() */ +#define XOF_DTRT XOF_BIT(10) /** Enable "do the right thing" mode */ +#define XOF_KEYS XOF_BIT(11) /** Flag 'key' fields for xml and json */ + +#define XOF_IGNORE_CLOSE XOF_BIT(12) /** Ignore errors on close tags */ +#define XOF_NOT_FIRST XOF_BIT(13) /* Not the first item (JSON) */ +#define XOF_NO_LOCALE XOF_BIT(14) /** Don't bother with locale */ +#define XOF_RESV15 XOF_BIT(15) /* Unused */ + +#define XOF_NO_TOP XOF_BIT(16) /** Don't emit the top braces in JSON */ +#define XOF_RESV17 XOF_BIT(17) /* Unused */ +#define XOF_UNITS XOF_BIT(18) /** Encode units in XML */ +#define XOF_RESV19 XOF_BIT(19) /* Unused */ + +#define XOF_UNDERSCORES XOF_BIT(20) /** Replace dashes with underscores (JSON)*/ +#define XOF_COLUMNS XOF_BIT(21) /** xo_emit should return a column count */ +#define XOF_FLUSH XOF_BIT(22) /** Flush after each xo_emit call */ +#define XOF_FLUSH_LINE XOF_BIT(23) /** Flush after each newline */ + +#define XOF_NO_CLOSE XOF_BIT(24) /** xo_finish won't close open elements */ +#define XOF_COLOR_ALLOWED XOF_BIT(25) /** Allow color/effects to be enabled */ +#define XOF_COLOR XOF_BIT(26) /** Enable color and effects */ +#define XOF_NO_HUMANIZE XOF_BIT(27) /** Block the {h:} modifier */ + +#define XOF_LOG_GETTEXT XOF_BIT(28) /** Log (stderr) gettext lookup strings */ +#define XOF_UTF8 XOF_BIT(29) /** Force text output to be UTF8 */ +#define XOF_RETAIN_ALL XOF_BIT(30) /** Force use of XOEF_RETAIN */ +#define XOF_RETAIN_NONE XOF_BIT(31) /** Prevent use of XOEF_RETAIN */ + +typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */ +#define XOEF_RETAIN (1<<0) /* Retain parsed formatting information */ + +/* + * The xo_info_t structure provides a mapping between names and + * additional data emitted via HTML. + */ +typedef struct xo_info_s { + const char *xi_name; /* Name of the element */ + const char *xi_type; /* Type of field */ + const char *xi_help; /* Description of field */ +} xo_info_t; + +#define XO_INFO_NULL NULL, NULL, NULL /* Use '{ XO_INFO_NULL }' to end lists */ + +struct xo_handle_s; /* Opaque structure forward */ +typedef struct xo_handle_s xo_handle_t; /* Handle for XO output */ + +typedef int (*xo_write_func_t)(void *, const char *); +typedef void (*xo_close_func_t)(void *); +typedef int (*xo_flush_func_t)(void *); +typedef void *(*xo_realloc_func_t)(void *, size_t); +typedef void (*xo_free_func_t)(void *); + +/* + * The formatter function mirrors "vsnprintf", with an additional argument + * of the xo handle. The caller should return the number of bytes _needed_ + * to fit the data, even if this exceeds 'len'. + */ +typedef int (*xo_formatter_t)(xo_handle_t *, char *, int, + const char *, va_list); +typedef void (*xo_checkpointer_t)(xo_handle_t *, va_list, int); + +xo_handle_t * +xo_create (xo_style_t style, xo_xof_flags_t flags); + +xo_handle_t * +xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags); + +void +xo_destroy (xo_handle_t *xop); + +void +xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func, + xo_close_func_t close_func, xo_flush_func_t flush_func); + +void +xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func); + +void +xo_set_style (xo_handle_t *xop, xo_style_t style); + +xo_style_t +xo_get_style (xo_handle_t *xop); + +int +xo_set_style_name (xo_handle_t *xop, const char *style); + +int +xo_set_options (xo_handle_t *xop, const char *input); + +xo_xof_flags_t +xo_get_flags (xo_handle_t *xop); + +void +xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags); + +void +xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags); + +int +xo_set_file_h (xo_handle_t *xop, FILE *fp); + +int +xo_set_file (FILE *fp); + +void +xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count); + +void +xo_set_formatter (xo_handle_t *xop, xo_formatter_t func, xo_checkpointer_t); + +void +xo_set_depth (xo_handle_t *xop, int depth); + +int +xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap); + +int +xo_emit_h (xo_handle_t *xop, const char *fmt, ...); + +int +xo_emit (const char *fmt, ...); + +int +xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags, + const char *fmt, va_list vap); + +int +xo_emit_hf (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...); + +int +xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...); + +PRINTFLIKE(2, 0) +static inline int +xo_emit_hvp (xo_handle_t *xop, const char *fmt, va_list vap) +{ + return xo_emit_hv(xop, fmt, vap); +} + +PRINTFLIKE(2, 3) +static inline int +xo_emit_hp (xo_handle_t *xop, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + int rc = xo_emit_hv(xop, fmt, vap); + va_end(vap); + return rc; +} + +PRINTFLIKE(1, 2) +static inline int +xo_emit_p (const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + int rc = xo_emit_hv(NULL, fmt, vap); + va_end(vap); + return rc; +} + +PRINTFLIKE(3, 0) +static inline int +xo_emit_hvfp (xo_handle_t *xop, xo_emit_flags_t flags, + const char *fmt, va_list vap) +{ + return xo_emit_hvf(xop, flags, fmt, vap); +} + +PRINTFLIKE(3, 4) +static inline int +xo_emit_hfp (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + int rc = xo_emit_hvf(xop, flags, fmt, vap); + va_end(vap); + return rc; +} + +PRINTFLIKE(2, 3) +static inline int +xo_emit_fp (xo_emit_flags_t flags, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + int rc = xo_emit_hvf(NULL, flags, fmt, vap); + va_end(vap); + return rc; +} + +int +xo_open_container_h (xo_handle_t *xop, const char *name); + +int +xo_open_container (const char *name); + +int +xo_open_container_hd (xo_handle_t *xop, const char *name); + +int +xo_open_container_d (const char *name); + +int +xo_close_container_h (xo_handle_t *xop, const char *name); + +int +xo_close_container (const char *name); + +int +xo_close_container_hd (xo_handle_t *xop); + +int +xo_close_container_d (void); + +int +xo_open_list_h (xo_handle_t *xop, const char *name); + +int +xo_open_list (const char *name); + +int +xo_open_list_hd (xo_handle_t *xop, const char *name); + +int +xo_open_list_d (const char *name); + +int +xo_close_list_h (xo_handle_t *xop, const char *name); + +int +xo_close_list (const char *name); + +int +xo_close_list_hd (xo_handle_t *xop); + +int +xo_close_list_d (void); + +int +xo_open_instance_h (xo_handle_t *xop, const char *name); + +int +xo_open_instance (const char *name); + +int +xo_open_instance_hd (xo_handle_t *xop, const char *name); + +int +xo_open_instance_d (const char *name); + +int +xo_close_instance_h (xo_handle_t *xop, const char *name); + +int +xo_close_instance (const char *name); + +int +xo_close_instance_hd (xo_handle_t *xop); + +int +xo_close_instance_d (void); + +int +xo_open_marker_h (xo_handle_t *xop, const char *name); + +int +xo_open_marker (const char *name); + +int +xo_close_marker_h (xo_handle_t *xop, const char *name); + +int +xo_close_marker (const char *name); + +int +xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...); + +int +xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap); + +int +xo_attr (const char *name, const char *fmt, ...); + +void +xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap); + +void +xo_error_h (xo_handle_t *xop, const char *fmt, ...); + +void +xo_error (const char *fmt, ...); + +int +xo_flush_h (xo_handle_t *xop); + +int +xo_flush (void); + +int +xo_finish_h (xo_handle_t *xop); + +int +xo_finish (void); + +void +xo_finish_atexit (void); + +void +xo_set_leading_xpath (xo_handle_t *xop, const char *path); + +void +xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4); + +void +xo_warn_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3); + +void +xo_warn (const char *fmt, ...) PRINTFLIKE(1, 2); + +void +xo_warnx (const char *fmt, ...) PRINTFLIKE(1, 2); + +void +xo_err (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3); + +void +xo_errx (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3); + +void +xo_errc (int eval, int code, const char *fmt, ...) NORETURN PRINTFLIKE(3, 4); + +void +xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) PRINTFLIKE(3, 0); + +void +xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4); + +void +xo_message_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3); + +void +xo_message_e (const char *fmt, ...) PRINTFLIKE(1, 2); + +void +xo_message (const char *fmt, ...) PRINTFLIKE(1, 2); + +void +xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code, + const char *fmt, va_list vap); + +void +xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...); + +void +xo_emit_warn_c (int code, const char *fmt, ...); + +void +xo_emit_warn (const char *fmt, ...); + +void +xo_emit_warnx (const char *fmt, ...); + +void +xo_emit_err (int eval, const char *fmt, ...) NORETURN; + +void +xo_emit_errx (int eval, const char *fmt, ...) NORETURN; + +void +xo_emit_errc (int eval, int code, const char *fmt, ...) NORETURN; + +PRINTFLIKE(4, 0) +static inline void +xo_emit_warn_hcvp (xo_handle_t *xop, int as_warning, int code, + const char *fmt, va_list vap) +{ + xo_emit_warn_hcv(xop, as_warning, code, fmt, vap); +} + +PRINTFLIKE(3, 4) +static inline void +xo_emit_warn_hcp (xo_handle_t *xop, int code, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(xop, 1, code, fmt, vap); + va_end(vap); +} + +PRINTFLIKE(2, 3) +static inline void +xo_emit_warn_cp (int code, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, code, fmt, vap); + va_end(vap); +} + +PRINTFLIKE(1, 2) +static inline void +xo_emit_warn_p (const char *fmt, ...) +{ + int code = errno; + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, code, fmt, vap); + va_end(vap); +} + +PRINTFLIKE(1, 2) +static inline void +xo_emit_warnx_p (const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 1, -1, fmt, vap); + va_end(vap); +} + +NORETURN PRINTFLIKE(2, 3) +static inline void +xo_emit_err_p (int eval, const char *fmt, ...) +{ + int code = errno; + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 0, code, fmt, vap); + va_end(vap); + + exit(eval); +} + +PRINTFLIKE(2, 3) +static inline void +xo_emit_errx_p (int eval, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 0, -1, fmt, vap); + va_end(vap); + exit(eval); +} + +PRINTFLIKE(3, 4) +static inline void +xo_emit_errc_p (int eval, int code, const char *fmt, ...) +{ + va_list vap; + va_start(vap, fmt); + xo_emit_warn_hcv(NULL, 0, code, fmt, vap); + va_end(vap); + exit(eval); +} + +void +xo_emit_err_v (int eval, int code, const char *fmt, va_list vap) NORETURN PRINTFLIKE(3, 0); + +void +xo_no_setlocale (void); + +/** + * @brief Lift libxo-specific arguments from a set of arguments + * + * libxo-enable programs typically use command line options to enable + * all the nifty-cool libxo features. xo_parse_args() makes this simple + * by pre-processing the command line arguments given to main(), handling + * and removing the libxo-specific ones, meaning anything starting with + * "--libxo". A full description of these arguments is in the base + * documentation. + * @param[in] argc Number of arguments (ala #main()) + * @param[in] argc Array of argument strings (ala #main()) + * @return New number of arguments, or -1 for failure. + */ +int +xo_parse_args (int argc, char **argv); + +/** + * This is the "magic" number returned by libxo-supporting commands + * when passed the equally magic "--libxo-check" option. If you + * return this, we can (unsafely) assume that since you know the magic + * handshake, you'll happily handle future --libxo options and not do + * something violent like reboot the box or create another hole in the + * ozone layer. + */ +#define XO_HAS_LIBXO 121 + +/** + * externs for libxo's version number strings + */ +extern const char xo_version[]; /** Base version triple string */ +extern const char xo_version_extra[]; /** Extra version magic content */ + +/** + * @brief Dump the internal stack of a libxo handle. + * + * This diagnostic function is something I will ask you to call from + * your program when you write to tell me libxo has gone bat-stink + * crazy and has discarded your list or container or content. Output + * content will be what we lovingly call "developer entertainment". + * @param[in] xop A valid libxo handle, or NULL for the default handle + */ +void +xo_dump_stack (xo_handle_t *xop); + +/** + * @brief Recode the name of the program, suitable for error output. + * + * libxo will record the given name for use while generating error + * messages. The contents are not copied, so the value must continue + * to point to a valid memory location. This allows the caller to change + * the value, but requires the caller to manage the memory. Typically + * this is called with argv[0] from main(). + * @param[in] name The name of the current application program + */ +void +xo_set_program (const char *name); + +/** + * @brief Add a version string to the output, where possible. + * + * Adds a version number to the output, suitable for tracking + * changes in the content. This is only important for the "encoding" + * format styles (XML and JSON) and allows a user of the data to + * discern which version of the data model is in use. + * @param[in] version The version number, encoded as a string + */ +void +xo_set_version (const char *version); + +/** + * #xo_set_version with a handle. + * @param[in] xop A valid libxo handle, or NULL for the default handle + * @param[in] version The version number, encoded as a string + */ +void +xo_set_version_h (xo_handle_t *xop, const char *version); + +void +xo_open_log (const char *ident, int logopt, int facility); + +void +xo_close_log (void); + +int +xo_set_logmask (int maskpri); + +void +xo_set_unit_test_mode (int value); + +void +xo_syslog (int priority, const char *name, const char *message, ...); + +void +xo_vsyslog (int priority, const char *name, const char *message, va_list args); + +typedef void (*xo_syslog_open_t)(void); +typedef void (*xo_syslog_send_t)(const char *full_msg, + const char *v0_hdr, const char *text_only); +typedef void (*xo_syslog_close_t)(void); + +void +xo_set_syslog_handler (xo_syslog_open_t open_func, xo_syslog_send_t send_func, + xo_syslog_close_t close_func); + +void +xo_set_syslog_enterprise_id (unsigned short eid); + +typedef void (*xo_simplify_field_func_t)(const char *, unsigned, int); + +char * +xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers, + xo_simplify_field_func_t field_cb); + +int +xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents, + const char *fmt, const char *efmt, + va_list vap); + +int +xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, + const char *fmt, const char *efmt, ...); + +int +xo_emit_field (const char *rolmod, const char *contents, + const char *fmt, const char *efmt, ...); + +void +xo_retain_clear_all (void); + +void +xo_retain_clear (const char *fmt); + +#endif /* INCLUDE_XO_H */ diff --git a/freebsd/contrib/libxo/libxo/xo_buf.h b/freebsd/contrib/libxo/libxo/xo_buf.h new file mode 100644 index 00000000..01eb397d --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_buf.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, August 2015 + */ + +/* + * This file is an _internal_ part of the libxo plumbing, not suitable + * for external use. It is not considered part of the libxo API and + * will not be a stable part of that API. Mine, not your's, dude... + * The real hope is that something like this will become a standard part + * of libc and I can kill this off. + */ + +#ifndef XO_BUF_H +#define XO_BUF_H + +#define XO_BUFSIZ (8*1024) /* Initial buffer size */ +#define XO_BUF_HIGH_WATER (XO_BUFSIZ - 512) /* When to auto-flush */ +/* + * xo_buffer_t: a memory buffer that can be grown as needed. We + * use them for building format strings and output data. + */ +typedef struct xo_buffer_s { + char *xb_bufp; /* Buffer memory */ + char *xb_curp; /* Current insertion point */ + unsigned xb_size; /* Size of buffer */ +} xo_buffer_t; + +/* + * Initialize the contents of an xo_buffer_t. + */ +static inline void +xo_buf_init (xo_buffer_t *xbp) +{ + xbp->xb_size = XO_BUFSIZ; + xbp->xb_bufp = xo_realloc(NULL, xbp->xb_size); + xbp->xb_curp = xbp->xb_bufp; +} + +/* + * Reset the buffer to empty + */ +static inline void +xo_buf_reset (xo_buffer_t *xbp) +{ + xbp->xb_curp = xbp->xb_bufp; +} + +/* + * Return the number of bytes left in the buffer + */ +static inline int +xo_buf_left (xo_buffer_t *xbp) +{ + return xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp); +} + +/* + * See if the buffer to empty + */ +static inline int +xo_buf_is_empty (xo_buffer_t *xbp) +{ + return (xbp->xb_curp == xbp->xb_bufp); +} + +/* + * Return the current offset + */ +static inline unsigned +xo_buf_offset (xo_buffer_t *xbp) +{ + return xbp ? (xbp->xb_curp - xbp->xb_bufp) : 0; +} + +static inline char * +xo_buf_data (xo_buffer_t *xbp, unsigned offset) +{ + if (xbp == NULL) + return NULL; + return xbp->xb_bufp + offset; +} + +static inline char * +xo_buf_cur (xo_buffer_t *xbp) +{ + if (xbp == NULL) + return NULL; + return xbp->xb_curp; +} + +/* + * Initialize the contents of an xo_buffer_t. + */ +static inline void +xo_buf_cleanup (xo_buffer_t *xbp) +{ + if (xbp->xb_bufp) + xo_free(xbp->xb_bufp); + bzero(xbp, sizeof(*xbp)); +} + +/* + * Does the buffer have room for the given number of bytes of data? + * If not, realloc the buffer to make room. If that fails, we + * return 0 to tell the caller they are in trouble. + */ +static inline int +xo_buf_has_room (xo_buffer_t *xbp, int len) +{ + if (xbp->xb_curp + len >= xbp->xb_bufp + xbp->xb_size) { + int sz = xbp->xb_size + XO_BUFSIZ; + char *bp = xo_realloc(xbp->xb_bufp, sz); + if (bp == NULL) + return 0; + + xbp->xb_curp = bp + (xbp->xb_curp - xbp->xb_bufp); + xbp->xb_bufp = bp; + xbp->xb_size = sz; + } + + return 1; +} + +/* + * Append the given string to the given buffer + */ +static inline void +xo_buf_append (xo_buffer_t *xbp, const char *str, int len) +{ + if (!xo_buf_has_room(xbp, len)) + return; + + memcpy(xbp->xb_curp, str, len); + xbp->xb_curp += len; +} + +/* + * Append the given NUL-terminated string to the given buffer + */ +static inline void +xo_buf_append_str (xo_buffer_t *xbp, const char *str) +{ + int len = strlen(str); + + if (!xo_buf_has_room(xbp, len)) + return; + + memcpy(xbp->xb_curp, str, len); + xbp->xb_curp += len; +} + +#endif /* XO_BUF_H */ diff --git a/freebsd/contrib/libxo/libxo/xo_config.h b/freebsd/contrib/libxo/libxo/xo_config.h new file mode 100644 index 00000000..9020b8c6 --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_config.h @@ -0,0 +1,254 @@ +/* $FreeBSD$ */ +/* libxo/xo_config.h. Generated from xo_config.h.in by configure. */ +/* libxo/xo_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the `asprintf' function. */ +#define HAVE_ASPRINTF 1 + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO 1 + +/* Define to 1 if you have the `ctime' function. */ +#define HAVE_CTIME 1 + +/* Define to 1 if you have the <ctype.h> header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the declaration of `__isthreaded', and to 0 if you + don't. */ +#define HAVE_DECL___ISTHREADED 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `dlfunc' function. */ +#define HAVE_DLFUNC 1 + +/* Define to 1 if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `flock' function. */ +#define HAVE_FLOCK 1 + +/* Define to 1 if you have the `getpass' function. */ +#define HAVE_GETPASS 1 + +/* Define to 1 if you have the `getprogname' function. */ +#define HAVE_GETPROGNAME 1 + +/* Define to 1 if you have the `getrusage' function. */ +#define HAVE_GETRUSAGE 1 + +/* gettext(3) */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* humanize_number(3) */ +#define HAVE_HUMANIZE_NUMBER 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM 1 + +/* Define to 1 if you have the <libutil.h> header file. */ +#define HAVE_LIBUTIL_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the <monitor.h> header file. */ +/* #undef HAVE_MONITOR_H */ + +/* Support printflike */ +/* #undef HAVE_PRINTFLIKE */ + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `srand' function. */ +#define HAVE_SRAND 1 + +/* Define to 1 if you have the `sranddev' function. */ +#define HAVE_SRANDDEV 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdio_ext.h> header file. */ +/* #undef HAVE_STDIO_EXT_H */ + +/* Define to 1 if you have the <stdio.h> header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <stdtime/tzfile.h> header file. */ +/* #undef HAVE_STDTIME_TZFILE_H */ + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcspn' function. */ +#define HAVE_STRCSPN 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strspn' function. */ +#define HAVE_STRSPN 1 + +/* Have struct sockaddr_un.sun_len */ +#define HAVE_SUN_LEN 1 + +/* Define to 1 if you have the `sysctlbyname' function. */ +#define HAVE_SYSCTLBYNAME 1 + +/* Define to 1 if you have the <sys/param.h> header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/sysctl.h> header file. */ +#define HAVE_SYS_SYSCTL_H 1 + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <threads.h> header file. */ +#define HAVE_THREADS_H 1 + +/* thread-local setting */ +#define HAVE_THREAD_LOCAL THREAD_LOCAL_before + +/* Define to 1 if you have the <tzfile.h> header file. */ +/* #undef HAVE_TZFILE_H */ + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `__flbf' function. */ +/* #undef HAVE___FLBF */ + +/* Enable debugging */ +/* #undef LIBXO_DEBUG */ + +/* Enable text-only rendering */ +/* #undef LIBXO_TEXT_ONLY */ + +/* Version number as dotted value */ +#define LIBXO_VERSION "0.6.2" + +/* Version number extra information */ +#define LIBXO_VERSION_EXTRA "" + +/* Version number as a number */ +#define LIBXO_VERSION_NUMBER 6002 + +/* Version number as string */ +#define LIBXO_VERSION_STRING "6002" + +/* Enable local wcwidth implementation */ +#define LIBXO_WCWIDTH 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libxo" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "phil@juniper.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libxo" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libxo 0.6.2" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libxo" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.6.2" + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.6.2" + +/* Retain hash bucket size */ +/* #undef XO_RETAIN_SIZE */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +/* #undef size_t */ diff --git a/freebsd/contrib/libxo/libxo/xo_encoder.c b/freebsd/contrib/libxo/libxo/xo_encoder.c new file mode 100644 index 00000000..8c3d9dbb --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_encoder.c @@ -0,0 +1,435 @@ +#include <machine/rtems-bsd-user-space.h> + +/* + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, August 2015 + */ + +#ifndef __rtems__ +/** + * libxo includes a number of fixed encoding styles. But other + * external encoders are need to deal with new encoders. Rather + * than expose a swarm of libxo internals, we create a distinct + * API, with a simpler API than we use internally. + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/queue.h> +#include <rtems/bsd/sys/param.h> +#include <dlfcn.h> + +#include "xo_config.h" +#include "xo.h" +#include "xo_encoder.h" + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#if !defined(HAVE_DLFUNC) +#define dlfunc(_p, _n) dlsym(_p, _n) +#endif +#else /* HAVE_DLFCN_H */ +#define dlopen(_n, _f) NULL /* Fail */ +#define dlsym(_p, _n) NULL /* Fail */ +#define dlfunc(_p, _n) NULL /* Fail */ +#endif /* HAVE_DLFCN_H */ + +static void xo_encoder_setup (void); /* Forward decl */ + +/* + * Need a simple string collection + */ +typedef struct xo_string_node_s { + TAILQ_ENTRY(xo_string_node_s) xs_link; /* Next string */ + char xs_data[0]; /* String data */ +} xo_string_node_t; + +typedef TAILQ_HEAD(xo_string_list_s, xo_string_node_s) xo_string_list_t; + +static inline void +xo_string_list_init (xo_string_list_t *listp) +{ + if (listp->tqh_last == NULL) + TAILQ_INIT(listp); +} + +static inline xo_string_node_t * +xo_string_add (xo_string_list_t *listp, const char *str) +{ + if (listp == NULL || str == NULL) + return NULL; + + xo_string_list_init(listp); + size_t len = strlen(str); + xo_string_node_t *xsp; + + xsp = xo_realloc(NULL, sizeof(*xsp) + len + 1); + if (xsp) { + memcpy(xsp->xs_data, str, len); + xsp->xs_data[len] = '\0'; + TAILQ_INSERT_TAIL(listp, xsp, xs_link); + } + + return xsp; +} + +#define XO_STRING_LIST_FOREACH(_xsp, _listp) \ + xo_string_list_init(_listp); \ + TAILQ_FOREACH(_xsp, _listp, xs_link) + +static inline void +xo_string_list_clean (xo_string_list_t *listp) +{ + xo_string_node_t *xsp; + + xo_string_list_init(listp); + + for (;;) { + xsp = TAILQ_FIRST(listp); + if (xsp == NULL) + break; + TAILQ_REMOVE(listp, xsp, xs_link); + xo_free(xsp); + } +} + +static xo_string_list_t xo_encoder_path; + +void +xo_encoder_path_add (const char *path) +{ + xo_encoder_setup(); + + if (path) + xo_string_add(&xo_encoder_path, path); +} + +/* ---------------------------------------------------------------------- */ + +typedef struct xo_encoder_node_s { + TAILQ_ENTRY(xo_encoder_node_s) xe_link; /* Next session */ + char *xe_name; /* Name for this encoder */ + xo_encoder_func_t xe_handler; /* Callback function */ + void *xe_dlhandle; /* dlopen handle */ +} xo_encoder_node_t; + +typedef TAILQ_HEAD(xo_encoder_list_s, xo_encoder_node_s) xo_encoder_list_t; + +#define XO_ENCODER_LIST_FOREACH(_xep, _listp) \ + xo_encoder_list_init(_listp); \ + TAILQ_FOREACH(_xep, _listp, xe_link) + +static xo_encoder_list_t xo_encoders; + +static void +xo_encoder_list_init (xo_encoder_list_t *listp) +{ + if (listp->tqh_last == NULL) + TAILQ_INIT(listp); +} + +static xo_encoder_node_t * +xo_encoder_list_add (const char *name) +{ + if (name == NULL) + return NULL; + + xo_encoder_node_t *xep = xo_realloc(NULL, sizeof(*xep)); + if (xep) { + int len = strlen(name) + 1; + xep->xe_name = xo_realloc(NULL, len); + if (xep->xe_name == NULL) { + xo_free(xep); + return NULL; + } + + memcpy(xep->xe_name, name, len); + + TAILQ_INSERT_TAIL(&xo_encoders, xep, xe_link); + } + + return xep; +} + +void +xo_encoders_clean (void) +{ + xo_encoder_node_t *xep; + + xo_encoder_setup(); + + for (;;) { + xep = TAILQ_FIRST(&xo_encoders); + if (xep == NULL) + break; + + TAILQ_REMOVE(&xo_encoders, xep, xe_link); + + if (xep->xe_dlhandle) + dlclose(xep->xe_dlhandle); + + xo_free(xep); + } + + xo_string_list_clean(&xo_encoder_path); +} + +static void +xo_encoder_setup (void) +{ + static int initted; + if (!initted) { + initted = 1; + + xo_string_list_init(&xo_encoder_path); + xo_encoder_list_init(&xo_encoders); + + xo_encoder_path_add(XO_ENCODERDIR); + } +} + +static xo_encoder_node_t * +xo_encoder_find (const char *name) +{ + xo_encoder_node_t *xep; + + xo_encoder_list_init(&xo_encoders); + + XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) { + if (strcmp(xep->xe_name, name) == 0) + return xep; + } + + return NULL; +} + +static xo_encoder_node_t * +xo_encoder_discover (const char *name) +{ + void *dlp = NULL; + char buf[MAXPATHLEN]; + xo_string_node_t *xsp; + xo_encoder_node_t *xep = NULL; + + XO_STRING_LIST_FOREACH(xsp, &xo_encoder_path) { + static const char fmt[] = "%s/%s.enc"; + char *dir = xsp->xs_data; + size_t len = snprintf(buf, sizeof(buf), fmt, dir, name); + + if (len > sizeof(buf)) /* Should not occur */ + continue; + + dlp = dlopen((const char *) buf, RTLD_NOW); + if (dlp) + break; + } + + if (dlp) { + /* + * If the library exists, find the initializer function and + * call it. + */ + xo_encoder_init_func_t func; + + func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME); + if (func) { + xo_encoder_init_args_t xei; + + bzero(&xei, sizeof(xei)); + + xei.xei_version = XO_ENCODER_VERSION; + int rc = func(&xei); + if (rc == 0 && xei.xei_handler) { + xep = xo_encoder_list_add(name); + if (xep) { + xep->xe_handler = xei.xei_handler; + xep->xe_dlhandle = dlp; + } + } + } + + if (xep == NULL) + dlclose(dlp); + } + + return xep; +} + +void +xo_encoder_register (const char *name, xo_encoder_func_t func) +{ + xo_encoder_setup(); + + xo_encoder_node_t *xep = xo_encoder_find(name); + + if (xep) /* "We alla-ready got one" */ + return; + + xep = xo_encoder_list_add(name); + if (xep) + xep->xe_handler = func; +} + +void +xo_encoder_unregister (const char *name) +{ + xo_encoder_setup(); + + xo_encoder_node_t *xep = xo_encoder_find(name); + if (xep) { + TAILQ_REMOVE(&xo_encoders, xep, xe_link); + xo_free(xep); + } +} + +int +xo_encoder_init (xo_handle_t *xop, const char *name) +{ + xo_encoder_setup(); + + /* Can't have names containing '/' or ':' */ + if (strchr(name, '/') != NULL || strchr(name, ':') != NULL) + return -1; + + /* + * First we look on the list of known (registered) encoders. + * If we don't find it, we follow the set of paths to find + * the encoding library. + */ + xo_encoder_node_t *xep = xo_encoder_find(name); + if (xep == NULL) { + xep = xo_encoder_discover(name); + if (xep == NULL) + return -1; + } + + xo_set_encoder(xop, xep->xe_handler); + + return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL); +} + +/* + * A couple of function varieties here, to allow for multiple + * use cases. This variant is for when the main program knows + * its own encoder needs. + */ +xo_handle_t * +xo_encoder_create (const char *name, xo_xof_flags_t flags) +{ + xo_handle_t *xop; + + xop = xo_create(XO_STYLE_ENCODER, flags); + if (xop) { + if (xo_encoder_init(xop, name)) { + xo_destroy(xop); + xop = NULL; + } + } + + return xop; +} + +int +xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op, + const char *name, const char *value) +{ + void *private = xo_get_private(xop); + xo_encoder_func_t func = xo_get_encoder(xop); + + if (func == NULL) + return -1; + + return func(xop, op, name, value, private); +} + +const char * +xo_encoder_op_name (xo_encoder_op_t op) +{ + static const char *names[] = { + /* 0 */ "unknown", + /* 1 */ "create", + /* 2 */ "open_container", + /* 3 */ "close_container", + /* 4 */ "open_list", + /* 5 */ "close_list", + /* 6 */ "open_leaf_list", + /* 7 */ "close_leaf_list", + /* 8 */ "open_instance", + /* 9 */ "close_instance", + /* 10 */ "string", + /* 11 */ "content", + /* 12 */ "finish", + /* 13 */ "flush", + /* 14 */ "destroy", + /* 15 */ "attr", + /* 16 */ "version", + }; + + if (op > sizeof(names) / sizeof(names[0])) + return "unknown"; + + return names[op]; +} +#else /* __rtems__ */ + +/* + * Not supported on RTEMS. Just return errors on all functions. + */ +#include "xo.h" +#include "xo_encoder.h" + +void +xo_encoder_register (const char *name, xo_encoder_func_t func) +{ + /* Nothing to do */ +} + +void +xo_encoder_unregister (const char *name) +{ + /* Nothing to do */ +} + +void +xo_encoder_path_add (const char *path) +{ + /* Nothing to do */ +} + +int +xo_encoder_init (xo_handle_t *xop, const char *name) +{ + return -1; +} + +xo_handle_t * +xo_encoder_create (const char *name, xo_xof_flags_t flags) +{ + return NULL; +} + +int +xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op, + const char *name, const char *value) +{ + return -1; +} + +void +xo_encoders_clean (void) +{ + /* Nothing to do */ +} + +const char * +xo_encoder_op_name (xo_encoder_op_t op) +{ + return "unknown"; +} +#endif /* __rtems__ */ diff --git a/freebsd/contrib/libxo/libxo/xo_encoder.h b/freebsd/contrib/libxo/libxo/xo_encoder.h new file mode 100644 index 00000000..f73552b1 --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_encoder.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, Juniper Networks, Inc. + * All rights reserved. + * This SOFTWARE is licensed under the LICENSE provided in the + * ../Copyright file. By downloading, installing, copying, or otherwise + * using the SOFTWARE, you agree to be bound by the terms of that + * LICENSE. + * Phil Shafer, August 2015 + */ + +/* + * NOTE WELL: This file is needed to software that implements an + * external encoder for libxo that allows libxo data to be encoded in + * new and bizarre formats. General libxo code should _never_ + * include this header file. + */ + +#ifndef XO_ENCODER_H +#define XO_ENCODER_H + +/* + * Expose libxo's memory allocation functions + */ +extern xo_realloc_func_t xo_realloc; +extern xo_free_func_t xo_free; + +typedef unsigned xo_encoder_op_t; + +/* Encoder operations; names are in xo_encoder.c:xo_encoder_op_name() */ +#define XO_OP_UNKNOWN 0 +#define XO_OP_CREATE 1 /* Called when the handle is init'd */ +#define XO_OP_OPEN_CONTAINER 2 +#define XO_OP_CLOSE_CONTAINER 3 +#define XO_OP_OPEN_LIST 4 +#define XO_OP_CLOSE_LIST 5 +#define XO_OP_OPEN_LEAF_LIST 6 +#define XO_OP_CLOSE_LEAF_LIST 7 +#define XO_OP_OPEN_INSTANCE 8 +#define XO_OP_CLOSE_INSTANCE 9 +#define XO_OP_STRING 10 /* Quoted UTF-8 string */ +#define XO_OP_CONTENT 11 /* Other content */ +#define XO_OP_FINISH 12 /* Finish any pending output */ +#define XO_OP_FLUSH 13 /* Flush any buffered output */ +#define XO_OP_DESTROY 14 /* Clean up function */ +#define XO_OP_ATTRIBUTE 15 /* Attribute name/value */ +#define XO_OP_VERSION 16 /* Version string */ + +#define XO_ENCODER_HANDLER_ARGS \ + xo_handle_t *xop __attribute__ ((__unused__)), \ + xo_encoder_op_t op __attribute__ ((__unused__)), \ + const char *name __attribute__ ((__unused__)), \ + const char *value __attribute__ ((__unused__)), \ + void *private __attribute__ ((__unused__)) + +typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS); + +typedef struct xo_encoder_init_args_s { + unsigned xei_version; /* Current version */ + xo_encoder_func_t xei_handler; /* Encoding handler */ +} xo_encoder_init_args_t; + +#define XO_ENCODER_VERSION 1 /* Current version */ + +#define XO_ENCODER_INIT_ARGS \ + xo_encoder_init_args_t *arg __attribute__ ((__unused__)) + +typedef int (*xo_encoder_init_func_t)(XO_ENCODER_INIT_ARGS); +/* + * Each encoder library must define a function named xo_encoder_init + * that takes the arguments defined in XO_ENCODER_INIT_ARGS. It + * should return zero for success. + */ +#define XO_ENCODER_INIT_NAME_TOKEN xo_encoder_library_init +#define XO_STRINGIFY(_x) #_x +#define XO_STRINGIFY2(_x) XO_STRINGIFY(_x) +#define XO_ENCODER_INIT_NAME XO_STRINGIFY2(XO_ENCODER_INIT_NAME_TOKEN) +extern int XO_ENCODER_INIT_NAME_TOKEN (XO_ENCODER_INIT_ARGS); + +void +xo_encoder_register (const char *name, xo_encoder_func_t func); + +void +xo_encoder_unregister (const char *name); + +void * +xo_get_private (xo_handle_t *xop); + +void +xo_encoder_path_add (const char *path); + +void +xo_set_private (xo_handle_t *xop, void *opaque); + +xo_encoder_func_t +xo_get_encoder (xo_handle_t *xop); + +void +xo_set_encoder (xo_handle_t *xop, xo_encoder_func_t encoder); + +int +xo_encoder_init (xo_handle_t *xop, const char *name); + +xo_handle_t * +xo_encoder_create (const char *name, xo_xof_flags_t flags); + +int +xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op, + const char *name, const char *value); + +void +xo_encoders_clean (void); + +const char * +xo_encoder_op_name (xo_encoder_op_t op); + +#endif /* XO_ENCODER_H */ diff --git a/freebsd/contrib/libxo/libxo/xo_humanize.h b/freebsd/contrib/libxo/libxo/xo_humanize.h new file mode 100644 index 00000000..edf85b8b --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_humanize.h @@ -0,0 +1,169 @@ +/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */ + +/* + * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <sys/types.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <stdint.h> +#include <limits.h> +#include <unistd.h> +#include <stdbool.h> + +/* humanize_number(3) */ +#define HN_DECIMAL 0x01 +#define HN_NOSPACE 0x02 +#define HN_B 0x04 +#define HN_DIVISOR_1000 0x08 + +#define HN_GETSCALE 0x10 +#define HN_AUTOSCALE 0x20 + +static int +xo_humanize_number (char *buf, size_t len, int64_t bytes, + const char *suffix, int scale, int flags) +{ + const char *prefixes, *sep; + int b, i, r, maxscale, s1, s2, sign; + int64_t divisor, max; + // We multiply bytes by 100 to deal with rounding, so we need something + // big enough to hold LLONG_MAX * 100. On 64-bit we can use 128-bit wide + // integers with __int128_t, but on 32-bit we have to use long double. +#ifdef __LP64__ + __int128_t scalable = (__int128_t)bytes; +#else + long double scalable = (long double)bytes; +#endif + size_t baselen; + + assert(buf != NULL); + assert(suffix != NULL); + assert(scale >= 0); + + if (flags & HN_DIVISOR_1000) { + /* SI for decimal multiplies */ + divisor = 1000; + if (flags & HN_B) + prefixes = "B\0k\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0k\0M\0G\0T\0P\0E"; + } else { + /* + * binary multiplies + * XXX IEC 60027-2 recommends Ki, Mi, Gi... + */ + divisor = 1024; + if (flags & HN_B) + prefixes = "B\0K\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0K\0M\0G\0T\0P\0E"; + } + +#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) + maxscale = 7; + + if (scale >= maxscale && + (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) + return (-1); + + if (buf == NULL || suffix == NULL) + return (-1); + + if (len > 0) + buf[0] = '\0'; + if (bytes < 0) { + sign = -1; + scalable *= -100; + baselen = 3; /* sign, digit, prefix */ + } else { + sign = 1; + scalable *= 100; + baselen = 2; /* digit, prefix */ + } + if (flags & HN_NOSPACE) + sep = ""; + else { + sep = " "; + baselen++; + } + baselen += strlen(suffix); + + /* Check if enough room for `x y' + suffix + `\0' */ + if (len < baselen + 1) + return (-1); + + if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { + /* See if there is additional columns can be used. */ + for (max = 100, i = len - baselen; i-- > 0;) + max *= 10; + + for (i = 0; scalable >= max && i < maxscale; i++) + scalable /= divisor; + + if (scale & HN_GETSCALE) + return (i); + } else + for (i = 0; i < scale && i < maxscale; i++) + scalable /= divisor; + + /* If a value <= 9.9 after rounding and ... */ + if (scalable < 995 && i > 0 && flags & HN_DECIMAL) { + /* baselen + \0 + .N */ + if (len < baselen + 1 + 2) + return (-1); + b = ((int)scalable + 5) / 10; + s1 = b / 10; + s2 = b % 10; + r = snprintf(buf, len, "%s%d%s%d%s%s%s", + ((sign == -1) ? "-" : ""), + s1, localeconv()->decimal_point, s2, + sep, SCALE2PREFIX(i), suffix); + } else + r = snprintf(buf, len, "%s%lld%s%s%s", + /* LONGLONG */ + ((sign == -1) ? "-" : ""), + (long long)((scalable + 50) / 100), + sep, SCALE2PREFIX(i), suffix); + + return (r); +} diff --git a/freebsd/contrib/libxo/libxo/xo_wcwidth.h b/freebsd/contrib/libxo/libxo/xo_wcwidth.h new file mode 100644 index 00000000..46d83f03 --- /dev/null +++ b/freebsd/contrib/libxo/libxo/xo_wcwidth.h @@ -0,0 +1,313 @@ +/* + * This is an implementation of wcwidth() and wcswidth() (defined in + * IEEE Std 1002.1-2001) for Unicode. + * + * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html + * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html + * + * In fixed-width output devices, Latin characters all occupy a single + * "cell" position of equal width, whereas ideographic CJK characters + * occupy two such cells. Interoperability between terminal-line + * applications and (teletype-style) character terminals using the + * UTF-8 encoding requires agreement on which character should advance + * the cursor by how many cell positions. No established formal + * standards exist at present on which Unicode character shall occupy + * how many cell positions on character terminals. These routines are + * a first attempt of defining such behavior based on simple rules + * applied to data provided by the Unicode Consortium. + * + * For some graphical characters, the Unicode standard explicitly + * defines a character-cell width via the definition of the East Asian + * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. + * In all these cases, there is no ambiguity about which width a + * terminal shall use. For characters in the East Asian Ambiguous (A) + * class, the width choice depends purely on a preference of backward + * compatibility with either historic CJK or Western practice. + * Choosing single-width for these characters is easy to justify as + * the appropriate long-term solution, as the CJK practice of + * displaying these characters as double-width comes from historic + * implementation simplicity (8-bit encoded characters were displayed + * single-width and 16-bit ones double-width, even for Greek, + * Cyrillic, etc.) and not any typographic considerations. + * + * Much less clear is the choice of width for the Not East Asian + * (Neutral) class. Existing practice does not dictate a width for any + * of these characters. It would nevertheless make sense + * typographically to allocate two character cells to characters such + * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be + * represented adequately with a single-width glyph. The following + * routines at present merely assign a single-cell width to all + * neutral characters, in the interest of simplicity. This is not + * entirely satisfactory and should be reconsidered before + * establishing a formal standard in this area. At the moment, the + * decision which Not East Asian (Neutral) characters should be + * represented by double-width glyphs cannot yet be answered by + * applying a simple rule from the Unicode database content. Setting + * up a proper standard for the behavior of UTF-8 character terminals + * will require a careful analysis not only of each Unicode character, + * but also of each presentation form, something the author of these + * routines has avoided to do so far. + * + * http://www.unicode.org/unicode/reports/tr11/ + * + * Markus Kuhn -- 2007-05-26 (Unicode 5.0) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + */ + +#include <wchar.h> + +struct interval { + wchar_t first; + wchar_t last; +}; + +/* auxiliary function for binary search in interval table */ +static int +xo_bisearch (wchar_t ucs, const struct interval *table, int max) +{ + int min = 0; + int mid; + + if (ucs < table[0].first || ucs > table[max].last) + return 0; + while (max >= min) { + mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + + +/* The following two functions define the column width of an ISO 10646 + * character as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - SOFT HYPHEN (U+00AD) has a column width of 1. + * + * - Other format characters (general category code Cf in the Unicode + * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. + * + * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) + * have a column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * Full-width (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that wchar_t characters are encoded + * in ISO 10646. + */ + +static int +xo_wcwidth (wchar_t ucs) +{ + /* sorted list of non-overlapping intervals of non-spacing characters */ + /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ + static const struct interval combining[] = { + { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, + { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, + { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, + { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, + { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, + { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, + { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, + { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, + { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, + { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, + { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, + { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, + { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, + { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, + { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, + { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, + { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, + { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, + { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, + { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, + { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, + { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, + { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, + { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, + { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, + { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, + { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, + { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, + { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, + { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, + { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, + { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, + { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, + { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, + { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, + { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, + { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, + { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, + { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, + { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, + { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, + { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, + { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, + { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, + { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, + { 0xE0100, 0xE01EF } + }; + + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* binary search in table of non-spacing characters */ + if (xo_bisearch(ucs, combining, + sizeof(combining) / sizeof(struct interval) - 1)) + return 0; + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + return 1 + + (ucs >= 0x1100 && + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ + ucs == 0x2329 || ucs == 0x232a || + (ucs >= 0x2e80 && ucs <= 0xa4cf && + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6) || + (ucs >= 0x20000 && ucs <= 0x2fffd) || + (ucs >= 0x30000 && ucs <= 0x3fffd))); +} + +#if UNUSED_CODE +static int xo_wcswidth(const wchar_t *pwcs, size_t n) +{ + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth(*pwcs)) < 0) + return -1; + else + width += w; + + return width; +} + + +/* + * The following functions are the same as mk_wcwidth() and + * mk_wcswidth(), except that spacing characters in the East Asian + * Ambiguous (A) category as defined in Unicode Technical Report #11 + * have a column width of 2. This variant might be useful for users of + * CJK legacy encodings who want to migrate to UCS without changing + * the traditional terminal character-width behaviour. It is not + * otherwise recommended for general use. + */ +int mk_wcwidth_cjk(wchar_t ucs) +{ + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ + static const struct interval ambiguous[] = { + { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, + { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, + { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, + { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, + { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, + { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, + { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, + { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, + { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, + { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, + { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, + { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, + { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, + { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, + { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, + { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, + { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, + { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 }, + { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 }, + { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 }, + { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 }, + { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 }, + { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 }, + { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 }, + { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, + { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, + { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 }, + { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 }, + { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, + { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 }, + { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 }, + { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B }, + { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 }, + { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 }, + { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E }, + { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 }, + { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 }, + { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F }, + { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 }, + { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF }, + { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B }, + { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 }, + { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, + { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, + { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, + { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, + { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 }, + { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 }, + { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 }, + { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F }, + { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF }, + { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD } + }; + + /* binary search in table of non-spacing characters */ + if (xo_bisearch(ucs, ambiguous, + sizeof(ambiguous) / sizeof(struct interval) - 1)) + return 2; + + return mk_wcwidth(ucs); +} + + +int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) +{ + int w, width = 0; + + for (;*pwcs && n-- > 0; pwcs++) + if ((w = mk_wcwidth_cjk(*pwcs)) < 0) + return -1; + else + width += w; + + return width; +} +#endif /* UNUSED_CODE */ diff --git a/freebsd/contrib/pf/pfctl/parse-data.h b/freebsd/contrib/pf/pfctl/parse-data.h deleted file mode 100644 index 22f62958..00000000 --- a/freebsd/contrib/pf/pfctl/parse-data.h +++ /dev/null @@ -1,42 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct antispoof_opts antispoof_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int blockpolicy); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int debug); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int default_statelock); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct file *file); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct files files); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct filter_opts filter_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct node_hfsc_opts hfsc_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct node_state_opt *keep_state_defaults); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct loadanchorshead loadanchorshead); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *parsebuf); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int parseindex); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfctl *pf); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pool_opts pool_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char pushback_buffer[]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pushback_index); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct queue_opts queue_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_queue *queues); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int require_order); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmp6default); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmpdefault); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int rulestate); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct scrub_opts scrub_opts); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct symhead symhead); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct table_opts table_opts); - -/* NOTE: the following variables are generated by yacc and may change with yacc - * version or generation options. */ -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int yychar); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int yydebug); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int yyerrflag); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE yylval); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int yynerrs); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE yyval); diff --git a/freebsd/contrib/pf/pfctl/parse.c b/freebsd/contrib/pf/pfctl/parse.c deleted file mode 100644 index ffe7c1a8..00000000 --- a/freebsd/contrib/pf/pfctl/parse.c +++ /dev/null @@ -1,9013 +0,0 @@ -/* original parser id follows */ -/* yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93" */ -/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */ - -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYPATCH 20141006 - -#define YYEMPTY (-1) -#define yyclearin (yychar = YYEMPTY) -#define yyerrok (yyerrflag = 0) -#define YYRECOVERING() (yyerrflag != 0) -#define YYENOMEM (-2) -#define YYEOF 0 - -#ifndef yyparse -#define yyparse pfctlyparse -#endif /* yyparse */ - -#ifndef yylex -#define yylex pfctlylex -#endif /* yylex */ - -#ifndef yyerror -#define yyerror pfctlyerror -#endif /* yyerror */ - -#ifndef yychar -#define yychar pfctlychar -#endif /* yychar */ - -#ifndef yyval -#define yyval pfctlyval -#endif /* yyval */ - -#ifndef yylval -#define yylval pfctlylval -#endif /* yylval */ - -#ifndef yydebug -#define yydebug pfctlydebug -#endif /* yydebug */ - -#ifndef yynerrs -#define yynerrs pfctlynerrs -#endif /* yynerrs */ - -#ifndef yyerrflag -#define yyerrflag pfctlyerrflag -#endif /* yyerrflag */ - -#ifndef yylhs -#define yylhs pfctlylhs -#endif /* yylhs */ - -#ifndef yylen -#define yylen pfctlylen -#endif /* yylen */ - -#ifndef yydefred -#define yydefred pfctlydefred -#endif /* yydefred */ - -#ifndef yydgoto -#define yydgoto pfctlydgoto -#endif /* yydgoto */ - -#ifndef yysindex -#define yysindex pfctlysindex -#endif /* yysindex */ - -#ifndef yyrindex -#define yyrindex pfctlyrindex -#endif /* yyrindex */ - -#ifndef yygindex -#define yygindex pfctlygindex -#endif /* yygindex */ - -#ifndef yytable -#define yytable pfctlytable -#endif /* yytable */ - -#ifndef yycheck -#define yycheck pfctlycheck -#endif /* yycheck */ - -#ifndef yyname -#define yyname pfctlyname -#endif /* yyname */ - -#ifndef yyrule -#define yyrule pfctlyrule -#endif /* yyrule */ -#define YYPREFIX "pfctly" - -#define YYPURE 0 - -#line 30 "../../freebsd/contrib/pf/pfctl/parse.y" -#ifdef __rtems__ -#include <machine/rtems-bsd-user-space.h> -#include <machine/rtems-bsd-program.h> -#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset -#define pf_anchor_setup _bsd_pf_anchor_setup -#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#ifdef __FreeBSD__ -#include <sys/sysctl.h> -#endif -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <netdb.h> -#include <stdarg.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include <err.h> -#include <limits.h> -#include <pwd.h> -#include <grp.h> -#include <md5.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -static struct pfctl *pf = NULL; -static int debug = 0; -static int rulestate = 0; -static u_int16_t returnicmpdefault = - (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; -static u_int16_t returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; -static int blockpolicy = PFRULE_DROP; -static int require_order = 1; -static int default_statelock; - -#ifndef __rtems__ -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -#else /* __rtems__ */ -static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -#endif /* __rtems__ */ -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - int lineno; - int errors; -} *file; -struct file *pushfile(const char *, int); -int popfile(void); -int check_file_secrecy(int, const char *); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...); -int kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(int); -int lungetc(int); -int findeol(void); - -#ifndef __rtems__ -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -#else /* __rtems__ */ -static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -#endif /* __rtems__ */ -struct sym { - TAILQ_ENTRY(sym) entry; - int used; - int persist; - char *nam; - char *val; -}; -int symset(const char *, const char *, int); -char *symget(const char *); - -int atoul(char *, u_long *); - -enum { - PFCTL_STATE_NONE, - PFCTL_STATE_OPTION, - PFCTL_STATE_SCRUB, - PFCTL_STATE_QUEUE, - PFCTL_STATE_NAT, - PFCTL_STATE_FILTER -}; - -struct node_proto { - u_int8_t proto; - struct node_proto *next; - struct node_proto *tail; -}; - -struct node_port { - u_int16_t port[2]; - u_int8_t op; - struct node_port *next; - struct node_port *tail; -}; - -struct node_uid { - uid_t uid[2]; - u_int8_t op; - struct node_uid *next; - struct node_uid *tail; -}; - -struct node_gid { - gid_t gid[2]; - u_int8_t op; - struct node_gid *next; - struct node_gid *tail; -}; - -struct node_icmp { - u_int8_t code; - u_int8_t type; - u_int8_t proto; - struct node_icmp *next; - struct node_icmp *tail; -}; - -enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, - PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, - PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, - PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, - PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, - PF_STATE_OPT_PFLOW }; - -enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; - -struct node_state_opt { - int type; - union { - u_int32_t max_states; - u_int32_t max_src_states; - u_int32_t max_src_conn; - struct { - u_int32_t limit; - u_int32_t seconds; - } max_src_conn_rate; - struct { - u_int8_t flush; - char tblname[PF_TABLE_NAME_SIZE]; - } overload; - u_int32_t max_src_nodes; - u_int8_t src_track; - u_int32_t statelock; - struct { - int number; - u_int32_t seconds; - } timeout; - } data; - struct node_state_opt *next; - struct node_state_opt *tail; -}; - -struct peer { - struct node_host *host; - struct node_port *port; -}; - -#ifndef __rtems__ -struct node_queue { -#else /* __rtems__ */ -static struct node_queue { -#endif /* __rtems__ */ - char queue[PF_QNAME_SIZE]; - char parent[PF_QNAME_SIZE]; - char ifname[IFNAMSIZ]; - int scheduler; - struct node_queue *next; - struct node_queue *tail; -} *queues = NULL; - -struct node_qassign { - char *qname; - char *pqname; -}; - -#ifndef __rtems__ -struct filter_opts { -#else /* __rtems__ */ -static struct filter_opts { -#endif /* __rtems__ */ - int marker; -#define FOM_FLAGS 0x01 -#define FOM_ICMP 0x02 -#define FOM_TOS 0x04 -#define FOM_KEEP 0x08 -#define FOM_SRCTRACK 0x10 - struct node_uid *uid; - struct node_gid *gid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } flags; - struct node_icmp *icmpspec; - u_int32_t tos; - u_int32_t prob; - struct { - int action; - struct node_state_opt *options; - } keep; - int fragment; - int allowopts; - char *label; - struct node_qassign queues; - char *tag; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; - struct { - struct node_host *addr; - u_int16_t port; - } divert; -} filter_opts; - -#ifndef __rtems__ -struct antispoof_opts { -#else /* __rtems__ */ -static struct antispoof_opts { -#endif /* __rtems__ */ - char *label; - u_int rtableid; -} antispoof_opts; - -#ifndef __rtems__ -struct scrub_opts { -#else /* __rtems__ */ -static struct scrub_opts { -#endif /* __rtems__ */ - int marker; -#define SOM_MINTTL 0x01 -#define SOM_MAXMSS 0x02 -#define SOM_FRAGCACHE 0x04 -#define SOM_SETTOS 0x08 - int nodf; - int minttl; - int maxmss; - int settos; - int fragcache; - int randomid; - int reassemble_tcp; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; -} scrub_opts; - -#ifndef __rtems__ -struct queue_opts { -#else /* __rtems__ */ -static struct queue_opts { -#endif /* __rtems__ */ - int marker; -#define QOM_BWSPEC 0x01 -#define QOM_SCHEDULER 0x02 -#define QOM_PRIORITY 0x04 -#define QOM_TBRSIZE 0x08 -#define QOM_QLIMIT 0x10 - struct node_queue_bw queue_bwspec; - struct node_queue_opt scheduler; - int priority; - int tbrsize; - int qlimit; -} queue_opts; - -#ifndef __rtems__ -struct table_opts { -#else /* __rtems__ */ -static struct table_opts { -#endif /* __rtems__ */ - int flags; - int init_addr; - struct node_tinithead init_nodes; -} table_opts; - -#ifndef __rtems__ -struct pool_opts { -#else /* __rtems__ */ -static struct pool_opts { -#endif /* __rtems__ */ - int marker; -#define POM_TYPE 0x01 -#define POM_STICKYADDRESS 0x02 - u_int8_t opts; - int type; - int staticport; - struct pf_poolhashkey *key; - -} pool_opts; - - -#ifndef __rtems__ -struct node_hfsc_opts hfsc_opts; -struct node_state_opt *keep_state_defaults = NULL; -#else /* __rtems__ */ -static struct node_hfsc_opts hfsc_opts; -static struct node_state_opt *keep_state_defaults = NULL; -#endif /* __rtems__ */ - -int disallow_table(struct node_host *, const char *); -int disallow_urpf_failed(struct node_host *, const char *); -int disallow_alias(struct node_host *, const char *); -int rule_consistent(struct pf_rule *, int); -int filter_consistent(struct pf_rule *, int); -int nat_consistent(struct pf_rule *); -int rdr_consistent(struct pf_rule *); -int process_tabledef(char *, struct table_opts *); -void expand_label_str(char *, size_t, const char *, const char *); -void expand_label_if(const char *, char *, size_t, const char *); -void expand_label_addr(const char *, char *, size_t, u_int8_t, - struct node_host *); -void expand_label_port(const char *, char *, size_t, - struct node_port *); -void expand_label_proto(const char *, char *, size_t, u_int8_t); -void expand_label_nr(const char *, char *, size_t); -void expand_label(char *, size_t, const char *, u_int8_t, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, u_int8_t); -void expand_rule(struct pf_rule *, struct node_if *, - struct node_host *, struct node_proto *, struct node_os *, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, struct node_uid *, struct node_gid *, - struct node_icmp *, const char *); -int expand_altq(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw bwspec, - struct node_queue_opt *); -int expand_queue(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw, - struct node_queue_opt *); -int expand_skip_interface(struct node_if *); - -int check_rulestate(int); -int getservice(char *); -int rule_label(struct pf_rule *, char *); -int rt_tableid_max(void); - -void mv_rules(struct pf_ruleset *, struct pf_ruleset *); -void decide_address_family(struct node_host *, sa_family_t *); -void remove_invalid_hosts(struct node_host **, sa_family_t *); -int invalid_redirect(struct node_host *, sa_family_t); -u_int16_t parseicmpspec(char *, sa_family_t); - -#ifndef __rtems__ -TAILQ_HEAD(loadanchorshead, loadanchors) -#else /* __rtems__ */ -static TAILQ_HEAD(loadanchorshead, loadanchors) -#endif /* __rtems__ */ - loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); - -struct loadanchors { - TAILQ_ENTRY(loadanchors) entries; - char *anchorname; - char *filename; -}; - -typedef struct { - union { - int64_t number; - double probability; - int i; - char *string; - u_int rtableid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } b; - struct range { - int a; - int b; - int t; - } range; - struct node_if *interface; - struct node_proto *proto; - struct node_icmp *icmp; - struct node_host *host; - struct node_os *os; - struct node_port *port; - struct node_uid *uid; - struct node_gid *gid; - struct node_state_opt *state_opt; - struct peer peer; - struct { - struct peer src, dst; - struct node_os *src_os; - } fromto; - struct { - struct node_host *host; - u_int8_t rt; - u_int8_t pool_opts; - sa_family_t af; - struct pf_poolhashkey *key; - } route; - struct redirection { - struct node_host *host; - struct range rport; - } *redirection; - struct { - int action; - struct node_state_opt *options; - } keep_state; - struct { - u_int8_t log; - u_int8_t logif; - u_int8_t quick; - } logquick; - struct { - int neg; - char *name; - } tagged; - struct pf_poolhashkey *hashkey; - struct node_queue *queue; - struct node_queue_opt queue_options; - struct node_queue_bw queue_bwspec; - struct node_qassign qassign; - struct filter_opts filter_opts; - struct antispoof_opts antispoof_opts; - struct queue_opts queue_opts; - struct scrub_opts scrub_opts; - struct table_opts table_opts; - struct pool_opts pool_opts; - struct node_hfsc_opts hfsc_opts; - } v; - int lineno; -} YYSTYPE; - -#define PPORT_RANGE 1 -#define PPORT_STAR 2 -int parseport(char *, struct range *r, int); - -#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ - (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ - !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) - -#line 562 "pfctly.tab.c" - -/* compatibility with bison */ -#ifdef YYPARSE_PARAM -/* compatibility with FreeBSD */ -# ifdef YYPARSE_PARAM_TYPE -# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) -# else -# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) -# endif -#else -# define YYPARSE_DECL() yyparse(void) -#endif - -/* Parameters sent to lex. */ -#ifdef YYLEX_PARAM -# define YYLEX_DECL() yylex(void *YYLEX_PARAM) -# define YYLEX yylex(YYLEX_PARAM) -#else -# define YYLEX_DECL() yylex(void) -# define YYLEX yylex() -#endif - -/* Parameters sent to yyerror. */ -#ifndef YYERROR_DECL -#define YYERROR_DECL() yyerror(const char *s) -#endif -#ifndef YYERROR_CALL -#define YYERROR_CALL(msg) yyerror(msg) -#endif - -extern int YYPARSE_DECL(); - -#define PASS 257 -#define BLOCK 258 -#define SCRUB 259 -#define RETURN 260 -#define IN 261 -#define OS 262 -#define OUT 263 -#define LOG 264 -#define QUICK 265 -#define ON 266 -#define FROM 267 -#define TO 268 -#define FLAGS 269 -#define RETURNRST 270 -#define RETURNICMP 271 -#define RETURNICMP6 272 -#define PROTO 273 -#define INET 274 -#define INET6 275 -#define ALL 276 -#define ANY 277 -#define ICMPTYPE 278 -#define ICMP6TYPE 279 -#define CODE 280 -#define KEEP 281 -#define MODULATE 282 -#define STATE 283 -#define PORT 284 -#define RDR 285 -#define NAT 286 -#define BINAT 287 -#define ARROW 288 -#define NODF 289 -#define MINTTL 290 -#define ERROR 291 -#define ALLOWOPTS 292 -#define FASTROUTE 293 -#define FILENAME 294 -#define ROUTETO 295 -#define DUPTO 296 -#define REPLYTO 297 -#define NO 298 -#define LABEL 299 -#define NOROUTE 300 -#define URPFFAILED 301 -#define FRAGMENT 302 -#define USER 303 -#define GROUP 304 -#define MAXMSS 305 -#define MAXIMUM 306 -#define TTL 307 -#define TOS 308 -#define DROP 309 -#define TABLE 310 -#define REASSEMBLE 311 -#define FRAGDROP 312 -#define FRAGCROP 313 -#define ANCHOR 314 -#define NATANCHOR 315 -#define RDRANCHOR 316 -#define BINATANCHOR 317 -#define SET 318 -#define OPTIMIZATION 319 -#define TIMEOUT 320 -#define LIMIT 321 -#define LOGINTERFACE 322 -#define BLOCKPOLICY 323 -#define RANDOMID 324 -#define REQUIREORDER 325 -#define SYNPROXY 326 -#define FINGERPRINTS 327 -#define NOSYNC 328 -#define DEBUG 329 -#define SKIP 330 -#define HOSTID 331 -#define ANTISPOOF 332 -#define FOR 333 -#define INCLUDE 334 -#define BITMASK 335 -#define RANDOM 336 -#define SOURCEHASH 337 -#define ROUNDROBIN 338 -#define STATICPORT 339 -#define PROBABILITY 340 -#define ALTQ 341 -#define CBQ 342 -#define PRIQ 343 -#define HFSC 344 -#define BANDWIDTH 345 -#define TBRSIZE 346 -#define LINKSHARE 347 -#define REALTIME 348 -#define UPPERLIMIT 349 -#define QUEUE 350 -#define PRIORITY 351 -#define QLIMIT 352 -#define RTABLE 353 -#define LOAD 354 -#define RULESET_OPTIMIZATION 355 -#define STICKYADDRESS 356 -#define MAXSRCSTATES 357 -#define MAXSRCNODES 358 -#define SOURCETRACK 359 -#define GLOBAL 360 -#define RULE 361 -#define MAXSRCCONN 362 -#define MAXSRCCONNRATE 363 -#define OVERLOAD 364 -#define FLUSH 365 -#define SLOPPY 366 -#define PFLOW 367 -#define TAGGED 368 -#define TAG 369 -#define IFBOUND 370 -#define FLOATING 371 -#define STATEPOLICY 372 -#define STATEDEFAULTS 373 -#define ROUTE 374 -#define SETTOS 375 -#define DIVERTTO 376 -#define DIVERTREPLY 377 -#define STRING 378 -#define NUMBER 379 -#define PORTBINARY 380 -#define YYERRCODE 256 -typedef int YYINT; -static const YYINT pfctlylhs[] = { -1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 127, 140, 140, - 140, 140, 140, 140, 18, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 76, 76, 79, 79, 80, 80, 81, 81, 137, - 78, 78, 146, 146, 146, 146, 148, 147, 147, 133, - 133, 133, 133, 134, 26, 129, 149, 116, 116, 118, - 118, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 17, 17, 17, 138, 91, 91, 92, 92, 93, 93, - 151, 110, 110, 112, 112, 111, 111, 11, 11, 139, - 152, 119, 119, 121, 121, 120, 120, 120, 120, 135, - 136, 153, 113, 113, 115, 115, 114, 114, 114, 114, - 114, 106, 106, 98, 98, 98, 98, 98, 98, 99, - 99, 100, 101, 101, 102, 154, 105, 103, 103, 104, - 104, 104, 104, 104, 104, 104, 95, 95, 95, 96, - 96, 97, 132, 155, 107, 107, 109, 109, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 13, 13, 23, 23, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 43, - 43, 44, 44, 15, 15, 15, 87, 87, 86, 86, - 86, 86, 86, 88, 88, 89, 89, 90, 90, 90, - 90, 1, 1, 1, 2, 2, 3, 4, 16, 16, - 16, 34, 34, 34, 35, 35, 36, 37, 37, 45, - 45, 60, 60, 60, 61, 62, 62, 47, 47, 48, - 48, 46, 46, 46, 142, 142, 49, 49, 49, 50, - 50, 54, 54, 51, 51, 51, 52, 52, 52, 52, - 52, 52, 52, 52, 5, 5, 53, 63, 63, 64, - 64, 65, 65, 65, 30, 32, 66, 66, 67, 67, - 68, 68, 68, 8, 8, 69, 69, 70, 70, 71, - 71, 71, 9, 9, 28, 27, 27, 27, 38, 38, - 38, 38, 39, 39, 41, 41, 40, 40, 40, 42, - 42, 42, 6, 6, 7, 7, 10, 10, 19, 19, - 19, 22, 22, 82, 82, 82, 82, 20, 20, 20, - 83, 83, 84, 84, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 75, 94, 94, 94, - 14, 14, 31, 56, 56, 55, 55, 74, 74, 74, - 33, 33, 156, 122, 122, 124, 124, 123, 123, 123, - 123, 123, 123, 73, 73, 73, 25, 25, 25, 25, - 24, 24, 130, 131, 77, 77, 125, 125, 126, 126, - 57, 57, 58, 58, 59, 59, 72, 72, 72, 72, - 72, 141, 143, 143, 144, 145, 145, 150, 150, 12, - 12, 21, 21, 21, 21, 21, 21, -}; -static const YYINT pfctlylen[] = { 2, - 0, 3, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 3, 2, 2, 3, - 3, 3, 3, 3, 1, 3, 3, 3, 6, 3, - 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 1, 2, 1, 2, 1, 1, 1, 3, - 1, 0, 0, 2, 3, 3, 0, 5, 0, 10, - 7, 7, 7, 5, 2, 8, 0, 2, 0, 2, - 1, 1, 2, 2, 2, 1, 2, 1, 2, 3, - 2, 2, 2, 5, 2, 5, 2, 4, 1, 3, - 0, 2, 0, 2, 1, 1, 2, 1, 0, 5, - 0, 2, 0, 2, 1, 1, 3, 4, 2, 5, - 5, 0, 2, 0, 2, 1, 2, 2, 2, 1, - 2, 1, 1, 1, 4, 1, 4, 1, 4, 1, - 3, 1, 1, 3, 1, 0, 2, 1, 3, 2, - 8, 2, 8, 2, 8, 1, 0, 1, 4, 2, - 4, 1, 9, 0, 2, 0, 2, 1, 2, 2, - 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, - 2, 2, 2, 4, 1, 1, 1, 1, 2, 0, - 1, 1, 5, 1, 1, 4, 4, 6, 1, 1, - 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, - 1, 2, 2, 1, 4, 1, 3, 1, 1, 1, - 2, 0, 2, 5, 2, 4, 2, 1, 0, 1, - 1, 0, 2, 5, 2, 4, 1, 1, 1, 1, - 3, 0, 2, 5, 1, 2, 4, 0, 2, 0, - 2, 1, 3, 2, 2, 0, 1, 1, 4, 2, - 0, 2, 4, 2, 2, 2, 1, 3, 3, 3, - 1, 3, 3, 2, 1, 1, 3, 1, 4, 2, - 4, 1, 2, 3, 1, 1, 1, 4, 2, 4, - 1, 2, 3, 1, 1, 1, 4, 2, 4, 1, - 2, 3, 1, 1, 1, 4, 3, 2, 2, 5, - 2, 5, 2, 4, 2, 4, 1, 3, 3, 1, - 3, 3, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 2, 3, 3, 3, 0, 1, 2, - 3, 0, 1, 3, 2, 1, 2, 2, 4, 5, - 2, 1, 1, 1, 1, 2, 2, 2, 4, 6, - 0, 1, 1, 1, 4, 2, 4, 0, 2, 4, - 0, 1, 0, 2, 0, 2, 1, 1, 1, 2, - 1, 1, 1, 0, 2, 4, 0, 1, 2, 1, - 3, 3, 10, 13, 0, 2, 0, 3, 0, 2, - 1, 4, 2, 4, 1, 4, 0, 1, 3, 3, - 3, 2, 4, 2, 2, 4, 2, 1, 0, 1, - 1, 1, 2, 2, 1, 2, 1, -}; -static const YYINT pfctlydefred[] = { 0, - 0, 0, 0, 0, 178, 0, 352, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, - 0, 0, 0, 0, 0, 17, 189, 0, 0, 0, - 181, 179, 0, 51, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, - 0, 0, 65, 0, 0, 0, 195, 196, 0, 0, - 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 24, 16, 22, 21, 23, 20, - 0, 0, 0, 0, 0, 44, 0, 0, 0, 26, - 0, 0, 28, 0, 0, 30, 43, 42, 32, 35, - 34, 410, 411, 36, 37, 39, 40, 266, 265, 33, - 27, 25, 322, 323, 38, 0, 336, 0, 0, 0, - 0, 0, 0, 344, 345, 0, 342, 343, 0, 333, - 0, 203, 0, 0, 202, 0, 98, 213, 0, 0, - 0, 0, 0, 49, 48, 50, 0, 0, 382, 380, - 381, 0, 0, 220, 221, 0, 0, 0, 190, 191, - 0, 192, 193, 0, 0, 198, 0, 0, 0, 0, - 402, 0, 0, 405, 0, 335, 337, 341, 320, 321, - 338, 0, 0, 346, 408, 0, 0, 208, 209, 210, - 0, 206, 218, 0, 0, 89, 85, 0, 0, 217, - 0, 0, 0, 0, 0, 0, 0, 0, 120, 116, - 0, 0, 0, 46, 379, 0, 0, 0, 0, 0, - 0, 186, 0, 187, 100, 0, 0, 0, 0, 0, - 245, 0, 0, 0, 0, 0, 0, 334, 211, 205, - 0, 0, 0, 84, 0, 0, 0, 152, 0, 110, - 148, 0, 0, 136, 122, 123, 117, 121, 118, 119, - 115, 111, 64, 0, 398, 0, 0, 0, 0, 228, - 229, 0, 223, 227, 0, 230, 0, 0, 0, 183, - 0, 0, 106, 0, 105, 0, 0, 0, 0, 0, - 404, 29, 0, 407, 31, 0, 339, 0, 207, 0, - 0, 90, 0, 0, 96, 95, 0, 214, 0, 215, - 0, 132, 0, 130, 135, 0, 133, 0, 0, 0, - 391, 0, 0, 395, 0, 0, 0, 0, 0, 247, - 0, 0, 0, 239, 0, 248, 0, 0, 0, 0, - 0, 188, 109, 0, 104, 0, 0, 61, 62, 63, - 0, 0, 0, 340, 86, 0, 87, 347, 97, 94, - 0, 0, 0, 125, 0, 127, 0, 129, 0, 0, - 0, 146, 0, 138, 0, 0, 0, 399, 0, 401, - 400, 0, 0, 0, 0, 412, 0, 0, 0, 0, - 0, 244, 268, 276, 0, 255, 256, 0, 0, 0, - 0, 0, 254, 0, 0, 386, 0, 0, 235, 0, - 233, 0, 231, 0, 107, 0, 0, 0, 390, 403, - 406, 330, 0, 216, 149, 0, 150, 131, 134, 0, - 140, 0, 142, 0, 144, 0, 0, 0, 0, 0, - 368, 369, 0, 371, 372, 373, 367, 0, 0, 224, - 0, 225, 0, 413, 414, 416, 273, 0, 0, 264, - 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, - 241, 66, 0, 252, 108, 0, 0, 0, 88, 0, - 0, 0, 0, 139, 0, 0, 393, 396, 0, 392, - 370, 362, 366, 153, 0, 0, 0, 274, 249, 258, - 259, 260, 267, 263, 262, 388, 0, 0, 0, 0, - 72, 0, 0, 0, 0, 78, 0, 0, 0, 76, - 71, 0, 0, 57, 60, 0, 0, 0, 0, 0, - 166, 0, 165, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 175, 0, 161, 162, 167, 164, 168, 158, - 0, 151, 0, 0, 0, 250, 0, 0, 226, 269, - 0, 270, 0, 354, 0, 383, 236, 234, 0, 73, - 81, 83, 82, 74, 77, 79, 317, 318, 75, 0, - 70, 253, 0, 298, 295, 0, 0, 313, 314, 0, - 0, 299, 315, 316, 0, 0, 301, 0, 0, 324, - 284, 285, 0, 0, 0, 159, 277, 293, 294, 0, - 0, 0, 160, 286, 163, 0, 176, 177, 171, 348, - 0, 172, 169, 0, 173, 275, 0, 157, 0, 0, - 0, 0, 394, 0, 0, 0, 0, 80, 53, 297, - 0, 0, 0, 0, 0, 0, 325, 326, 0, 0, - 282, 0, 0, 291, 327, 0, 0, 170, 0, 0, - 0, 0, 271, 0, 0, 360, 353, 237, 0, 296, - 0, 0, 308, 309, 0, 0, 311, 312, 0, 0, - 0, 283, 0, 0, 292, 349, 0, 174, 0, 0, - 0, 0, 384, 356, 355, 0, 54, 58, 0, 0, - 300, 0, 303, 302, 0, 305, 331, 278, 0, 279, - 287, 0, 288, 0, 141, 143, 145, 0, 0, 55, - 56, 0, 0, 0, 0, 350, 0, 357, 304, 306, - 280, 289, 376, -}; -static const YYINT pfctlydgoto[] = { 2, - 79, 276, 168, 226, 140, 621, 626, 634, 641, 609, - 363, 134, 649, 21, 89, 186, 550, 141, 157, 384, - 420, 158, 22, 23, 179, 24, 575, 617, 52, 655, - 696, 421, 521, 249, 413, 303, 304, 576, 701, 622, - 705, 627, 191, 194, 307, 364, 308, 443, 365, 516, - 366, 433, 434, 447, 695, 595, 354, 469, 355, 370, - 441, 540, 422, 526, 423, 636, 710, 637, 643, 713, - 644, 299, 723, 538, 335, 129, 368, 55, 57, 176, - 424, 578, 677, 159, 160, 75, 197, 76, 221, 222, - 164, 330, 227, 579, 280, 392, 281, 239, 343, 344, - 346, 347, 403, 404, 348, 287, 507, 580, 581, 274, - 336, 337, 170, 240, 241, 502, 551, 552, 255, 315, - 316, 408, 477, 478, 438, 378, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 3, - 123, 203, 263, 126, 265, 699, 555, 613, 503, 216, - 275, 256, 171, 349, 508, 409, -}; -static const YYINT pfctlysindex[] = { -41, - 0, 240, 1290, 91, 0, 289, 0, 36, -160, -144, - -144, -144, 1628, 235, -129, 26, -113, 29, 258, 0, - 423, -155, 26, -155, 321, 368, 372, 376, 388, 406, - 437, 460, 479, 516, 520, 526, 563, 568, 0, 579, - -57, 605, 633, 636, 638, 0, 0, 529, 614, 617, - 0, 0, 231, 0, -155, -144, 26, 26, 26, 297, - -89, -84, -196, -45, -189, 300, 302, 26, -124, -144, - 134, 1742, 648, 427, 385, 440, 0, 8, 0, 26, - -144, 168, 0, -162, -162, -162, 0, 0, 235, 354, - 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 429, 280, 291, 688, 488, 0, 354, 354, 354, 0, - 379, 753, 0, 436, 753, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 438, 0, 471, 477, 312, - 486, 497, 710, 0, 0, 507, 0, 0, 764, 0, - 417, 0, 14, 354, 0, 753, 0, 0, 464, 548, - 1505, 0, 580, 0, 0, 0, 168, 427, 0, 0, - 0, 26, 26, 0, 0, 632, 26, 510, 0, 0, - 370, 0, 0, 866, 0, 0, 26, 632, 632, 632, - 0, 753, 544, 0, 550, 0, 0, 0, 0, 0, - 0, 883, 556, 0, 0, 1742, -144, 0, 0, 0, - 381, 0, 0, 753, 464, 0, 0, 0, 906, 0, - -81, 903, 905, 908, 316, 570, 578, 594, 0, 0, - 1505, -81, -144, 0, 0, 354, 671, -64, -59, 354, - 909, 0, 291, 0, 0, -94, 354, -59, -59, -59, - 0, 753, 49, 753, 63, 595, 898, 0, 0, 0, - 417, -24, 938, 0, -211, 73, 753, 0, 753, 0, - 0, 604, 613, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 632, 0, 24, 24, 24, 354, 0, - 0, 753, 0, 0, -9, 0, 623, 721, 632, 0, - 952, 618, 0, 753, 0, -94, 632, 645, 645, 645, - 0, 0, 544, 0, 0, 550, 0, 639, 0, 74, - 753, 0, 629, 635, 0, 0, -211, 0, 906, 0, - 642, 0, 474, 0, 0, 523, 0, 975, 272, 750, - 0, 753, 644, 0, 0, 0, 0, 632, 333, 0, - 78, 753, 1053, 0, 741, 0, 649, 906, -58, 760, - -59, 0, 0, -10, 0, -59, 651, 0, 0, 0, - 753, 753, 678, 0, 0, -24, 0, 0, 0, 0, - 753, 86, 753, 0, 604, 0, 613, 0, 64, 80, - 85, 0, 764, 0, 206, -4, 206, 0, 1280, 0, - 0, -59, 128, 753, 753, 0, 970, 978, 982, 168, - 664, 0, 0, 0, -7, 0, 0, 667, 195, 999, - 682, 687, 0, 1021, 78, 0, 701, 645, 0, 753, - 0, -9, 0, 0, 0, 753, 131, 0, 0, 0, - 0, 0, 753, 0, 0, 642, 0, 0, 0, 316, - 0, 316, 0, 316, 0, 272, 802, 753, 182, 1032, - 0, 0, -144, 0, 0, 0, 0, 1280, 0, 0, - 333, 0, 130, 0, 0, 0, 0, 168, 197, 0, - 698, 699, 700, 1039, 1020, 704, 0, -144, 798, 706, - 0, 0, 815, 0, 0, -7, 964, 4116, 0, 753, - 764, 764, 764, 0, -7, 623, 0, 0, -4, 0, - 0, 0, 0, 0, 753, 213, 753, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 877, 0, 753, 217, - 0, 715, 311, 719, 711, 0, 720, 336, 735, 0, - 0, 815, 753, 0, 0, 5, -53, 99, 823, 824, - 0, 835, 0, 116, 124, 336, 838, 346, 27, 743, - -144, 377, 0, 748, 0, 0, 0, 0, 0, 0, - 4116, 0, 744, 745, 749, 0, 906, 753, 0, 0, - 130, 0, 753, 0, 843, 0, 0, 0, 706, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -144, - 0, 0, 1124, 0, 0, 762, 1091, 0, 0, 753, - 862, 0, 0, 0, 753, 864, 0, 1105, 1105, 0, - 0, 0, 753, 767, 390, 0, 0, 0, 0, 753, - 768, 411, 0, 0, 0, 1105, 0, 0, 0, 0, - 772, 0, 0, 867, 0, 0, -144, 0, 764, 764, - 764, 645, 0, 753, 206, 168, 753, 0, 0, 0, - 762, 414, 432, 446, 450, 1742, 0, 0, 163, 390, - 0, 198, 411, 0, 0, 559, 168, 0, 316, 316, - 316, 865, 0, 753, 325, 0, 0, 0, 1257, 0, - 463, 753, 0, 0, 468, 753, 0, 0, 573, 476, - 753, 0, 491, 753, 0, 0, 774, 0, 1113, 1115, - 1116, 206, 0, 0, 0, 206, 0, 0, 1148, 1150, - 0, 414, 0, 0, 446, 0, 0, 0, 163, 0, - 0, 198, 0, 1122, 0, 0, 0, 880, 753, 0, - 0, 753, 753, 753, 753, 0, 168, 0, 0, 0, - 0, 0, 0, -}; -static const YYINT pfctlyrindex[] = { 43, - 0, 545, 352, 0, 0, 1520, 0, 0, 2567, 0, - 0, 0, 0, 834, 0, 1412, 0, 0, 0, 0, - 0, 2174, 3980, 1569, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1637, 1757, 1874, - 0, 0, 0, 0, 2798, 1183, 337, 337, 337, 0, - 0, 0, 0, 0, 0, 0, 0, 1156, 0, 0, - 0, 0, 1067, 1288, 0, 1400, 0, 801, 1428, 84, - 0, 0, 0, 3867, 3867, 539, 0, 0, 2630, 4002, - 1705, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2854, 0, 481, 481, 481, 0, - 0, 803, 0, 0, 803, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, - 0, 0, 0, 0, 0, 0, 0, 0, 960, 0, - 0, 0, 0, 46, 0, -16, 0, 0, 0, 0, - 0, 712, 0, 0, 0, 0, 1166, 3924, 0, 0, - 0, 571, 2742, 0, 0, 4037, 3769, 0, 0, 0, - 462, 0, 0, 0, 9, 0, 2975, 56, 56, 56, - 0, 1591, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 498, 0, 0, 34, 0, 0, 0, 47, 801, 0, - 1170, 558, 569, 581, 0, 0, 0, 0, 0, 0, - 1, 1170, 0, 0, 0, -54, 3093, 0, 2622, 2979, - 0, 0, 0, 0, 0, 0, 3254, 23, 23, 23, - 0, -34, 804, -34, 804, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, -12, -13, 0, 803, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 917, 0, 0, 0, 0, 3317, 0, - 0, 485, 0, 0, 1089, 0, 391, 2058, 2062, 0, - 0, 0, 0, 39, 0, 520, 3370, 1175, 1175, 1175, - 0, 0, 0, 0, 0, 0, 0, 109, 0, 41, - -22, 0, 0, 0, 0, 0, 321, 0, 801, 0, - 0, 0, 804, 0, 0, 804, 0, 0, 0, 0, - 0, 34, 0, 0, 2335, 2335, 2335, 3450, 0, 0, - 0, 154, 0, 0, 1966, 0, 0, 943, 0, 2230, - 2469, 0, 0, 1089, 0, 3530, 0, 0, 0, 0, - -34, -34, 521, 0, 0, 0, 0, 0, 0, 0, - -13, 804, -34, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 204, 0, 0, 0, 0, 0, 0, 0, - 0, 3593, 462, 161, 218, 0, 0, 489, 496, 0, - 673, 0, 0, 0, 1089, 0, 0, 0, 363, 0, - 0, 0, 0, 483, 0, 0, 0, 650, 0, 803, - 0, 1089, 0, 713, 0, 11, 1007, 3646, 0, 0, - 0, 0, -22, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1, -22, 41, 0, - 0, 0, 2447, 0, 0, 0, 0, 3149, 3869, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1007, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 441, 0, - 0, 0, 819, 0, 0, 1089, 1179, 819, 0, -34, - 812, 812, 812, 0, 1089, -5, 0, 0, 0, 0, - 0, 0, 0, 0, 161, 248, 16, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 534, -34, 804, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 11, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, 2, -22, 0, 0, - 0, 0, 421, 0, 697, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 485, - 896, 0, 0, 0, 485, 936, 0, 3726, 3726, 0, - 0, 0, 218, 793, 0, 0, 0, 0, 0, 218, - 833, 0, 0, 0, 0, 3726, 0, 0, 0, 0, - 0, 0, 0, 3806, 0, 0, 0, 0, 462, 462, - 462, 17, 0, 16, 0, 0, -34, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 804, 0, 0, 0, 0, - 0, 1182, 0, 192, 616, 0, 0, 0, 0, 0, - 462, 161, 0, 0, 462, 161, 0, 0, 1859, 248, - 16, 0, 248, 16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1186, 192, 0, - 0, 161, 161, 16, 16, 0, 0, 0, 0, 0, - 0, 0, 0, -}; -static const YYINT pfctlygindex[] = { 0, - 1552, 0, -166, 51, 0, 0, 0, -470, -439, 631, - -70, 0, 0, 1200, 66, 991, 0, 0, 0, 0, - 737, 1135, 0, 0, 796, 0, 0, -423, 0, 532, - 451, -322, 0, 1328, 0, -352, 0, 0, 0, -622, - 0, -613, 0, 954, -174, 771, 0, 0, 7, 0, - 0, 279, 0, 795, 0, 0, -348, 0, 599, 0, - -431, 0, 786, 0, -443, 0, 0, -611, 0, 0, - -607, 0, 0, 0, -375, 0, 707, 0, -8, 1048, - -80, 0, -425, 553, 1010, 215, 0, 95, 0, 959, - 0, 0, -242, 0, 990, 0, -295, 0, 0, 847, - 0, 836, 0, 777, 0, 1038, 766, 666, 0, 0, - 913, 0, 1080, 1012, 0, 0, 702, 0, 0, 941, - 0, -205, 780, 0, 672, -282, 0, 0, 0, 1258, - 1260, -3, -2, 0, 0, 0, 0, 0, 0, 0, - -168, -119, 0, -180, 0, 0, 0, 0, 0, -176, - 0, 0, 0, 0, 0, 0, -}; -#define YYTABLESIZE 4493 -static const YYINT pfctlytable[] = { 44, - 45, 177, 58, 59, 385, 205, 414, 169, 251, 246, - 113, 387, 68, 155, 253, 225, 246, 246, 103, 246, - 409, 246, 167, 167, 264, 167, 389, 385, 314, 331, - 246, 251, 238, 122, 262, 353, 379, 380, 125, 527, - 167, 279, 1, 246, 271, 393, 229, 116, 246, 702, - 246, 616, 1, 225, 246, 219, 93, 468, 302, 246, - 706, 142, 277, 353, 440, 222, 651, 711, 539, 620, - 246, 246, 173, 246, 714, 246, 246, 246, 246, 127, - 409, 1, 261, 318, 319, 320, 323, 333, 326, 91, - 246, 319, 215, 212, 178, 53, 177, 487, 246, 339, - 46, 73, 246, 460, 272, 87, 215, 88, 132, 752, - 417, 246, 362, 362, 445, 362, 215, 215, 328, 462, - 115, 753, 319, 113, 464, 319, 155, 754, 525, 215, - 166, 101, 577, 246, 755, 246, 224, 418, 416, 419, - 246, 334, 321, 453, 324, 382, 352, 664, 417, 328, - 410, 411, 328, 386, 381, 499, 417, 340, 169, 341, - 510, 246, 417, 246, 681, 528, 395, 667, 162, 397, - 588, 215, 391, 322, 215, 418, 416, 419, 180, 180, - 180, 128, 359, 418, 416, 419, 246, 325, 133, 418, - 416, 419, 670, 246, 374, 417, 444, 338, 385, 312, - 415, 448, 684, 678, 246, 577, 212, 305, 269, 712, - 455, 387, 219, 246, 130, 456, 306, 54, 219, 230, - 685, 625, 418, 416, 419, 215, 466, 84, 85, 86, - 417, 246, 406, 56, 293, 246, 481, 479, 633, 491, - 215, 492, 425, 715, 137, 431, 640, 700, 77, 20, - 246, 246, 480, 138, 139, 505, 215, 418, 416, 419, - 215, 450, 451, 131, 80, 432, 360, 360, 169, 360, - 506, 454, 245, 457, 361, 273, 246, 246, 246, 246, - 409, 614, 385, 313, 238, 246, 251, 246, 121, 387, - 238, 78, 519, 124, 482, 483, 278, 437, 1, 1, - 1, 1, 101, 183, 389, 187, 518, 409, 409, 409, - 246, 246, 506, 300, 301, 246, 246, 222, 82, 439, - 500, 529, 222, 222, 618, 619, 504, 1, 1, 1, - 92, 222, 596, 509, 583, 584, 585, 590, 246, 246, - 1, 598, 81, 246, 219, 91, 212, 385, 517, 591, - 113, 251, 1, 223, 387, 246, 1, 1, 1, 1, - 1, 246, 385, 599, 246, 409, 251, 251, 215, 99, - 99, 99, 257, 351, 1, 238, 1, 93, 113, 692, - 446, 94, 615, 1, 246, 95, 101, 319, 246, 246, - 582, 223, 1, 246, 246, 257, 1, 96, 219, 91, - 385, 351, 257, 257, 650, 589, 257, 592, 222, 319, - 252, 246, 246, 215, 328, 97, 246, 246, 409, 597, - 1, 270, 257, 385, 215, 212, 212, 212, 212, 212, - 246, 446, 549, 612, 212, 212, 328, 574, 319, 319, - 319, 285, 286, 319, 319, 319, 98, 319, 319, 725, - 358, 319, 319, 246, 246, 174, 175, 285, 286, 319, - 246, 212, 285, 286, 522, 328, 328, 328, 663, 99, - 328, 328, 328, 665, 328, 328, 623, 624, 328, 328, - 246, 549, 689, 690, 691, 257, 328, 257, 100, 536, - 219, 656, 261, 631, 632, 4, 5, 6, 73, 74, - 672, 638, 639, 143, 144, 674, 215, 174, 175, 717, - 574, 215, 553, 679, 394, 261, 437, 215, 726, 215, - 682, 586, 261, 261, 732, 101, 261, 246, 735, 102, - 329, 246, 246, 739, 215, 103, 742, 7, 246, 246, - 631, 632, 261, 365, 693, 174, 175, 698, 47, 8, - 409, 409, 409, 9, 10, 11, 12, 13, 48, 49, - 50, 329, 653, 396, 329, 246, 215, 124, 111, 246, - 246, 14, 104, 15, 724, 638, 639, 105, 126, 428, - 16, 409, 733, 429, 430, 697, 736, 731, 106, 17, - 128, 740, 734, 18, 743, 246, 246, 51, 212, 716, - 738, 668, 215, 212, 212, 261, 656, 261, 114, 212, - 212, 212, 212, 737, 107, 741, 215, 19, 399, 400, - 401, 601, 602, 603, 257, 409, 409, 184, 185, 758, - 257, 257, 759, 760, 761, 762, 351, 351, 351, 257, - 257, 257, 108, 257, 257, 109, 257, 110, 688, 402, - 257, 257, 257, 112, 257, 409, 113, 189, 190, 389, - 257, 257, 257, 257, 257, 257, 257, 257, 192, 193, - 257, 209, 210, 257, 120, 409, 697, 135, 385, 136, - 124, 83, 272, 467, 217, 470, 257, 161, 257, 212, - 73, 126, 218, 285, 286, 729, 730, 257, 257, 257, - 257, 257, 257, 128, 165, 272, 359, 84, 85, 86, - 300, 301, 257, 607, 608, 257, 272, 163, 257, 219, - 220, 114, 69, 647, 648, 385, 385, 385, 385, 385, - 257, 257, 272, 272, 272, 188, 257, 257, 257, 257, - 257, 257, 219, 385, 261, 67, 385, 219, 219, 195, - 261, 261, 196, 219, 654, 175, 219, 201, 385, 261, - 261, 261, 202, 261, 261, 409, 261, 631, 632, 213, - 261, 261, 261, 409, 261, 358, 358, 358, 358, 358, - 261, 261, 261, 261, 261, 261, 261, 261, 638, 639, - 261, 618, 619, 261, 246, 272, 358, 272, 246, 246, - 409, 409, 281, 351, 377, 377, 261, 215, 261, 703, - 704, 377, 377, 377, 204, 594, 206, 261, 261, 261, - 261, 261, 261, 623, 624, 281, 329, 707, 708, 351, - 351, 351, 261, 219, 114, 261, 281, 212, 261, 409, - 409, 223, 290, 212, 212, 212, 243, 167, 329, 207, - 261, 261, 281, 281, 281, 208, 261, 261, 261, 261, - 261, 261, 246, 246, 211, 290, 415, 415, 363, 363, - 363, 363, 363, 417, 417, 212, 290, 329, 329, 329, - 181, 182, 329, 329, 329, 214, 329, 329, 251, 363, - 329, 329, 290, 290, 290, 356, 357, 231, 329, 124, - 124, 124, 124, 124, 248, 307, 254, 124, 124, 124, - 126, 126, 126, 126, 126, 281, 431, 281, 126, 126, - 126, 121, 128, 128, 128, 128, 128, 124, 307, 266, - 128, 128, 128, 267, 272, 124, 432, 389, 167, 307, - 272, 272, 282, 694, 283, 310, 126, 284, 288, 310, - 272, 272, 387, 272, 272, 290, 289, 290, 128, 328, - 272, 272, 272, 295, 272, 296, 297, 298, 310, 41, - 272, 272, 290, 327, 272, 272, 272, 272, 332, 310, - 272, 342, 369, 272, 389, 389, 389, 389, 389, 409, - 345, 367, 372, 409, 409, 373, 272, 377, 272, 593, - 748, 67, 67, 383, 749, 389, 388, 272, 272, 272, - 272, 272, 272, 389, 67, 398, 405, 67, 307, 278, - 307, 407, 272, 67, 435, 272, 436, 442, 272, 449, - 484, 359, 359, 359, 359, 359, 67, 452, 485, 409, - 272, 272, 486, 488, 490, 493, 409, 272, 272, 272, - 272, 272, 359, 112, 112, 112, 112, 112, 310, 494, - 310, 281, 112, 112, 495, 67, 409, 496, 498, 515, - 281, 281, 520, 281, 281, 530, 204, 531, 532, 533, - 67, 534, 535, 439, 281, 537, 554, 67, 605, 114, - 281, 281, 431, 600, 281, 281, 281, 604, 606, 204, - 281, 290, 610, 541, 542, 628, 629, 198, 199, 200, - 290, 290, 432, 290, 290, 657, 543, 630, 281, 544, - 646, 652, 659, 660, 290, 545, 666, 661, 99, 409, - 290, 290, 281, 669, 290, 290, 290, 671, 546, 615, - 290, 673, 281, 675, 676, 281, 680, 683, 99, 686, - 687, 744, 722, 745, 228, 746, 747, 750, 290, 751, - 281, 281, 756, 757, 307, 212, 199, 547, 281, 281, - 281, 281, 290, 307, 307, 47, 307, 307, 99, 147, - 246, 409, 290, 222, 389, 290, 99, 307, 59, 548, - 409, 374, 45, 307, 307, 375, 645, 307, 307, 307, - 290, 290, 41, 307, 310, 145, 311, 763, 290, 290, - 290, 290, 501, 310, 310, 45, 310, 310, 718, 489, - 497, 307, 587, 45, 244, 268, 45, 310, 709, 329, - 387, 292, 459, 310, 310, 307, 294, 310, 310, 310, - 309, 458, 514, 310, 524, 307, 658, 317, 307, 390, - 428, 242, 291, 611, 429, 430, 375, 523, 662, 0, - 42, 310, 43, 307, 307, 409, 727, 0, 0, 0, - 0, 307, 307, 307, 307, 310, 0, 387, 387, 387, - 387, 387, 0, 409, 0, 310, 0, 409, 310, 358, - 0, 0, 0, 0, 0, 387, 0, 201, 387, 39, - 635, 642, 0, 310, 310, 45, 409, 409, 0, 0, - 99, 310, 310, 310, 310, 0, 409, 409, 409, 0, - 201, 409, 409, 409, 0, 409, 409, 0, 204, 409, - 409, 204, 204, 204, 204, 204, 0, 409, 0, 204, - 204, 204, 204, 0, 204, 204, 0, 204, 204, 0, - 0, 0, 426, 427, 204, 204, 204, 0, 204, 204, - 0, 204, 204, 204, 204, 204, 0, 0, 204, 204, - 204, 204, 0, 0, 204, 0, 0, 204, 0, 0, - 409, 728, 0, 0, 409, 409, 0, 0, 99, 99, - 204, 0, 204, 0, 0, 0, 0, 0, 0, 204, - 0, 204, 204, 204, 204, 204, 204, 0, 0, 200, - 0, 0, 0, 0, 40, 635, 204, 0, 642, 204, - 0, 0, 204, 0, 0, 0, 428, 0, 0, 0, - 429, 430, 200, 0, 204, 204, 461, 463, 465, 0, - 0, 204, 204, 204, 45, 0, 0, 0, 45, 45, - 45, 45, 0, 0, 0, 45, 45, 45, 45, 0, - 45, 45, 99, 45, 45, 0, 99, 99, 0, 0, - 45, 45, 45, 0, 45, 635, 0, 0, 642, 0, - 45, 45, 0, 0, 45, 45, 45, 45, 0, 0, - 45, 0, 0, 45, 0, 0, 0, 511, 0, 512, - 0, 513, 0, 0, 0, 0, 45, 0, 45, 0, - 0, 0, 0, 5, 6, 0, 0, 45, 45, 45, - 45, 45, 45, 0, 0, 258, 259, 260, 0, 180, - 0, 0, 45, 0, 0, 45, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 38, 5, 6, 0, 201, - 45, 45, 180, 201, 201, 201, 201, 45, 45, 45, - 201, 201, 201, 201, 0, 201, 201, 0, 201, 201, - 9, 10, 11, 12, 90, 0, 201, 201, 194, 201, - 201, 0, 201, 201, 201, 201, 201, 7, 0, 201, - 201, 201, 201, 0, 0, 201, 0, 0, 201, 0, - 0, 194, 0, 9, 10, 11, 12, 0, 117, 118, - 119, 201, 0, 201, 471, 472, 473, 474, 475, 137, - 201, 350, 0, 246, 0, 0, 0, 201, 0, 0, - 246, 172, 0, 0, 246, 476, 371, 201, 0, 0, - 201, 0, 0, 0, 376, 0, 182, 0, 0, 0, - 246, 246, 246, 0, 0, 201, 201, 0, 0, 0, - 0, 200, 201, 201, 201, 200, 200, 200, 200, 182, - 0, 0, 200, 200, 200, 200, 0, 200, 200, 0, - 200, 200, 0, 0, 0, 412, 0, 0, 200, 200, - 0, 200, 200, 0, 200, 200, 200, 200, 200, 0, - 0, 200, 200, 200, 200, 0, 0, 200, 0, 0, - 200, 0, 0, 246, 199, 246, 0, 0, 0, 0, - 0, 0, 0, 200, 0, 200, 719, 720, 721, 0, - 0, 0, 200, 246, 247, 0, 0, 199, 250, 200, - 0, 0, 0, 0, 0, 0, 0, 0, 257, 200, - 0, 0, 200, 212, 212, 212, 212, 212, 0, 0, - 0, 212, 212, 212, 0, 0, 184, 200, 200, 112, - 112, 112, 112, 112, 200, 200, 200, 114, 112, 112, - 180, 180, 180, 180, 180, 180, 180, 180, 180, 184, - 0, 0, 180, 180, 180, 180, 0, 180, 180, 0, - 180, 180, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 180, 180, 0, 180, 180, 180, 180, 180, 0, - 0, 180, 180, 180, 0, 0, 0, 180, 0, 0, - 194, 0, 194, 194, 194, 194, 194, 0, 0, 0, - 0, 194, 194, 194, 194, 180, 232, 233, 234, 235, - 236, 0, 0, 0, 0, 237, 238, 194, 194, 180, - 0, 0, 0, 0, 0, 0, 0, 246, 0, 180, - 194, 0, 180, 194, 0, 0, 0, 0, 0, 194, - 0, 0, 0, 185, 0, 0, 0, 180, 180, 0, - 246, 246, 194, 0, 0, 180, 180, 182, 182, 182, - 182, 182, 182, 182, 182, 182, 185, 0, 0, 182, - 182, 182, 182, 0, 182, 182, 0, 182, 182, 0, - 0, 194, 0, 0, 0, 0, 0, 0, 182, 182, - 0, 182, 182, 182, 182, 182, 194, 0, 182, 182, - 182, 0, 0, 194, 182, 0, 60, 61, 62, 63, - 64, 0, 65, 0, 66, 0, 67, 68, 69, 0, - 0, 0, 182, 0, 246, 0, 199, 0, 246, 246, - 199, 199, 199, 0, 0, 242, 182, 199, 199, 199, - 199, 0, 70, 0, 0, 0, 182, 0, 0, 182, - 0, 0, 0, 199, 199, 0, 0, 0, 242, 71, - 72, 0, 0, 0, 182, 182, 199, 0, 0, 199, - 0, 0, 182, 182, 0, 199, 0, 184, 184, 184, - 184, 184, 184, 184, 184, 184, 0, 0, 199, 184, - 184, 184, 184, 0, 184, 184, 0, 184, 184, 0, - 0, 0, 0, 0, 0, 0, 0, 146, 184, 184, - 0, 184, 184, 184, 184, 184, 0, 199, 184, 184, - 184, 0, 0, 0, 184, 0, 0, 232, 0, 147, - 0, 222, 199, 0, 0, 0, 0, 0, 0, 199, - 0, 0, 184, 0, 0, 0, 0, 0, 242, 0, - 232, 0, 0, 0, 222, 0, 184, 0, 148, 149, - 150, 0, 0, 151, 152, 153, 184, 154, 155, 184, - 0, 143, 144, 0, 0, 0, 0, 0, 0, 156, - 0, 0, 0, 0, 184, 184, 0, 0, 0, 0, - 0, 0, 184, 184, 185, 185, 185, 185, 185, 185, - 185, 185, 185, 0, 0, 0, 185, 185, 185, 185, - 0, 185, 185, 0, 185, 185, 0, 0, 0, 0, - 0, 0, 0, 0, 409, 185, 185, 0, 185, 185, - 185, 185, 185, 0, 0, 185, 185, 185, 0, 0, - 232, 185, 0, 194, 0, 0, 409, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, - 0, 0, 0, 0, 0, 0, 194, 0, 0, 0, - 0, 0, 0, 185, 0, 409, 409, 409, 0, 0, - 409, 409, 409, 185, 409, 409, 185, 242, 409, 409, - 0, 0, 0, 242, 242, 0, 409, 0, 0, 240, - 0, 185, 185, 242, 242, 0, 242, 242, 0, 185, - 185, 0, 0, 242, 242, 242, 0, 242, 0, 0, - 0, 0, 240, 242, 242, 0, 0, 242, 242, 242, - 242, 0, 0, 242, 0, 0, 242, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, - 0, 242, 0, 0, 0, 0, 0, 0, 0, 0, - 242, 242, 242, 242, 242, 242, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 242, 0, 0, 242, 0, - 0, 242, 0, 222, 0, 232, 232, 0, 222, 222, - 0, 0, 0, 242, 242, 232, 232, 222, 232, 232, - 242, 242, 242, 0, 365, 232, 232, 232, 0, 232, - 222, 222, 240, 0, 0, 232, 232, 0, 0, 232, - 232, 232, 232, 222, 0, 232, 222, 365, 232, 0, - 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, - 0, 232, 0, 232, 0, 222, 0, 0, 0, 0, - 0, 0, 232, 232, 232, 232, 232, 232, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 232, 0, 0, - 232, 0, 0, 232, 222, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 232, 232, 0, 0, 222, - 0, 0, 232, 232, 232, 194, 222, 194, 194, 194, - 194, 194, 194, 0, 0, 0, 194, 194, 194, 194, - 0, 194, 194, 0, 194, 194, 361, 0, 0, 0, - 0, 0, 0, 0, 0, 194, 194, 0, 194, 194, - 194, 194, 194, 0, 0, 194, 194, 194, 238, 361, - 0, 194, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 240, 194, - 0, 238, 0, 0, 0, 0, 0, 240, 240, 0, - 240, 240, 0, 194, 0, 0, 0, 240, 240, 240, - 0, 240, 0, 194, 0, 0, 194, 240, 240, 0, - 0, 240, 240, 240, 240, 0, 0, 240, 0, 0, - 240, 194, 194, 0, 0, 0, 0, 0, 0, 194, - 194, 0, 0, 240, 0, 240, 0, 0, 0, 0, - 0, 0, 0, 0, 240, 240, 240, 240, 240, 240, - 0, 0, 0, 0, 0, 0, 52, 0, 0, 240, - 0, 0, 240, 0, 0, 240, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 365, 240, 240, 52, - 0, 365, 365, 365, 240, 240, 240, 365, 365, 365, - 365, 0, 365, 365, 0, 365, 365, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 365, 0, 0, 0, - 0, 238, 365, 365, 0, 0, 365, 365, 365, 199, - 0, 0, 365, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, - 365, 0, 199, 0, 0, 0, 0, 0, 0, 363, - 363, 363, 363, 363, 365, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 365, 0, 0, 365, 0, 52, - 363, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 365, 365, 0, 0, 0, 0, 361, 0, - 365, 365, 0, 361, 361, 361, 0, 0, 0, 361, - 361, 361, 361, 0, 361, 361, 0, 361, 361, 0, - 238, 0, 0, 0, 0, 0, 238, 0, 361, 0, - 0, 0, 0, 0, 361, 361, 0, 0, 361, 361, - 361, 212, 0, 0, 361, 0, 0, 238, 238, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 238, 0, 361, 238, 212, 0, 0, 0, 0, 238, - 0, 361, 361, 361, 361, 361, 361, 0, 0, 0, - 0, 0, 238, 0, 0, 0, 361, 0, 0, 361, - 0, 0, 361, 0, 0, 0, 0, 194, 0, 0, - 0, 0, 0, 0, 361, 361, 0, 0, 0, 0, - 0, 238, 361, 361, 0, 0, 0, 52, 52, 52, - 194, 52, 52, 52, 52, 52, 238, 0, 0, 52, - 52, 52, 52, 238, 52, 52, 0, 52, 52, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, - 0, 0, 0, 197, 52, 52, 0, 0, 52, 52, - 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, - 0, 0, 0, 238, 0, 0, 197, 0, 0, 238, - 0, 199, 52, 0, 0, 199, 199, 199, 199, 0, - 0, 0, 199, 199, 199, 199, 52, 199, 199, 238, - 199, 199, 0, 0, 0, 0, 52, 0, 0, 52, - 194, 199, 199, 0, 199, 199, 199, 199, 199, 0, - 0, 199, 199, 199, 52, 52, 0, 199, 0, 0, - 0, 0, 52, 52, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 199, 238, 238, 238, 238, - 238, 0, 0, 0, 0, 0, 0, 0, 0, 199, - 0, 0, 0, 0, 238, 0, 197, 238, 0, 199, - 0, 0, 199, 0, 212, 0, 0, 0, 219, 238, - 238, 0, 0, 0, 0, 0, 0, 199, 199, 0, - 0, 0, 0, 212, 0, 199, 199, 212, 212, 212, - 212, 219, 0, 0, 212, 212, 212, 212, 0, 212, - 212, 0, 212, 212, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 212, 212, 0, 212, 212, 212, 212, - 212, 0, 0, 212, 212, 212, 0, 0, 0, 212, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, - 0, 0, 194, 194, 194, 194, 194, 212, 0, 0, - 194, 194, 194, 194, 0, 194, 194, 0, 194, 194, - 0, 212, 0, 0, 0, 0, 0, 0, 0, 194, - 0, 212, 0, 0, 212, 194, 194, 212, 0, 194, - 194, 194, 397, 0, 0, 194, 0, 0, 0, 212, - 212, 0, 0, 0, 0, 197, 0, 212, 212, 197, - 197, 197, 197, 194, 0, 397, 197, 197, 197, 197, - 0, 197, 197, 0, 197, 197, 0, 194, 0, 0, - 0, 0, 0, 0, 0, 197, 0, 194, 0, 0, - 194, 197, 197, 0, 0, 197, 197, 197, 364, 0, - 0, 197, 0, 0, 0, 194, 194, 0, 0, 0, - 0, 0, 0, 194, 194, 0, 0, 0, 0, 197, - 0, 364, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 197, 0, 0, 197, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 197, 197, 0, 0, 0, 0, 0, 0, 197, - 197, 0, 0, 0, 0, 0, 212, 0, 0, 0, - 219, 212, 212, 212, 0, 219, 219, 212, 212, 212, - 212, 219, 212, 212, 219, 212, 212, 0, 0, 0, - 0, 0, 0, 219, 0, 0, 212, 219, 219, 0, - 0, 0, 212, 212, 0, 0, 212, 212, 212, 0, - 219, 0, 212, 219, 0, 0, 219, 0, 0, 219, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 212, 0, 219, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 212, 0, 219, 212, 0, 0, - 0, 219, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 212, 212, 0, 0, 219, 0, 0, 219, - 212, 212, 0, 219, 397, 0, 0, 0, 0, 397, - 397, 397, 0, 0, 0, 397, 397, 397, 397, 0, - 397, 397, 0, 397, 397, 0, 219, 0, 0, 222, - 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, - 397, 397, 0, 0, 397, 397, 397, 0, 0, 0, - 397, 0, 222, 0, 0, 0, 0, 0, 0, 0, - 364, 0, 0, 0, 0, 364, 364, 364, 397, 0, - 0, 364, 364, 364, 364, 0, 364, 364, 0, 364, - 364, 0, 397, 0, 0, 0, 0, 0, 0, 0, - 364, 0, 397, 0, 0, 397, 364, 364, 0, 0, - 364, 364, 364, 0, 0, 0, 364, 0, 0, 222, - 397, 397, 0, 0, 0, 0, 0, 0, 397, 397, - 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, - 0, 0, 222, 0, 0, 0, 0, 0, 364, 0, - 0, 0, 222, 0, 0, 0, 0, 0, 364, 0, - 0, 364, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 219, 364, 364, 0, 0, - 219, 219, 219, 0, 364, 364, 219, 0, 0, 219, - 0, 219, 219, 0, 219, 219, 0, 0, 0, 238, - 0, 0, 0, 0, 0, 219, 0, 0, 0, 0, - 0, 219, 219, 0, 0, 219, 219, 219, 0, 0, - 0, 219, 238, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 219, 219, - 0, 0, 0, 219, 219, 219, 0, 0, 0, 219, - 0, 0, 219, 219, 219, 219, 0, 219, 219, 0, - 0, 0, 238, 219, 0, 0, 219, 0, 219, 0, - 0, 0, 0, 0, 219, 219, 0, 0, 219, 219, - 219, 219, 219, 0, 219, 238, 0, 0, 0, 219, - 219, 222, 0, 0, 0, 0, 222, 222, 222, 0, - 0, 0, 219, 0, 0, 222, 0, 222, 222, 0, - 222, 222, 238, 0, 0, 156, 219, 0, 0, 0, - 0, 222, 0, 0, 0, 0, 219, 222, 222, 219, - 0, 222, 222, 222, 0, 0, 0, 222, 154, 0, - 0, 0, 0, 0, 219, 219, 0, 0, 0, 0, - 0, 0, 219, 219, 0, 222, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, - 0, 222, 0, 0, 0, 0, 222, 222, 222, 222, - 0, 0, 222, 0, 0, 222, 0, 222, 222, 0, - 222, 222, 0, 0, 0, 332, 0, 222, 222, 0, - 0, 222, 0, 0, 0, 222, 222, 222, 222, 0, - 0, 222, 222, 222, 0, 0, 0, 222, 332, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 156, 0, - 0, 0, 0, 0, 0, 222, 0, 0, 212, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, - 0, 238, 0, 0, 0, 0, 0, 238, 238, 222, - 0, 212, 222, 0, 0, 0, 0, 238, 238, 0, - 238, 238, 0, 0, 0, 49, 0, 222, 222, 0, - 0, 238, 0, 0, 0, 222, 222, 238, 238, 0, - 0, 238, 238, 238, 0, 0, 0, 238, 49, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 332, 0, - 0, 0, 0, 0, 238, 238, 0, 0, 0, 0, - 238, 238, 0, 0, 0, 0, 0, 0, 0, 238, - 238, 238, 0, 238, 238, 0, 377, 0, 156, 238, - 0, 0, 238, 0, 238, 0, 0, 0, 0, 0, - 238, 238, 0, 0, 238, 238, 238, 238, 238, 377, - 238, 154, 0, 0, 0, 238, 238, 0, 0, 0, - 0, 0, 0, 0, 154, 0, 0, 0, 238, 0, - 0, 0, 0, 154, 154, 0, 154, 154, 49, 0, - 0, 0, 238, 378, 0, 0, 0, 154, 0, 0, - 0, 0, 238, 154, 154, 238, 0, 154, 154, 154, - 0, 0, 0, 154, 0, 0, 378, 0, 0, 0, - 238, 238, 0, 0, 0, 0, 0, 0, 238, 238, - 0, 154, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 154, 0, 0, 0, 212, - 0, 0, 0, 0, 332, 154, 0, 0, 154, 0, - 0, 0, 0, 332, 332, 0, 332, 332, 0, 0, - 0, 219, 212, 154, 154, 0, 0, 332, 0, 0, - 0, 154, 154, 332, 332, 0, 0, 332, 332, 332, - 212, 0, 0, 332, 219, 212, 212, 0, 0, 0, - 0, 212, 212, 212, 212, 0, 222, 0, 0, 0, - 0, 332, 0, 0, 0, 0, 0, 212, 212, 0, - 0, 0, 0, 0, 0, 332, 0, 0, 0, 222, - 212, 0, 0, 212, 49, 332, 0, 0, 332, 212, - 0, 0, 0, 49, 49, 0, 49, 49, 0, 0, - 0, 0, 212, 332, 332, 0, 0, 49, 0, 0, - 0, 332, 332, 49, 49, 0, 0, 49, 49, 49, - 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, - 0, 212, 0, 0, 0, 0, 0, 0, 377, 0, - 0, 49, 377, 377, 377, 0, 212, 154, 0, 377, - 377, 377, 377, 212, 0, 49, 154, 154, 167, 154, - 154, 0, 0, 0, 377, 49, 0, 0, 49, 0, - 154, 0, 0, 0, 0, 0, 154, 154, 0, 0, - 154, 154, 154, 49, 49, 0, 154, 0, 0, 0, - 0, 49, 49, 0, 0, 378, 0, 0, 0, 378, - 378, 378, 0, 0, 154, 0, 378, 378, 378, 378, - 0, 377, 377, 377, 377, 377, 0, 0, 154, 0, - 0, 378, 0, 0, 0, 0, 0, 0, 154, 377, - 0, 154, 377, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 377, 377, 154, 154, 0, 0, - 0, 212, 0, 0, 154, 154, 212, 212, 0, 0, - 0, 0, 212, 212, 212, 212, 0, 0, 378, 378, - 378, 378, 378, 219, 0, 0, 0, 212, 219, 219, - 0, 0, 0, 0, 219, 0, 378, 219, 0, 378, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 219, - 0, 378, 378, 0, 0, 0, 0, 0, 222, 0, - 0, 0, 0, 222, 222, 0, 0, 0, 0, 0, - 0, 0, 222, 0, 212, 212, 212, 212, 212, 0, - 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, - 0, 0, 212, 0, 0, 212, 219, 219, 219, 219, - 219, 0, 0, 0, 0, 0, 0, 212, 212, 0, - 0, 0, 0, 0, 219, 0, 0, 219, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 219, - 219, 222, 222, 222, 222, 222, 0, 0, 0, 0, - 0, 0, 0, 0, 556, 0, 0, 0, 0, 222, - 0, 0, 222, 557, 558, 0, 559, 560, 0, 0, - 0, 0, 0, 0, 222, 222, 0, 561, 0, 0, - 0, 0, 0, 562, 333, 0, 0, 563, 564, 565, - 0, 0, 0, 566, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 567, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 568, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 569, 0, 0, 570, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 571, 0, 0, 0, 0, 0, - 0, 572, 573, -}; -static const YYINT pfctlycheck[] = { 3, - 3, 82, 11, 12, 10, 125, 359, 78, 10, 44, - 10, 10, 10, 10, 191, 40, 33, 40, 10, 33, - 33, 44, 33, 33, 205, 33, 10, 33, 123, 272, - 44, 33, 10, 123, 203, 40, 319, 320, 123, 483, - 33, 123, 0, 33, 221, 341, 166, 56, 33, 672, - 40, 47, 10, 40, 44, 10, 10, 406, 123, 44, - 674, 70, 229, 40, 123, 10, 40, 679, 500, 123, - 60, 33, 81, 40, 682, 60, 61, 62, 40, 276, - 40, 123, 202, 258, 259, 260, 263, 299, 265, 24, - 125, 10, 44, 10, 257, 60, 177, 420, 60, 276, - 10, 264, 125, 40, 224, 261, 44, 263, 298, 732, - 33, 125, 123, 123, 125, 123, 44, 44, 10, 40, - 55, 735, 41, 123, 40, 44, 123, 739, 481, 44, - 123, 123, 508, 123, 742, 125, 123, 60, 61, 62, - 125, 353, 262, 386, 264, 326, 123, 591, 33, 41, - 356, 357, 44, 330, 323, 438, 33, 277, 229, 279, - 456, 123, 33, 125, 635, 488, 343, 599, 74, 346, - 519, 44, 339, 125, 44, 60, 61, 62, 84, 85, - 86, 378, 302, 60, 61, 62, 33, 125, 378, 60, - 61, 62, 616, 40, 314, 33, 371, 125, 125, 294, - 123, 376, 642, 629, 44, 581, 123, 267, 217, 680, - 125, 331, 267, 60, 260, 392, 276, 378, 273, 169, - 646, 123, 60, 61, 62, 44, 403, 285, 286, 287, - 33, 40, 352, 378, 243, 44, 413, 412, 123, 45, - 44, 47, 362, 683, 41, 40, 123, 671, 378, 10, - 33, 60, 125, 378, 379, 125, 44, 60, 61, 62, - 44, 381, 382, 309, 378, 60, 277, 277, 339, 277, - 447, 391, 178, 393, 284, 225, 123, 60, 61, 62, - 33, 277, 288, 378, 262, 125, 288, 277, 378, 288, - 268, 266, 469, 378, 414, 415, 378, 368, 256, 257, - 258, 259, 294, 89, 288, 91, 125, 60, 61, 62, - 300, 301, 489, 378, 379, 277, 125, 262, 61, 378, - 440, 125, 267, 268, 378, 379, 446, 285, 286, 287, - 10, 276, 538, 453, 511, 512, 513, 125, 300, 301, - 298, 125, 314, 378, 299, 299, 10, 353, 468, 526, - 350, 353, 310, 378, 353, 378, 314, 315, 316, 317, - 318, 378, 368, 540, 378, 378, 368, 369, 44, 368, - 368, 368, 10, 378, 332, 353, 334, 10, 378, 662, - 374, 10, 378, 341, 374, 10, 378, 306, 378, 379, - 510, 378, 350, 378, 379, 33, 354, 10, 353, 353, - 10, 378, 40, 41, 378, 525, 44, 527, 353, 328, - 41, 378, 374, 44, 306, 10, 378, 379, 378, 539, - 378, 41, 60, 33, 44, 342, 343, 344, 345, 346, - 277, 425, 503, 553, 351, 352, 328, 508, 357, 358, - 359, 378, 379, 362, 363, 364, 10, 366, 367, 125, - 10, 370, 371, 300, 301, 378, 379, 378, 379, 378, - 40, 378, 378, 379, 473, 357, 358, 359, 588, 10, - 362, 363, 364, 593, 366, 367, 378, 379, 370, 371, - 60, 552, 659, 660, 661, 123, 378, 125, 10, 498, - 10, 572, 10, 378, 379, 256, 257, 258, 264, 265, - 620, 378, 379, 370, 371, 625, 44, 378, 379, 686, - 581, 44, 506, 633, 41, 33, 587, 44, 695, 44, - 640, 515, 40, 41, 701, 10, 44, 374, 705, 10, - 10, 378, 379, 710, 44, 10, 713, 298, 378, 379, - 378, 379, 60, 10, 664, 378, 379, 667, 260, 310, - 347, 348, 349, 314, 315, 316, 317, 318, 270, 271, - 272, 41, 571, 41, 44, 374, 44, 10, 40, 378, - 379, 332, 10, 334, 694, 378, 379, 10, 10, 374, - 341, 378, 702, 378, 379, 666, 706, 125, 10, 350, - 10, 711, 125, 354, 714, 378, 379, 309, 262, 41, - 125, 610, 44, 267, 268, 123, 687, 125, 378, 273, - 274, 275, 276, 41, 10, 125, 44, 378, 347, 348, - 349, 311, 312, 313, 262, 378, 379, 274, 275, 749, - 268, 269, 752, 753, 754, 755, 285, 286, 287, 277, - 278, 279, 10, 281, 282, 10, 284, 10, 657, 378, - 288, 289, 290, 40, 292, 40, 40, 378, 379, 10, - 298, 299, 300, 301, 302, 303, 304, 305, 378, 379, - 308, 360, 361, 311, 378, 60, 757, 378, 288, 378, - 123, 259, 10, 405, 268, 407, 324, 40, 326, 353, - 264, 123, 276, 378, 379, 699, 699, 335, 336, 337, - 338, 339, 340, 123, 265, 33, 10, 285, 286, 287, - 378, 379, 350, 378, 379, 353, 44, 333, 356, 303, - 304, 10, 10, 378, 379, 335, 336, 337, 338, 339, - 368, 369, 60, 61, 62, 307, 374, 375, 376, 377, - 378, 379, 262, 353, 262, 33, 356, 267, 268, 62, - 268, 269, 265, 273, 378, 379, 276, 379, 368, 277, - 278, 279, 10, 281, 282, 268, 284, 378, 379, 60, - 288, 289, 290, 276, 292, 335, 336, 337, 338, 339, - 298, 299, 300, 301, 302, 303, 304, 305, 378, 379, - 308, 378, 379, 311, 374, 123, 356, 125, 378, 379, - 303, 304, 10, 259, 266, 267, 324, 44, 326, 378, - 379, 273, 274, 275, 379, 537, 379, 335, 336, 337, - 338, 339, 340, 378, 379, 33, 306, 378, 379, 285, - 286, 287, 350, 353, 123, 353, 44, 267, 356, 378, - 379, 378, 10, 273, 274, 275, 267, 33, 328, 379, - 368, 369, 60, 61, 62, 379, 374, 375, 376, 377, - 378, 379, 378, 379, 379, 33, 378, 379, 335, 336, - 337, 338, 339, 378, 379, 379, 44, 357, 358, 359, - 85, 86, 362, 363, 364, 379, 366, 367, 379, 356, - 370, 371, 60, 61, 62, 297, 298, 350, 378, 342, - 343, 344, 345, 346, 273, 10, 41, 350, 351, 352, - 342, 343, 344, 345, 346, 123, 40, 125, 350, 351, - 352, 378, 342, 343, 344, 345, 346, 378, 33, 47, - 350, 351, 352, 378, 262, 378, 60, 288, 33, 44, - 268, 269, 40, 665, 40, 10, 378, 40, 379, 41, - 278, 279, 10, 281, 282, 123, 379, 125, 378, 62, - 288, 289, 290, 293, 292, 295, 296, 297, 33, 10, - 298, 299, 379, 379, 302, 303, 304, 305, 41, 44, - 308, 378, 262, 311, 335, 336, 337, 338, 339, 374, - 378, 369, 41, 378, 379, 378, 324, 353, 326, 123, - 722, 289, 290, 365, 726, 356, 378, 335, 336, 337, - 338, 339, 340, 379, 302, 41, 267, 305, 123, 378, - 125, 378, 350, 311, 284, 353, 378, 268, 356, 379, - 61, 335, 336, 337, 338, 339, 324, 360, 61, 33, - 368, 369, 61, 380, 378, 47, 40, 375, 376, 377, - 378, 379, 356, 342, 343, 344, 345, 346, 123, 378, - 125, 269, 351, 352, 378, 353, 60, 47, 368, 268, - 278, 279, 41, 281, 282, 378, 10, 379, 379, 41, - 368, 62, 379, 378, 292, 288, 123, 375, 378, 378, - 298, 299, 40, 379, 302, 303, 304, 379, 379, 33, - 308, 269, 368, 289, 290, 283, 283, 117, 118, 119, - 278, 279, 60, 281, 282, 368, 302, 283, 326, 305, - 283, 379, 379, 379, 292, 311, 284, 379, 40, 123, - 298, 299, 340, 10, 302, 303, 304, 47, 324, 378, - 308, 280, 350, 280, 40, 353, 380, 380, 60, 378, - 284, 378, 288, 41, 164, 41, 41, 10, 326, 10, - 368, 369, 41, 284, 269, 10, 333, 353, 376, 377, - 378, 379, 340, 278, 279, 10, 281, 282, 378, 10, - 378, 378, 350, 267, 10, 353, 368, 292, 10, 375, - 379, 10, 10, 298, 299, 10, 566, 302, 303, 304, - 368, 369, 3, 308, 269, 71, 253, 757, 376, 377, - 378, 379, 442, 278, 279, 33, 281, 282, 687, 425, - 435, 326, 516, 41, 177, 216, 44, 292, 676, 271, - 288, 242, 397, 298, 299, 340, 246, 302, 303, 304, - 250, 395, 466, 308, 479, 350, 581, 257, 353, 337, - 374, 172, 241, 552, 378, 379, 316, 478, 587, -1, - 3, 326, 3, 368, 369, 306, 10, -1, -1, -1, - -1, 376, 377, 378, 379, 340, -1, 335, 336, 337, - 338, 339, -1, 277, -1, 350, -1, 328, 353, 299, - -1, -1, -1, -1, -1, 353, -1, 10, 356, 10, - 564, 565, -1, 368, 369, 123, 300, 301, -1, -1, - 368, 376, 377, 378, 379, -1, 357, 358, 359, -1, - 33, 362, 363, 364, -1, 366, 367, -1, 262, 370, - 371, 265, 266, 267, 268, 269, -1, 378, -1, 273, - 274, 275, 276, -1, 278, 279, -1, 281, 282, -1, - -1, -1, 300, 301, 288, 289, 290, -1, 292, 293, - -1, 295, 296, 297, 298, 299, -1, -1, 302, 303, - 304, 305, -1, -1, 308, -1, -1, 311, -1, -1, - 374, 125, -1, -1, 378, 379, -1, -1, 300, 301, - 324, -1, 326, -1, -1, -1, -1, -1, -1, 333, - -1, 335, 336, 337, 338, 339, 340, -1, -1, 10, - -1, -1, -1, -1, 125, 679, 350, -1, 682, 353, - -1, -1, 356, -1, -1, -1, 374, -1, -1, -1, - 378, 379, 33, -1, 368, 369, 399, 400, 401, -1, - -1, 375, 376, 377, 262, -1, -1, -1, 266, 267, - 268, 269, -1, -1, -1, 273, 274, 275, 276, -1, - 278, 279, 374, 281, 282, -1, 378, 379, -1, -1, - 288, 289, 290, -1, 292, 739, -1, -1, 742, -1, - 298, 299, -1, -1, 302, 303, 304, 305, -1, -1, - 308, -1, -1, 311, -1, -1, -1, 460, -1, 462, - -1, 464, -1, -1, -1, -1, 324, -1, 326, -1, - -1, -1, -1, 257, 258, -1, -1, 335, 336, 337, - 338, 339, 340, -1, -1, 198, 199, 200, -1, 10, - -1, -1, 350, -1, -1, 353, -1, -1, 356, -1, - -1, -1, -1, -1, -1, 256, 257, 258, -1, 262, - 368, 369, 33, 266, 267, 268, 269, 375, 376, 377, - 273, 274, 275, 276, -1, 278, 279, -1, 281, 282, - 314, 315, 316, 317, 23, -1, 289, 290, 10, 292, - 293, -1, 295, 296, 297, 298, 299, 298, -1, 302, - 303, 304, 305, -1, -1, 308, -1, -1, 311, -1, - -1, 33, -1, 314, 315, 316, 317, -1, 57, 58, - 59, 324, -1, 326, 335, 336, 337, 338, 339, 68, - 333, 294, -1, 33, -1, -1, -1, 340, -1, -1, - 40, 80, -1, -1, 44, 356, 309, 350, -1, -1, - 353, -1, -1, -1, 317, -1, 10, -1, -1, -1, - 60, 61, 62, -1, -1, 368, 369, -1, -1, -1, - -1, 262, 375, 376, 377, 266, 267, 268, 269, 33, - -1, -1, 273, 274, 275, 276, -1, 278, 279, -1, - 281, 282, -1, -1, -1, 358, -1, -1, 289, 290, - -1, 292, 293, -1, 295, 296, 297, 298, 299, -1, - -1, 302, 303, 304, 305, -1, -1, 308, -1, -1, - 311, -1, -1, 123, 10, 125, -1, -1, -1, -1, - -1, -1, -1, 324, -1, 326, 689, 690, 691, -1, - -1, -1, 333, 182, 183, -1, -1, 33, 187, 340, - -1, -1, -1, -1, -1, -1, -1, -1, 197, 350, - -1, -1, 353, 342, 343, 344, 345, 346, -1, -1, - -1, 350, 351, 352, -1, -1, 10, 368, 369, 342, - 343, 344, 345, 346, 375, 376, 377, 350, 351, 352, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 33, - -1, -1, 273, 274, 275, 276, -1, 278, 279, -1, - 281, 282, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 292, 293, -1, 295, 296, 297, 298, 299, -1, - -1, 302, 303, 304, -1, -1, -1, 308, -1, -1, - 262, -1, 264, 265, 266, 267, 268, -1, -1, -1, - -1, 273, 274, 275, 276, 326, 342, 343, 344, 345, - 346, -1, -1, -1, -1, 351, 352, 289, 290, 340, - -1, -1, -1, -1, -1, -1, -1, 277, -1, 350, - 302, -1, 353, 305, -1, -1, -1, -1, -1, 311, - -1, -1, -1, 10, -1, -1, -1, 368, 369, -1, - 300, 301, 324, -1, -1, 376, 377, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 33, -1, -1, 273, - 274, 275, 276, -1, 278, 279, -1, 281, 282, -1, - -1, 353, -1, -1, -1, -1, -1, -1, 292, 293, - -1, 295, 296, 297, 298, 299, 368, -1, 302, 303, - 304, -1, -1, 375, 308, -1, 319, 320, 321, 322, - 323, -1, 325, -1, 327, -1, 329, 330, 331, -1, - -1, -1, 326, -1, 374, -1, 262, -1, 378, 379, - 266, 267, 268, -1, -1, 10, 340, 273, 274, 275, - 276, -1, 355, -1, -1, -1, 350, -1, -1, 353, - -1, -1, -1, 289, 290, -1, -1, -1, 33, 372, - 373, -1, -1, -1, 368, 369, 302, -1, -1, 305, - -1, -1, 376, 377, -1, 311, -1, 261, 262, 263, - 264, 265, 266, 267, 268, 269, -1, -1, 324, 273, - 274, 275, 276, -1, 278, 279, -1, 281, 282, -1, - -1, -1, -1, -1, -1, -1, -1, 306, 292, 293, - -1, 295, 296, 297, 298, 299, -1, 353, 302, 303, - 304, -1, -1, -1, 308, -1, -1, 10, -1, 328, - -1, 10, 368, -1, -1, -1, -1, -1, -1, 375, - -1, -1, 326, -1, -1, -1, -1, -1, 123, -1, - 33, -1, -1, -1, 33, -1, 340, -1, 357, 358, - 359, -1, -1, 362, 363, 364, 350, 366, 367, 353, - -1, 370, 371, -1, -1, -1, -1, -1, -1, 378, - -1, -1, -1, -1, 368, 369, -1, -1, -1, -1, - -1, -1, 376, 377, 261, 262, 263, 264, 265, 266, - 267, 268, 269, -1, -1, -1, 273, 274, 275, 276, - -1, 278, 279, -1, 281, 282, -1, -1, -1, -1, - -1, -1, -1, -1, 306, 292, 293, -1, 295, 296, - 297, 298, 299, -1, -1, 302, 303, 304, -1, -1, - 123, 308, -1, 10, -1, -1, 328, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 326, - -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, - -1, -1, -1, 340, -1, 357, 358, 359, -1, -1, - 362, 363, 364, 350, 366, 367, 353, 262, 370, 371, - -1, -1, -1, 268, 269, -1, 378, -1, -1, 10, - -1, 368, 369, 278, 279, -1, 281, 282, -1, 376, - 377, -1, -1, 288, 289, 290, -1, 292, -1, -1, - -1, -1, 33, 298, 299, -1, -1, 302, 303, 304, - 305, -1, -1, 308, -1, -1, 311, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 324, - -1, 326, -1, -1, -1, -1, -1, -1, -1, -1, - 335, 336, 337, 338, 339, 340, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 350, -1, -1, 353, -1, - -1, 356, -1, 262, -1, 268, 269, -1, 267, 268, - -1, -1, -1, 368, 369, 278, 279, 276, 281, 282, - 375, 376, 377, -1, 10, 288, 289, 290, -1, 292, - 289, 290, 123, -1, -1, 298, 299, -1, -1, 302, - 303, 304, 305, 302, -1, 308, 305, 33, 311, -1, - -1, -1, 311, -1, -1, -1, -1, -1, -1, -1, - -1, 324, -1, 326, -1, 324, -1, -1, -1, -1, - -1, -1, 335, 336, 337, 338, 339, 340, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 350, -1, -1, - 353, -1, -1, 356, 353, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 368, 369, -1, -1, 368, - -1, -1, 375, 376, 377, 262, 375, 264, 265, 266, - 267, 268, 269, -1, -1, -1, 273, 274, 275, 276, - -1, 278, 279, -1, 281, 282, 10, -1, -1, -1, - -1, -1, -1, -1, -1, 292, 293, -1, 295, 296, - 297, 298, 299, -1, -1, 302, 303, 304, 10, 33, - -1, 308, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 269, 326, - -1, 33, -1, -1, -1, -1, -1, 278, 279, -1, - 281, 282, -1, 340, -1, -1, -1, 288, 289, 290, - -1, 292, -1, 350, -1, -1, 353, 298, 299, -1, - -1, 302, 303, 304, 305, -1, -1, 308, -1, -1, - 311, 368, 369, -1, -1, -1, -1, -1, -1, 376, - 377, -1, -1, 324, -1, 326, -1, -1, -1, -1, - -1, -1, -1, -1, 335, 336, 337, 338, 339, 340, - -1, -1, -1, -1, -1, -1, 10, -1, -1, 350, - -1, -1, 353, -1, -1, 356, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 262, 368, 369, 33, - -1, 267, 268, 269, 375, 376, 377, 273, 274, 275, - 276, -1, 278, 279, -1, 281, 282, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 292, -1, -1, -1, - -1, 10, 298, 299, -1, -1, 302, 303, 304, 10, - -1, -1, 308, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, - 326, -1, 33, -1, -1, -1, -1, -1, -1, 335, - 336, 337, 338, 339, 340, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 350, -1, -1, 353, -1, 123, - 356, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 368, 369, -1, -1, -1, -1, 262, -1, - 376, 377, -1, 267, 268, 269, -1, -1, -1, 273, - 274, 275, 276, -1, 278, 279, -1, 281, 282, -1, - 262, -1, -1, -1, -1, -1, 268, -1, 292, -1, - -1, -1, -1, -1, 298, 299, -1, -1, 302, 303, - 304, 10, -1, -1, 308, -1, -1, 289, 290, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 302, -1, 326, 305, 33, -1, -1, -1, -1, 311, - -1, 335, 336, 337, 338, 339, 340, -1, -1, -1, - -1, -1, 324, -1, -1, -1, 350, -1, -1, 353, - -1, -1, 356, -1, -1, -1, -1, 10, -1, -1, - -1, -1, -1, -1, 368, 369, -1, -1, -1, -1, - -1, 353, 376, 377, -1, -1, -1, 261, 262, 263, - 33, 265, 266, 267, 268, 269, 368, -1, -1, 273, - 274, 275, 276, 375, 278, 279, -1, 281, 282, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 292, -1, - -1, -1, -1, 10, 298, 299, -1, -1, 302, 303, - 304, -1, -1, -1, 308, -1, -1, -1, -1, -1, - -1, -1, -1, 262, -1, -1, 33, -1, -1, 268, - -1, 262, 326, -1, -1, 266, 267, 268, 269, -1, - -1, -1, 273, 274, 275, 276, 340, 278, 279, 288, - 281, 282, -1, -1, -1, -1, 350, -1, -1, 353, - 123, 292, 293, -1, 295, 296, 297, 298, 299, -1, - -1, 302, 303, 304, 368, 369, -1, 308, -1, -1, - -1, -1, 376, 377, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 326, 335, 336, 337, 338, - 339, -1, -1, -1, -1, -1, -1, -1, -1, 340, - -1, -1, -1, -1, 353, -1, 123, 356, -1, 350, - -1, -1, 353, -1, 10, -1, -1, -1, 10, 368, - 369, -1, -1, -1, -1, -1, -1, 368, 369, -1, - -1, -1, -1, 262, -1, 376, 377, 33, 267, 268, - 269, 33, -1, -1, 273, 274, 275, 276, -1, 278, - 279, -1, 281, 282, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 292, 293, -1, 295, 296, 297, 298, - 299, -1, -1, 302, 303, 304, -1, -1, -1, 308, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 262, - -1, -1, 265, 266, 267, 268, 269, 326, -1, -1, - 273, 274, 275, 276, -1, 278, 279, -1, 281, 282, - -1, 340, -1, -1, -1, -1, -1, -1, -1, 292, - -1, 350, -1, -1, 353, 298, 299, 123, -1, 302, - 303, 304, 10, -1, -1, 308, -1, -1, -1, 368, - 369, -1, -1, -1, -1, 262, -1, 376, 377, 266, - 267, 268, 269, 326, -1, 33, 273, 274, 275, 276, - -1, 278, 279, -1, 281, 282, -1, 340, -1, -1, - -1, -1, -1, -1, -1, 292, -1, 350, -1, -1, - 353, 298, 299, -1, -1, 302, 303, 304, 10, -1, - -1, 308, -1, -1, -1, 368, 369, -1, -1, -1, - -1, -1, -1, 376, 377, -1, -1, -1, -1, 326, - -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 340, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 350, -1, -1, 353, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 368, 369, -1, -1, -1, -1, -1, -1, 376, - 377, -1, -1, -1, -1, -1, 262, -1, -1, -1, - 262, 267, 268, 269, -1, 267, 268, 273, 274, 275, - 276, 273, 278, 279, 276, 281, 282, -1, -1, -1, - -1, -1, -1, 10, -1, -1, 292, 289, 290, -1, - -1, -1, 298, 299, -1, -1, 302, 303, 304, -1, - 302, -1, 308, 305, -1, -1, 33, -1, -1, 311, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 326, -1, 324, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 340, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 350, -1, 10, 353, -1, -1, - -1, 353, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 368, 369, -1, -1, 368, -1, -1, 33, - 376, 377, -1, 375, 262, -1, -1, -1, -1, 267, - 268, 269, -1, -1, -1, 273, 274, 275, 276, -1, - 278, 279, -1, 281, 282, -1, 123, -1, -1, 10, - -1, -1, -1, -1, 292, -1, -1, -1, -1, -1, - 298, 299, -1, -1, 302, 303, 304, -1, -1, -1, - 308, -1, 33, -1, -1, -1, -1, -1, -1, -1, - 262, -1, -1, -1, -1, 267, 268, 269, 326, -1, - -1, 273, 274, 275, 276, -1, 278, 279, -1, 281, - 282, -1, 340, -1, -1, -1, -1, -1, -1, -1, - 292, -1, 350, -1, -1, 353, 298, 299, -1, -1, - 302, 303, 304, -1, -1, -1, 308, -1, -1, 10, - 368, 369, -1, -1, -1, -1, -1, -1, 376, 377, - -1, -1, -1, -1, 326, -1, -1, -1, -1, -1, - -1, -1, 33, -1, -1, -1, -1, -1, 340, -1, - -1, -1, 123, -1, -1, -1, -1, -1, 350, -1, - -1, 353, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 262, 368, 369, -1, -1, - 267, 268, 269, -1, 376, 377, 273, -1, -1, 276, - -1, 278, 279, -1, 281, 282, -1, -1, -1, 10, - -1, -1, -1, -1, -1, 292, -1, -1, -1, -1, - -1, 298, 299, -1, -1, 302, 303, 304, -1, -1, - -1, 308, 33, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 262, 326, - -1, -1, -1, 267, 268, 269, -1, -1, -1, 273, - -1, -1, 276, 340, 278, 279, -1, 281, 282, -1, - -1, -1, 10, 350, -1, -1, 353, -1, 292, -1, - -1, -1, -1, -1, 298, 299, -1, -1, 302, 303, - 304, 368, 369, -1, 308, 33, -1, -1, -1, 376, - 377, 262, -1, -1, -1, -1, 267, 268, 269, -1, - -1, -1, 326, -1, -1, 276, -1, 278, 279, -1, - 281, 282, 123, -1, -1, 10, 340, -1, -1, -1, - -1, 292, -1, -1, -1, -1, 350, 298, 299, 353, - -1, 302, 303, 304, -1, -1, -1, 308, 33, -1, - -1, -1, -1, -1, 368, 369, -1, -1, -1, -1, - -1, -1, 376, 377, -1, 326, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 340, - -1, 262, -1, -1, -1, -1, 267, 268, 269, 350, - -1, -1, 353, -1, -1, 276, -1, 278, 279, -1, - 281, 282, -1, -1, -1, 10, -1, 368, 369, -1, - -1, 292, -1, -1, -1, 376, 377, 298, 299, -1, - -1, 302, 303, 304, -1, -1, -1, 308, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 123, -1, - -1, -1, -1, -1, -1, 326, -1, -1, 10, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 340, - -1, 262, -1, -1, -1, -1, -1, 268, 269, 350, - -1, 33, 353, -1, -1, -1, -1, 278, 279, -1, - 281, 282, -1, -1, -1, 10, -1, 368, 369, -1, - -1, 292, -1, -1, -1, 376, 377, 298, 299, -1, - -1, 302, 303, 304, -1, -1, -1, 308, 33, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 123, -1, - -1, -1, -1, -1, 262, 326, -1, -1, -1, -1, - 268, 269, -1, -1, -1, -1, -1, -1, -1, 340, - 278, 279, -1, 281, 282, -1, 10, -1, 10, 350, - -1, -1, 353, -1, 292, -1, -1, -1, -1, -1, - 298, 299, -1, -1, 302, 303, 304, 368, 369, 33, - 308, 33, -1, -1, -1, 376, 377, -1, -1, -1, - -1, -1, -1, -1, 269, -1, -1, -1, 326, -1, - -1, -1, -1, 278, 279, -1, 281, 282, 123, -1, - -1, -1, 340, 10, -1, -1, -1, 292, -1, -1, - -1, -1, 350, 298, 299, 353, -1, 302, 303, 304, - -1, -1, -1, 308, -1, -1, 33, -1, -1, -1, - 368, 369, -1, -1, -1, -1, -1, -1, 376, 377, - -1, 326, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 340, -1, -1, -1, 10, - -1, -1, -1, -1, 269, 350, -1, -1, 353, -1, - -1, -1, -1, 278, 279, -1, 281, 282, -1, -1, - -1, 10, 33, 368, 369, -1, -1, 292, -1, -1, - -1, 376, 377, 298, 299, -1, -1, 302, 303, 304, - 262, -1, -1, 308, 33, 267, 268, -1, -1, -1, - -1, 273, 274, 275, 276, -1, 10, -1, -1, -1, - -1, 326, -1, -1, -1, -1, -1, 289, 290, -1, - -1, -1, -1, -1, -1, 340, -1, -1, -1, 33, - 302, -1, -1, 305, 269, 350, -1, -1, 353, 311, - -1, -1, -1, 278, 279, -1, 281, 282, -1, -1, - -1, -1, 324, 368, 369, -1, -1, 292, -1, -1, - -1, 376, 377, 298, 299, -1, -1, 302, 303, 304, - -1, -1, -1, 308, -1, -1, -1, -1, -1, -1, - -1, 353, -1, -1, -1, -1, -1, -1, 262, -1, - -1, 326, 266, 267, 268, -1, 368, 269, -1, 273, - 274, 275, 276, 375, -1, 340, 278, 279, 33, 281, - 282, -1, -1, -1, 288, 350, -1, -1, 353, -1, - 292, -1, -1, -1, -1, -1, 298, 299, -1, -1, - 302, 303, 304, 368, 369, -1, 308, -1, -1, -1, - -1, 376, 377, -1, -1, 262, -1, -1, -1, 266, - 267, 268, -1, -1, 326, -1, 273, 274, 275, 276, - -1, 335, 336, 337, 338, 339, -1, -1, 340, -1, - -1, 288, -1, -1, -1, -1, -1, -1, 350, 353, - -1, 353, 356, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 368, 369, 368, 369, -1, -1, - -1, 262, -1, -1, 376, 377, 267, 268, -1, -1, - -1, -1, 273, 274, 275, 276, -1, -1, 335, 336, - 337, 338, 339, 262, -1, -1, -1, 288, 267, 268, - -1, -1, -1, -1, 273, -1, 353, 276, -1, 356, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 288, - -1, 368, 369, -1, -1, -1, -1, -1, 262, -1, - -1, -1, -1, 267, 268, -1, -1, -1, -1, -1, - -1, -1, 276, -1, 335, 336, 337, 338, 339, -1, - -1, -1, -1, -1, 288, -1, -1, -1, -1, -1, - -1, -1, 353, -1, -1, 356, 335, 336, 337, 338, - 339, -1, -1, -1, -1, -1, -1, 368, 369, -1, - -1, -1, -1, -1, 353, -1, -1, 356, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 368, - 369, 335, 336, 337, 338, 339, -1, -1, -1, -1, - -1, -1, -1, -1, 269, -1, -1, -1, -1, 353, - -1, -1, 356, 278, 279, -1, 281, 282, -1, -1, - -1, -1, -1, -1, 368, 369, -1, 292, -1, -1, - -1, -1, -1, 298, 299, -1, -1, 302, 303, 304, - -1, -1, -1, 308, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 326, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 340, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 350, -1, -1, 353, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 369, -1, -1, -1, -1, -1, - -1, 376, 377, -}; -#define YYFINAL 2 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 380 -#define YYUNDFTOKEN 539 -#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a)) -#if YYDEBUG -static const char *const pfctlyname[] = { - -"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,"'!'",0,0,0,0,0,0,"'('","')'",0,0,"','","'-'",0,"'/'",0,0,0,0,0,0,0,0,0,0,0, -0,"'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,"PASS","BLOCK","SCRUB","RETURN","IN","OS","OUT","LOG","QUICK", -"ON","FROM","TO","FLAGS","RETURNRST","RETURNICMP","RETURNICMP6","PROTO","INET", -"INET6","ALL","ANY","ICMPTYPE","ICMP6TYPE","CODE","KEEP","MODULATE","STATE", -"PORT","RDR","NAT","BINAT","ARROW","NODF","MINTTL","ERROR","ALLOWOPTS", -"FASTROUTE","FILENAME","ROUTETO","DUPTO","REPLYTO","NO","LABEL","NOROUTE", -"URPFFAILED","FRAGMENT","USER","GROUP","MAXMSS","MAXIMUM","TTL","TOS","DROP", -"TABLE","REASSEMBLE","FRAGDROP","FRAGCROP","ANCHOR","NATANCHOR","RDRANCHOR", -"BINATANCHOR","SET","OPTIMIZATION","TIMEOUT","LIMIT","LOGINTERFACE", -"BLOCKPOLICY","RANDOMID","REQUIREORDER","SYNPROXY","FINGERPRINTS","NOSYNC", -"DEBUG","SKIP","HOSTID","ANTISPOOF","FOR","INCLUDE","BITMASK","RANDOM", -"SOURCEHASH","ROUNDROBIN","STATICPORT","PROBABILITY","ALTQ","CBQ","PRIQ","HFSC", -"BANDWIDTH","TBRSIZE","LINKSHARE","REALTIME","UPPERLIMIT","QUEUE","PRIORITY", -"QLIMIT","RTABLE","LOAD","RULESET_OPTIMIZATION","STICKYADDRESS","MAXSRCSTATES", -"MAXSRCNODES","SOURCETRACK","GLOBAL","RULE","MAXSRCCONN","MAXSRCCONNRATE", -"OVERLOAD","FLUSH","SLOPPY","PFLOW","TAGGED","TAG","IFBOUND","FLOATING", -"STATEPOLICY","STATEDEFAULTS","ROUTE","SETTOS","DIVERTTO","DIVERTREPLY", -"STRING","NUMBER","PORTBINARY",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,"illegal-symbol", -}; -static const char *const pfctlyrule[] = { -"$accept : ruleset", -"ruleset :", -"ruleset : ruleset include '\\n'", -"ruleset : ruleset '\\n'", -"ruleset : ruleset option '\\n'", -"ruleset : ruleset scrubrule '\\n'", -"ruleset : ruleset natrule '\\n'", -"ruleset : ruleset binatrule '\\n'", -"ruleset : ruleset pfrule '\\n'", -"ruleset : ruleset anchorrule '\\n'", -"ruleset : ruleset loadrule '\\n'", -"ruleset : ruleset altqif '\\n'", -"ruleset : ruleset queuespec '\\n'", -"ruleset : ruleset varset '\\n'", -"ruleset : ruleset antispoof '\\n'", -"ruleset : ruleset tabledef '\\n'", -"ruleset : '{' fakeanchor '}' '\\n'", -"ruleset : ruleset error '\\n'", -"include : INCLUDE STRING", -"fakeanchor : fakeanchor '\\n'", -"fakeanchor : fakeanchor anchorrule '\\n'", -"fakeanchor : fakeanchor binatrule '\\n'", -"fakeanchor : fakeanchor natrule '\\n'", -"fakeanchor : fakeanchor pfrule '\\n'", -"fakeanchor : fakeanchor error '\\n'", -"optimizer : string", -"option : SET OPTIMIZATION STRING", -"option : SET RULESET_OPTIMIZATION optimizer", -"option : SET TIMEOUT timeout_spec", -"option : SET TIMEOUT '{' optnl timeout_list '}'", -"option : SET LIMIT limit_spec", -"option : SET LIMIT '{' optnl limit_list '}'", -"option : SET LOGINTERFACE stringall", -"option : SET HOSTID number", -"option : SET BLOCKPOLICY DROP", -"option : SET BLOCKPOLICY RETURN", -"option : SET REQUIREORDER yesno", -"option : SET FINGERPRINTS STRING", -"option : SET STATEPOLICY statelock", -"option : SET DEBUG STRING", -"option : SET SKIP interface", -"option : SET STATEDEFAULTS state_opt_list", -"stringall : STRING", -"stringall : ALL", -"string : STRING string", -"string : STRING", -"varstring : numberstring varstring", -"varstring : numberstring", -"numberstring : NUMBER", -"numberstring : STRING", -"varset : STRING '=' varstring", -"anchorname : STRING", -"anchorname :", -"pfa_anchorlist :", -"pfa_anchorlist : pfa_anchorlist '\\n'", -"pfa_anchorlist : pfa_anchorlist pfrule '\\n'", -"pfa_anchorlist : pfa_anchorlist anchorrule '\\n'", -"$$1 :", -"pfa_anchor : '{' $$1 '\\n' pfa_anchorlist '}'", -"pfa_anchor :", -"anchorrule : ANCHOR anchorname dir quick interface af proto fromto filter_opts pfa_anchor", -"anchorrule : NATANCHOR string interface af proto fromto rtable", -"anchorrule : RDRANCHOR string interface af proto fromto rtable", -"anchorrule : BINATANCHOR string interface af proto fromto rtable", -"loadrule : LOAD ANCHOR string FROM string", -"scrubaction : no SCRUB", -"scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts", -"$$2 :", -"scrub_opts : $$2 scrub_opts_l", -"scrub_opts :", -"scrub_opts_l : scrub_opts_l scrub_opt", -"scrub_opts_l : scrub_opt", -"scrub_opt : NODF", -"scrub_opt : MINTTL NUMBER", -"scrub_opt : MAXMSS NUMBER", -"scrub_opt : SETTOS tos", -"scrub_opt : fragcache", -"scrub_opt : REASSEMBLE STRING", -"scrub_opt : RANDOMID", -"scrub_opt : RTABLE NUMBER", -"scrub_opt : not TAGGED string", -"fragcache : FRAGMENT REASSEMBLE", -"fragcache : FRAGMENT FRAGCROP", -"fragcache : FRAGMENT FRAGDROP", -"antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts", -"antispoof_ifspc : FOR antispoof_if", -"antispoof_ifspc : FOR '{' optnl antispoof_iflst '}'", -"antispoof_iflst : antispoof_if optnl", -"antispoof_iflst : antispoof_iflst comma antispoof_if optnl", -"antispoof_if : if_item", -"antispoof_if : '(' if_item ')'", -"$$3 :", -"antispoof_opts : $$3 antispoof_opts_l", -"antispoof_opts :", -"antispoof_opts_l : antispoof_opts_l antispoof_opt", -"antispoof_opts_l : antispoof_opt", -"antispoof_opt : label", -"antispoof_opt : RTABLE NUMBER", -"not : '!'", -"not :", -"tabledef : TABLE '<' STRING '>' table_opts", -"$$4 :", -"table_opts : $$4 table_opts_l", -"table_opts :", -"table_opts_l : table_opts_l table_opt", -"table_opts_l : table_opt", -"table_opt : STRING", -"table_opt : '{' optnl '}'", -"table_opt : '{' optnl host_list '}'", -"table_opt : FILENAME STRING", -"altqif : ALTQ interface queue_opts QUEUE qassign", -"queuespec : QUEUE STRING interface queue_opts qassign", -"$$5 :", -"queue_opts : $$5 queue_opts_l", -"queue_opts :", -"queue_opts_l : queue_opts_l queue_opt", -"queue_opts_l : queue_opt", -"queue_opt : BANDWIDTH bandwidth", -"queue_opt : PRIORITY NUMBER", -"queue_opt : QLIMIT NUMBER", -"queue_opt : scheduler", -"queue_opt : TBRSIZE NUMBER", -"bandwidth : STRING", -"bandwidth : NUMBER", -"scheduler : CBQ", -"scheduler : CBQ '(' cbqflags_list ')'", -"scheduler : PRIQ", -"scheduler : PRIQ '(' priqflags_list ')'", -"scheduler : HFSC", -"scheduler : HFSC '(' hfsc_opts ')'", -"cbqflags_list : cbqflags_item", -"cbqflags_list : cbqflags_list comma cbqflags_item", -"cbqflags_item : STRING", -"priqflags_list : priqflags_item", -"priqflags_list : priqflags_list comma priqflags_item", -"priqflags_item : STRING", -"$$6 :", -"hfsc_opts : $$6 hfscopts_list", -"hfscopts_list : hfscopts_item", -"hfscopts_list : hfscopts_list comma hfscopts_item", -"hfscopts_item : LINKSHARE bandwidth", -"hfscopts_item : LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'", -"hfscopts_item : REALTIME bandwidth", -"hfscopts_item : REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'", -"hfscopts_item : UPPERLIMIT bandwidth", -"hfscopts_item : UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'", -"hfscopts_item : STRING", -"qassign :", -"qassign : qassign_item", -"qassign : '{' optnl qassign_list '}'", -"qassign_list : qassign_item optnl", -"qassign_list : qassign_list comma qassign_item optnl", -"qassign_item : STRING", -"pfrule : action dir logquick interface route af proto fromto filter_opts", -"$$7 :", -"filter_opts : $$7 filter_opts_l", -"filter_opts :", -"filter_opts_l : filter_opts_l filter_opt", -"filter_opts_l : filter_opt", -"filter_opt : USER uids", -"filter_opt : GROUP gids", -"filter_opt : flags", -"filter_opt : icmpspec", -"filter_opt : TOS tos", -"filter_opt : keep", -"filter_opt : FRAGMENT", -"filter_opt : ALLOWOPTS", -"filter_opt : label", -"filter_opt : qname", -"filter_opt : TAG string", -"filter_opt : not TAGGED string", -"filter_opt : PROBABILITY probability", -"filter_opt : RTABLE NUMBER", -"filter_opt : DIVERTTO portplain", -"filter_opt : DIVERTTO STRING PORT portplain", -"filter_opt : DIVERTREPLY", -"probability : STRING", -"probability : NUMBER", -"action : PASS", -"action : BLOCK blockspec", -"blockspec :", -"blockspec : DROP", -"blockspec : RETURNRST", -"blockspec : RETURNRST '(' TTL NUMBER ')'", -"blockspec : RETURNICMP", -"blockspec : RETURNICMP6", -"blockspec : RETURNICMP '(' reticmpspec ')'", -"blockspec : RETURNICMP6 '(' reticmp6spec ')'", -"blockspec : RETURNICMP '(' reticmpspec comma reticmp6spec ')'", -"blockspec : RETURN", -"reticmpspec : STRING", -"reticmpspec : NUMBER", -"reticmp6spec : STRING", -"reticmp6spec : NUMBER", -"dir :", -"dir : IN", -"dir : OUT", -"quick :", -"quick : QUICK", -"logquick :", -"logquick : log", -"logquick : QUICK", -"logquick : log QUICK", -"logquick : QUICK log", -"log : LOG", -"log : LOG '(' logopts ')'", -"logopts : logopt", -"logopts : logopts comma logopt", -"logopt : ALL", -"logopt : USER", -"logopt : GROUP", -"logopt : TO string", -"interface :", -"interface : ON if_item_not", -"interface : ON '{' optnl if_list '}'", -"if_list : if_item_not optnl", -"if_list : if_list comma if_item_not optnl", -"if_item_not : not if_item", -"if_item : STRING", -"af :", -"af : INET", -"af : INET6", -"proto :", -"proto : PROTO proto_item", -"proto : PROTO '{' optnl proto_list '}'", -"proto_list : proto_item optnl", -"proto_list : proto_list comma proto_item optnl", -"proto_item : protoval", -"protoval : STRING", -"protoval : NUMBER", -"fromto : ALL", -"fromto : from os to", -"os :", -"os : OS xos", -"os : OS '{' optnl os_list '}'", -"xos : STRING", -"os_list : xos optnl", -"os_list : os_list comma xos optnl", -"from :", -"from : FROM ipportspec", -"to :", -"to : TO ipportspec", -"ipportspec : ipspec", -"ipportspec : ipspec PORT portspec", -"ipportspec : PORT portspec", -"optnl : '\\n' optnl", -"optnl :", -"ipspec : ANY", -"ipspec : xhost", -"ipspec : '{' optnl host_list '}'", -"toipspec : TO ipspec", -"toipspec :", -"host_list : ipspec optnl", -"host_list : host_list comma ipspec optnl", -"xhost : not host", -"xhost : not NOROUTE", -"xhost : not URPFFAILED", -"host : STRING", -"host : STRING '-' STRING", -"host : STRING '/' NUMBER", -"host : NUMBER '/' NUMBER", -"host : dynaddr", -"host : dynaddr '/' NUMBER", -"host : '<' STRING '>'", -"host : ROUTE STRING", -"number : NUMBER", -"number : STRING", -"dynaddr : '(' STRING ')'", -"portspec : port_item", -"portspec : '{' optnl port_list '}'", -"port_list : port_item optnl", -"port_list : port_list comma port_item optnl", -"port_item : portrange", -"port_item : unaryop portrange", -"port_item : portrange PORTBINARY portrange", -"portplain : numberstring", -"portrange : numberstring", -"uids : uid_item", -"uids : '{' optnl uid_list '}'", -"uid_list : uid_item optnl", -"uid_list : uid_list comma uid_item optnl", -"uid_item : uid", -"uid_item : unaryop uid", -"uid_item : uid PORTBINARY uid", -"uid : STRING", -"uid : NUMBER", -"gids : gid_item", -"gids : '{' optnl gid_list '}'", -"gid_list : gid_item optnl", -"gid_list : gid_list comma gid_item optnl", -"gid_item : gid", -"gid_item : unaryop gid", -"gid_item : gid PORTBINARY gid", -"gid : STRING", -"gid : NUMBER", -"flag : STRING", -"flags : FLAGS flag '/' flag", -"flags : FLAGS '/' flag", -"flags : FLAGS ANY", -"icmpspec : ICMPTYPE icmp_item", -"icmpspec : ICMPTYPE '{' optnl icmp_list '}'", -"icmpspec : ICMP6TYPE icmp6_item", -"icmpspec : ICMP6TYPE '{' optnl icmp6_list '}'", -"icmp_list : icmp_item optnl", -"icmp_list : icmp_list comma icmp_item optnl", -"icmp6_list : icmp6_item optnl", -"icmp6_list : icmp6_list comma icmp6_item optnl", -"icmp_item : icmptype", -"icmp_item : icmptype CODE STRING", -"icmp_item : icmptype CODE NUMBER", -"icmp6_item : icmp6type", -"icmp6_item : icmp6type CODE STRING", -"icmp6_item : icmp6type CODE NUMBER", -"icmptype : STRING", -"icmptype : NUMBER", -"icmp6type : STRING", -"icmp6type : NUMBER", -"tos : STRING", -"tos : NUMBER", -"sourcetrack : SOURCETRACK", -"sourcetrack : SOURCETRACK GLOBAL", -"sourcetrack : SOURCETRACK RULE", -"statelock : IFBOUND", -"statelock : FLOATING", -"keep : NO STATE", -"keep : KEEP STATE state_opt_spec", -"keep : MODULATE STATE state_opt_spec", -"keep : SYNPROXY STATE state_opt_spec", -"flush :", -"flush : FLUSH", -"flush : FLUSH GLOBAL", -"state_opt_spec : '(' state_opt_list ')'", -"state_opt_spec :", -"state_opt_list : state_opt_item", -"state_opt_list : state_opt_list comma state_opt_item", -"state_opt_item : MAXIMUM NUMBER", -"state_opt_item : NOSYNC", -"state_opt_item : MAXSRCSTATES NUMBER", -"state_opt_item : MAXSRCCONN NUMBER", -"state_opt_item : MAXSRCCONNRATE NUMBER '/' NUMBER", -"state_opt_item : OVERLOAD '<' STRING '>' flush", -"state_opt_item : MAXSRCNODES NUMBER", -"state_opt_item : sourcetrack", -"state_opt_item : statelock", -"state_opt_item : SLOPPY", -"state_opt_item : PFLOW", -"state_opt_item : STRING NUMBER", -"label : LABEL STRING", -"qname : QUEUE STRING", -"qname : QUEUE '(' STRING ')'", -"qname : QUEUE '(' STRING comma STRING ')'", -"no :", -"no : NO", -"portstar : numberstring", -"redirspec : host", -"redirspec : '{' optnl redir_host_list '}'", -"redir_host_list : host optnl", -"redir_host_list : redir_host_list comma host optnl", -"redirpool :", -"redirpool : ARROW redirspec", -"redirpool : ARROW redirspec PORT portstar", -"hashkey :", -"hashkey : string", -"$$8 :", -"pool_opts : $$8 pool_opts_l", -"pool_opts :", -"pool_opts_l : pool_opts_l pool_opt", -"pool_opts_l : pool_opt", -"pool_opt : BITMASK", -"pool_opt : RANDOM", -"pool_opt : SOURCEHASH hashkey", -"pool_opt : ROUNDROBIN", -"pool_opt : STATICPORT", -"pool_opt : STICKYADDRESS", -"redirection :", -"redirection : ARROW host", -"redirection : ARROW host PORT portstar", -"natpasslog :", -"natpasslog : PASS", -"natpasslog : PASS log", -"natpasslog : log", -"nataction : no NAT natpasslog", -"nataction : no RDR natpasslog", -"natrule : nataction interface af proto fromto tag tagged rtable redirpool pool_opts", -"binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection", -"tag :", -"tag : TAG STRING", -"tagged :", -"tagged : not TAGGED string", -"rtable :", -"rtable : RTABLE NUMBER", -"route_host : STRING", -"route_host : '(' STRING host ')'", -"route_host_list : route_host optnl", -"route_host_list : route_host_list comma route_host optnl", -"routespec : route_host", -"routespec : '{' optnl route_host_list '}'", -"route :", -"route : FASTROUTE", -"route : ROUTETO routespec pool_opts", -"route : REPLYTO routespec pool_opts", -"route : DUPTO routespec pool_opts", -"timeout_spec : STRING NUMBER", -"timeout_list : timeout_list comma timeout_spec optnl", -"timeout_list : timeout_spec optnl", -"limit_spec : STRING NUMBER", -"limit_list : limit_list comma limit_spec optnl", -"limit_list : limit_spec optnl", -"comma : ','", -"comma :", -"yesno : NO", -"yesno : STRING", -"unaryop : '='", -"unaryop : '!' '='", -"unaryop : '<' '='", -"unaryop : '<'", -"unaryop : '>' '='", -"unaryop : '>'", - -}; -#endif - -int yydebug; -int yynerrs; - -int yyerrflag; -int yychar; -YYSTYPE yyval; -YYSTYPE yylval; - -/* define the initial stack-sizes */ -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 10000 -#define YYMAXDEPTH 10000 -#endif -#endif - -#define YYINITSTACKSIZE 200 - -typedef struct { - unsigned stacksize; - YYINT *s_base; - YYINT *s_mark; - YYINT *s_last; - YYSTYPE *l_base; - YYSTYPE *l_mark; -} YYSTACKDATA; -/* variables for the parser stack */ -static YYSTACKDATA yystack; -#line 4397 "../../freebsd/contrib/pf/pfctl/parse.y" - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - - file->errors++; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - return (0); -} - -int -disallow_table(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_TABLE) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -disallow_urpf_failed(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_URPFFAILED) { - yyerror(fmt); - return (1); - } - return (0); -} - -int -disallow_alias(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (DYNIF_MULTIADDR(h->addr)) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -rule_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - switch (r->action) { - case PF_PASS: - case PF_DROP: - case PF_SCRUB: - case PF_NOSCRUB: - problems = filter_consistent(r, anchor_call); - break; - case PF_NAT: - case PF_NONAT: - problems = nat_consistent(r); - break; - case PF_RDR: - case PF_NORDR: - problems = rdr_consistent(r); - break; - case PF_BINAT: - case PF_NOBINAT: - default: - break; - } - return (problems); -} - -int -filter_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && - (r->src.port_op || r->dst.port_op)) { - yyerror("port only applies to tcp/udp"); - problems++; - } - if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && - (r->type || r->code)) { - yyerror("icmp-type/code only applies to icmp"); - problems++; - } - if (!r->af && (r->type || r->code)) { - yyerror("must indicate address family with icmp-type/code"); - problems++; - } - if (r->overload_tblname[0] && - r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { - yyerror("'overload' requires 'max-src-conn' " - "or 'max-src-conn-rate'"); - problems++; - } - if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || - (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { - yyerror("proto %s doesn't match address family %s", - r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", - r->af == AF_INET ? "inet" : "inet6"); - problems++; - } - if (r->allow_opts && r->action != PF_PASS) { - yyerror("allow-opts can only be specified for pass rules"); - problems++; - } - if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || - r->dst.port_op || r->flagset || r->type || r->code)) { - yyerror("fragments can be filtered only on IP header fields"); - problems++; - } - if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { - yyerror("return-rst can only be applied to TCP rules"); - problems++; - } - if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { - yyerror("max-src-nodes requires 'source-track rule'"); - problems++; - } - if (r->action == PF_DROP && r->keep_state) { - yyerror("keep state on block rules doesn't make sense"); - problems++; - } - if (r->rule_flag & PFRULE_STATESLOPPY && - (r->keep_state == PF_STATE_MODULATE || - r->keep_state == PF_STATE_SYNPROXY)) { - yyerror("sloppy state matching cannot be used with " - "synproxy state or modulate state"); - problems++; - } - return (-problems); -} - -int -nat_consistent(struct pf_rule *r) -{ - return (0); /* yeah! */ -} - -int -rdr_consistent(struct pf_rule *r) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { - if (r->src.port_op) { - yyerror("src port only applies to tcp/udp"); - problems++; - } - if (r->dst.port_op) { - yyerror("dst port only applies to tcp/udp"); - problems++; - } - if (r->rpool.proxy_port[0]) { - yyerror("rpool port only applies to tcp/udp"); - problems++; - } - } - if (r->dst.port_op && - r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { - yyerror("invalid port operator for rdr destination port"); - problems++; - } - return (-problems); -} - -int -process_tabledef(char *name, struct table_opts *opts) -{ - struct pfr_buffer ab; - struct node_tinit *ti; - - bzero(&ab, sizeof(ab)); - ab.pfrb_type = PFRB_ADDRS; - SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { - if (ti->file) - if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { - if (errno) - yyerror("cannot load \"%s\": %s", - ti->file, strerror(errno)); - else - yyerror("file \"%s\" contains bad data", - ti->file); - goto _error; - } - if (ti->host) - if (append_addr_host(&ab, ti->host, 0, 0)) { - yyerror("cannot create address buffer: %s", - strerror(errno)); - goto _error; - } - } - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(name, opts->flags, opts->init_addr, - &opts->init_nodes); - if (!(pf->opts & PF_OPT_NOACTION) && - pfctl_define_table(name, opts->flags, opts->init_addr, - pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { - yyerror("cannot define table %s: %s", name, - pfr_strerror(errno)); - goto _error; - } - pf->tdirty = 1; - pfr_buf_clear(&ab); - return (0); -_error: - pfr_buf_clear(&ab); - return (-1); -} - -struct keywords { - const char *k_name; - int k_val; -}; - -/* macro gore, but you should've seen the prior indentation nightmare... */ - -#define FREE_LIST(T,r) \ - do { \ - T *p, *node = r; \ - while (node != NULL) { \ - p = node; \ - node = node->next; \ - free(p); \ - } \ - } while (0) - -#define LOOP_THROUGH(T,n,r,C) \ - do { \ - T *n; \ - if (r == NULL) { \ - r = calloc(1, sizeof(T)); \ - if (r == NULL) \ - err(1, "LOOP: calloc"); \ - r->next = NULL; \ - } \ - n = r; \ - while (n != NULL) { \ - do { \ - C; \ - } while (0); \ - n = n->next; \ - } \ - } while (0) - -void -expand_label_str(char *label, size_t len, const char *srch, const char *repl) -{ - char *tmp; - char *p, *q; - - if ((tmp = calloc(1, len)) == NULL) - err(1, "expand_label_str: calloc"); - p = q = label; - while ((q = strstr(p, srch)) != NULL) { - *q = '\0'; - if ((strlcat(tmp, p, len) >= len) || - (strlcat(tmp, repl, len) >= len)) - errx(1, "expand_label: label too long"); - q += strlen(srch); - p = q; - } - if (strlcat(tmp, p, len) >= len) - errx(1, "expand_label: label too long"); - strlcpy(label, tmp, len); /* always fits */ - free(tmp); -} - -void -expand_label_if(const char *name, char *label, size_t len, const char *ifname) -{ - if (strstr(label, name) != NULL) { - if (!*ifname) - expand_label_str(label, len, name, "any"); - else - expand_label_str(label, len, name, ifname); - } -} - -void -expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, - struct node_host *h) -{ - char tmp[64], tmp_not[66]; - - if (strstr(label, name) != NULL) { - switch (h->addr.type) { - case PF_ADDR_DYNIFTL: - snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); - break; - case PF_ADDR_TABLE: - snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); - break; - case PF_ADDR_NOROUTE: - snprintf(tmp, sizeof(tmp), "no-route"); - break; - case PF_ADDR_URPFFAILED: - snprintf(tmp, sizeof(tmp), "urpf-failed"); - break; - case PF_ADDR_ADDRMASK: - if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && - PF_AZERO(&h->addr.v.a.mask, af))) - snprintf(tmp, sizeof(tmp), "any"); - else { - char a[48]; - int bits; - - if (inet_ntop(af, &h->addr.v.a.addr, a, - sizeof(a)) == NULL) - snprintf(tmp, sizeof(tmp), "?"); - else { - bits = unmask(&h->addr.v.a.mask, af); - if ((af == AF_INET && bits < 32) || - (af == AF_INET6 && bits < 128)) - snprintf(tmp, sizeof(tmp), - "%s/%d", a, bits); - else - snprintf(tmp, sizeof(tmp), - "%s", a); - } - } - break; - default: - snprintf(tmp, sizeof(tmp), "?"); - break; - } - - if (h->not) { - snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); - expand_label_str(label, len, name, tmp_not); - } else - expand_label_str(label, len, name, tmp); - } -} - -void -expand_label_port(const char *name, char *label, size_t len, - struct node_port *port) -{ - char a1[6], a2[6], op[13] = ""; - - if (strstr(label, name) != NULL) { - snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); - snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); - if (!port->op) - ; - else if (port->op == PF_OP_IRG) - snprintf(op, sizeof(op), "%s><%s", a1, a2); - else if (port->op == PF_OP_XRG) - snprintf(op, sizeof(op), "%s<>%s", a1, a2); - else if (port->op == PF_OP_EQ) - snprintf(op, sizeof(op), "%s", a1); - else if (port->op == PF_OP_NE) - snprintf(op, sizeof(op), "!=%s", a1); - else if (port->op == PF_OP_LT) - snprintf(op, sizeof(op), "<%s", a1); - else if (port->op == PF_OP_LE) - snprintf(op, sizeof(op), "<=%s", a1); - else if (port->op == PF_OP_GT) - snprintf(op, sizeof(op), ">%s", a1); - else if (port->op == PF_OP_GE) - snprintf(op, sizeof(op), ">=%s", a1); - expand_label_str(label, len, name, op); - } -} - -void -expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) -{ - struct protoent *pe; - char n[4]; - - if (strstr(label, name) != NULL) { - pe = getprotobynumber(proto); - if (pe != NULL) - expand_label_str(label, len, name, pe->p_name); - else { - snprintf(n, sizeof(n), "%u", proto); - expand_label_str(label, len, name, n); - } - } -} - -void -expand_label_nr(const char *name, char *label, size_t len) -{ - char n[11]; - - if (strstr(label, name) != NULL) { - snprintf(n, sizeof(n), "%u", pf->anchor->match); - expand_label_str(label, len, name, n); - } -} - -void -expand_label(char *label, size_t len, const char *ifname, sa_family_t af, - struct node_host *src_host, struct node_port *src_port, - struct node_host *dst_host, struct node_port *dst_port, - u_int8_t proto) -{ - expand_label_if("$if", label, len, ifname); - expand_label_addr("$srcaddr", label, len, af, src_host); - expand_label_addr("$dstaddr", label, len, af, dst_host); - expand_label_port("$srcport", label, len, src_port); - expand_label_port("$dstport", label, len, dst_port); - expand_label_proto("$proto", label, len, proto); - expand_label_nr("$nr", label, len); -} - -int -expand_altq(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct pf_altq pa, pb; - char qname[PF_QNAME_SIZE]; - struct node_queue *n; - struct node_queue_bw bw; - int errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - memcpy(&pa, a, sizeof(struct pf_altq)); - if (strlcpy(pa.ifname, interface->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_altq: strlcpy"); - - if (interface->not) { - yyerror("altq on ! <interface> is not supported"); - errs++; - } else { - if (eval_pfaltq(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - if (pf->opts & PF_OPT_VERBOSE) { - print_altq(&pf->paltq->altq, 0, - &bwspec, opts); - if (nqueues && nqueues->tail) { - printf("queue { "); - LOOP_THROUGH(struct node_queue, queue, - nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) { - /* now create a root queue */ - memset(&pb, 0, sizeof(struct pf_altq)); - if (strlcpy(qname, "root_", sizeof(qname)) >= - sizeof(qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcat(qname, interface->ifname, - sizeof(qname)) >= sizeof(qname)) - errx(1, "expand_altq: strlcat"); - if (strlcpy(pb.qname, qname, - sizeof(pb.qname)) >= sizeof(pb.qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(pb.ifname, interface->ifname, - sizeof(pb.ifname)) >= sizeof(pb.ifname)) - errx(1, "expand_altq: strlcpy"); - pb.qlimit = pa.qlimit; - pb.scheduler = pa.scheduler; - bw.bw_absolute = pa.ifbandwidth; - bw.bw_percent = 0; - if (eval_pfqueue(pf, &pb, &bw, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pb)) - errs++; - } - - LOOP_THROUGH(struct node_queue, queue, nqueues, - n = calloc(1, sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_altq: calloc"); - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) - if (strlcpy(n->parent, qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->queue, queue->queue, - sizeof(n->queue)) >= sizeof(n->queue)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->ifname, interface->ifname, - sizeof(n->ifname)) >= sizeof(n->ifname)) - errx(1, "expand_altq: strlcpy"); - n->scheduler = pa.scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - ); - } - ); - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - - return (errs); -} - -int -expand_queue(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct node_queue *n, *nq; - struct pf_altq pa; - u_int8_t found = 0; - u_int8_t errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - if (queues == NULL) { - yyerror("queue %s has no parent", a->qname); - FREE_LIST(struct node_queue, nqueues); - return (1); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_queue, tqueue, queues, - if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && - (interface->ifname[0] == 0 || - (!interface->not && !strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)) || - (interface->not && strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)))) { - /* found ourself in queues */ - found++; - - memcpy(&pa, a, sizeof(struct pf_altq)); - - if (pa.scheduler != ALTQT_NONE && - pa.scheduler != tqueue->scheduler) { - yyerror("exactly one scheduler type " - "per interface allowed"); - return (1); - } - pa.scheduler = tqueue->scheduler; - - /* scheduler dependent error checking */ - switch (pa.scheduler) { - case ALTQT_PRIQ: - if (nqueues != NULL) { - yyerror("priq queues cannot " - "have child queues"); - return (1); - } - if (bwspec.bw_absolute > 0 || - bwspec.bw_percent < 100) { - yyerror("priq doesn't take " - "bandwidth"); - return (1); - } - break; - default: - break; - } - - if (strlcpy(pa.ifname, tqueue->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_queue: strlcpy"); - if (strlcpy(pa.parent, tqueue->parent, - sizeof(pa.parent)) >= sizeof(pa.parent)) - errx(1, "expand_queue: strlcpy"); - - if (eval_pfqueue(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - for (nq = nqueues; nq != NULL; nq = nq->next) { - if (!strcmp(a->qname, nq->queue)) { - yyerror("queue cannot have " - "itself as child"); - errs++; - continue; - } - n = calloc(1, - sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_queue: calloc"); - if (strlcpy(n->parent, a->qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->queue, nq->queue, - sizeof(n->queue)) >= - sizeof(n->queue)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->ifname, tqueue->ifname, - sizeof(n->ifname)) >= - sizeof(n->ifname)) - errx(1, "expand_queue strlcpy"); - n->scheduler = tqueue->scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - } - if ((pf->opts & PF_OPT_VERBOSE) && ( - (found == 1 && interface->ifname[0] == 0) || - (found > 0 && interface->ifname[0] != 0))) { - print_queue(&pf->paltq->altq, 0, - &bwspec, interface->ifname[0] != 0, - opts); - if (nqueues && nqueues->tail) { - printf("{ "); - LOOP_THROUGH(struct node_queue, - queue, nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - } - ); - ); - - FREE_LIST(struct node_queue, nqueues); - FREE_LIST(struct node_if, interfaces); - - if (!found) { - yyerror("queue %s has no parent", a->qname); - errs++; - } - - if (errs) - return (1); - else - return (0); -} - -void -expand_rule(struct pf_rule *r, - struct node_if *interfaces, struct node_host *rpool_hosts, - struct node_proto *protos, struct node_os *src_oses, - struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports, - struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, - const char *anchor_call) -{ - sa_family_t af = r->af; - int added = 0, error = 0; - char ifname[IF_NAMESIZE]; - char label[PF_RULE_LABEL_SIZE]; - char tagname[PF_TAG_NAME_SIZE]; - char match_tagname[PF_TAG_NAME_SIZE]; - struct pf_pooladdr *pa; - struct node_host *h; - u_int8_t flags, flagset, keep_state; - - if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= - sizeof(match_tagname)) - errx(1, "expand_rule: strlcpy"); - flags = r->flags; - flagset = r->flagset; - keep_state = r->keep_state; - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_proto, proto, protos, - LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, - LOOP_THROUGH(struct node_host, src_host, src_hosts, - LOOP_THROUGH(struct node_port, src_port, src_ports, - LOOP_THROUGH(struct node_os, src_os, src_oses, - LOOP_THROUGH(struct node_host, dst_host, dst_hosts, - LOOP_THROUGH(struct node_port, dst_port, dst_ports, - LOOP_THROUGH(struct node_uid, uid, uids, - LOOP_THROUGH(struct node_gid, gid, gids, - - r->af = af; - /* for link-local IPv6 address, interface must match up */ - if ((r->af && src_host->af && r->af != src_host->af) || - (r->af && dst_host->af && r->af != dst_host->af) || - (src_host->af && dst_host->af && - src_host->af != dst_host->af) || - (src_host->ifindex && dst_host->ifindex && - src_host->ifindex != dst_host->ifindex) || - (src_host->ifindex && *interface->ifname && - src_host->ifindex != if_nametoindex(interface->ifname)) || - (dst_host->ifindex && *interface->ifname && - dst_host->ifindex != if_nametoindex(interface->ifname))) - continue; - if (!r->af && src_host->af) - r->af = src_host->af; - else if (!r->af && dst_host->af) - r->af = dst_host->af; - - if (*interface->ifname) - strlcpy(r->ifname, interface->ifname, - sizeof(r->ifname)); - else if (if_indextoname(src_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else if (if_indextoname(dst_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else - memset(r->ifname, '\0', sizeof(r->ifname)); - - if (strlcpy(r->label, label, sizeof(r->label)) >= - sizeof(r->label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= - sizeof(r->tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->match_tagname, match_tagname, - sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) - errx(1, "expand_rule: strlcpy"); - expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, - r->af, src_host, src_port, dst_host, dst_port, - proto->proto); - - error += check_netmask(src_host, r->af); - error += check_netmask(dst_host, r->af); - - r->ifnot = interface->not; - r->proto = proto->proto; - r->src.addr = src_host->addr; - r->src.neg = src_host->not; - r->src.port[0] = src_port->port[0]; - r->src.port[1] = src_port->port[1]; - r->src.port_op = src_port->op; - r->dst.addr = dst_host->addr; - r->dst.neg = dst_host->not; - r->dst.port[0] = dst_port->port[0]; - r->dst.port[1] = dst_port->port[1]; - r->dst.port_op = dst_port->op; - r->uid.op = uid->op; - r->uid.uid[0] = uid->uid[0]; - r->uid.uid[1] = uid->uid[1]; - r->gid.op = gid->op; - r->gid.gid[0] = gid->gid[0]; - r->gid.gid[1] = gid->gid[1]; - r->type = icmp_type->type; - r->code = icmp_type->code; - - if ((keep_state == PF_STATE_MODULATE || - keep_state == PF_STATE_SYNPROXY) && - r->proto && r->proto != IPPROTO_TCP) - r->keep_state = PF_STATE_NORMAL; - else - r->keep_state = keep_state; - - if (r->proto && r->proto != IPPROTO_TCP) { - r->flags = 0; - r->flagset = 0; - } else { - r->flags = flags; - r->flagset = flagset; - } - if (icmp_type->proto && r->proto != icmp_type->proto) { - yyerror("icmp-type mismatch"); - error++; - } - - if (src_os && src_os->os) { - r->os_fingerprint = pfctl_get_fingerprint(src_os->os); - if ((pf->opts & PF_OPT_VERBOSE2) && - r->os_fingerprint == PF_OSFP_NOMATCH) - fprintf(stderr, - "warning: unknown '%s' OS fingerprint\n", - src_os->os); - } else { - r->os_fingerprint = PF_OSFP_ANY; - } - - TAILQ_INIT(&r->rpool.list); - for (h = rpool_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); - } - - if (rule_consistent(r, anchor_call[0]) < 0 || error) - yyerror("skipping rule due to errors"); - else { - r->nr = pf->astack[pf->asd]->match++; - pfctl_add_rule(pf, r, anchor_call); - added++; - } - - )))))))))); - - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_proto, protos); - FREE_LIST(struct node_host, src_hosts); - FREE_LIST(struct node_port, src_ports); - FREE_LIST(struct node_os, src_oses); - FREE_LIST(struct node_host, dst_hosts); - FREE_LIST(struct node_port, dst_ports); - FREE_LIST(struct node_uid, uids); - FREE_LIST(struct node_gid, gids); - FREE_LIST(struct node_icmp, icmp_types); - FREE_LIST(struct node_host, rpool_hosts); - - if (!added) - yyerror("rule expands to no valid combination"); -} - -int -expand_skip_interface(struct node_if *interfaces) -{ - int errs = 0; - - if (!interfaces || (!interfaces->next && !interfaces->not && - !strcmp(interfaces->ifname, "none"))) { - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on none\n"); - errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); - return (errs); - } - - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on {"); - LOOP_THROUGH(struct node_if, interface, interfaces, - if (pf->opts & PF_OPT_VERBOSE) - printf(" %s", interface->ifname); - if (interface->not) { - yyerror("skip on ! <interface> is not supported"); - errs++; - } else - errs += pfctl_set_interface_flags(pf, - interface->ifname, PFI_IFLAG_SKIP, 1); - ); - if (pf->opts & PF_OPT_VERBOSE) - printf(" }\n"); - - FREE_LIST(struct node_if, interfaces); - - if (errs) - return (1); - else - return (0); -} - -#undef FREE_LIST -#undef LOOP_THROUGH - -int -check_rulestate(int desired_state) -{ - if (require_order && (rulestate > desired_state)) { - yyerror("Rules must be in order: options, normalization, " - "queueing, translation, filtering"); - return (1); - } - rulestate = desired_state; - return (0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* this has to be sorted always */ - static const struct keywords keywords[] = { - { "all", ALL}, - { "allow-opts", ALLOWOPTS}, - { "altq", ALTQ}, - { "anchor", ANCHOR}, - { "antispoof", ANTISPOOF}, - { "any", ANY}, - { "bandwidth", BANDWIDTH}, - { "binat", BINAT}, - { "binat-anchor", BINATANCHOR}, - { "bitmask", BITMASK}, - { "block", BLOCK}, - { "block-policy", BLOCKPOLICY}, - { "cbq", CBQ}, - { "code", CODE}, - { "crop", FRAGCROP}, - { "debug", DEBUG}, - { "divert-reply", DIVERTREPLY}, - { "divert-to", DIVERTTO}, - { "drop", DROP}, - { "drop-ovl", FRAGDROP}, - { "dup-to", DUPTO}, - { "fastroute", FASTROUTE}, - { "file", FILENAME}, - { "fingerprints", FINGERPRINTS}, - { "flags", FLAGS}, - { "floating", FLOATING}, - { "flush", FLUSH}, - { "for", FOR}, - { "fragment", FRAGMENT}, - { "from", FROM}, - { "global", GLOBAL}, - { "group", GROUP}, - { "hfsc", HFSC}, - { "hostid", HOSTID}, - { "icmp-type", ICMPTYPE}, - { "icmp6-type", ICMP6TYPE}, - { "if-bound", IFBOUND}, - { "in", IN}, - { "include", INCLUDE}, - { "inet", INET}, - { "inet6", INET6}, - { "keep", KEEP}, - { "label", LABEL}, - { "limit", LIMIT}, - { "linkshare", LINKSHARE}, - { "load", LOAD}, - { "log", LOG}, - { "loginterface", LOGINTERFACE}, - { "max", MAXIMUM}, - { "max-mss", MAXMSS}, - { "max-src-conn", MAXSRCCONN}, - { "max-src-conn-rate", MAXSRCCONNRATE}, - { "max-src-nodes", MAXSRCNODES}, - { "max-src-states", MAXSRCSTATES}, - { "min-ttl", MINTTL}, - { "modulate", MODULATE}, - { "nat", NAT}, - { "nat-anchor", NATANCHOR}, - { "no", NO}, - { "no-df", NODF}, - { "no-route", NOROUTE}, - { "no-sync", NOSYNC}, - { "on", ON}, - { "optimization", OPTIMIZATION}, - { "os", OS}, - { "out", OUT}, - { "overload", OVERLOAD}, - { "pass", PASS}, - { "pflow", PFLOW}, - { "port", PORT}, - { "priority", PRIORITY}, - { "priq", PRIQ}, - { "probability", PROBABILITY}, - { "proto", PROTO}, - { "qlimit", QLIMIT}, - { "queue", QUEUE}, - { "quick", QUICK}, - { "random", RANDOM}, - { "random-id", RANDOMID}, - { "rdr", RDR}, - { "rdr-anchor", RDRANCHOR}, - { "realtime", REALTIME}, - { "reassemble", REASSEMBLE}, - { "reply-to", REPLYTO}, - { "require-order", REQUIREORDER}, - { "return", RETURN}, - { "return-icmp", RETURNICMP}, - { "return-icmp6", RETURNICMP6}, - { "return-rst", RETURNRST}, - { "round-robin", ROUNDROBIN}, - { "route", ROUTE}, - { "route-to", ROUTETO}, - { "rtable", RTABLE}, - { "rule", RULE}, - { "ruleset-optimization", RULESET_OPTIMIZATION}, - { "scrub", SCRUB}, - { "set", SET}, - { "set-tos", SETTOS}, - { "skip", SKIP}, - { "sloppy", SLOPPY}, - { "source-hash", SOURCEHASH}, - { "source-track", SOURCETRACK}, - { "state", STATE}, - { "state-defaults", STATEDEFAULTS}, - { "state-policy", STATEPOLICY}, - { "static-port", STATICPORT}, - { "sticky-address", STICKYADDRESS}, - { "synproxy", SYNPROXY}, - { "table", TABLE}, - { "tag", TAG}, - { "tagged", TAGGED}, - { "tbrsize", TBRSIZE}, - { "timeout", TIMEOUT}, - { "to", TO}, - { "tos", TOS}, - { "ttl", TTL}, - { "upperlimit", UPPERLIMIT}, - { "urpf-failed", URPFFAILED}, - { "user", USER}, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) { - if (debug > 1) - fprintf(stderr, "%s: %d\n", s, p->k_val); - return (p->k_val); - } else { - if (debug > 1) - fprintf(stderr, "string: %s\n", s); - return (STRING); - } -} - -#define MAXPUSHBACK 128 - -#ifndef __rtems__ -char *parsebuf; -int parseindex; -char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; -#else /* __rtems__ */ -static char *parsebuf; -static int parseindex; -static char pushback_buffer[MAXPUSHBACK]; -static int pushback_index = 0; -#endif /* __rtems__ */ - -int -lgetc(int quotec) -{ - int c, next; - - if (parsebuf) { - /* Read character from the parsebuffer instead of input. */ - if (parseindex >= 0) { - c = parsebuf[parseindex++]; - if (c != '\0') - return (c); - parsebuf = NULL; - } else - parseindex++; - } - - if (pushback_index) - return (pushback_buffer[--pushback_index]); - - if (quotec) { - if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); - if (popfile() == EOF) - return (EOF); - return (quotec); - } - return (c); - } - - while ((c = getc(file->stream)) == '\\') { - next = getc(file->stream); - if (next != '\n') { - c = next; - break; - } - yylval.lineno = file->lineno; - file->lineno++; - } - - while (c == EOF) { - if (popfile() == EOF) - return (EOF); - c = getc(file->stream); - } - return (c); -} - -int -lungetc(int c) -{ - if (c == EOF) - return (EOF); - if (parsebuf) { - parseindex--; - if (parseindex >= 0) - return (c); - } - if (pushback_index < MAXPUSHBACK-1) - return (pushback_buffer[pushback_index++] = c); - else - return (EOF); -} - -int -findeol(void) -{ - int c; - - parsebuf = NULL; - - /* skip to either EOF or the first real EOL */ - while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; - -top: - p = buf; - while ((c = lgetc(0)) == ' ' || c == '\t') - ; /* nothing */ - - yylval.lineno = file->lineno; - if (c == '#') - while ((c = lgetc(0)) != '\n' && c != EOF) - ; /* nothing */ - if (c == '$' && parsebuf == NULL) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = (char)c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - parsebuf = val; - parseindex = 0; - goto top; - } - - switch (c) { - case '\'': - case '"': - quotec = c; - while (1) { - if ((c = lgetc(quotec)) == EOF) - return (0); - if (c == '\n') { - file->lineno++; - continue; - } else if (c == '\\') { - if ((next = lgetc(quotec)) == EOF) - return (0); - if (next == quotec || c == ' ' || c == '\t') - c = next; - else if (next == '\n') - continue; - else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; - break; - } - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - *p++ = (char)c; - } - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - err(1, "yylex: strdup"); - return (STRING); - case '<': - next = lgetc(0); - if (next == '>') { - yylval.v.i = PF_OP_XRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '>': - next = lgetc(0); - if (next == '<') { - yylval.v.i = PF_OP_IRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '-': - next = lgetc(0); - if (next == '>') - return (ARROW); - lungetc(next); - break; - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && isdigit(c)); - lungetc(c); - if (p == buf + 1 && buf[0] == '-') - goto nodigits; - if (c == EOF || allowed_to_end_number(c)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - return (findeol()); - } - return (NUMBER); - } else { -nodigits: - while (p > buf + 1) - lungetc(*--p); - c = *--p; - if (c == '-') - return (c); - } - } - -#define allowed_in_string(x) \ - (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && x != '<' && x != '>' && \ - x != '!' && x != '=' && x != '/' && x != '#' && \ - x != ',')) - - if (isalnum(c) || c == ':' || c == '_') { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); - lungetc(c); - *p = '\0'; - if ((token = lookup(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - err(1, "yylex: strdup"); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -int -check_file_secrecy(int fd, const char *fname) -{ - struct stat st; - - if (fstat(fd, &st)) { - warn("cannot stat %s", fname); - return (-1); - } - if (st.st_uid != 0 && st.st_uid != getuid()) { - warnx("%s: owner not root or current user", fname); - return (-1); - } - if (st.st_mode & (S_IRWXG | S_IRWXO)) { - warnx("%s: group/world readable/writeable", fname); - return (-1); - } - return (0); -} - -struct file * -pushfile(const char *name, int secret) -{ - struct file *nfile; - - if ((nfile = calloc(1, sizeof(struct file))) == NULL || - (nfile->name = strdup(name)) == NULL) { - warn("malloc"); - return (NULL); - } - if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { - nfile->stream = stdin; - free(nfile->name); - if ((nfile->name = strdup("stdin")) == NULL) { - warn("strdup"); - free(nfile); - return (NULL); - } - } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - warn("%s", nfile->name); - free(nfile->name); - free(nfile); - return (NULL); - } else if (secret && - check_file_secrecy(fileno(nfile->stream), nfile->name)) { - fclose(nfile->stream); - free(nfile->name); - free(nfile); - return (NULL); - } - nfile->lineno = 1; - TAILQ_INSERT_TAIL(&files, nfile, entry); - return (nfile); -} - -int -popfile(void) -{ - struct file *prev; - - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { - prev->errors += file->errors; - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file); - file = prev; - return (0); - } - return (EOF); -} - -int -parse_config(char *filename, struct pfctl *xpf) -{ - int errors = 0; - struct sym *sym; - - pf = xpf; - errors = 0; - rulestate = PFCTL_STATE_NONE; - returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; - returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; - blockpolicy = PFRULE_DROP; - require_order = 1; - - if ((file = pushfile(filename, 0)) == NULL) { - warn("cannot open the main config file!"); - return (-1); - } - - yyparse(); - errors = file->errors; - popfile(); - - /* Free macros and check which have not been used. */ - while ((sym = TAILQ_FIRST(&symhead))) { - if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) - fprintf(stderr, "warning: macro '%s' not " - "used\n", sym->nam); - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - - return (errors ? -1 : 0); -} - -int -symset(const char *nam, const char *val, int persist) -{ - struct sym *sym; - - for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); - sym = TAILQ_NEXT(sym, entry)) - ; /* nothing */ - - if (sym != NULL) { - if (sym->persist == 1) - return (0); - else { - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - } - if ((sym = calloc(1, sizeof(*sym))) == NULL) - return (-1); - - sym->nam = strdup(nam); - if (sym->nam == NULL) { - free(sym); - return (-1); - } - sym->val = strdup(val); - if (sym->val == NULL) { - free(sym->nam); - free(sym); - return (-1); - } - sym->used = 0; - sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entry); - return (0); -} - -int -pfctl_cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - - if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) - err(1, "pfctl_cmdline_symset: malloc"); - - strlcpy(sym, s, strlen(s) - strlen(val) + 1); - - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - -char * -symget(const char *nam) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) - if (strcmp(nam, sym->nam) == 0) { - sym->used = 1; - return (sym->val); - } - return (NULL); -} - -void -mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) -{ - int i; - struct pf_rule *r; - - for (i = 0; i < PF_RULESET_MAX; ++i) { - while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); - dst->anchor->match++; - } - src->anchor->match = 0; - while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, - r, entries); - } - } -} - -void -decide_address_family(struct node_host *n, sa_family_t *af) -{ - if (*af != 0 || n == NULL) - return; - *af = n->af; - while ((n = n->next) != NULL) { - if (n->af != *af) { - *af = 0; - return; - } - } -} - -void -remove_invalid_hosts(struct node_host **nh, sa_family_t *af) -{ - struct node_host *n = *nh, *prev = NULL; - - while (n != NULL) { - if (*af && n->af && n->af != *af) { - /* unlink and free n */ - struct node_host *next = n->next; - - /* adjust tail pointer */ - if (n == (*nh)->tail) - (*nh)->tail = prev; - /* adjust previous node's next pointer */ - if (prev == NULL) - *nh = next; - else - prev->next = next; - /* free node */ - if (n->ifname != NULL) - free(n->ifname); - free(n); - n = next; - } else { - if (n->af && !*af) - *af = n->af; - prev = n; - n = n->next; - } - } -} - -int -invalid_redirect(struct node_host *nh, sa_family_t af) -{ - if (!af) { - struct node_host *n; - - /* tables and dyniftl are ok without an address family */ - for (n = nh; n != NULL; n = n->next) { - if (n->addr.type != PF_ADDR_TABLE && - n->addr.type != PF_ADDR_DYNIFTL) { - yyerror("address family not given and " - "translation address expands to multiple " - "address families"); - return (1); - } - } - } - if (nh == NULL) { - yyerror("no translation address with matching address family " - "found."); - return (1); - } - return (0); -} - -int -atoul(char *s, u_long *ulvalp) -{ - u_long ulval; - char *ep; - - errno = 0; - ulval = strtoul(s, &ep, 0); - if (s[0] == '\0' || *ep != '\0') - return (-1); - if (errno == ERANGE && ulval == ULONG_MAX) - return (-1); - *ulvalp = ulval; - return (0); -} - -int -getservice(char *n) -{ - struct servent *s; - u_long ulval; - - if (atoul(n, &ulval) == 0) { - if (ulval > 65535) { - yyerror("illegal port value %lu", ulval); - return (-1); - } - return (htons(ulval)); - } else { - s = getservbyname(n, "tcp"); - if (s == NULL) - s = getservbyname(n, "udp"); - if (s == NULL) { - yyerror("unknown port %s", n); - return (-1); - } - return (s->s_port); - } -} - -int -rule_label(struct pf_rule *r, char *s) -{ - if (s) { - if (strlcpy(r->label, s, sizeof(r->label)) >= - sizeof(r->label)) { - yyerror("rule label too long (max %d chars)", - sizeof(r->label)-1); - return (-1); - } - } - return (0); -} - -u_int16_t -parseicmpspec(char *w, sa_family_t af) -{ - const struct icmpcodeent *p; - u_long ulval; - u_int8_t icmptype; - - if (af == AF_INET) - icmptype = returnicmpdefault >> 8; - else - icmptype = returnicmp6default >> 8; - - if (atoul(w, &ulval) == -1) { - if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { - yyerror("unknown icmp code %s", w); - return (0); - } - ulval = p->code; - } - if (ulval > 255) { - yyerror("invalid icmp code %lu", ulval); - return (0); - } - return (icmptype << 8 | ulval); -} - -int -parseport(char *port, struct range *r, int extensions) -{ - char *p = strchr(port, ':'); - - if (p == NULL) { - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_NONE; - return (0); - } - if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { - *p = 0; - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_IRG; - return (0); - } - if ((extensions & PPORT_RANGE)) { - *p++ = 0; - if ((r->a = getservice(port)) == -1 || - (r->b = getservice(p)) == -1) - return (-1); - if (r->a == r->b) { - r->b = 0; - r->t = PF_OP_NONE; - } else - r->t = PF_OP_RRG; - return (0); - } - return (-1); -} - -int -pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) -{ - struct loadanchors *la; - - TAILQ_FOREACH(la, &loadanchorshead, entries) { - if (pf->opts & PF_OPT_VERBOSE) - fprintf(stderr, "\nLoading anchor %s from %s\n", - la->anchorname, la->filename); - if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, - la->anchorname, trans) == -1) - return (-1); - } - - return (0); -} - -int -rt_tableid_max(void) -{ -#ifdef __FreeBSD__ - int fibs; - size_t l = sizeof(fibs); - - if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) - fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ - /* - * As the OpenBSD code only compares > and not >= we need to adjust - * here given we only accept values of 0..n and want to avoid #ifdefs - * in the grammer. - */ - return (fibs - 1); -#else - return (RT_TABLEID_MAX); -#endif -} -#ifdef __rtems__ -#include "parse-data.h" -#endif /* __rtems__ */ -#line 4226 "pfctly.tab.c" - -#if YYDEBUG -#include <stdio.h> /* needed for printf */ -#endif - -#include <stdlib.h> /* needed for malloc, etc */ -#include <string.h> /* needed for memset */ - -/* allocate initial stack or double stack size, up to YYMAXDEPTH */ -static int yygrowstack(YYSTACKDATA *data) -{ - int i; - unsigned newsize; - YYINT *newss; - YYSTYPE *newvs; - - if ((newsize = data->stacksize) == 0) - newsize = YYINITSTACKSIZE; - else if (newsize >= YYMAXDEPTH) - return YYENOMEM; - else if ((newsize *= 2) > YYMAXDEPTH) - newsize = YYMAXDEPTH; - - i = (int) (data->s_mark - data->s_base); - newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss)); - if (newss == 0) - return YYENOMEM; - - data->s_base = newss; - data->s_mark = newss + i; - - newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs)); - if (newvs == 0) - return YYENOMEM; - - data->l_base = newvs; - data->l_mark = newvs + i; - - data->stacksize = newsize; - data->s_last = data->s_base + newsize - 1; - return 0; -} - -#if YYPURE || defined(YY_NO_LEAKS) -static void yyfreestack(YYSTACKDATA *data) -{ - free(data->s_base); - free(data->l_base); - memset(data, 0, sizeof(*data)); -} -#else -#define yyfreestack(data) /* nothing */ -#endif - -#define YYABORT goto yyabort -#define YYREJECT goto yyabort -#define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab - -int -YYPARSE_DECL() -{ - int yym, yyn, yystate; -#if YYDEBUG - const char *yys; - - if ((yys = getenv("YYDEBUG")) != 0) - { - yyn = *yys; - if (yyn >= '0' && yyn <= '9') - yydebug = yyn - '0'; - } -#endif - - yynerrs = 0; - yyerrflag = 0; - yychar = YYEMPTY; - yystate = 0; - -#if YYPURE - memset(&yystack, 0, sizeof(yystack)); -#endif - - if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow; - yystack.s_mark = yystack.s_base; - yystack.l_mark = yystack.l_base; - yystate = 0; - *yystack.s_mark = 0; - -yyloop: - if ((yyn = yydefred[yystate]) != 0) goto yyreduce; - if (yychar < 0) - { - if ((yychar = YYLEX) < 0) yychar = YYEOF; -#if YYDEBUG - if (yydebug) - { - yys = yyname[YYTRANSLATE(yychar)]; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - } - if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, yystate, yytable[yyn]); -#endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) - { - goto yyoverflow; - } - yystate = yytable[yyn]; - *++yystack.s_mark = yytable[yyn]; - *++yystack.l_mark = yylval; - yychar = YYEMPTY; - if (yyerrflag > 0) --yyerrflag; - goto yyloop; - } - if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { - yyn = yytable[yyn]; - goto yyreduce; - } - if (yyerrflag) goto yyinrecovery; - - YYERROR_CALL("syntax error"); - - goto yyerrlab; - -yyerrlab: - ++yynerrs; - -yyinrecovery: - if (yyerrflag < 3) - { - yyerrflag = 3; - for (;;) - { - if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]); -#endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) - { - goto yyoverflow; - } - yystate = yytable[yyn]; - *++yystack.s_mark = yytable[yyn]; - *++yystack.l_mark = yylval; - goto yyloop; - } - else - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yystack.s_mark); -#endif - if (yystack.s_mark <= yystack.s_base) goto yyabort; - --yystack.s_mark; - --yystack.l_mark; - } - } - } - else - { - if (yychar == YYEOF) goto yyabort; -#if YYDEBUG - if (yydebug) - { - yys = yyname[YYTRANSLATE(yychar)]; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - yychar = YYEMPTY; - goto yyloop; - } - -yyreduce: -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, yystate, yyn, yyrule[yyn]); -#endif - yym = yylen[yyn]; - if (yym) - yyval = yystack.l_mark[1-yym]; - else - memset(&yyval, 0, sizeof yyval); - switch (yyn) - { -case 17: -#line 578 "../../freebsd/contrib/pf/pfctl/parse.y" - { file->errors++; } -break; -case 18: -#line 581 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct file *nfile; - - if ((nfile = pushfile(yystack.l_mark[0].v.string, 0)) == NULL) { - yyerror("failed to include file %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - - file = nfile; - lungetc('\n'); - } -break; -case 25: -#line 608 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "none")) - yyval.v.i = 0; - else if (!strcmp(yystack.l_mark[0].v.string, "basic")) - yyval.v.i = PF_OPTIMIZE_BASIC; - else if (!strcmp(yystack.l_mark[0].v.string, "profile")) - yyval.v.i = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; - else { - yyerror("unknown ruleset-optimization %s", yystack.l_mark[0].v.string); - YYERROR; - } - } -break; -case 26: -#line 622 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - if (pfctl_set_optimization(pf, yystack.l_mark[0].v.string) != 0) { - yyerror("unknown optimization %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 27: -#line 634 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!(pf->opts & PF_OPT_OPTIMIZE)) { - pf->opts |= PF_OPT_OPTIMIZE; - pf->optimize = yystack.l_mark[0].v.i; - } - } -break; -case 32: -#line 644 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - if (pfctl_set_logif(pf, yystack.l_mark[0].v.string) != 0) { - yyerror("error setting loginterface %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 33: -#line 656 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number == 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("hostid must be non-zero"); - YYERROR; - } - if (pfctl_set_hostid(pf, yystack.l_mark[0].v.number) != 0) { - yyerror("error setting hostid %08x", yystack.l_mark[0].v.number); - YYERROR; - } - } -break; -case 34: -#line 666 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy drop\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_DROP; - } -break; -case 35: -#line 673 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy return\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_RETURN; - } -break; -case 36: -#line 680 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - printf("set require-order %s\n", - yystack.l_mark[0].v.number == 1 ? "yes" : "no"); - require_order = yystack.l_mark[0].v.number; - } -break; -case 37: -#line 686 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - printf("set fingerprints \"%s\"\n", yystack.l_mark[0].v.string); - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - if (!pf->anchor->name[0]) { - if (pfctl_file_fingerprints(pf->dev, - pf->opts, yystack.l_mark[0].v.string)) { - yyerror("error loading " - "fingerprints %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - } - free(yystack.l_mark[0].v.string); - } -break; -case 38: -#line 704 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - switch (yystack.l_mark[0].v.i) { - case 0: - printf("set state-policy floating\n"); - break; - case PFRULE_IFBOUND: - printf("set state-policy if-bound\n"); - break; - } - default_statelock = yystack.l_mark[0].v.i; - } -break; -case 39: -#line 716 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - if (pfctl_set_debug(pf, yystack.l_mark[0].v.string) != 0) { - yyerror("error setting debuglevel %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 40: -#line 728 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (expand_skip_interface(yystack.l_mark[0].v.interface) != 0) { - yyerror("error setting skip interface(s)"); - YYERROR; - } - } -break; -case 41: -#line 734 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (keep_state_defaults != NULL) { - yyerror("cannot redefine state-defaults"); - YYERROR; - } - keep_state_defaults = yystack.l_mark[0].v.state_opt; - } -break; -case 42: -#line 743 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.string = yystack.l_mark[0].v.string; } -break; -case 43: -#line 744 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if ((yyval.v.string = strdup("all")) == NULL) { - err(1, "stringall: strdup"); - } - } -break; -case 44: -#line 751 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1) - err(1, "string: asprintf"); - free(yystack.l_mark[-1].v.string); - free(yystack.l_mark[0].v.string); - } -break; -case 46: -#line 760 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1) - err(1, "string: asprintf"); - free(yystack.l_mark[-1].v.string); - free(yystack.l_mark[0].v.string); - } -break; -case 48: -#line 769 "../../freebsd/contrib/pf/pfctl/parse.y" - { - char *s; - if (asprintf(&s, "%lld", (long long)yystack.l_mark[0].v.number) == -1) { - yyerror("string: asprintf"); - YYERROR; - } - yyval.v.string = s; - } -break; -case 50: -#line 780 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pf->opts & PF_OPT_VERBOSE) - printf("%s = \"%s\"\n", yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string); - if (symset(yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string, 0) == -1) - err(1, "cannot store variable %s", yystack.l_mark[-2].v.string); - free(yystack.l_mark[-2].v.string); - free(yystack.l_mark[0].v.string); - } -break; -case 51: -#line 790 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.string = yystack.l_mark[0].v.string; } -break; -case 52: -#line 791 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.string = NULL; } -break; -case 57: -#line 801 "../../freebsd/contrib/pf/pfctl/parse.y" - { - char ta[PF_ANCHOR_NAME_SIZE]; - struct pf_ruleset *rs; - - /* steping into a brace anchor */ - pf->asd++; - pf->bn++; - pf->brace = 1; - - /* create a holding ruleset in the root */ - snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); - rs = pf_find_or_create_ruleset(ta); - if (rs == NULL) - err(1, "pfa_anchor: pf_find_or_create_ruleset"); - pf->astack[pf->asd] = rs->anchor; - pf->anchor = rs->anchor; - } -break; -case 58: -#line 818 "../../freebsd/contrib/pf/pfctl/parse.y" - { - pf->alast = pf->anchor; - pf->asd--; - pf->anchor = pf->astack[pf->asd]; - } -break; -case 60: -#line 828 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - struct node_proto *proto; - - if (check_rulestate(PFCTL_STATE_FILTER)) { - if (yystack.l_mark[-8].v.string) - free(yystack.l_mark[-8].v.string); - YYERROR; - } - - if (yystack.l_mark[-8].v.string && (yystack.l_mark[-8].v.string[0] == '_' || strstr(yystack.l_mark[-8].v.string, "/_") != NULL)) { - free(yystack.l_mark[-8].v.string); - yyerror("anchor names beginning with '_' " - "are reserved for internal use"); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - if (pf->astack[pf->asd + 1]) { - /* move inline rules into relative location */ - pf_anchor_setup(&r, - &pf->astack[pf->asd]->ruleset, - yystack.l_mark[-8].v.string ? yystack.l_mark[-8].v.string : pf->alast->name); - - if (r.anchor == NULL) - err(1, "anchorrule: unable to " - "create ruleset"); - - if (pf->alast != r.anchor) { - if (r.anchor->match) { - yyerror("inline anchor '%s' " - "already exists", - r.anchor->name); - YYERROR; - } - mv_rules(&pf->alast->ruleset, - &r.anchor->ruleset); - } - pf_remove_if_empty_ruleset(&pf->alast->ruleset); - pf->alast = r.anchor; - } else { - if (!yystack.l_mark[-8].v.string) { - yyerror("anchors without explicit " - "rules must specify a name"); - YYERROR; - } - } - r.direction = yystack.l_mark[-7].v.i; - r.quick = yystack.l_mark[-6].v.logquick.quick; - r.af = yystack.l_mark[-4].v.i; - r.prob = yystack.l_mark[-1].v.filter_opts.prob; - r.rtableid = yystack.l_mark[-1].v.filter_opts.rtableid; - - if (yystack.l_mark[-1].v.filter_opts.tag) - if (strlcpy(r.tagname, yystack.l_mark[-1].v.filter_opts.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if (yystack.l_mark[-1].v.filter_opts.match_tag) - if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not; - if (rule_label(&r, yystack.l_mark[-1].v.filter_opts.label)) - YYERROR; - free(yystack.l_mark[-1].v.filter_opts.label); - r.flags = yystack.l_mark[-1].v.filter_opts.flags.b1; - r.flagset = yystack.l_mark[-1].v.filter_opts.flags.b2; - if ((yystack.l_mark[-1].v.filter_opts.flags.b1 & yystack.l_mark[-1].v.filter_opts.flags.b2) != yystack.l_mark[-1].v.filter_opts.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2 || yystack.l_mark[-2].v.fromto.src_os) { - for (proto = yystack.l_mark[-3].v.proto; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && yystack.l_mark[-3].v.proto != NULL) { - if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2) - yyerror( - "flags only apply to tcp"); - if (yystack.l_mark[-2].v.fromto.src_os) - yyerror( - "OS fingerprinting only " - "applies to tcp"); - YYERROR; - } - } - - r.tos = yystack.l_mark[-1].v.filter_opts.tos; - - if (yystack.l_mark[-1].v.filter_opts.keep.action) { - yyerror("cannot specify state handling " - "on anchors"); - YYERROR; - } - - if (yystack.l_mark[-1].v.filter_opts.match_tag) - if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not; - - decide_address_family(yystack.l_mark[-2].v.fromto.src.host, &r.af); - decide_address_family(yystack.l_mark[-2].v.fromto.dst.host, &r.af); - - expand_rule(&r, yystack.l_mark[-5].v.interface, NULL, yystack.l_mark[-3].v.proto, yystack.l_mark[-2].v.fromto.src_os, - yystack.l_mark[-2].v.fromto.src.host, yystack.l_mark[-2].v.fromto.src.port, yystack.l_mark[-2].v.fromto.dst.host, yystack.l_mark[-2].v.fromto.dst.port, - yystack.l_mark[-1].v.filter_opts.uid, yystack.l_mark[-1].v.filter_opts.gid, yystack.l_mark[-1].v.filter_opts.icmpspec, - pf->astack[pf->asd + 1] ? pf->alast->name : yystack.l_mark[-8].v.string); - free(yystack.l_mark[-8].v.string); - pf->astack[pf->asd + 1] = NULL; - } -break; -case 61: -#line 949 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free(yystack.l_mark[-5].v.string); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_NAT; - r.af = yystack.l_mark[-3].v.i; - r.rtableid = yystack.l_mark[0].v.rtableid; - - decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); - decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); - - expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, - yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, - 0, 0, 0, yystack.l_mark[-5].v.string); - free(yystack.l_mark[-5].v.string); - } -break; -case 62: -#line 970 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free(yystack.l_mark[-5].v.string); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_RDR; - r.af = yystack.l_mark[-3].v.i; - r.rtableid = yystack.l_mark[0].v.rtableid; - - decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); - decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); - - if (yystack.l_mark[-1].v.fromto.src.port != NULL) { - yyerror("source port parameter not supported" - " in rdr-anchor"); - YYERROR; - } - if (yystack.l_mark[-1].v.fromto.dst.port != NULL) { - if (yystack.l_mark[-1].v.fromto.dst.port->next != NULL) { - yyerror("destination port list " - "expansion not supported in " - "rdr-anchor"); - YYERROR; - } else if (yystack.l_mark[-1].v.fromto.dst.port->op != PF_OP_EQ) { - yyerror("destination port operators" - " not supported in rdr-anchor"); - YYERROR; - } - r.dst.port[0] = yystack.l_mark[-1].v.fromto.dst.port->port[0]; - r.dst.port[1] = yystack.l_mark[-1].v.fromto.dst.port->port[1]; - r.dst.port_op = yystack.l_mark[-1].v.fromto.dst.port->op; - } - - expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, - yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, - 0, 0, 0, yystack.l_mark[-5].v.string); - free(yystack.l_mark[-5].v.string); - } -break; -case 63: -#line 1012 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free(yystack.l_mark[-5].v.string); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_BINAT; - r.af = yystack.l_mark[-3].v.i; - r.rtableid = yystack.l_mark[0].v.rtableid; - if (yystack.l_mark[-2].v.proto != NULL) { - if (yystack.l_mark[-2].v.proto->next != NULL) { - yyerror("proto list expansion" - " not supported in binat-anchor"); - YYERROR; - } - r.proto = yystack.l_mark[-2].v.proto->proto; - free(yystack.l_mark[-2].v.proto); - } - - if (yystack.l_mark[-1].v.fromto.src.host != NULL || yystack.l_mark[-1].v.fromto.src.port != NULL || - yystack.l_mark[-1].v.fromto.dst.host != NULL || yystack.l_mark[-1].v.fromto.dst.port != NULL) { - yyerror("fromto parameter not supported" - " in binat-anchor"); - YYERROR; - } - - decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); - decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); - - pfctl_add_rule(pf, &r, yystack.l_mark[-5].v.string); - free(yystack.l_mark[-5].v.string); - } -break; -case 64: -#line 1049 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct loadanchors *loadanchor; - - if (strlen(pf->anchor->name) + 1 + - strlen(yystack.l_mark[-2].v.string) >= MAXPATHLEN) { - yyerror("anchorname %s too long, max %u\n", - yystack.l_mark[-2].v.string, MAXPATHLEN - 1); - free(yystack.l_mark[-2].v.string); - YYERROR; - } - loadanchor = calloc(1, sizeof(struct loadanchors)); - if (loadanchor == NULL) - err(1, "loadrule: calloc"); - if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == - NULL) - err(1, "loadrule: malloc"); - if (pf->anchor->name[0]) - snprintf(loadanchor->anchorname, MAXPATHLEN, - "%s/%s", pf->anchor->name, yystack.l_mark[-2].v.string); - else - strlcpy(loadanchor->anchorname, yystack.l_mark[-2].v.string, MAXPATHLEN); - if ((loadanchor->filename = strdup(yystack.l_mark[0].v.string)) == NULL) - err(1, "loadrule: strdup"); - - TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, - entries); - - free(yystack.l_mark[-2].v.string); - free(yystack.l_mark[0].v.string); - } -break; -case 65: -#line 1080 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = yyval.v.b.w = 0; - if (yystack.l_mark[-1].v.i) - yyval.v.b.b1 = PF_NOSCRUB; - else - yyval.v.b.b1 = PF_SCRUB; - } -break; -case 66: -#line 1090 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_SCRUB)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = yystack.l_mark[-7].v.b.b1; - r.direction = yystack.l_mark[-6].v.i; - - r.log = yystack.l_mark[-5].v.logquick.log; - r.logif = yystack.l_mark[-5].v.logquick.logif; - if (yystack.l_mark[-5].v.logquick.quick) { - yyerror("scrub rules do not support 'quick'"); - YYERROR; - } - - r.af = yystack.l_mark[-3].v.i; - if (yystack.l_mark[0].v.scrub_opts.nodf) - r.rule_flag |= PFRULE_NODF; - if (yystack.l_mark[0].v.scrub_opts.randomid) - r.rule_flag |= PFRULE_RANDOMID; - if (yystack.l_mark[0].v.scrub_opts.reassemble_tcp) { - if (r.direction != PF_INOUT) { - yyerror("reassemble tcp rules can not " - "specify direction"); - YYERROR; - } - r.rule_flag |= PFRULE_REASSEMBLE_TCP; - } - if (yystack.l_mark[0].v.scrub_opts.minttl) - r.min_ttl = yystack.l_mark[0].v.scrub_opts.minttl; - if (yystack.l_mark[0].v.scrub_opts.maxmss) - r.max_mss = yystack.l_mark[0].v.scrub_opts.maxmss; - if (yystack.l_mark[0].v.scrub_opts.marker & SOM_SETTOS) { - r.rule_flag |= PFRULE_SET_TOS; - r.set_tos = yystack.l_mark[0].v.scrub_opts.settos; - } - if (yystack.l_mark[0].v.scrub_opts.fragcache) - r.rule_flag |= yystack.l_mark[0].v.scrub_opts.fragcache; - if (yystack.l_mark[0].v.scrub_opts.match_tag) - if (strlcpy(r.match_tagname, yystack.l_mark[0].v.scrub_opts.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = yystack.l_mark[0].v.scrub_opts.match_tag_not; - r.rtableid = yystack.l_mark[0].v.scrub_opts.rtableid; - - expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, - yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, - NULL, NULL, NULL, ""); - } -break; -case 67: -#line 1147 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - } -break; -case 68: -#line 1152 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.scrub_opts = scrub_opts; } -break; -case 69: -#line 1153 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - yyval.v.scrub_opts = scrub_opts; - } -break; -case 72: -#line 1164 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.nodf) { - yyerror("no-df cannot be respecified"); - YYERROR; - } - scrub_opts.nodf = 1; - } -break; -case 73: -#line 1171 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.marker & SOM_MINTTL) { - yyerror("min-ttl cannot be respecified"); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("illegal min-ttl value %d", yystack.l_mark[0].v.number); - YYERROR; - } - scrub_opts.marker |= SOM_MINTTL; - scrub_opts.minttl = yystack.l_mark[0].v.number; - } -break; -case 74: -#line 1183 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.marker & SOM_MAXMSS) { - yyerror("max-mss cannot be respecified"); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { - yyerror("illegal max-mss value %d", yystack.l_mark[0].v.number); - YYERROR; - } - scrub_opts.marker |= SOM_MAXMSS; - scrub_opts.maxmss = yystack.l_mark[0].v.number; - } -break; -case 75: -#line 1195 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.marker & SOM_SETTOS) { - yyerror("set-tos cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_SETTOS; - scrub_opts.settos = yystack.l_mark[0].v.number; - } -break; -case 76: -#line 1203 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.marker & SOM_FRAGCACHE) { - yyerror("fragcache cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_FRAGCACHE; - scrub_opts.fragcache = yystack.l_mark[0].v.i; - } -break; -case 77: -#line 1211 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (strcasecmp(yystack.l_mark[0].v.string, "tcp") != 0) { - yyerror("scrub reassemble supports only tcp, " - "not '%s'", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - if (scrub_opts.reassemble_tcp) { - yyerror("reassemble tcp cannot be respecified"); - YYERROR; - } - scrub_opts.reassemble_tcp = 1; - } -break; -case 78: -#line 1225 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (scrub_opts.randomid) { - yyerror("random-id cannot be respecified"); - YYERROR; - } - scrub_opts.randomid = 1; - } -break; -case 79: -#line 1232 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - scrub_opts.rtableid = yystack.l_mark[0].v.number; - } -break; -case 80: -#line 1239 "../../freebsd/contrib/pf/pfctl/parse.y" - { - scrub_opts.match_tag = yystack.l_mark[0].v.string; - scrub_opts.match_tag_not = yystack.l_mark[-2].v.number; - } -break; -case 81: -#line 1245 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = 0; /* default */ } -break; -case 82: -#line 1246 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PFRULE_FRAGCROP; } -break; -case 83: -#line 1247 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PFRULE_FRAGDROP; } -break; -case 84: -#line 1250 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - struct node_host *h = NULL, *hh; - struct node_if *i, *j; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - for (i = yystack.l_mark[-2].v.interface; i; i = i->next) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = yystack.l_mark[-3].v.logquick.log; - r.logif = yystack.l_mark[-3].v.logquick.logif; - r.quick = yystack.l_mark[-3].v.logquick.quick; - r.af = yystack.l_mark[-1].v.i; - if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label)) - YYERROR; - r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid; - j = calloc(1, sizeof(struct node_if)); - if (j == NULL) - err(1, "antispoof: calloc"); - if (strlcpy(j->ifname, i->ifname, - sizeof(j->ifname)) >= sizeof(j->ifname)) { - free(j); - yyerror("interface name too long"); - YYERROR; - } - j->not = 1; - if (i->dynamic) { - h = calloc(1, sizeof(*h)); - if (h == NULL) - err(1, "address: calloc"); - h->addr.type = PF_ADDR_DYNIFTL; - set_ipmask(h, 128); - if (strlcpy(h->addr.v.ifname, i->ifname, - sizeof(h->addr.v.ifname)) >= - sizeof(h->addr.v.ifname)) { - free(h); - yyerror( - "interface name too long"); - YYERROR; - } - hh = malloc(sizeof(*hh)); - if (hh == NULL) - err(1, "address: malloc"); - bcopy(h, hh, sizeof(*hh)); - h->addr.iflags = PFI_AFLAG_NETWORK; - } else { - h = ifa_lookup(j->ifname, - PFI_AFLAG_NETWORK); - hh = NULL; - } - - if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, h, - NULL, NULL, NULL, NULL, NULL, - NULL, ""); - - if ((i->ifa_flags & IFF_LOOPBACK) == 0) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = yystack.l_mark[-3].v.logquick.log; - r.logif = yystack.l_mark[-3].v.logquick.logif; - r.quick = yystack.l_mark[-3].v.logquick.quick; - r.af = yystack.l_mark[-1].v.i; - if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label)) - YYERROR; - r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid; - if (hh != NULL) - h = hh; - else - h = ifa_lookup(i->ifname, 0); - if (h != NULL) - expand_rule(&r, NULL, NULL, - NULL, NULL, h, NULL, NULL, - NULL, NULL, NULL, NULL, ""); - } else - free(hh); - } - free(yystack.l_mark[0].v.antispoof_opts.label); - } -break; -case 85: -#line 1337 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[0].v.interface; } -break; -case 86: -#line 1338 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[-1].v.interface; } -break; -case 87: -#line 1341 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[-1].v.interface; } -break; -case 88: -#line 1342 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface; - yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface; - yyval.v.interface = yystack.l_mark[-3].v.interface; - } -break; -case 89: -#line 1349 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[0].v.interface; } -break; -case 90: -#line 1350 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-1].v.interface->dynamic = 1; - yyval.v.interface = yystack.l_mark[-1].v.interface; - } -break; -case 91: -#line 1356 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - } -break; -case 92: -#line 1361 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.antispoof_opts = antispoof_opts; } -break; -case 93: -#line 1362 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - yyval.v.antispoof_opts = antispoof_opts; - } -break; -case 96: -#line 1373 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (antispoof_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - antispoof_opts.label = yystack.l_mark[0].v.string; - } -break; -case 97: -#line 1380 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - antispoof_opts.rtableid = yystack.l_mark[0].v.number; - } -break; -case 98: -#line 1389 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number = 1; } -break; -case 99: -#line 1390 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number = 0; } -break; -case 100: -#line 1393 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *h, *nh; - struct node_tinit *ti, *nti; - - if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) { - yyerror("table name too long, max %d chars", - PF_TABLE_NAME_SIZE - 1); - free(yystack.l_mark[-2].v.string); - YYERROR; - } - if (pf->loadopt & PFCTL_FLAG_TABLE) - if (process_tabledef(yystack.l_mark[-2].v.string, &yystack.l_mark[0].v.table_opts)) { - free(yystack.l_mark[-2].v.string); - YYERROR; - } - free(yystack.l_mark[-2].v.string); - for (ti = SIMPLEQ_FIRST(&yystack.l_mark[0].v.table_opts.init_nodes); - ti != SIMPLEQ_END(&yystack.l_mark[0].v.table_opts.init_nodes); ti = nti) { - if (ti->file) - free(ti->file); - for (h = ti->host; h != NULL; h = nh) { - nh = h->next; - free(h); - } - nti = SIMPLEQ_NEXT(ti, entries); - free(ti); - } - } -break; -case 101: -#line 1423 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - } -break; -case 102: -#line 1428 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.table_opts = table_opts; } -break; -case 103: -#line 1430 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - yyval.v.table_opts = table_opts; - } -break; -case 106: -#line 1441 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "const")) - table_opts.flags |= PFR_TFLAG_CONST; - else if (!strcmp(yystack.l_mark[0].v.string, "persist")) - table_opts.flags |= PFR_TFLAG_PERSIST; - else if (!strcmp(yystack.l_mark[0].v.string, "counters")) - table_opts.flags |= PFR_TFLAG_COUNTERS; - else { - yyerror("invalid table option '%s'", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 107: -#line 1455 "../../freebsd/contrib/pf/pfctl/parse.y" - { table_opts.init_addr = 1; } -break; -case 108: -#line 1456 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *n; - struct node_tinit *ti; - - for (n = yystack.l_mark[-1].v.host; n != NULL; n = n->next) { - switch (n->addr.type) { - case PF_ADDR_ADDRMASK: - continue; /* ok */ - case PF_ADDR_RANGE: - yyerror("address ranges are not " - "permitted inside tables"); - break; - case PF_ADDR_DYNIFTL: - yyerror("dynamic addresses are not " - "permitted inside tables"); - break; - case PF_ADDR_TABLE: - yyerror("tables cannot contain tables"); - break; - case PF_ADDR_NOROUTE: - yyerror("\"no-route\" is not permitted " - "inside tables"); - break; - case PF_ADDR_URPFFAILED: - yyerror("\"urpf-failed\" is not " - "permitted inside tables"); - break; - default: - yyerror("unknown address type %d", - n->addr.type); - } - YYERROR; - } - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->host = yystack.l_mark[-1].v.host; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } -break; -case 109: -#line 1496 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_tinit *ti; - - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->file = yystack.l_mark[0].v.string; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } -break; -case 110: -#line 1508 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) - YYERROR; - - memset(&a, 0, sizeof(a)); - if (yystack.l_mark[-2].v.queue_opts.scheduler.qtype == ALTQT_NONE) { - yyerror("no scheduler specified!"); - YYERROR; - } - a.scheduler = yystack.l_mark[-2].v.queue_opts.scheduler.qtype; - a.qlimit = yystack.l_mark[-2].v.queue_opts.qlimit; - a.tbrsize = yystack.l_mark[-2].v.queue_opts.tbrsize; - if (yystack.l_mark[0].v.queue == NULL) { - yyerror("no child queues specified"); - YYERROR; - } - if (expand_altq(&a, yystack.l_mark[-3].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-2].v.queue_opts.queue_bwspec, - &yystack.l_mark[-2].v.queue_opts.scheduler)) - YYERROR; - } -break; -case 111: -#line 1532 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) { - free(yystack.l_mark[-3].v.string); - YYERROR; - } - - memset(&a, 0, sizeof(a)); - - if (strlcpy(a.qname, yystack.l_mark[-3].v.string, sizeof(a.qname)) >= - sizeof(a.qname)) { - yyerror("queue name too long (max " - "%d chars)", PF_QNAME_SIZE-1); - free(yystack.l_mark[-3].v.string); - YYERROR; - } - free(yystack.l_mark[-3].v.string); - if (yystack.l_mark[-1].v.queue_opts.tbrsize) { - yyerror("cannot specify tbrsize for queue"); - YYERROR; - } - if (yystack.l_mark[-1].v.queue_opts.priority > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - a.priority = yystack.l_mark[-1].v.queue_opts.priority; - a.qlimit = yystack.l_mark[-1].v.queue_opts.qlimit; - a.scheduler = yystack.l_mark[-1].v.queue_opts.scheduler.qtype; - if (expand_queue(&a, yystack.l_mark[-2].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-1].v.queue_opts.queue_bwspec, - &yystack.l_mark[-1].v.queue_opts.scheduler)) { - yyerror("errors in queue definition"); - YYERROR; - } - } -break; -case 112: -#line 1569 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - } -break; -case 113: -#line 1577 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.queue_opts = queue_opts; } -break; -case 114: -#line 1578 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - yyval.v.queue_opts = queue_opts; - } -break; -case 117: -#line 1592 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (queue_opts.marker & QOM_BWSPEC) { - yyerror("bandwidth cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_BWSPEC; - queue_opts.queue_bwspec = yystack.l_mark[0].v.queue_bwspec; - } -break; -case 118: -#line 1600 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (queue_opts.marker & QOM_PRIORITY) { - yyerror("priority cannot be respecified"); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - queue_opts.marker |= QOM_PRIORITY; - queue_opts.priority = yystack.l_mark[0].v.number; - } -break; -case 119: -#line 1612 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (queue_opts.marker & QOM_QLIMIT) { - yyerror("qlimit cannot be respecified"); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { - yyerror("qlimit out of range: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_QLIMIT; - queue_opts.qlimit = yystack.l_mark[0].v.number; - } -break; -case 120: -#line 1624 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (queue_opts.marker & QOM_SCHEDULER) { - yyerror("scheduler cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_SCHEDULER; - queue_opts.scheduler = yystack.l_mark[0].v.queue_options; - } -break; -case 121: -#line 1632 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (queue_opts.marker & QOM_TBRSIZE) { - yyerror("tbrsize cannot be respecified"); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { - yyerror("tbrsize too big: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_TBRSIZE; - queue_opts.tbrsize = yystack.l_mark[0].v.number; - } -break; -case 122: -#line 1646 "../../freebsd/contrib/pf/pfctl/parse.y" - { - double bps; - char *cp; - - yyval.v.queue_bwspec.bw_percent = 0; - - bps = strtod(yystack.l_mark[0].v.string, &cp); - if (cp != NULL) { - if (!strcmp(cp, "b")) - ; /* nothing */ - else if (!strcmp(cp, "Kb")) - bps *= 1000; - else if (!strcmp(cp, "Mb")) - bps *= 1000 * 1000; - else if (!strcmp(cp, "Gb")) - bps *= 1000 * 1000 * 1000; - else if (!strcmp(cp, "%")) { - if (bps < 0 || bps > 100) { - yyerror("bandwidth spec " - "out of range"); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.queue_bwspec.bw_percent = bps; - bps = 0; - } else { - yyerror("unknown unit %s", cp); - free(yystack.l_mark[0].v.string); - YYERROR; - } - } - free(yystack.l_mark[0].v.string); - yyval.v.queue_bwspec.bw_absolute = (u_int32_t)bps; - } -break; -case 123: -#line 1680 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("bandwidth number too big"); - YYERROR; - } - yyval.v.queue_bwspec.bw_percent = 0; - yyval.v.queue_bwspec.bw_absolute = yystack.l_mark[0].v.number; - } -break; -case 124: -#line 1690 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_CBQ; - yyval.v.queue_options.data.cbq_opts.flags = 0; - } -break; -case 125: -#line 1694 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_CBQ; - yyval.v.queue_options.data.cbq_opts.flags = yystack.l_mark[-1].v.number; - } -break; -case 126: -#line 1698 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_PRIQ; - yyval.v.queue_options.data.priq_opts.flags = 0; - } -break; -case 127: -#line 1702 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_PRIQ; - yyval.v.queue_options.data.priq_opts.flags = yystack.l_mark[-1].v.number; - } -break; -case 128: -#line 1706 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_HFSC; - bzero(&yyval.v.queue_options.data.hfsc_opts, - sizeof(struct node_hfsc_opts)); - } -break; -case 129: -#line 1711 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue_options.qtype = ALTQT_HFSC; - yyval.v.queue_options.data.hfsc_opts = yystack.l_mark[-1].v.hfsc_opts; - } -break; -case 130: -#line 1717 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number |= yystack.l_mark[0].v.number; } -break; -case 131: -#line 1718 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number |= yystack.l_mark[0].v.number; } -break; -case 132: -#line 1721 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "default")) - yyval.v.number = CBQCLF_DEFCLASS; - else if (!strcmp(yystack.l_mark[0].v.string, "borrow")) - yyval.v.number = CBQCLF_BORROW; - else if (!strcmp(yystack.l_mark[0].v.string, "red")) - yyval.v.number = CBQCLF_RED; - else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) - yyval.v.number = CBQCLF_RED|CBQCLF_ECN; - else if (!strcmp(yystack.l_mark[0].v.string, "rio")) - yyval.v.number = CBQCLF_RIO; - else { - yyerror("unknown cbq flag \"%s\"", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 133: -#line 1741 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number |= yystack.l_mark[0].v.number; } -break; -case 134: -#line 1742 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number |= yystack.l_mark[0].v.number; } -break; -case 135: -#line 1745 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "default")) - yyval.v.number = PRCF_DEFAULTCLASS; - else if (!strcmp(yystack.l_mark[0].v.string, "red")) - yyval.v.number = PRCF_RED; - else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) - yyval.v.number = PRCF_RED|PRCF_ECN; - else if (!strcmp(yystack.l_mark[0].v.string, "rio")) - yyval.v.number = PRCF_RIO; - else { - yyerror("unknown priq flag \"%s\"", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 136: -#line 1763 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&hfsc_opts, - sizeof(struct node_hfsc_opts)); - } -break; -case 137: -#line 1767 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.hfsc_opts = hfsc_opts; - } -break; -case 140: -#line 1776 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec; - hfsc_opts.linkshare.used = 1; - } -break; -case 141: -#line 1785 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m1 = yystack.l_mark[-5].v.queue_bwspec; - hfsc_opts.linkshare.d = yystack.l_mark[-3].v.number; - hfsc_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec; - hfsc_opts.linkshare.used = 1; - } -break; -case 142: -#line 1799 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m2 = yystack.l_mark[0].v.queue_bwspec; - hfsc_opts.realtime.used = 1; - } -break; -case 143: -#line 1808 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m1 = yystack.l_mark[-5].v.queue_bwspec; - hfsc_opts.realtime.d = yystack.l_mark[-3].v.number; - hfsc_opts.realtime.m2 = yystack.l_mark[-1].v.queue_bwspec; - hfsc_opts.realtime.used = 1; - } -break; -case 144: -#line 1822 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m2 = yystack.l_mark[0].v.queue_bwspec; - hfsc_opts.upperlimit.used = 1; - } -break; -case 145: -#line 1831 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m1 = yystack.l_mark[-5].v.queue_bwspec; - hfsc_opts.upperlimit.d = yystack.l_mark[-3].v.number; - hfsc_opts.upperlimit.m2 = yystack.l_mark[-1].v.queue_bwspec; - hfsc_opts.upperlimit.used = 1; - } -break; -case 146: -#line 1845 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "default")) - hfsc_opts.flags |= HFCF_DEFAULTCLASS; - else if (!strcmp(yystack.l_mark[0].v.string, "red")) - hfsc_opts.flags |= HFCF_RED; - else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) - hfsc_opts.flags |= HFCF_RED|HFCF_ECN; - else if (!strcmp(yystack.l_mark[0].v.string, "rio")) - hfsc_opts.flags |= HFCF_RIO; - else { - yyerror("unknown hfsc flag \"%s\"", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 147: -#line 1863 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.queue = NULL; } -break; -case 148: -#line 1864 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.queue = yystack.l_mark[0].v.queue; } -break; -case 149: -#line 1865 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.queue = yystack.l_mark[-1].v.queue; } -break; -case 150: -#line 1868 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.queue = yystack.l_mark[-1].v.queue; } -break; -case 151: -#line 1869 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.queue->tail->next = yystack.l_mark[-1].v.queue; - yystack.l_mark[-3].v.queue->tail = yystack.l_mark[-1].v.queue; - yyval.v.queue = yystack.l_mark[-3].v.queue; - } -break; -case 152: -#line 1876 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.queue = calloc(1, sizeof(struct node_queue)); - if (yyval.v.queue == NULL) - err(1, "qassign_item: calloc"); - if (strlcpy(yyval.v.queue->queue, yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)) >= - sizeof(yyval.v.queue->queue)) { - yyerror("queue name '%s' too long (max " - "%d chars)", yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)-1); - free(yystack.l_mark[0].v.string); - free(yyval.v.queue); - YYERROR; - } - free(yystack.l_mark[0].v.string); - yyval.v.queue->next = NULL; - yyval.v.queue->tail = yyval.v.queue; - } -break; -case 153: -#line 1896 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - struct node_state_opt *o; - struct node_proto *proto; - int srctrack = 0; - int statelock = 0; - int adaptive = 0; - int defaults = 0; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = yystack.l_mark[-8].v.b.b1; - switch (yystack.l_mark[-8].v.b.b2) { - case PFRULE_RETURNRST: - r.rule_flag |= PFRULE_RETURNRST; - r.return_ttl = yystack.l_mark[-8].v.b.w; - break; - case PFRULE_RETURNICMP: - r.rule_flag |= PFRULE_RETURNICMP; - r.return_icmp = yystack.l_mark[-8].v.b.w; - r.return_icmp6 = yystack.l_mark[-8].v.b.w2; - break; - case PFRULE_RETURN: - r.rule_flag |= PFRULE_RETURN; - r.return_icmp = yystack.l_mark[-8].v.b.w; - r.return_icmp6 = yystack.l_mark[-8].v.b.w2; - break; - } - r.direction = yystack.l_mark[-7].v.i; - r.log = yystack.l_mark[-6].v.logquick.log; - r.logif = yystack.l_mark[-6].v.logquick.logif; - r.quick = yystack.l_mark[-6].v.logquick.quick; - r.prob = yystack.l_mark[0].v.filter_opts.prob; - r.rtableid = yystack.l_mark[0].v.filter_opts.rtableid; - - r.af = yystack.l_mark[-3].v.i; - if (yystack.l_mark[0].v.filter_opts.tag) - if (strlcpy(r.tagname, yystack.l_mark[0].v.filter_opts.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if (yystack.l_mark[0].v.filter_opts.match_tag) - if (strlcpy(r.match_tagname, yystack.l_mark[0].v.filter_opts.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = yystack.l_mark[0].v.filter_opts.match_tag_not; - if (rule_label(&r, yystack.l_mark[0].v.filter_opts.label)) - YYERROR; - free(yystack.l_mark[0].v.filter_opts.label); - r.flags = yystack.l_mark[0].v.filter_opts.flags.b1; - r.flagset = yystack.l_mark[0].v.filter_opts.flags.b2; - if ((yystack.l_mark[0].v.filter_opts.flags.b1 & yystack.l_mark[0].v.filter_opts.flags.b2) != yystack.l_mark[0].v.filter_opts.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2 || yystack.l_mark[-1].v.fromto.src_os) { - for (proto = yystack.l_mark[-2].v.proto; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && yystack.l_mark[-2].v.proto != NULL) { - if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2) - yyerror( - "flags only apply to tcp"); - if (yystack.l_mark[-1].v.fromto.src_os) - yyerror( - "OS fingerprinting only " - "apply to tcp"); - YYERROR; - } -#if 0 - if ((yystack.l_mark[0].v.filter_opts.flags.b1 & parse_flags("S")) == 0 && - yystack.l_mark[-1].v.fromto.src_os) { - yyerror("OS fingerprinting requires " - "the SYN TCP flag (flags S/SA)"); - YYERROR; - } -#endif - } - - r.tos = yystack.l_mark[0].v.filter_opts.tos; - r.keep_state = yystack.l_mark[0].v.filter_opts.keep.action; - o = yystack.l_mark[0].v.filter_opts.keep.options; - - /* 'keep state' by default on pass rules. */ - if (!r.keep_state && !r.action && - !(yystack.l_mark[0].v.filter_opts.marker & FOM_KEEP)) { - r.keep_state = PF_STATE_NORMAL; - o = keep_state_defaults; - defaults = 1; - } - - while (o) { - struct node_state_opt *p = o; - - switch (o->type) { - case PF_STATE_OPT_MAX: - if (r.max_states) { - yyerror("state option 'max' " - "multiple definitions"); - YYERROR; - } - r.max_states = o->data.max_states; - break; - case PF_STATE_OPT_NOSYNC: - if (r.rule_flag & PFRULE_NOSYNC) { - yyerror("state option 'sync' " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_NOSYNC; - break; - case PF_STATE_OPT_SRCTRACK: - if (srctrack) { - yyerror("state option " - "'source-track' " - "multiple definitions"); - YYERROR; - } - srctrack = o->data.src_track; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_STATES: - if (r.max_src_states) { - yyerror("state option " - "'max-src-states' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_states == 0) { - yyerror("'max-src-states' must " - "be > 0"); - YYERROR; - } - r.max_src_states = - o->data.max_src_states; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_OVERLOAD: - if (r.overload_tblname[0]) { - yyerror("multiple 'overload' " - "table definitions"); - YYERROR; - } - if (strlcpy(r.overload_tblname, - o->data.overload.tblname, - PF_TABLE_NAME_SIZE) >= - PF_TABLE_NAME_SIZE) { - yyerror("state option: " - "strlcpy"); - YYERROR; - } - r.flush = o->data.overload.flush; - break; - case PF_STATE_OPT_MAX_SRC_CONN: - if (r.max_src_conn) { - yyerror("state option " - "'max-src-conn' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_conn == 0) { - yyerror("'max-src-conn' " - "must be > 0"); - YYERROR; - } - r.max_src_conn = - o->data.max_src_conn; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_CONN_RATE: - if (r.max_src_conn_rate.limit) { - yyerror("state option " - "'max-src-conn-rate' " - "multiple definitions"); - YYERROR; - } - if (!o->data.max_src_conn_rate.limit || - !o->data.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' " - "values must be > 0"); - YYERROR; - } - if (o->data.max_src_conn_rate.limit > - PF_THRESHOLD_MAX) { - yyerror("'max-src-conn-rate' " - "maximum rate must be < %u", - PF_THRESHOLD_MAX); - YYERROR; - } - r.max_src_conn_rate.limit = - o->data.max_src_conn_rate.limit; - r.max_src_conn_rate.seconds = - o->data.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_NODES: - if (r.max_src_nodes) { - yyerror("state option " - "'max-src-nodes' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_nodes == 0) { - yyerror("'max-src-nodes' must " - "be > 0"); - YYERROR; - } - r.max_src_nodes = - o->data.max_src_nodes; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_STATELOCK: - if (statelock) { - yyerror("state locking option: " - "multiple definitions"); - YYERROR; - } - statelock = 1; - r.rule_flag |= o->data.statelock; - break; - case PF_STATE_OPT_SLOPPY: - if (r.rule_flag & PFRULE_STATESLOPPY) { - yyerror("state sloppy option: " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_STATESLOPPY; - break; - case PF_STATE_OPT_PFLOW: - if (r.rule_flag & PFRULE_PFLOW) { - yyerror("state pflow " - "option: multiple " - "definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_PFLOW; - break; - case PF_STATE_OPT_TIMEOUT: - if (o->data.timeout.number == - PFTM_ADAPTIVE_START || - o->data.timeout.number == - PFTM_ADAPTIVE_END) - adaptive = 1; - if (r.timeout[o->data.timeout.number]) { - yyerror("state timeout %s " - "multiple definitions", - pf_timeouts[o->data. - timeout.number].name); - YYERROR; - } - r.timeout[o->data.timeout.number] = - o->data.timeout.seconds; - } - o = o->next; - if (!defaults) - free(p); - } - - /* 'flags S/SA' by default on stateful rules */ - if (!r.action && !r.flags && !r.flagset && - !yystack.l_mark[0].v.filter_opts.fragment && !(yystack.l_mark[0].v.filter_opts.marker & FOM_FLAGS) && - r.keep_state) { - r.flags = parse_flags("S"); - r.flagset = parse_flags("SA"); - } - if (!adaptive && r.max_states) { - r.timeout[PFTM_ADAPTIVE_START] = - (r.max_states / 10) * 6; - r.timeout[PFTM_ADAPTIVE_END] = - (r.max_states / 10) * 12; - } - if (r.rule_flag & PFRULE_SRCTRACK) { - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_nodes) { - yyerror("'max-src-nodes' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn) { - yyerror("'max-src-conn' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (r.timeout[PFTM_SRC_NODE] < - r.max_src_conn_rate.seconds) - r.timeout[PFTM_SRC_NODE] = - r.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK; - if (srctrack == PF_SRCTRACK_RULE) - r.rule_flag |= PFRULE_RULESRCTRACK; - } - if (r.keep_state && !statelock) - r.rule_flag |= default_statelock; - - if (yystack.l_mark[0].v.filter_opts.fragment) - r.rule_flag |= PFRULE_FRAGMENT; - r.allow_opts = yystack.l_mark[0].v.filter_opts.allowopts; - - decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); - decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); - - if (yystack.l_mark[-4].v.route.rt) { - if (!r.direction) { - yyerror("direction must be explicit " - "with rules that specify routing"); - YYERROR; - } - r.rt = yystack.l_mark[-4].v.route.rt; - r.rpool.opts = yystack.l_mark[-4].v.route.pool_opts; - if (yystack.l_mark[-4].v.route.key != NULL) - memcpy(&r.rpool.key, yystack.l_mark[-4].v.route.key, - sizeof(struct pf_poolhashkey)); - } - if (r.rt && r.rt != PF_FASTROUTE) { - decide_address_family(yystack.l_mark[-4].v.route.host, &r.af); - remove_invalid_hosts(&yystack.l_mark[-4].v.route.host, &r.af); - if (yystack.l_mark[-4].v.route.host == NULL) { - yyerror("no routing address with " - "matching address family found."); - YYERROR; - } - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && (yystack.l_mark[-4].v.route.host->next != NULL || - yystack.l_mark[-4].v.route.host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR(yystack.l_mark[-4].v.route.host->addr))) - r.rpool.opts |= PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table(yystack.l_mark[-4].v.route.host, "tables are only " - "supported in round-robin routing pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias(yystack.l_mark[-4].v.route.host, "interface (%s) " - "is only supported in round-robin " - "routing pools")) - YYERROR; - if (yystack.l_mark[-4].v.route.host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("r.rpool.opts must " - "be PF_POOL_ROUNDROBIN"); - YYERROR; - } - } - } - if (yystack.l_mark[0].v.filter_opts.queues.qname != NULL) { - if (strlcpy(r.qname, yystack.l_mark[0].v.filter_opts.queues.qname, - sizeof(r.qname)) >= sizeof(r.qname)) { - yyerror("rule qname too long (max " - "%d chars)", sizeof(r.qname)-1); - YYERROR; - } - free(yystack.l_mark[0].v.filter_opts.queues.qname); - } - if (yystack.l_mark[0].v.filter_opts.queues.pqname != NULL) { - if (strlcpy(r.pqname, yystack.l_mark[0].v.filter_opts.queues.pqname, - sizeof(r.pqname)) >= sizeof(r.pqname)) { - yyerror("rule pqname too long (max " - "%d chars)", sizeof(r.pqname)-1); - YYERROR; - } - free(yystack.l_mark[0].v.filter_opts.queues.pqname); - } -#ifdef __FreeBSD__ - r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port; -#else - if ((r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port)) { - if (r.direction == PF_OUT) { - if (yystack.l_mark[0].v.filter_opts.divert.addr) { - yyerror("address specified " - "for outgoing divert"); - YYERROR; - } - bzero(&r.divert.addr, - sizeof(r.divert.addr)); - } else { - if (!yystack.l_mark[0].v.filter_opts.divert.addr) { - yyerror("no address specified " - "for incoming divert"); - YYERROR; - } - if (yystack.l_mark[0].v.filter_opts.divert.addr->af != r.af) { - yyerror("address family " - "mismatch for divert"); - YYERROR; - } - r.divert.addr = - yystack.l_mark[0].v.filter_opts.divert.addr->addr.v.a.addr; - } - } -#endif - - expand_rule(&r, yystack.l_mark[-5].v.interface, yystack.l_mark[-4].v.route.host, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, - yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, - yystack.l_mark[0].v.filter_opts.uid, yystack.l_mark[0].v.filter_opts.gid, yystack.l_mark[0].v.filter_opts.icmpspec, ""); - } -break; -case 154: -#line 2317 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - } -break; -case 155: -#line 2322 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.filter_opts = filter_opts; } -break; -case 156: -#line 2323 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - yyval.v.filter_opts = filter_opts; - } -break; -case 159: -#line 2334 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.uid) - yystack.l_mark[0].v.uid->tail->next = filter_opts.uid; - filter_opts.uid = yystack.l_mark[0].v.uid; - } -break; -case 160: -#line 2339 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.gid) - yystack.l_mark[0].v.gid->tail->next = filter_opts.gid; - filter_opts.gid = yystack.l_mark[0].v.gid; - } -break; -case 161: -#line 2344 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.marker & FOM_FLAGS) { - yyerror("flags cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_FLAGS; - filter_opts.flags.b1 |= yystack.l_mark[0].v.b.b1; - filter_opts.flags.b2 |= yystack.l_mark[0].v.b.b2; - filter_opts.flags.w |= yystack.l_mark[0].v.b.w; - filter_opts.flags.w2 |= yystack.l_mark[0].v.b.w2; - } -break; -case 162: -#line 2355 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.marker & FOM_ICMP) { - yyerror("icmp-type cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_ICMP; - filter_opts.icmpspec = yystack.l_mark[0].v.icmp; - } -break; -case 163: -#line 2363 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.marker & FOM_TOS) { - yyerror("tos cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_TOS; - filter_opts.tos = yystack.l_mark[0].v.number; - } -break; -case 164: -#line 2371 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.marker & FOM_KEEP) { - yyerror("modulate or keep cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_KEEP; - filter_opts.keep.action = yystack.l_mark[0].v.keep_state.action; - filter_opts.keep.options = yystack.l_mark[0].v.keep_state.options; - } -break; -case 165: -#line 2380 "../../freebsd/contrib/pf/pfctl/parse.y" - { - filter_opts.fragment = 1; - } -break; -case 166: -#line 2383 "../../freebsd/contrib/pf/pfctl/parse.y" - { - filter_opts.allowopts = 1; - } -break; -case 167: -#line 2386 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - filter_opts.label = yystack.l_mark[0].v.string; - } -break; -case 168: -#line 2393 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.queues.qname) { - yyerror("queue cannot be redefined"); - YYERROR; - } - filter_opts.queues = yystack.l_mark[0].v.qassign; - } -break; -case 169: -#line 2400 "../../freebsd/contrib/pf/pfctl/parse.y" - { - filter_opts.tag = yystack.l_mark[0].v.string; - } -break; -case 170: -#line 2403 "../../freebsd/contrib/pf/pfctl/parse.y" - { - filter_opts.match_tag = yystack.l_mark[0].v.string; - filter_opts.match_tag_not = yystack.l_mark[-2].v.number; - } -break; -case 171: -#line 2407 "../../freebsd/contrib/pf/pfctl/parse.y" - { - double p; - - p = floor(yystack.l_mark[0].v.probability * UINT_MAX + 0.5); - if (p < 0.0 || p > UINT_MAX) { - yyerror("invalid probability: %lf", p); - YYERROR; - } - filter_opts.prob = (u_int32_t)p; - if (filter_opts.prob == 0) - filter_opts.prob = 1; - } -break; -case 172: -#line 2419 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - filter_opts.rtableid = yystack.l_mark[0].v.number; - } -break; -case 173: -#line 2426 "../../freebsd/contrib/pf/pfctl/parse.y" - { -#ifdef __FreeBSD__ - filter_opts.divert.port = yystack.l_mark[0].v.range.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a)); - YYERROR; - } -#endif - } -break; -case 174: -#line 2435 "../../freebsd/contrib/pf/pfctl/parse.y" - { -#ifndef __FreeBSD__ - if ((filter_opts.divert.addr = host(yystack.l_mark[-2].v.string)) == NULL) { - yyerror("could not parse divert address: %s", - yystack.l_mark[-2].v.string); - free(yystack.l_mark[-2].v.string); - YYERROR; - } -#else - if (yystack.l_mark[-2].v.string) -#endif - free(yystack.l_mark[-2].v.string); - filter_opts.divert.port = yystack.l_mark[0].v.range.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a)); - YYERROR; - } - } -break; -case 175: -#line 2453 "../../freebsd/contrib/pf/pfctl/parse.y" - { -#ifdef __FreeBSD__ - yyerror("divert-reply has no meaning in FreeBSD pf(4)"); - YYERROR; -#else - filter_opts.divert.port = 1; /* some random value */ -#endif - } -break; -case 176: -#line 2463 "../../freebsd/contrib/pf/pfctl/parse.y" - { - char *e; - double p = strtod(yystack.l_mark[0].v.string, &e); - - if (*e == '%') { - p *= 0.01; - e++; - } - if (*e) { - yyerror("invalid probability: %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - yyval.v.probability = p; - } -break; -case 177: -#line 2479 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.probability = (double)yystack.l_mark[0].v.number; - } -break; -case 178: -#line 2485 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = PF_PASS; yyval.v.b.b2 = yyval.v.b.w = 0; } -break; -case 179: -#line 2486 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b = yystack.l_mark[0].v.b; yyval.v.b.b1 = PF_DROP; } -break; -case 180: -#line 2489 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = blockpolicy; - yyval.v.b.w = returnicmpdefault; - yyval.v.b.w2 = returnicmp6default; - } -break; -case 181: -#line 2494 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_DROP; - yyval.v.b.w = 0; - yyval.v.b.w2 = 0; - } -break; -case 182: -#line 2499 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNRST; - yyval.v.b.w = 0; - yyval.v.b.w2 = 0; - } -break; -case 183: -#line 2504 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > 255) { - yyerror("illegal ttl value %d", yystack.l_mark[-1].v.number); - YYERROR; - } - yyval.v.b.b2 = PFRULE_RETURNRST; - yyval.v.b.w = yystack.l_mark[-1].v.number; - yyval.v.b.w2 = 0; - } -break; -case 184: -#line 2513 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNICMP; - yyval.v.b.w = returnicmpdefault; - yyval.v.b.w2 = returnicmp6default; - } -break; -case 185: -#line 2518 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNICMP; - yyval.v.b.w = returnicmpdefault; - yyval.v.b.w2 = returnicmp6default; - } -break; -case 186: -#line 2523 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNICMP; - yyval.v.b.w = yystack.l_mark[-1].v.number; - yyval.v.b.w2 = returnicmpdefault; - } -break; -case 187: -#line 2528 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNICMP; - yyval.v.b.w = returnicmpdefault; - yyval.v.b.w2 = yystack.l_mark[-1].v.number; - } -break; -case 188: -#line 2533 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURNICMP; - yyval.v.b.w = yystack.l_mark[-3].v.number; - yyval.v.b.w2 = yystack.l_mark[-1].v.number; - } -break; -case 189: -#line 2538 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.b.b2 = PFRULE_RETURN; - yyval.v.b.w = returnicmpdefault; - yyval.v.b.w2 = returnicmp6default; - } -break; -case 190: -#line 2545 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET))) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 191: -#line 2552 "../../freebsd/contrib/pf/pfctl/parse.y" - { - u_int8_t icmptype; - - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number); - YYERROR; - } - icmptype = returnicmpdefault >> 8; - yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number); - } -break; -case 192: -#line 2564 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET6))) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 193: -#line 2571 "../../freebsd/contrib/pf/pfctl/parse.y" - { - u_int8_t icmptype; - - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number); - YYERROR; - } - icmptype = returnicmp6default >> 8; - yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number); - } -break; -case 194: -#line 2583 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_INOUT; } -break; -case 195: -#line 2584 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_IN; } -break; -case 196: -#line 2585 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OUT; } -break; -case 197: -#line 2588 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.quick = 0; } -break; -case 198: -#line 2589 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.quick = 1; } -break; -case 199: -#line 2592 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.log = 0; yyval.v.logquick.quick = 0; yyval.v.logquick.logif = 0; } -break; -case 200: -#line 2593 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 0; } -break; -case 201: -#line 2594 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.quick = 1; yyval.v.logquick.log = 0; yyval.v.logquick.logif = 0; } -break; -case 202: -#line 2595 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick = yystack.l_mark[-1].v.logquick; yyval.v.logquick.quick = 1; } -break; -case 203: -#line 2596 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 1; } -break; -case 204: -#line 2599 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.log = PF_LOG; yyval.v.logquick.logif = 0; } -break; -case 205: -#line 2600 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.logquick.log = PF_LOG | yystack.l_mark[-1].v.logquick.log; - yyval.v.logquick.logif = yystack.l_mark[-1].v.logquick.logif; - } -break; -case 206: -#line 2606 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick = yystack.l_mark[0].v.logquick; } -break; -case 207: -#line 2607 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.logquick.log = yystack.l_mark[-2].v.logquick.log | yystack.l_mark[0].v.logquick.log; - yyval.v.logquick.logif = yystack.l_mark[0].v.logquick.logif; - if (yyval.v.logquick.logif == 0) - yyval.v.logquick.logif = yystack.l_mark[-2].v.logquick.logif; - } -break; -case 208: -#line 2615 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.log = PF_LOG_ALL; yyval.v.logquick.logif = 0; } -break; -case 209: -#line 2616 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; } -break; -case 210: -#line 2617 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; } -break; -case 211: -#line 2618 "../../freebsd/contrib/pf/pfctl/parse.y" - { - const char *errstr; - u_int i; - - yyval.v.logquick.log = 0; - if (strncmp(yystack.l_mark[0].v.string, "pflog", 5)) { - yyerror("%s: should be a pflog interface", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - i = strtonum(yystack.l_mark[0].v.string + 5, 0, 255, &errstr); - if (errstr) { - yyerror("%s: %s", yystack.l_mark[0].v.string, errstr); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - yyval.v.logquick.logif = i; - } -break; -case 212: -#line 2639 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = NULL; } -break; -case 213: -#line 2640 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[0].v.interface; } -break; -case 214: -#line 2641 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[-1].v.interface; } -break; -case 215: -#line 2644 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[-1].v.interface; } -break; -case 216: -#line 2645 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface; - yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface; - yyval.v.interface = yystack.l_mark[-3].v.interface; - } -break; -case 217: -#line 2652 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.interface = yystack.l_mark[0].v.interface; yyval.v.interface->not = yystack.l_mark[-1].v.number; } -break; -case 218: -#line 2655 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *n; - - yyval.v.interface = calloc(1, sizeof(struct node_if)); - if (yyval.v.interface == NULL) - err(1, "if_item: calloc"); - if (strlcpy(yyval.v.interface->ifname, yystack.l_mark[0].v.string, sizeof(yyval.v.interface->ifname)) >= - sizeof(yyval.v.interface->ifname)) { - free(yystack.l_mark[0].v.string); - free(yyval.v.interface); - yyerror("interface name too long"); - YYERROR; - } - - if ((n = ifa_exists(yystack.l_mark[0].v.string)) != NULL) - yyval.v.interface->ifa_flags = n->ifa_flags; - - free(yystack.l_mark[0].v.string); - yyval.v.interface->not = 0; - yyval.v.interface->next = NULL; - yyval.v.interface->tail = yyval.v.interface; - } -break; -case 219: -#line 2679 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = 0; } -break; -case 220: -#line 2680 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = AF_INET; } -break; -case 221: -#line 2681 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = AF_INET6; } -break; -case 222: -#line 2684 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.proto = NULL; } -break; -case 223: -#line 2685 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.proto = yystack.l_mark[0].v.proto; } -break; -case 224: -#line 2686 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.proto = yystack.l_mark[-1].v.proto; } -break; -case 225: -#line 2689 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.proto = yystack.l_mark[-1].v.proto; } -break; -case 226: -#line 2690 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.proto->tail->next = yystack.l_mark[-1].v.proto; - yystack.l_mark[-3].v.proto->tail = yystack.l_mark[-1].v.proto; - yyval.v.proto = yystack.l_mark[-3].v.proto; - } -break; -case 227: -#line 2697 "../../freebsd/contrib/pf/pfctl/parse.y" - { - u_int8_t pr; - - pr = (u_int8_t)yystack.l_mark[0].v.number; - if (pr == 0) { - yyerror("proto 0 cannot be used"); - YYERROR; - } - yyval.v.proto = calloc(1, sizeof(struct node_proto)); - if (yyval.v.proto == NULL) - err(1, "proto_item: calloc"); - yyval.v.proto->proto = pr; - yyval.v.proto->next = NULL; - yyval.v.proto->tail = yyval.v.proto; - } -break; -case 228: -#line 2714 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct protoent *p; - - p = getprotobyname(yystack.l_mark[0].v.string); - if (p == NULL) { - yyerror("unknown protocol %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.number = p->p_proto; - free(yystack.l_mark[0].v.string); - } -break; -case 229: -#line 2726 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("protocol outside range"); - YYERROR; - } - } -break; -case 230: -#line 2734 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.fromto.src.host = NULL; - yyval.v.fromto.src.port = NULL; - yyval.v.fromto.dst.host = NULL; - yyval.v.fromto.dst.port = NULL; - yyval.v.fromto.src_os = NULL; - } -break; -case 231: -#line 2741 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.fromto.src = yystack.l_mark[-2].v.peer; - yyval.v.fromto.src_os = yystack.l_mark[-1].v.os; - yyval.v.fromto.dst = yystack.l_mark[0].v.peer; - } -break; -case 232: -#line 2748 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.os = NULL; } -break; -case 233: -#line 2749 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.os = yystack.l_mark[0].v.os; } -break; -case 234: -#line 2750 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.os = yystack.l_mark[-1].v.os; } -break; -case 235: -#line 2753 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.os = calloc(1, sizeof(struct node_os)); - if (yyval.v.os == NULL) - err(1, "os: calloc"); - yyval.v.os->os = yystack.l_mark[0].v.string; - yyval.v.os->tail = yyval.v.os; - } -break; -case 236: -#line 2762 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.os = yystack.l_mark[-1].v.os; } -break; -case 237: -#line 2763 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.os->tail->next = yystack.l_mark[-1].v.os; - yystack.l_mark[-3].v.os->tail = yystack.l_mark[-1].v.os; - yyval.v.os = yystack.l_mark[-3].v.os; - } -break; -case 238: -#line 2770 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer.host = NULL; - yyval.v.peer.port = NULL; - } -break; -case 239: -#line 2774 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer = yystack.l_mark[0].v.peer; - } -break; -case 240: -#line 2779 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer.host = NULL; - yyval.v.peer.port = NULL; - } -break; -case 241: -#line 2783 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (disallow_urpf_failed(yystack.l_mark[0].v.peer.host, "\"urpf-failed\" is " - "not permitted in a destination address")) - YYERROR; - yyval.v.peer = yystack.l_mark[0].v.peer; - } -break; -case 242: -#line 2791 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer.host = yystack.l_mark[0].v.host; - yyval.v.peer.port = NULL; - } -break; -case 243: -#line 2795 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer.host = yystack.l_mark[-2].v.host; - yyval.v.peer.port = yystack.l_mark[0].v.port; - } -break; -case 244: -#line 2799 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.peer.host = NULL; - yyval.v.peer.port = yystack.l_mark[0].v.port; - } -break; -case 247: -#line 2809 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = NULL; } -break; -case 248: -#line 2810 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[0].v.host; } -break; -case 249: -#line 2811 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 250: -#line 2814 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[0].v.host; } -break; -case 251: -#line 2815 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = NULL; } -break; -case 252: -#line 2818 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 253: -#line 2819 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-1].v.host == NULL) - yyval.v.host = yystack.l_mark[-3].v.host; - else if (yystack.l_mark[-3].v.host == NULL) - yyval.v.host = yystack.l_mark[-1].v.host; - else { - yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; - yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; - yyval.v.host = yystack.l_mark[-3].v.host; - } - } -break; -case 254: -#line 2832 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *n; - - for (n = yystack.l_mark[0].v.host; n != NULL; n = n->next) - n->not = yystack.l_mark[-1].v.number; - yyval.v.host = yystack.l_mark[0].v.host; - } -break; -case 255: -#line 2839 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) - err(1, "xhost: calloc"); - yyval.v.host->addr.type = PF_ADDR_NOROUTE; - yyval.v.host->next = NULL; - yyval.v.host->not = yystack.l_mark[-1].v.number; - yyval.v.host->tail = yyval.v.host; - } -break; -case 256: -#line 2848 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) - err(1, "xhost: calloc"); - yyval.v.host->addr.type = PF_ADDR_URPFFAILED; - yyval.v.host->next = NULL; - yyval.v.host->not = yystack.l_mark[-1].v.number; - yyval.v.host->tail = yyval.v.host; - } -break; -case 257: -#line 2859 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if ((yyval.v.host = host(yystack.l_mark[0].v.string)) == NULL) { - /* error. "any" is handled elsewhere */ - free(yystack.l_mark[0].v.string); - yyerror("could not parse host specification"); - YYERROR; - } - free(yystack.l_mark[0].v.string); - - } -break; -case 258: -#line 2869 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *b, *e; - - if ((b = host(yystack.l_mark[-2].v.string)) == NULL || (e = host(yystack.l_mark[0].v.string)) == NULL) { - free(yystack.l_mark[-2].v.string); - free(yystack.l_mark[0].v.string); - yyerror("could not parse host specification"); - YYERROR; - } - if (b->af != e->af || - b->addr.type != PF_ADDR_ADDRMASK || - e->addr.type != PF_ADDR_ADDRMASK || - unmask(&b->addr.v.a.mask, b->af) != - (b->af == AF_INET ? 32 : 128) || - unmask(&e->addr.v.a.mask, e->af) != - (e->af == AF_INET ? 32 : 128) || - b->next != NULL || b->not || - e->next != NULL || e->not) { - free(b); - free(e); - free(yystack.l_mark[-2].v.string); - free(yystack.l_mark[0].v.string); - yyerror("invalid address range"); - YYERROR; - } - memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, - sizeof(b->addr.v.a.mask)); - b->addr.type = PF_ADDR_RANGE; - yyval.v.host = b; - free(e); - free(yystack.l_mark[-2].v.string); - free(yystack.l_mark[0].v.string); - } -break; -case 259: -#line 2902 "../../freebsd/contrib/pf/pfctl/parse.y" - { - char *buf; - - if (asprintf(&buf, "%s/%lld", yystack.l_mark[-2].v.string, (long long)yystack.l_mark[0].v.number) == -1) - err(1, "host: asprintf"); - free(yystack.l_mark[-2].v.string); - if ((yyval.v.host = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } -break; -case 260: -#line 2916 "../../freebsd/contrib/pf/pfctl/parse.y" - { - char *buf; - - /* ie. for 10/8 parsing */ -#ifdef __FreeBSD__ - if (asprintf(&buf, "%lld/%lld", (long long)yystack.l_mark[-2].v.number, (long long)yystack.l_mark[0].v.number) == -1) -#else - if (asprintf(&buf, "%lld/%lld", yystack.l_mark[-2].v.number, yystack.l_mark[0].v.number) == -1) -#endif - err(1, "host: asprintf"); - if ((yyval.v.host = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } -break; -case 262: -#line 2935 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct node_host *n; - - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 128) { - yyerror("bit number too big"); - YYERROR; - } - yyval.v.host = yystack.l_mark[-2].v.host; - for (n = yystack.l_mark[-2].v.host; n != NULL; n = n->next) - set_ipmask(n, yystack.l_mark[0].v.number); - } -break; -case 263: -#line 2946 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (strlen(yystack.l_mark[-1].v.string) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", yystack.l_mark[-1].v.string); - free(yystack.l_mark[-1].v.string); - YYERROR; - } - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) - err(1, "host: calloc"); - yyval.v.host->addr.type = PF_ADDR_TABLE; - if (strlcpy(yyval.v.host->addr.v.tblname, yystack.l_mark[-1].v.string, - sizeof(yyval.v.host->addr.v.tblname)) >= - sizeof(yyval.v.host->addr.v.tblname)) - errx(1, "host: strlcpy"); - free(yystack.l_mark[-1].v.string); - yyval.v.host->next = NULL; - yyval.v.host->tail = yyval.v.host; - } -break; -case 264: -#line 2964 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) { - free(yystack.l_mark[0].v.string); - err(1, "host: calloc"); - } - yyval.v.host->addr.type = PF_ADDR_RTLABEL; - if (strlcpy(yyval.v.host->addr.v.rtlabelname, yystack.l_mark[0].v.string, - sizeof(yyval.v.host->addr.v.rtlabelname)) >= - sizeof(yyval.v.host->addr.v.rtlabelname)) { - yyerror("route label too long, max %u chars", - sizeof(yyval.v.host->addr.v.rtlabelname) - 1); - free(yystack.l_mark[0].v.string); - free(yyval.v.host); - YYERROR; - } - yyval.v.host->next = NULL; - yyval.v.host->tail = yyval.v.host; - free(yystack.l_mark[0].v.string); - } -break; -case 266: -#line 2987 "../../freebsd/contrib/pf/pfctl/parse.y" - { - u_long ulval; - - if (atoul(yystack.l_mark[0].v.string, &ulval) == -1) { - yyerror("%s is not a number", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } else - yyval.v.number = ulval; - free(yystack.l_mark[0].v.string); - } -break; -case 267: -#line 3000 "../../freebsd/contrib/pf/pfctl/parse.y" - { - int flags = 0; - char *p, *op; - - op = yystack.l_mark[-1].v.string; - if (!isalpha(op[0])) { - yyerror("invalid interface name '%s'", op); - free(op); - YYERROR; - } - while ((p = strrchr(yystack.l_mark[-1].v.string, ':')) != NULL) { - if (!strcmp(p+1, "network")) - flags |= PFI_AFLAG_NETWORK; - else if (!strcmp(p+1, "broadcast")) - flags |= PFI_AFLAG_BROADCAST; - else if (!strcmp(p+1, "peer")) - flags |= PFI_AFLAG_PEER; - else if (!strcmp(p+1, "0")) - flags |= PFI_AFLAG_NOALIAS; - else { - yyerror("interface %s has bad modifier", - yystack.l_mark[-1].v.string); - free(op); - YYERROR; - } - *p = '\0'; - } - if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { - free(op); - yyerror("illegal combination of " - "interface modifiers"); - YYERROR; - } - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) - err(1, "address: calloc"); - yyval.v.host->af = 0; - set_ipmask(yyval.v.host, 128); - yyval.v.host->addr.type = PF_ADDR_DYNIFTL; - yyval.v.host->addr.iflags = flags; - if (strlcpy(yyval.v.host->addr.v.ifname, yystack.l_mark[-1].v.string, - sizeof(yyval.v.host->addr.v.ifname)) >= - sizeof(yyval.v.host->addr.v.ifname)) { - free(op); - free(yyval.v.host); - yyerror("interface name too long"); - YYERROR; - } - free(op); - yyval.v.host->next = NULL; - yyval.v.host->tail = yyval.v.host; - } -break; -case 268: -#line 3054 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.port = yystack.l_mark[0].v.port; } -break; -case 269: -#line 3055 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.port = yystack.l_mark[-1].v.port; } -break; -case 270: -#line 3058 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.port = yystack.l_mark[-1].v.port; } -break; -case 271: -#line 3059 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.port->tail->next = yystack.l_mark[-1].v.port; - yystack.l_mark[-3].v.port->tail = yystack.l_mark[-1].v.port; - yyval.v.port = yystack.l_mark[-3].v.port; - } -break; -case 272: -#line 3066 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.port = calloc(1, sizeof(struct node_port)); - if (yyval.v.port == NULL) - err(1, "port_item: calloc"); - yyval.v.port->port[0] = yystack.l_mark[0].v.range.a; - yyval.v.port->port[1] = yystack.l_mark[0].v.range.b; - if (yystack.l_mark[0].v.range.t) - yyval.v.port->op = PF_OP_RRG; - else - yyval.v.port->op = PF_OP_EQ; - yyval.v.port->next = NULL; - yyval.v.port->tail = yyval.v.port; - } -break; -case 273: -#line 3079 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.range.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - yyval.v.port = calloc(1, sizeof(struct node_port)); - if (yyval.v.port == NULL) - err(1, "port_item: calloc"); - yyval.v.port->port[0] = yystack.l_mark[0].v.range.a; - yyval.v.port->port[1] = yystack.l_mark[0].v.range.b; - yyval.v.port->op = yystack.l_mark[-1].v.i; - yyval.v.port->next = NULL; - yyval.v.port->tail = yyval.v.port; - } -break; -case 274: -#line 3094 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.range.t || yystack.l_mark[0].v.range.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - yyval.v.port = calloc(1, sizeof(struct node_port)); - if (yyval.v.port == NULL) - err(1, "port_item: calloc"); - yyval.v.port->port[0] = yystack.l_mark[-2].v.range.a; - yyval.v.port->port[1] = yystack.l_mark[0].v.range.a; - yyval.v.port->op = yystack.l_mark[-1].v.i; - yyval.v.port->next = NULL; - yyval.v.port->tail = yyval.v.port; - } -break; -case 275: -#line 3111 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, 0) == -1) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 276: -#line 3120 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE) == -1) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 277: -#line 3129 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.uid = yystack.l_mark[0].v.uid; } -break; -case 278: -#line 3130 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.uid = yystack.l_mark[-1].v.uid; } -break; -case 279: -#line 3133 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.uid = yystack.l_mark[-1].v.uid; } -break; -case 280: -#line 3134 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.uid->tail->next = yystack.l_mark[-1].v.uid; - yystack.l_mark[-3].v.uid->tail = yystack.l_mark[-1].v.uid; - yyval.v.uid = yystack.l_mark[-3].v.uid; - } -break; -case 281: -#line 3141 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.uid = calloc(1, sizeof(struct node_uid)); - if (yyval.v.uid == NULL) - err(1, "uid_item: calloc"); - yyval.v.uid->uid[0] = yystack.l_mark[0].v.number; - yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; - yyval.v.uid->op = PF_OP_EQ; - yyval.v.uid->next = NULL; - yyval.v.uid->tail = yyval.v.uid; - } -break; -case 282: -#line 3151 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number == UID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - yyval.v.uid = calloc(1, sizeof(struct node_uid)); - if (yyval.v.uid == NULL) - err(1, "uid_item: calloc"); - yyval.v.uid->uid[0] = yystack.l_mark[0].v.number; - yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; - yyval.v.uid->op = yystack.l_mark[-1].v.i; - yyval.v.uid->next = NULL; - yyval.v.uid->tail = yyval.v.uid; - } -break; -case 283: -#line 3166 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.number == UID_MAX || yystack.l_mark[0].v.number == UID_MAX) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - yyval.v.uid = calloc(1, sizeof(struct node_uid)); - if (yyval.v.uid == NULL) - err(1, "uid_item: calloc"); - yyval.v.uid->uid[0] = yystack.l_mark[-2].v.number; - yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; - yyval.v.uid->op = yystack.l_mark[-1].v.i; - yyval.v.uid->next = NULL; - yyval.v.uid->tail = yyval.v.uid; - } -break; -case 284: -#line 3183 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "unknown")) - yyval.v.number = UID_MAX; - else { - struct passwd *pw; - - if ((pw = getpwnam(yystack.l_mark[0].v.string)) == NULL) { - yyerror("unknown user %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.number = pw->pw_uid; - } - free(yystack.l_mark[0].v.string); - } -break; -case 285: -#line 3198 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= UID_MAX) { - yyerror("illegal uid value %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.number = yystack.l_mark[0].v.number; - } -break; -case 286: -#line 3207 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.gid = yystack.l_mark[0].v.gid; } -break; -case 287: -#line 3208 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.gid = yystack.l_mark[-1].v.gid; } -break; -case 288: -#line 3211 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.gid = yystack.l_mark[-1].v.gid; } -break; -case 289: -#line 3212 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.gid->tail->next = yystack.l_mark[-1].v.gid; - yystack.l_mark[-3].v.gid->tail = yystack.l_mark[-1].v.gid; - yyval.v.gid = yystack.l_mark[-3].v.gid; - } -break; -case 290: -#line 3219 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.gid = calloc(1, sizeof(struct node_gid)); - if (yyval.v.gid == NULL) - err(1, "gid_item: calloc"); - yyval.v.gid->gid[0] = yystack.l_mark[0].v.number; - yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; - yyval.v.gid->op = PF_OP_EQ; - yyval.v.gid->next = NULL; - yyval.v.gid->tail = yyval.v.gid; - } -break; -case 291: -#line 3229 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number == GID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - yyval.v.gid = calloc(1, sizeof(struct node_gid)); - if (yyval.v.gid == NULL) - err(1, "gid_item: calloc"); - yyval.v.gid->gid[0] = yystack.l_mark[0].v.number; - yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; - yyval.v.gid->op = yystack.l_mark[-1].v.i; - yyval.v.gid->next = NULL; - yyval.v.gid->tail = yyval.v.gid; - } -break; -case 292: -#line 3244 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.number == GID_MAX || yystack.l_mark[0].v.number == GID_MAX) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - yyval.v.gid = calloc(1, sizeof(struct node_gid)); - if (yyval.v.gid == NULL) - err(1, "gid_item: calloc"); - yyval.v.gid->gid[0] = yystack.l_mark[-2].v.number; - yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; - yyval.v.gid->op = yystack.l_mark[-1].v.i; - yyval.v.gid->next = NULL; - yyval.v.gid->tail = yyval.v.gid; - } -break; -case 293: -#line 3261 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "unknown")) - yyval.v.number = GID_MAX; - else { - struct group *grp; - - if ((grp = getgrnam(yystack.l_mark[0].v.string)) == NULL) { - yyerror("unknown group %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.number = grp->gr_gid; - } - free(yystack.l_mark[0].v.string); - } -break; -case 294: -#line 3276 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= GID_MAX) { - yyerror("illegal gid value %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.number = yystack.l_mark[0].v.number; - } -break; -case 295: -#line 3285 "../../freebsd/contrib/pf/pfctl/parse.y" - { - int f; - - if ((f = parse_flags(yystack.l_mark[0].v.string)) < 0) { - yyerror("bad flags %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - yyval.v.b.b1 = f; - } -break; -case 296: -#line 3298 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = yystack.l_mark[-2].v.b.b1; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; } -break; -case 297: -#line 3299 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; } -break; -case 298: -#line 3300 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = 0; yyval.v.b.b2 = 0; } -break; -case 299: -#line 3303 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[0].v.icmp; } -break; -case 300: -#line 3304 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } -break; -case 301: -#line 3305 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[0].v.icmp; } -break; -case 302: -#line 3306 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } -break; -case 303: -#line 3309 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } -break; -case 304: -#line 3310 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp; - yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp; - yyval.v.icmp = yystack.l_mark[-3].v.icmp; - } -break; -case 305: -#line 3317 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } -break; -case 306: -#line 3318 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp; - yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp; - yyval.v.icmp = yystack.l_mark[-3].v.icmp; - } -break; -case 307: -#line 3325 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[0].v.number; - yyval.v.icmp->code = 0; - yyval.v.icmp->proto = IPPROTO_ICMP; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 308: -#line 3335 "../../freebsd/contrib/pf/pfctl/parse.y" - { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET)) == NULL) { - yyerror("unknown icmp-code %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - - free(yystack.l_mark[0].v.string); - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[-2].v.number; - yyval.v.icmp->code = p->code + 1; - yyval.v.icmp->proto = IPPROTO_ICMP; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 309: -#line 3354 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[-2].v.number; - yyval.v.icmp->code = yystack.l_mark[0].v.number + 1; - yyval.v.icmp->proto = IPPROTO_ICMP; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 310: -#line 3370 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[0].v.number; - yyval.v.icmp->code = 0; - yyval.v.icmp->proto = IPPROTO_ICMPV6; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 311: -#line 3380 "../../freebsd/contrib/pf/pfctl/parse.y" - { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET6)) == NULL) { - yyerror("unknown icmp6-code %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[-2].v.number; - yyval.v.icmp->code = p->code + 1; - yyval.v.icmp->proto = IPPROTO_ICMPV6; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 312: -#line 3399 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); - if (yyval.v.icmp == NULL) - err(1, "icmp_item: calloc"); - yyval.v.icmp->type = yystack.l_mark[-2].v.number; - yyval.v.icmp->code = yystack.l_mark[0].v.number + 1; - yyval.v.icmp->proto = IPPROTO_ICMPV6; - yyval.v.icmp->next = NULL; - yyval.v.icmp->tail = yyval.v.icmp; - } -break; -case 313: -#line 3415 "../../freebsd/contrib/pf/pfctl/parse.y" - { - const struct icmptypeent *p; - - if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET)) == NULL) { - yyerror("unknown icmp-type %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.number = p->type + 1; - free(yystack.l_mark[0].v.string); - } -break; -case 314: -#line 3426 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("illegal icmp-type %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.number = yystack.l_mark[0].v.number + 1; - } -break; -case 315: -#line 3435 "../../freebsd/contrib/pf/pfctl/parse.y" - { - const struct icmptypeent *p; - - if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET6)) == - NULL) { - yyerror("unknown icmp6-type %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - yyval.v.number = p->type + 1; - free(yystack.l_mark[0].v.string); - } -break; -case 316: -#line 3447 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { - yyerror("illegal icmp6-type %lu", yystack.l_mark[0].v.number); - YYERROR; - } - yyval.v.number = yystack.l_mark[0].v.number + 1; - } -break; -case 317: -#line 3456 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "lowdelay")) - yyval.v.number = IPTOS_LOWDELAY; - else if (!strcmp(yystack.l_mark[0].v.string, "throughput")) - yyval.v.number = IPTOS_THROUGHPUT; - else if (!strcmp(yystack.l_mark[0].v.string, "reliability")) - yyval.v.number = IPTOS_RELIABILITY; - else if (yystack.l_mark[0].v.string[0] == '0' && yystack.l_mark[0].v.string[1] == 'x') - yyval.v.number = strtoul(yystack.l_mark[0].v.string, NULL, 16); - else - yyval.v.number = 0; /* flag bad argument */ - if (!yyval.v.number || yyval.v.number > 255) { - yyerror("illegal tos value %s", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 318: -#line 3474 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.number = yystack.l_mark[0].v.number; - if (!yyval.v.number || yyval.v.number > 255) { - yyerror("illegal tos value %s", yystack.l_mark[0].v.number); - YYERROR; - } - } -break; -case 319: -#line 3483 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_SRCTRACK; } -break; -case 320: -#line 3484 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_SRCTRACK_GLOBAL; } -break; -case 321: -#line 3485 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_SRCTRACK_RULE; } -break; -case 322: -#line 3488 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.i = PFRULE_IFBOUND; - } -break; -case 323: -#line 3491 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.i = 0; - } -break; -case 324: -#line 3496 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.keep_state.action = 0; - yyval.v.keep_state.options = NULL; - } -break; -case 325: -#line 3500 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.keep_state.action = PF_STATE_NORMAL; - yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; - } -break; -case 326: -#line 3504 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.keep_state.action = PF_STATE_MODULATE; - yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; - } -break; -case 327: -#line 3508 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.keep_state.action = PF_STATE_SYNPROXY; - yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; - } -break; -case 328: -#line 3514 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = 0; } -break; -case 329: -#line 3515 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_FLUSH; } -break; -case 330: -#line 3516 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.i = PF_FLUSH | PF_FLUSH_GLOBAL; - } -break; -case 331: -#line 3521 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.state_opt = yystack.l_mark[-1].v.state_opt; } -break; -case 332: -#line 3522 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.state_opt = NULL; } -break; -case 333: -#line 3525 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.state_opt = yystack.l_mark[0].v.state_opt; } -break; -case 334: -#line 3526 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-2].v.state_opt->tail->next = yystack.l_mark[0].v.state_opt; - yystack.l_mark[-2].v.state_opt->tail = yystack.l_mark[0].v.state_opt; - yyval.v.state_opt = yystack.l_mark[-2].v.state_opt; - } -break; -case 335: -#line 3533 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_MAX; - yyval.v.state_opt->data.max_states = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 336: -#line 3546 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_NOSYNC; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 337: -#line 3554 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_STATES; - yyval.v.state_opt->data.max_src_states = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 338: -#line 3567 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN; - yyval.v.state_opt->data.max_src_conn = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 339: -#line 3580 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.number < 0 || yystack.l_mark[-2].v.number > UINT_MAX || - yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; - yyval.v.state_opt->data.max_src_conn_rate.limit = yystack.l_mark[-2].v.number; - yyval.v.state_opt->data.max_src_conn_rate.seconds = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 340: -#line 3595 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", yystack.l_mark[-2].v.string); - free(yystack.l_mark[-2].v.string); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - if (strlcpy(yyval.v.state_opt->data.overload.tblname, yystack.l_mark[-2].v.string, - PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) - errx(1, "state_opt_item: strlcpy"); - free(yystack.l_mark[-2].v.string); - yyval.v.state_opt->type = PF_STATE_OPT_OVERLOAD; - yyval.v.state_opt->data.overload.flush = yystack.l_mark[0].v.i; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 341: -#line 3613 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_NODES; - yyval.v.state_opt->data.max_src_nodes = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 342: -#line 3626 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_SRCTRACK; - yyval.v.state_opt->data.src_track = yystack.l_mark[0].v.i; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 343: -#line 3635 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_STATELOCK; - yyval.v.state_opt->data.statelock = yystack.l_mark[0].v.i; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 344: -#line 3644 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_SLOPPY; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 345: -#line 3652 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_PFLOW; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 346: -#line 3660 "../../freebsd/contrib/pf/pfctl/parse.y" - { - int i; - - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - for (i = 0; pf_timeouts[i].name && - strcmp(pf_timeouts[i].name, yystack.l_mark[-1].v.string); ++i) - ; /* nothing */ - if (!pf_timeouts[i].name) { - yyerror("illegal timeout name %s", yystack.l_mark[-1].v.string); - free(yystack.l_mark[-1].v.string); - YYERROR; - } - if (strchr(pf_timeouts[i].name, '.') == NULL) { - yyerror("illegal state timeout %s", yystack.l_mark[-1].v.string); - free(yystack.l_mark[-1].v.string); - YYERROR; - } - free(yystack.l_mark[-1].v.string); - yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); - if (yyval.v.state_opt == NULL) - err(1, "state_opt_item: calloc"); - yyval.v.state_opt->type = PF_STATE_OPT_TIMEOUT; - yyval.v.state_opt->data.timeout.number = pf_timeouts[i].timeout; - yyval.v.state_opt->data.timeout.seconds = yystack.l_mark[0].v.number; - yyval.v.state_opt->next = NULL; - yyval.v.state_opt->tail = yyval.v.state_opt; - } -break; -case 347: -#line 3692 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.string = yystack.l_mark[0].v.string; - } -break; -case 348: -#line 3697 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.qassign.qname = yystack.l_mark[0].v.string; - yyval.v.qassign.pqname = NULL; - } -break; -case 349: -#line 3701 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.qassign.qname = yystack.l_mark[-1].v.string; - yyval.v.qassign.pqname = NULL; - } -break; -case 350: -#line 3705 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.qassign.qname = yystack.l_mark[-3].v.string; - yyval.v.qassign.pqname = yystack.l_mark[-1].v.string; - } -break; -case 351: -#line 3711 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = 0; } -break; -case 352: -#line 3712 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = 1; } -break; -case 353: -#line 3715 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE|PPORT_STAR) == -1) { - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 354: -#line 3724 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[0].v.host; } -break; -case 355: -#line 3725 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 356: -#line 3728 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 357: -#line 3729 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; - yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; - yyval.v.host = yystack.l_mark[-3].v.host; - } -break; -case 358: -#line 3736 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.redirection = NULL; } -break; -case 359: -#line 3737 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.redirection = calloc(1, sizeof(struct redirection)); - if (yyval.v.redirection == NULL) - err(1, "redirection: calloc"); - yyval.v.redirection->host = yystack.l_mark[0].v.host; - yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0; - } -break; -case 360: -#line 3744 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.redirection = calloc(1, sizeof(struct redirection)); - if (yyval.v.redirection == NULL) - err(1, "redirection: calloc"); - yyval.v.redirection->host = yystack.l_mark[-2].v.host; - yyval.v.redirection->rport = yystack.l_mark[0].v.range; - } -break; -case 361: -#line 3754 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); - if (yyval.v.hashkey == NULL) - err(1, "hashkey: calloc"); - yyval.v.hashkey->key32[0] = arc4random(); - yyval.v.hashkey->key32[1] = arc4random(); - yyval.v.hashkey->key32[2] = arc4random(); - yyval.v.hashkey->key32[3] = arc4random(); - } -break; -case 362: -#line 3764 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strncmp(yystack.l_mark[0].v.string, "0x", 2)) { - if (strlen(yystack.l_mark[0].v.string) != 34) { - free(yystack.l_mark[0].v.string); - yyerror("hex key must be 128 bits " - "(32 hex digits) long"); - YYERROR; - } - yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); - if (yyval.v.hashkey == NULL) - err(1, "hashkey: calloc"); - - if (sscanf(yystack.l_mark[0].v.string, "0x%8x%8x%8x%8x", - &yyval.v.hashkey->key32[0], &yyval.v.hashkey->key32[1], - &yyval.v.hashkey->key32[2], &yyval.v.hashkey->key32[3]) != 4) { - free(yyval.v.hashkey); - free(yystack.l_mark[0].v.string); - yyerror("invalid hex key"); - YYERROR; - } - } else { - MD5_CTX context; - - yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); - if (yyval.v.hashkey == NULL) - err(1, "hashkey: calloc"); - MD5Init(&context); - MD5Update(&context, (unsigned char *)yystack.l_mark[0].v.string, - strlen(yystack.l_mark[0].v.string)); - MD5Final((unsigned char *)yyval.v.hashkey, &context); - HTONL(yyval.v.hashkey->key32[0]); - HTONL(yyval.v.hashkey->key32[1]); - HTONL(yyval.v.hashkey->key32[2]); - HTONL(yyval.v.hashkey->key32[3]); - } - free(yystack.l_mark[0].v.string); - } -break; -case 363: -#line 3803 "../../freebsd/contrib/pf/pfctl/parse.y" - { bzero(&pool_opts, sizeof pool_opts); } -break; -case 364: -#line 3805 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.pool_opts = pool_opts; } -break; -case 365: -#line 3806 "../../freebsd/contrib/pf/pfctl/parse.y" - { - bzero(&pool_opts, sizeof pool_opts); - yyval.v.pool_opts = pool_opts; - } -break; -case 368: -#line 3816 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_BITMASK; - } -break; -case 369: -#line 3823 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_RANDOM; - } -break; -case 370: -#line 3830 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_SRCHASH; - pool_opts.key = yystack.l_mark[0].v.hashkey; - } -break; -case 371: -#line 3838 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_ROUNDROBIN; - } -break; -case 372: -#line 3845 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (pool_opts.staticport) { - yyerror("static-port cannot be redefined"); - YYERROR; - } - pool_opts.staticport = 1; - } -break; -case 373: -#line 3852 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (filter_opts.marker & POM_STICKYADDRESS) { - yyerror("sticky-address cannot be redefined"); - YYERROR; - } - pool_opts.marker |= POM_STICKYADDRESS; - pool_opts.opts |= PF_POOL_STICKYADDR; - } -break; -case 374: -#line 3862 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.redirection = NULL; } -break; -case 375: -#line 3863 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.redirection = calloc(1, sizeof(struct redirection)); - if (yyval.v.redirection == NULL) - err(1, "redirection: calloc"); - yyval.v.redirection->host = yystack.l_mark[0].v.host; - yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0; - } -break; -case 376: -#line 3870 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.redirection = calloc(1, sizeof(struct redirection)); - if (yyval.v.redirection == NULL) - err(1, "redirection: calloc"); - yyval.v.redirection->host = yystack.l_mark[-2].v.host; - yyval.v.redirection->rport = yystack.l_mark[0].v.range; - } -break; -case 377: -#line 3879 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; } -break; -case 378: -#line 3880 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = 1; yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; } -break; -case 379: -#line 3881 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = 1; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; } -break; -case 380: -#line 3882 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; } -break; -case 381: -#line 3885 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if (yystack.l_mark[-2].v.i) - yyval.v.b.b1 = PF_NONAT; - else - yyval.v.b.b1 = PF_NAT; - yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; - yyval.v.b.w = yystack.l_mark[0].v.b.b2; - yyval.v.b.w2 = yystack.l_mark[0].v.b.w2; - } -break; -case 382: -#line 3898 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if (yystack.l_mark[-2].v.i) - yyval.v.b.b1 = PF_NORDR; - else - yyval.v.b.b1 = PF_RDR; - yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; - yyval.v.b.w = yystack.l_mark[0].v.b.b2; - yyval.v.b.w2 = yystack.l_mark[0].v.b.w2; - } -break; -case 383: -#line 3915 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = yystack.l_mark[-9].v.b.b1; - r.natpass = yystack.l_mark[-9].v.b.b2; - r.log = yystack.l_mark[-9].v.b.w; - r.logif = yystack.l_mark[-9].v.b.w2; - r.af = yystack.l_mark[-7].v.i; - - if (!r.af) { - if (yystack.l_mark[-5].v.fromto.src.host && yystack.l_mark[-5].v.fromto.src.host->af && - !yystack.l_mark[-5].v.fromto.src.host->ifindex) - r.af = yystack.l_mark[-5].v.fromto.src.host->af; - else if (yystack.l_mark[-5].v.fromto.dst.host && yystack.l_mark[-5].v.fromto.dst.host->af && - !yystack.l_mark[-5].v.fromto.dst.host->ifindex) - r.af = yystack.l_mark[-5].v.fromto.dst.host->af; - } - - if (yystack.l_mark[-4].v.string != NULL) - if (strlcpy(r.tagname, yystack.l_mark[-4].v.string, PF_TAG_NAME_SIZE) >= - PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - - if (yystack.l_mark[-3].v.tagged.name) - if (strlcpy(r.match_tagname, yystack.l_mark[-3].v.tagged.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = yystack.l_mark[-3].v.tagged.neg; - r.rtableid = yystack.l_mark[-2].v.rtableid; - - if (r.action == PF_NONAT || r.action == PF_NORDR) { - if (yystack.l_mark[-1].v.redirection != NULL) { - yyerror("translation rule with 'no' " - "does not need '->'"); - YYERROR; - } - } else { - if (yystack.l_mark[-1].v.redirection == NULL || yystack.l_mark[-1].v.redirection->host == NULL) { - yyerror("translation rule requires '-> " - "address'"); - YYERROR; - } - if (!r.af && ! yystack.l_mark[-1].v.redirection->host->ifindex) - r.af = yystack.l_mark[-1].v.redirection->host->af; - - remove_invalid_hosts(&yystack.l_mark[-1].v.redirection->host, &r.af); - if (invalid_redirect(yystack.l_mark[-1].v.redirection->host, r.af)) - YYERROR; - if (check_netmask(yystack.l_mark[-1].v.redirection->host, r.af)) - YYERROR; - - r.rpool.proxy_port[0] = ntohs(yystack.l_mark[-1].v.redirection->rport.a); - - switch (r.action) { - case PF_RDR: - if (!yystack.l_mark[-1].v.redirection->rport.b && yystack.l_mark[-1].v.redirection->rport.t && - yystack.l_mark[-5].v.fromto.dst.port != NULL) { - r.rpool.proxy_port[1] = - ntohs(yystack.l_mark[-1].v.redirection->rport.a) + - (ntohs( - yystack.l_mark[-5].v.fromto.dst.port->port[1]) - - ntohs( - yystack.l_mark[-5].v.fromto.dst.port->port[0])); - } else - r.rpool.proxy_port[1] = - ntohs(yystack.l_mark[-1].v.redirection->rport.b); - break; - case PF_NAT: - r.rpool.proxy_port[1] = - ntohs(yystack.l_mark[-1].v.redirection->rport.b); - if (!r.rpool.proxy_port[0] && - !r.rpool.proxy_port[1]) { - r.rpool.proxy_port[0] = - PF_NAT_PROXY_PORT_LOW; - r.rpool.proxy_port[1] = - PF_NAT_PROXY_PORT_HIGH; - } else if (!r.rpool.proxy_port[1]) - r.rpool.proxy_port[1] = - r.rpool.proxy_port[0]; - break; - default: - break; - } - - r.rpool.opts = yystack.l_mark[0].v.pool_opts.type; - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && (yystack.l_mark[-1].v.redirection->host->next != NULL || - yystack.l_mark[-1].v.redirection->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR(yystack.l_mark[-1].v.redirection->host->addr))) - r.rpool.opts = PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table(yystack.l_mark[-1].v.redirection->host, "tables are only " - "supported in round-robin redirection " - "pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias(yystack.l_mark[-1].v.redirection->host, "interface (%s) " - "is only supported in round-robin " - "redirection pools")) - YYERROR; - if (yystack.l_mark[-1].v.redirection->host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("only round-robin " - "valid for multiple " - "redirection addresses"); - YYERROR; - } - } - } - - if (yystack.l_mark[0].v.pool_opts.key != NULL) - memcpy(&r.rpool.key, yystack.l_mark[0].v.pool_opts.key, - sizeof(struct pf_poolhashkey)); - - if (yystack.l_mark[0].v.pool_opts.opts) - r.rpool.opts |= yystack.l_mark[0].v.pool_opts.opts; - - if (yystack.l_mark[0].v.pool_opts.staticport) { - if (r.action != PF_NAT) { - yyerror("the 'static-port' option is " - "only valid with nat rules"); - YYERROR; - } - if (r.rpool.proxy_port[0] != - PF_NAT_PROXY_PORT_LOW && - r.rpool.proxy_port[1] != - PF_NAT_PROXY_PORT_HIGH) { - yyerror("the 'static-port' option can't" - " be used when specifying a port" - " range"); - YYERROR; - } - r.rpool.proxy_port[0] = 0; - r.rpool.proxy_port[1] = 0; - } - - expand_rule(&r, yystack.l_mark[-8].v.interface, yystack.l_mark[-1].v.redirection == NULL ? NULL : yystack.l_mark[-1].v.redirection->host, yystack.l_mark[-6].v.proto, - yystack.l_mark[-5].v.fromto.src_os, yystack.l_mark[-5].v.fromto.src.host, yystack.l_mark[-5].v.fromto.src.port, yystack.l_mark[-5].v.fromto.dst.host, - yystack.l_mark[-5].v.fromto.dst.port, 0, 0, 0, ""); - free(yystack.l_mark[-1].v.redirection); - } -break; -case 384: -#line 4074 "../../freebsd/contrib/pf/pfctl/parse.y" - { - struct pf_rule binat; - struct pf_pooladdr *pa; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - if (disallow_urpf_failed(yystack.l_mark[-4].v.host, "\"urpf-failed\" is not " - "permitted as a binat destination")) - YYERROR; - - memset(&binat, 0, sizeof(binat)); - - if (yystack.l_mark[-12].v.i && yystack.l_mark[-10].v.b.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if (yystack.l_mark[-12].v.i) - binat.action = PF_NOBINAT; - else - binat.action = PF_BINAT; - binat.natpass = yystack.l_mark[-10].v.b.b1; - binat.log = yystack.l_mark[-10].v.b.b2; - binat.logif = yystack.l_mark[-10].v.b.w2; - binat.af = yystack.l_mark[-8].v.i; - if (!binat.af && yystack.l_mark[-5].v.host != NULL && yystack.l_mark[-5].v.host->af) - binat.af = yystack.l_mark[-5].v.host->af; - if (!binat.af && yystack.l_mark[-4].v.host != NULL && yystack.l_mark[-4].v.host->af) - binat.af = yystack.l_mark[-4].v.host->af; - - if (!binat.af && yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host) - binat.af = yystack.l_mark[0].v.redirection->host->af; - if (!binat.af) { - yyerror("address family (inet/inet6) " - "undefined"); - YYERROR; - } - - if (yystack.l_mark[-9].v.interface != NULL) { - memcpy(binat.ifname, yystack.l_mark[-9].v.interface->ifname, - sizeof(binat.ifname)); - binat.ifnot = yystack.l_mark[-9].v.interface->not; - free(yystack.l_mark[-9].v.interface); - } - - if (yystack.l_mark[-3].v.string != NULL) - if (strlcpy(binat.tagname, yystack.l_mark[-3].v.string, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if (yystack.l_mark[-2].v.tagged.name) - if (strlcpy(binat.match_tagname, yystack.l_mark[-2].v.tagged.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - binat.match_tag_not = yystack.l_mark[-2].v.tagged.neg; - binat.rtableid = yystack.l_mark[-1].v.rtableid; - - if (yystack.l_mark[-7].v.proto != NULL) { - binat.proto = yystack.l_mark[-7].v.proto->proto; - free(yystack.l_mark[-7].v.proto); - } - - if (yystack.l_mark[-5].v.host != NULL && disallow_table(yystack.l_mark[-5].v.host, "invalid use of " - "table <%s> as the source address of a binat rule")) - YYERROR; - if (yystack.l_mark[-5].v.host != NULL && disallow_alias(yystack.l_mark[-5].v.host, "invalid use of " - "interface (%s) as the source address of a binat " - "rule")) - YYERROR; - if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_table( - yystack.l_mark[0].v.redirection->host, "invalid use of table <%s> as the " - "redirect address of a binat rule")) - YYERROR; - if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_alias( - yystack.l_mark[0].v.redirection->host, "invalid use of interface (%s) as the " - "redirect address of a binat rule")) - YYERROR; - - if (yystack.l_mark[-5].v.host != NULL) { - if (yystack.l_mark[-5].v.host->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if (yystack.l_mark[-5].v.host->addr.type == PF_ADDR_DYNIFTL) - yystack.l_mark[-5].v.host->af = binat.af; - if (yystack.l_mark[-5].v.host->af != binat.af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask(yystack.l_mark[-5].v.host, binat.af)) - YYERROR; - memcpy(&binat.src.addr, &yystack.l_mark[-5].v.host->addr, - sizeof(binat.src.addr)); - free(yystack.l_mark[-5].v.host); - } - if (yystack.l_mark[-4].v.host != NULL) { - if (yystack.l_mark[-4].v.host->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if (yystack.l_mark[-4].v.host->af != binat.af && yystack.l_mark[-4].v.host->af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask(yystack.l_mark[-4].v.host, binat.af)) - YYERROR; - memcpy(&binat.dst.addr, &yystack.l_mark[-4].v.host->addr, - sizeof(binat.dst.addr)); - binat.dst.neg = yystack.l_mark[-4].v.host->not; - free(yystack.l_mark[-4].v.host); - } - - if (binat.action == PF_NOBINAT) { - if (yystack.l_mark[0].v.redirection != NULL) { - yyerror("'no binat' rule does not need" - " '->'"); - YYERROR; - } - } else { - if (yystack.l_mark[0].v.redirection == NULL || yystack.l_mark[0].v.redirection->host == NULL) { - yyerror("'binat' rule requires" - " '-> address'"); - YYERROR; - } - - remove_invalid_hosts(&yystack.l_mark[0].v.redirection->host, &binat.af); - if (invalid_redirect(yystack.l_mark[0].v.redirection->host, binat.af)) - YYERROR; - if (yystack.l_mark[0].v.redirection->host->next != NULL) { - yyerror("binat rule must redirect to " - "a single address"); - YYERROR; - } - if (check_netmask(yystack.l_mark[0].v.redirection->host, binat.af)) - YYERROR; - - if (!PF_AZERO(&binat.src.addr.v.a.mask, - binat.af) && - !PF_AEQ(&binat.src.addr.v.a.mask, - &yystack.l_mark[0].v.redirection->host->addr.v.a.mask, binat.af)) { - yyerror("'binat' source mask and " - "redirect mask must be the same"); - YYERROR; - } - - TAILQ_INIT(&binat.rpool.list); - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "binat: calloc"); - pa->addr = yystack.l_mark[0].v.redirection->host->addr; - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&binat.rpool.list, - pa, entries); - - free(yystack.l_mark[0].v.redirection); - } - - pfctl_add_rule(pf, &binat, ""); - } -break; -case 385: -#line 4239 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.string = NULL; } -break; -case 386: -#line 4240 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.string = yystack.l_mark[0].v.string; } -break; -case 387: -#line 4243 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.tagged.neg = 0; yyval.v.tagged.name = NULL; } -break; -case 388: -#line 4244 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.tagged.neg = yystack.l_mark[-2].v.number; yyval.v.tagged.name = yystack.l_mark[0].v.string; } -break; -case 389: -#line 4247 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.rtableid = -1; } -break; -case 390: -#line 4248 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - yyval.v.rtableid = yystack.l_mark[0].v.number; - } -break; -case 391: -#line 4257 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.host = calloc(1, sizeof(struct node_host)); - if (yyval.v.host == NULL) - err(1, "route_host: calloc"); - yyval.v.host->ifname = yystack.l_mark[0].v.string; - set_ipmask(yyval.v.host, 128); - yyval.v.host->next = NULL; - yyval.v.host->tail = yyval.v.host; - } -break; -case 392: -#line 4266 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.host = yystack.l_mark[-1].v.host; - yyval.v.host->ifname = yystack.l_mark[-2].v.string; - } -break; -case 393: -#line 4272 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 394: -#line 4273 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (yystack.l_mark[-3].v.host->af == 0) - yystack.l_mark[-3].v.host->af = yystack.l_mark[-1].v.host->af; - if (yystack.l_mark[-3].v.host->af != yystack.l_mark[-1].v.host->af) { - yyerror("all pool addresses must be in the " - "same address family"); - YYERROR; - } - yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; - yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; - yyval.v.host = yystack.l_mark[-3].v.host; - } -break; -case 395: -#line 4287 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[0].v.host; } -break; -case 396: -#line 4288 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.host = yystack.l_mark[-1].v.host; } -break; -case 397: -#line 4291 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.route.host = NULL; - yyval.v.route.rt = 0; - yyval.v.route.pool_opts = 0; - } -break; -case 398: -#line 4296 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.route.host = NULL; - yyval.v.route.rt = PF_FASTROUTE; - yyval.v.route.pool_opts = 0; - } -break; -case 399: -#line 4301 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.route.host = yystack.l_mark[-1].v.host; - yyval.v.route.rt = PF_ROUTETO; - yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; - if (yystack.l_mark[0].v.pool_opts.key != NULL) - yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; - } -break; -case 400: -#line 4308 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.route.host = yystack.l_mark[-1].v.host; - yyval.v.route.rt = PF_REPLYTO; - yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; - if (yystack.l_mark[0].v.pool_opts.key != NULL) - yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; - } -break; -case 401: -#line 4315 "../../freebsd/contrib/pf/pfctl/parse.y" - { - yyval.v.route.host = yystack.l_mark[-1].v.host; - yyval.v.route.rt = PF_DUPTO; - yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; - if (yystack.l_mark[0].v.pool_opts.key != NULL) - yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; - } -break; -case 402: -#line 4325 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[-1].v.string); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_timeout(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number, 0) != 0) { - yyerror("unknown timeout %s", yystack.l_mark[-1].v.string); - free(yystack.l_mark[-1].v.string); - YYERROR; - } - free(yystack.l_mark[-1].v.string); - } -break; -case 405: -#line 4348 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free(yystack.l_mark[-1].v.string); - YYERROR; - } - if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_limit(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number) != 0) { - yyerror("unable to set limit %s %u", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number); - free(yystack.l_mark[-1].v.string); - YYERROR; - } - free(yystack.l_mark[-1].v.string); - } -break; -case 410: -#line 4374 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.number = 0; } -break; -case 411: -#line 4375 "../../freebsd/contrib/pf/pfctl/parse.y" - { - if (!strcmp(yystack.l_mark[0].v.string, "yes")) - yyval.v.number = 1; - else { - yyerror("invalid value '%s', expected 'yes' " - "or 'no'", yystack.l_mark[0].v.string); - free(yystack.l_mark[0].v.string); - YYERROR; - } - free(yystack.l_mark[0].v.string); - } -break; -case 412: -#line 4388 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_EQ; } -break; -case 413: -#line 4389 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_NE; } -break; -case 414: -#line 4390 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_LE; } -break; -case 415: -#line 4391 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_LT; } -break; -case 416: -#line 4392 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_GE; } -break; -case 417: -#line 4393 "../../freebsd/contrib/pf/pfctl/parse.y" - { yyval.v.i = PF_OP_GT; } -break; -#line 8955 "pfctly.tab.c" - } - yystack.s_mark -= yym; - yystate = *yystack.s_mark; - yystack.l_mark -= yym; - yym = yylhs[yyn]; - if (yystate == 0 && yym == 0) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - yystate = YYFINAL; - *++yystack.s_mark = YYFINAL; - *++yystack.l_mark = yyval; - if (yychar < 0) - { - if ((yychar = YYLEX) < 0) yychar = YYEOF; -#if YYDEBUG - if (yydebug) - { - yys = yyname[YYTRANSLATE(yychar)]; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, yychar, yys); - } -#endif - } - if (yychar == YYEOF) goto yyaccept; - goto yyloop; - } - if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yystate) - yystate = yytable[yyn]; - else - yystate = yydgoto[yym]; -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yystack.s_mark, yystate); -#endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) - { - goto yyoverflow; - } - *++yystack.s_mark = (YYINT) yystate; - *++yystack.l_mark = yyval; - goto yyloop; - -yyoverflow: - YYERROR_CALL("yacc stack overflow"); - -yyabort: - yyfreestack(&yystack); - return (1); - -yyaccept: - yyfreestack(&yystack); - return (0); -} diff --git a/freebsd/contrib/pf/pfctl/parse.y b/freebsd/contrib/pf/pfctl/parse.y deleted file mode 100644 index df865066..00000000 --- a/freebsd/contrib/pf/pfctl/parse.y +++ /dev/null @@ -1,6139 +0,0 @@ -/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ - -/* - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. - * Copyright (c) 2001 Theo de Raadt. All rights reserved. - * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -%{ -#ifdef __rtems__ -#include <machine/rtems-bsd-user-space.h> -#include <machine/rtems-bsd-program.h> -#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset -#define pf_anchor_setup _bsd_pf_anchor_setup -#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#ifdef __FreeBSD__ -#include <sys/sysctl.h> -#endif -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <netdb.h> -#include <stdarg.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include <err.h> -#include <limits.h> -#include <pwd.h> -#include <grp.h> -#include <md5.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -static struct pfctl *pf = NULL; -static int debug = 0; -static int rulestate = 0; -static u_int16_t returnicmpdefault = - (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; -static u_int16_t returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; -static int blockpolicy = PFRULE_DROP; -static int require_order = 1; -static int default_statelock; - -#ifndef __rtems__ -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -#else /* __rtems__ */ -static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -#endif /* __rtems__ */ -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - int lineno; - int errors; -} *file; -struct file *pushfile(const char *, int); -int popfile(void); -int check_file_secrecy(int, const char *); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...); -int kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(int); -int lungetc(int); -int findeol(void); - -#ifndef __rtems__ -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -#else /* __rtems__ */ -static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -#endif /* __rtems__ */ -struct sym { - TAILQ_ENTRY(sym) entry; - int used; - int persist; - char *nam; - char *val; -}; -int symset(const char *, const char *, int); -char *symget(const char *); - -int atoul(char *, u_long *); - -enum { - PFCTL_STATE_NONE, - PFCTL_STATE_OPTION, - PFCTL_STATE_SCRUB, - PFCTL_STATE_QUEUE, - PFCTL_STATE_NAT, - PFCTL_STATE_FILTER -}; - -struct node_proto { - u_int8_t proto; - struct node_proto *next; - struct node_proto *tail; -}; - -struct node_port { - u_int16_t port[2]; - u_int8_t op; - struct node_port *next; - struct node_port *tail; -}; - -struct node_uid { - uid_t uid[2]; - u_int8_t op; - struct node_uid *next; - struct node_uid *tail; -}; - -struct node_gid { - gid_t gid[2]; - u_int8_t op; - struct node_gid *next; - struct node_gid *tail; -}; - -struct node_icmp { - u_int8_t code; - u_int8_t type; - u_int8_t proto; - struct node_icmp *next; - struct node_icmp *tail; -}; - -enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, - PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, - PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, - PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, - PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, - PF_STATE_OPT_PFLOW }; - -enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; - -struct node_state_opt { - int type; - union { - u_int32_t max_states; - u_int32_t max_src_states; - u_int32_t max_src_conn; - struct { - u_int32_t limit; - u_int32_t seconds; - } max_src_conn_rate; - struct { - u_int8_t flush; - char tblname[PF_TABLE_NAME_SIZE]; - } overload; - u_int32_t max_src_nodes; - u_int8_t src_track; - u_int32_t statelock; - struct { - int number; - u_int32_t seconds; - } timeout; - } data; - struct node_state_opt *next; - struct node_state_opt *tail; -}; - -struct peer { - struct node_host *host; - struct node_port *port; -}; - -#ifndef __rtems__ -struct node_queue { -#else /* __rtems__ */ -static struct node_queue { -#endif /* __rtems__ */ - char queue[PF_QNAME_SIZE]; - char parent[PF_QNAME_SIZE]; - char ifname[IFNAMSIZ]; - int scheduler; - struct node_queue *next; - struct node_queue *tail; -} *queues = NULL; - -struct node_qassign { - char *qname; - char *pqname; -}; - -#ifndef __rtems__ -struct filter_opts { -#else /* __rtems__ */ -static struct filter_opts { -#endif /* __rtems__ */ - int marker; -#define FOM_FLAGS 0x01 -#define FOM_ICMP 0x02 -#define FOM_TOS 0x04 -#define FOM_KEEP 0x08 -#define FOM_SRCTRACK 0x10 - struct node_uid *uid; - struct node_gid *gid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } flags; - struct node_icmp *icmpspec; - u_int32_t tos; - u_int32_t prob; - struct { - int action; - struct node_state_opt *options; - } keep; - int fragment; - int allowopts; - char *label; - struct node_qassign queues; - char *tag; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; - struct { - struct node_host *addr; - u_int16_t port; - } divert; -} filter_opts; - -#ifndef __rtems__ -struct antispoof_opts { -#else /* __rtems__ */ -static struct antispoof_opts { -#endif /* __rtems__ */ - char *label; - u_int rtableid; -} antispoof_opts; - -#ifndef __rtems__ -struct scrub_opts { -#else /* __rtems__ */ -static struct scrub_opts { -#endif /* __rtems__ */ - int marker; -#define SOM_MINTTL 0x01 -#define SOM_MAXMSS 0x02 -#define SOM_FRAGCACHE 0x04 -#define SOM_SETTOS 0x08 - int nodf; - int minttl; - int maxmss; - int settos; - int fragcache; - int randomid; - int reassemble_tcp; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; -} scrub_opts; - -#ifndef __rtems__ -struct queue_opts { -#else /* __rtems__ */ -static struct queue_opts { -#endif /* __rtems__ */ - int marker; -#define QOM_BWSPEC 0x01 -#define QOM_SCHEDULER 0x02 -#define QOM_PRIORITY 0x04 -#define QOM_TBRSIZE 0x08 -#define QOM_QLIMIT 0x10 - struct node_queue_bw queue_bwspec; - struct node_queue_opt scheduler; - int priority; - int tbrsize; - int qlimit; -} queue_opts; - -#ifndef __rtems__ -struct table_opts { -#else /* __rtems__ */ -static struct table_opts { -#endif /* __rtems__ */ - int flags; - int init_addr; - struct node_tinithead init_nodes; -} table_opts; - -#ifndef __rtems__ -struct pool_opts { -#else /* __rtems__ */ -static struct pool_opts { -#endif /* __rtems__ */ - int marker; -#define POM_TYPE 0x01 -#define POM_STICKYADDRESS 0x02 - u_int8_t opts; - int type; - int staticport; - struct pf_poolhashkey *key; - -} pool_opts; - - -#ifndef __rtems__ -struct node_hfsc_opts hfsc_opts; -struct node_state_opt *keep_state_defaults = NULL; -#else /* __rtems__ */ -static struct node_hfsc_opts hfsc_opts; -static struct node_state_opt *keep_state_defaults = NULL; -#endif /* __rtems__ */ - -int disallow_table(struct node_host *, const char *); -int disallow_urpf_failed(struct node_host *, const char *); -int disallow_alias(struct node_host *, const char *); -int rule_consistent(struct pf_rule *, int); -int filter_consistent(struct pf_rule *, int); -int nat_consistent(struct pf_rule *); -int rdr_consistent(struct pf_rule *); -int process_tabledef(char *, struct table_opts *); -void expand_label_str(char *, size_t, const char *, const char *); -void expand_label_if(const char *, char *, size_t, const char *); -void expand_label_addr(const char *, char *, size_t, u_int8_t, - struct node_host *); -void expand_label_port(const char *, char *, size_t, - struct node_port *); -void expand_label_proto(const char *, char *, size_t, u_int8_t); -void expand_label_nr(const char *, char *, size_t); -void expand_label(char *, size_t, const char *, u_int8_t, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, u_int8_t); -void expand_rule(struct pf_rule *, struct node_if *, - struct node_host *, struct node_proto *, struct node_os *, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, struct node_uid *, struct node_gid *, - struct node_icmp *, const char *); -int expand_altq(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw bwspec, - struct node_queue_opt *); -int expand_queue(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw, - struct node_queue_opt *); -int expand_skip_interface(struct node_if *); - -int check_rulestate(int); -int getservice(char *); -int rule_label(struct pf_rule *, char *); -int rt_tableid_max(void); - -void mv_rules(struct pf_ruleset *, struct pf_ruleset *); -void decide_address_family(struct node_host *, sa_family_t *); -void remove_invalid_hosts(struct node_host **, sa_family_t *); -int invalid_redirect(struct node_host *, sa_family_t); -u_int16_t parseicmpspec(char *, sa_family_t); - -#ifndef __rtems__ -TAILQ_HEAD(loadanchorshead, loadanchors) -#else /* __rtems__ */ -static TAILQ_HEAD(loadanchorshead, loadanchors) -#endif /* __rtems__ */ - loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); - -struct loadanchors { - TAILQ_ENTRY(loadanchors) entries; - char *anchorname; - char *filename; -}; - -typedef struct { - union { - int64_t number; - double probability; - int i; - char *string; - u_int rtableid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } b; - struct range { - int a; - int b; - int t; - } range; - struct node_if *interface; - struct node_proto *proto; - struct node_icmp *icmp; - struct node_host *host; - struct node_os *os; - struct node_port *port; - struct node_uid *uid; - struct node_gid *gid; - struct node_state_opt *state_opt; - struct peer peer; - struct { - struct peer src, dst; - struct node_os *src_os; - } fromto; - struct { - struct node_host *host; - u_int8_t rt; - u_int8_t pool_opts; - sa_family_t af; - struct pf_poolhashkey *key; - } route; - struct redirection { - struct node_host *host; - struct range rport; - } *redirection; - struct { - int action; - struct node_state_opt *options; - } keep_state; - struct { - u_int8_t log; - u_int8_t logif; - u_int8_t quick; - } logquick; - struct { - int neg; - char *name; - } tagged; - struct pf_poolhashkey *hashkey; - struct node_queue *queue; - struct node_queue_opt queue_options; - struct node_queue_bw queue_bwspec; - struct node_qassign qassign; - struct filter_opts filter_opts; - struct antispoof_opts antispoof_opts; - struct queue_opts queue_opts; - struct scrub_opts scrub_opts; - struct table_opts table_opts; - struct pool_opts pool_opts; - struct node_hfsc_opts hfsc_opts; - } v; - int lineno; -} YYSTYPE; - -#define PPORT_RANGE 1 -#define PPORT_STAR 2 -int parseport(char *, struct range *r, int); - -#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ - (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ - !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) - -%} - -%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS -%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE -%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF -%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL -%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE -%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR -%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID -%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID -%token ANTISPOOF FOR INCLUDE -%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY -%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT -%token QUEUE PRIORITY QLIMIT RTABLE -%token LOAD RULESET_OPTIMIZATION -%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE -%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW -%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS -%token DIVERTTO DIVERTREPLY -%token <v.string> STRING -%token <v.number> NUMBER -%token <v.i> PORTBINARY -%type <v.interface> interface if_list if_item_not if_item -%type <v.number> number icmptype icmp6type uid gid -%type <v.number> tos not yesno -%type <v.probability> probability -%type <v.i> no dir af fragcache optimizer -%type <v.i> sourcetrack flush unaryop statelock -%type <v.b> action nataction natpasslog scrubaction -%type <v.b> flags flag blockspec -%type <v.range> portplain portstar portrange -%type <v.hashkey> hashkey -%type <v.proto> proto proto_list proto_item -%type <v.number> protoval -%type <v.icmp> icmpspec -%type <v.icmp> icmp_list icmp_item -%type <v.icmp> icmp6_list icmp6_item -%type <v.number> reticmpspec reticmp6spec -%type <v.fromto> fromto -%type <v.peer> ipportspec from to -%type <v.host> ipspec toipspec xhost host dynaddr host_list -%type <v.host> redir_host_list redirspec -%type <v.host> route_host route_host_list routespec -%type <v.os> os xos os_list -%type <v.port> portspec port_list port_item -%type <v.uid> uids uid_list uid_item -%type <v.gid> gids gid_list gid_item -%type <v.route> route -%type <v.redirection> redirection redirpool -%type <v.string> label stringall tag anchorname -%type <v.string> string varstring numberstring -%type <v.keep_state> keep -%type <v.state_opt> state_opt_spec state_opt_list state_opt_item -%type <v.logquick> logquick quick log logopts logopt -%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if -%type <v.qassign> qname -%type <v.queue> qassign qassign_list qassign_item -%type <v.queue_options> scheduler -%type <v.number> cbqflags_list cbqflags_item -%type <v.number> priqflags_list priqflags_item -%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts -%type <v.queue_bwspec> bandwidth -%type <v.filter_opts> filter_opts filter_opt filter_opts_l -%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l -%type <v.queue_opts> queue_opts queue_opt queue_opts_l -%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l -%type <v.table_opts> table_opts table_opt table_opts_l -%type <v.pool_opts> pool_opts pool_opt pool_opts_l -%type <v.tagged> tagged -%type <v.rtableid> rtable -%% - -ruleset : /* empty */ - | ruleset include '\n' - | ruleset '\n' - | ruleset option '\n' - | ruleset scrubrule '\n' - | ruleset natrule '\n' - | ruleset binatrule '\n' - | ruleset pfrule '\n' - | ruleset anchorrule '\n' - | ruleset loadrule '\n' - | ruleset altqif '\n' - | ruleset queuespec '\n' - | ruleset varset '\n' - | ruleset antispoof '\n' - | ruleset tabledef '\n' - | '{' fakeanchor '}' '\n'; - | ruleset error '\n' { file->errors++; } - ; - -include : INCLUDE STRING { - struct file *nfile; - - if ((nfile = pushfile($2, 0)) == NULL) { - yyerror("failed to include file %s", $2); - free($2); - YYERROR; - } - free($2); - - file = nfile; - lungetc('\n'); - } - ; - -/* - * apply to previouslys specified rule: must be careful to note - * what that is: pf or nat or binat or rdr - */ -fakeanchor : fakeanchor '\n' - | fakeanchor anchorrule '\n' - | fakeanchor binatrule '\n' - | fakeanchor natrule '\n' - | fakeanchor pfrule '\n' - | fakeanchor error '\n' - ; - -optimizer : string { - if (!strcmp($1, "none")) - $$ = 0; - else if (!strcmp($1, "basic")) - $$ = PF_OPTIMIZE_BASIC; - else if (!strcmp($1, "profile")) - $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; - else { - yyerror("unknown ruleset-optimization %s", $1); - YYERROR; - } - } - ; - -option : SET OPTIMIZATION STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_optimization(pf, $3) != 0) { - yyerror("unknown optimization %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET RULESET_OPTIMIZATION optimizer { - if (!(pf->opts & PF_OPT_OPTIMIZE)) { - pf->opts |= PF_OPT_OPTIMIZE; - pf->optimize = $3; - } - } - | SET TIMEOUT timeout_spec - | SET TIMEOUT '{' optnl timeout_list '}' - | SET LIMIT limit_spec - | SET LIMIT '{' optnl limit_list '}' - | SET LOGINTERFACE stringall { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_logif(pf, $3) != 0) { - yyerror("error setting loginterface %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET HOSTID number { - if ($3 == 0 || $3 > UINT_MAX) { - yyerror("hostid must be non-zero"); - YYERROR; - } - if (pfctl_set_hostid(pf, $3) != 0) { - yyerror("error setting hostid %08x", $3); - YYERROR; - } - } - | SET BLOCKPOLICY DROP { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy drop\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_DROP; - } - | SET BLOCKPOLICY RETURN { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy return\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_RETURN; - } - | SET REQUIREORDER yesno { - if (pf->opts & PF_OPT_VERBOSE) - printf("set require-order %s\n", - $3 == 1 ? "yes" : "no"); - require_order = $3; - } - | SET FINGERPRINTS STRING { - if (pf->opts & PF_OPT_VERBOSE) - printf("set fingerprints \"%s\"\n", $3); - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (!pf->anchor->name[0]) { - if (pfctl_file_fingerprints(pf->dev, - pf->opts, $3)) { - yyerror("error loading " - "fingerprints %s", $3); - free($3); - YYERROR; - } - } - free($3); - } - | SET STATEPOLICY statelock { - if (pf->opts & PF_OPT_VERBOSE) - switch ($3) { - case 0: - printf("set state-policy floating\n"); - break; - case PFRULE_IFBOUND: - printf("set state-policy if-bound\n"); - break; - } - default_statelock = $3; - } - | SET DEBUG STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_debug(pf, $3) != 0) { - yyerror("error setting debuglevel %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET SKIP interface { - if (expand_skip_interface($3) != 0) { - yyerror("error setting skip interface(s)"); - YYERROR; - } - } - | SET STATEDEFAULTS state_opt_list { - if (keep_state_defaults != NULL) { - yyerror("cannot redefine state-defaults"); - YYERROR; - } - keep_state_defaults = $3; - } - ; - -stringall : STRING { $$ = $1; } - | ALL { - if (($$ = strdup("all")) == NULL) { - err(1, "stringall: strdup"); - } - } - ; - -string : STRING string { - if (asprintf(&$$, "%s %s", $1, $2) == -1) - err(1, "string: asprintf"); - free($1); - free($2); - } - | STRING - ; - -varstring : numberstring varstring { - if (asprintf(&$$, "%s %s", $1, $2) == -1) - err(1, "string: asprintf"); - free($1); - free($2); - } - | numberstring - ; - -numberstring : NUMBER { - char *s; - if (asprintf(&s, "%lld", (long long)$1) == -1) { - yyerror("string: asprintf"); - YYERROR; - } - $$ = s; - } - | STRING - ; - -varset : STRING '=' varstring { - if (pf->opts & PF_OPT_VERBOSE) - printf("%s = \"%s\"\n", $1, $3); - if (symset($1, $3, 0) == -1) - err(1, "cannot store variable %s", $1); - free($1); - free($3); - } - ; - -anchorname : STRING { $$ = $1; } - | /* empty */ { $$ = NULL; } - ; - -pfa_anchorlist : /* empty */ - | pfa_anchorlist '\n' - | pfa_anchorlist pfrule '\n' - | pfa_anchorlist anchorrule '\n' - ; - -pfa_anchor : '{' - { - char ta[PF_ANCHOR_NAME_SIZE]; - struct pf_ruleset *rs; - - /* steping into a brace anchor */ - pf->asd++; - pf->bn++; - pf->brace = 1; - - /* create a holding ruleset in the root */ - snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); - rs = pf_find_or_create_ruleset(ta); - if (rs == NULL) - err(1, "pfa_anchor: pf_find_or_create_ruleset"); - pf->astack[pf->asd] = rs->anchor; - pf->anchor = rs->anchor; - } '\n' pfa_anchorlist '}' - { - pf->alast = pf->anchor; - pf->asd--; - pf->anchor = pf->astack[pf->asd]; - } - | /* empty */ - ; - -anchorrule : ANCHOR anchorname dir quick interface af proto fromto - filter_opts pfa_anchor - { - struct pf_rule r; - struct node_proto *proto; - - if (check_rulestate(PFCTL_STATE_FILTER)) { - if ($2) - free($2); - YYERROR; - } - - if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { - free($2); - yyerror("anchor names beginning with '_' " - "are reserved for internal use"); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - if (pf->astack[pf->asd + 1]) { - /* move inline rules into relative location */ - pf_anchor_setup(&r, - &pf->astack[pf->asd]->ruleset, - $2 ? $2 : pf->alast->name); - - if (r.anchor == NULL) - err(1, "anchorrule: unable to " - "create ruleset"); - - if (pf->alast != r.anchor) { - if (r.anchor->match) { - yyerror("inline anchor '%s' " - "already exists", - r.anchor->name); - YYERROR; - } - mv_rules(&pf->alast->ruleset, - &r.anchor->ruleset); - } - pf_remove_if_empty_ruleset(&pf->alast->ruleset); - pf->alast = r.anchor; - } else { - if (!$2) { - yyerror("anchors without explicit " - "rules must specify a name"); - YYERROR; - } - } - r.direction = $3; - r.quick = $4.quick; - r.af = $6; - r.prob = $9.prob; - r.rtableid = $9.rtableid; - - if ($9.tag) - if (strlcpy(r.tagname, $9.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - if (rule_label(&r, $9.label)) - YYERROR; - free($9.label); - r.flags = $9.flags.b1; - r.flagset = $9.flags.b2; - if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { - for (proto = $7; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && $7 != NULL) { - if ($9.flags.b1 || $9.flags.b2) - yyerror( - "flags only apply to tcp"); - if ($8.src_os) - yyerror( - "OS fingerprinting only " - "applies to tcp"); - YYERROR; - } - } - - r.tos = $9.tos; - - if ($9.keep.action) { - yyerror("cannot specify state handling " - "on anchors"); - YYERROR; - } - - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - - decide_address_family($8.src.host, &r.af); - decide_address_family($8.dst.host, &r.af); - - expand_rule(&r, $5, NULL, $7, $8.src_os, - $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - $9.uid, $9.gid, $9.icmpspec, - pf->astack[pf->asd + 1] ? pf->alast->name : $2); - free($2); - pf->astack[pf->asd + 1] = NULL; - } - | NATANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_NAT; - r.af = $4; - r.rtableid = $7; - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - expand_rule(&r, $3, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, $2); - free($2); - } - | RDRANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_RDR; - r.af = $4; - r.rtableid = $7; - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - if ($6.src.port != NULL) { - yyerror("source port parameter not supported" - " in rdr-anchor"); - YYERROR; - } - if ($6.dst.port != NULL) { - if ($6.dst.port->next != NULL) { - yyerror("destination port list " - "expansion not supported in " - "rdr-anchor"); - YYERROR; - } else if ($6.dst.port->op != PF_OP_EQ) { - yyerror("destination port operators" - " not supported in rdr-anchor"); - YYERROR; - } - r.dst.port[0] = $6.dst.port->port[0]; - r.dst.port[1] = $6.dst.port->port[1]; - r.dst.port_op = $6.dst.port->op; - } - - expand_rule(&r, $3, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, $2); - free($2); - } - | BINATANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_BINAT; - r.af = $4; - r.rtableid = $7; - if ($5 != NULL) { - if ($5->next != NULL) { - yyerror("proto list expansion" - " not supported in binat-anchor"); - YYERROR; - } - r.proto = $5->proto; - free($5); - } - - if ($6.src.host != NULL || $6.src.port != NULL || - $6.dst.host != NULL || $6.dst.port != NULL) { - yyerror("fromto parameter not supported" - " in binat-anchor"); - YYERROR; - } - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - pfctl_add_rule(pf, &r, $2); - free($2); - } - ; - -loadrule : LOAD ANCHOR string FROM string { - struct loadanchors *loadanchor; - - if (strlen(pf->anchor->name) + 1 + - strlen($3) >= MAXPATHLEN) { - yyerror("anchorname %s too long, max %u\n", - $3, MAXPATHLEN - 1); - free($3); - YYERROR; - } - loadanchor = calloc(1, sizeof(struct loadanchors)); - if (loadanchor == NULL) - err(1, "loadrule: calloc"); - if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == - NULL) - err(1, "loadrule: malloc"); - if (pf->anchor->name[0]) - snprintf(loadanchor->anchorname, MAXPATHLEN, - "%s/%s", pf->anchor->name, $3); - else - strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); - if ((loadanchor->filename = strdup($5)) == NULL) - err(1, "loadrule: strdup"); - - TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, - entries); - - free($3); - free($5); - }; - -scrubaction : no SCRUB { - $$.b2 = $$.w = 0; - if ($1) - $$.b1 = PF_NOSCRUB; - else - $$.b1 = PF_SCRUB; - } - ; - -scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_SCRUB)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - r.direction = $2; - - r.log = $3.log; - r.logif = $3.logif; - if ($3.quick) { - yyerror("scrub rules do not support 'quick'"); - YYERROR; - } - - r.af = $5; - if ($8.nodf) - r.rule_flag |= PFRULE_NODF; - if ($8.randomid) - r.rule_flag |= PFRULE_RANDOMID; - if ($8.reassemble_tcp) { - if (r.direction != PF_INOUT) { - yyerror("reassemble tcp rules can not " - "specify direction"); - YYERROR; - } - r.rule_flag |= PFRULE_REASSEMBLE_TCP; - } - if ($8.minttl) - r.min_ttl = $8.minttl; - if ($8.maxmss) - r.max_mss = $8.maxmss; - if ($8.marker & SOM_SETTOS) { - r.rule_flag |= PFRULE_SET_TOS; - r.set_tos = $8.settos; - } - if ($8.fragcache) - r.rule_flag |= $8.fragcache; - if ($8.match_tag) - if (strlcpy(r.match_tagname, $8.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $8.match_tag_not; - r.rtableid = $8.rtableid; - - expand_rule(&r, $4, NULL, $6, $7.src_os, - $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, - NULL, NULL, NULL, ""); - } - ; - -scrub_opts : { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - } - scrub_opts_l - { $$ = scrub_opts; } - | /* empty */ { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - $$ = scrub_opts; - } - ; - -scrub_opts_l : scrub_opts_l scrub_opt - | scrub_opt - ; - -scrub_opt : NODF { - if (scrub_opts.nodf) { - yyerror("no-df cannot be respecified"); - YYERROR; - } - scrub_opts.nodf = 1; - } - | MINTTL NUMBER { - if (scrub_opts.marker & SOM_MINTTL) { - yyerror("min-ttl cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 255) { - yyerror("illegal min-ttl value %d", $2); - YYERROR; - } - scrub_opts.marker |= SOM_MINTTL; - scrub_opts.minttl = $2; - } - | MAXMSS NUMBER { - if (scrub_opts.marker & SOM_MAXMSS) { - yyerror("max-mss cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("illegal max-mss value %d", $2); - YYERROR; - } - scrub_opts.marker |= SOM_MAXMSS; - scrub_opts.maxmss = $2; - } - | SETTOS tos { - if (scrub_opts.marker & SOM_SETTOS) { - yyerror("set-tos cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_SETTOS; - scrub_opts.settos = $2; - } - | fragcache { - if (scrub_opts.marker & SOM_FRAGCACHE) { - yyerror("fragcache cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_FRAGCACHE; - scrub_opts.fragcache = $1; - } - | REASSEMBLE STRING { - if (strcasecmp($2, "tcp") != 0) { - yyerror("scrub reassemble supports only tcp, " - "not '%s'", $2); - free($2); - YYERROR; - } - free($2); - if (scrub_opts.reassemble_tcp) { - yyerror("reassemble tcp cannot be respecified"); - YYERROR; - } - scrub_opts.reassemble_tcp = 1; - } - | RANDOMID { - if (scrub_opts.randomid) { - yyerror("random-id cannot be respecified"); - YYERROR; - } - scrub_opts.randomid = 1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - scrub_opts.rtableid = $2; - } - | not TAGGED string { - scrub_opts.match_tag = $3; - scrub_opts.match_tag_not = $1; - } - ; - -fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } - | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; } - | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; } - ; - -antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { - struct pf_rule r; - struct node_host *h = NULL, *hh; - struct node_if *i, *j; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - for (i = $3; i; i = i->next) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = $2.log; - r.logif = $2.logif; - r.quick = $2.quick; - r.af = $4; - if (rule_label(&r, $5.label)) - YYERROR; - r.rtableid = $5.rtableid; - j = calloc(1, sizeof(struct node_if)); - if (j == NULL) - err(1, "antispoof: calloc"); - if (strlcpy(j->ifname, i->ifname, - sizeof(j->ifname)) >= sizeof(j->ifname)) { - free(j); - yyerror("interface name too long"); - YYERROR; - } - j->not = 1; - if (i->dynamic) { - h = calloc(1, sizeof(*h)); - if (h == NULL) - err(1, "address: calloc"); - h->addr.type = PF_ADDR_DYNIFTL; - set_ipmask(h, 128); - if (strlcpy(h->addr.v.ifname, i->ifname, - sizeof(h->addr.v.ifname)) >= - sizeof(h->addr.v.ifname)) { - free(h); - yyerror( - "interface name too long"); - YYERROR; - } - hh = malloc(sizeof(*hh)); - if (hh == NULL) - err(1, "address: malloc"); - bcopy(h, hh, sizeof(*hh)); - h->addr.iflags = PFI_AFLAG_NETWORK; - } else { - h = ifa_lookup(j->ifname, - PFI_AFLAG_NETWORK); - hh = NULL; - } - - if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, h, - NULL, NULL, NULL, NULL, NULL, - NULL, ""); - - if ((i->ifa_flags & IFF_LOOPBACK) == 0) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = $2.log; - r.logif = $2.logif; - r.quick = $2.quick; - r.af = $4; - if (rule_label(&r, $5.label)) - YYERROR; - r.rtableid = $5.rtableid; - if (hh != NULL) - h = hh; - else - h = ifa_lookup(i->ifname, 0); - if (h != NULL) - expand_rule(&r, NULL, NULL, - NULL, NULL, h, NULL, NULL, - NULL, NULL, NULL, NULL, ""); - } else - free(hh); - } - free($5.label); - } - ; - -antispoof_ifspc : FOR antispoof_if { $$ = $2; } - | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } - ; - -antispoof_iflst : antispoof_if optnl { $$ = $1; } - | antispoof_iflst comma antispoof_if optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -antispoof_if : if_item { $$ = $1; } - | '(' if_item ')' { - $2->dynamic = 1; - $$ = $2; - } - ; - -antispoof_opts : { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - } - antispoof_opts_l - { $$ = antispoof_opts; } - | /* empty */ { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - $$ = antispoof_opts; - } - ; - -antispoof_opts_l : antispoof_opts_l antispoof_opt - | antispoof_opt - ; - -antispoof_opt : label { - if (antispoof_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - antispoof_opts.label = $1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - antispoof_opts.rtableid = $2; - } - ; - -not : '!' { $$ = 1; } - | /* empty */ { $$ = 0; } - ; - -tabledef : TABLE '<' STRING '>' table_opts { - struct node_host *h, *nh; - struct node_tinit *ti, *nti; - - if (strlen($3) >= PF_TABLE_NAME_SIZE) { - yyerror("table name too long, max %d chars", - PF_TABLE_NAME_SIZE - 1); - free($3); - YYERROR; - } - if (pf->loadopt & PFCTL_FLAG_TABLE) - if (process_tabledef($3, &$5)) { - free($3); - YYERROR; - } - free($3); - for (ti = SIMPLEQ_FIRST(&$5.init_nodes); - ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { - if (ti->file) - free(ti->file); - for (h = ti->host; h != NULL; h = nh) { - nh = h->next; - free(h); - } - nti = SIMPLEQ_NEXT(ti, entries); - free(ti); - } - } - ; - -table_opts : { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - } - table_opts_l - { $$ = table_opts; } - | /* empty */ - { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - $$ = table_opts; - } - ; - -table_opts_l : table_opts_l table_opt - | table_opt - ; - -table_opt : STRING { - if (!strcmp($1, "const")) - table_opts.flags |= PFR_TFLAG_CONST; - else if (!strcmp($1, "persist")) - table_opts.flags |= PFR_TFLAG_PERSIST; - else if (!strcmp($1, "counters")) - table_opts.flags |= PFR_TFLAG_COUNTERS; - else { - yyerror("invalid table option '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - | '{' optnl '}' { table_opts.init_addr = 1; } - | '{' optnl host_list '}' { - struct node_host *n; - struct node_tinit *ti; - - for (n = $3; n != NULL; n = n->next) { - switch (n->addr.type) { - case PF_ADDR_ADDRMASK: - continue; /* ok */ - case PF_ADDR_RANGE: - yyerror("address ranges are not " - "permitted inside tables"); - break; - case PF_ADDR_DYNIFTL: - yyerror("dynamic addresses are not " - "permitted inside tables"); - break; - case PF_ADDR_TABLE: - yyerror("tables cannot contain tables"); - break; - case PF_ADDR_NOROUTE: - yyerror("\"no-route\" is not permitted " - "inside tables"); - break; - case PF_ADDR_URPFFAILED: - yyerror("\"urpf-failed\" is not " - "permitted inside tables"); - break; - default: - yyerror("unknown address type %d", - n->addr.type); - } - YYERROR; - } - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->host = $3; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } - | FILENAME STRING { - struct node_tinit *ti; - - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->file = $2; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } - ; - -altqif : ALTQ interface queue_opts QUEUE qassign { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) - YYERROR; - - memset(&a, 0, sizeof(a)); - if ($3.scheduler.qtype == ALTQT_NONE) { - yyerror("no scheduler specified!"); - YYERROR; - } - a.scheduler = $3.scheduler.qtype; - a.qlimit = $3.qlimit; - a.tbrsize = $3.tbrsize; - if ($5 == NULL) { - yyerror("no child queues specified"); - YYERROR; - } - if (expand_altq(&a, $2, $5, $3.queue_bwspec, - &$3.scheduler)) - YYERROR; - } - ; - -queuespec : QUEUE STRING interface queue_opts qassign { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) { - free($2); - YYERROR; - } - - memset(&a, 0, sizeof(a)); - - if (strlcpy(a.qname, $2, sizeof(a.qname)) >= - sizeof(a.qname)) { - yyerror("queue name too long (max " - "%d chars)", PF_QNAME_SIZE-1); - free($2); - YYERROR; - } - free($2); - if ($4.tbrsize) { - yyerror("cannot specify tbrsize for queue"); - YYERROR; - } - if ($4.priority > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - a.priority = $4.priority; - a.qlimit = $4.qlimit; - a.scheduler = $4.scheduler.qtype; - if (expand_queue(&a, $3, $5, $4.queue_bwspec, - &$4.scheduler)) { - yyerror("errors in queue definition"); - YYERROR; - } - } - ; - -queue_opts : { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - } - queue_opts_l - { $$ = queue_opts; } - | /* empty */ { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - $$ = queue_opts; - } - ; - -queue_opts_l : queue_opts_l queue_opt - | queue_opt - ; - -queue_opt : BANDWIDTH bandwidth { - if (queue_opts.marker & QOM_BWSPEC) { - yyerror("bandwidth cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_BWSPEC; - queue_opts.queue_bwspec = $2; - } - | PRIORITY NUMBER { - if (queue_opts.marker & QOM_PRIORITY) { - yyerror("priority cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - queue_opts.marker |= QOM_PRIORITY; - queue_opts.priority = $2; - } - | QLIMIT NUMBER { - if (queue_opts.marker & QOM_QLIMIT) { - yyerror("qlimit cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("qlimit out of range: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_QLIMIT; - queue_opts.qlimit = $2; - } - | scheduler { - if (queue_opts.marker & QOM_SCHEDULER) { - yyerror("scheduler cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_SCHEDULER; - queue_opts.scheduler = $1; - } - | TBRSIZE NUMBER { - if (queue_opts.marker & QOM_TBRSIZE) { - yyerror("tbrsize cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("tbrsize too big: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_TBRSIZE; - queue_opts.tbrsize = $2; - } - ; - -bandwidth : STRING { - double bps; - char *cp; - - $$.bw_percent = 0; - - bps = strtod($1, &cp); - if (cp != NULL) { - if (!strcmp(cp, "b")) - ; /* nothing */ - else if (!strcmp(cp, "Kb")) - bps *= 1000; - else if (!strcmp(cp, "Mb")) - bps *= 1000 * 1000; - else if (!strcmp(cp, "Gb")) - bps *= 1000 * 1000 * 1000; - else if (!strcmp(cp, "%")) { - if (bps < 0 || bps > 100) { - yyerror("bandwidth spec " - "out of range"); - free($1); - YYERROR; - } - $$.bw_percent = bps; - bps = 0; - } else { - yyerror("unknown unit %s", cp); - free($1); - YYERROR; - } - } - free($1); - $$.bw_absolute = (u_int32_t)bps; - } - | NUMBER { - if ($1 < 0 || $1 > UINT_MAX) { - yyerror("bandwidth number too big"); - YYERROR; - } - $$.bw_percent = 0; - $$.bw_absolute = $1; - } - ; - -scheduler : CBQ { - $$.qtype = ALTQT_CBQ; - $$.data.cbq_opts.flags = 0; - } - | CBQ '(' cbqflags_list ')' { - $$.qtype = ALTQT_CBQ; - $$.data.cbq_opts.flags = $3; - } - | PRIQ { - $$.qtype = ALTQT_PRIQ; - $$.data.priq_opts.flags = 0; - } - | PRIQ '(' priqflags_list ')' { - $$.qtype = ALTQT_PRIQ; - $$.data.priq_opts.flags = $3; - } - | HFSC { - $$.qtype = ALTQT_HFSC; - bzero(&$$.data.hfsc_opts, - sizeof(struct node_hfsc_opts)); - } - | HFSC '(' hfsc_opts ')' { - $$.qtype = ALTQT_HFSC; - $$.data.hfsc_opts = $3; - } - ; - -cbqflags_list : cbqflags_item { $$ |= $1; } - | cbqflags_list comma cbqflags_item { $$ |= $3; } - ; - -cbqflags_item : STRING { - if (!strcmp($1, "default")) - $$ = CBQCLF_DEFCLASS; - else if (!strcmp($1, "borrow")) - $$ = CBQCLF_BORROW; - else if (!strcmp($1, "red")) - $$ = CBQCLF_RED; - else if (!strcmp($1, "ecn")) - $$ = CBQCLF_RED|CBQCLF_ECN; - else if (!strcmp($1, "rio")) - $$ = CBQCLF_RIO; - else { - yyerror("unknown cbq flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -priqflags_list : priqflags_item { $$ |= $1; } - | priqflags_list comma priqflags_item { $$ |= $3; } - ; - -priqflags_item : STRING { - if (!strcmp($1, "default")) - $$ = PRCF_DEFAULTCLASS; - else if (!strcmp($1, "red")) - $$ = PRCF_RED; - else if (!strcmp($1, "ecn")) - $$ = PRCF_RED|PRCF_ECN; - else if (!strcmp($1, "rio")) - $$ = PRCF_RIO; - else { - yyerror("unknown priq flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -hfsc_opts : { - bzero(&hfsc_opts, - sizeof(struct node_hfsc_opts)); - } - hfscopts_list { - $$ = hfsc_opts; - } - ; - -hfscopts_list : hfscopts_item - | hfscopts_list comma hfscopts_item - ; - -hfscopts_item : LINKSHARE bandwidth { - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m2 = $2; - hfsc_opts.linkshare.used = 1; - } - | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m1 = $3; - hfsc_opts.linkshare.d = $5; - hfsc_opts.linkshare.m2 = $7; - hfsc_opts.linkshare.used = 1; - } - | REALTIME bandwidth { - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m2 = $2; - hfsc_opts.realtime.used = 1; - } - | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m1 = $3; - hfsc_opts.realtime.d = $5; - hfsc_opts.realtime.m2 = $7; - hfsc_opts.realtime.used = 1; - } - | UPPERLIMIT bandwidth { - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m2 = $2; - hfsc_opts.upperlimit.used = 1; - } - | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m1 = $3; - hfsc_opts.upperlimit.d = $5; - hfsc_opts.upperlimit.m2 = $7; - hfsc_opts.upperlimit.used = 1; - } - | STRING { - if (!strcmp($1, "default")) - hfsc_opts.flags |= HFCF_DEFAULTCLASS; - else if (!strcmp($1, "red")) - hfsc_opts.flags |= HFCF_RED; - else if (!strcmp($1, "ecn")) - hfsc_opts.flags |= HFCF_RED|HFCF_ECN; - else if (!strcmp($1, "rio")) - hfsc_opts.flags |= HFCF_RIO; - else { - yyerror("unknown hfsc flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -qassign : /* empty */ { $$ = NULL; } - | qassign_item { $$ = $1; } - | '{' optnl qassign_list '}' { $$ = $3; } - ; - -qassign_list : qassign_item optnl { $$ = $1; } - | qassign_list comma qassign_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -qassign_item : STRING { - $$ = calloc(1, sizeof(struct node_queue)); - if ($$ == NULL) - err(1, "qassign_item: calloc"); - if (strlcpy($$->queue, $1, sizeof($$->queue)) >= - sizeof($$->queue)) { - yyerror("queue name '%s' too long (max " - "%d chars)", $1, sizeof($$->queue)-1); - free($1); - free($$); - YYERROR; - } - free($1); - $$->next = NULL; - $$->tail = $$; - } - ; - -pfrule : action dir logquick interface route af proto fromto - filter_opts - { - struct pf_rule r; - struct node_state_opt *o; - struct node_proto *proto; - int srctrack = 0; - int statelock = 0; - int adaptive = 0; - int defaults = 0; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - switch ($1.b2) { - case PFRULE_RETURNRST: - r.rule_flag |= PFRULE_RETURNRST; - r.return_ttl = $1.w; - break; - case PFRULE_RETURNICMP: - r.rule_flag |= PFRULE_RETURNICMP; - r.return_icmp = $1.w; - r.return_icmp6 = $1.w2; - break; - case PFRULE_RETURN: - r.rule_flag |= PFRULE_RETURN; - r.return_icmp = $1.w; - r.return_icmp6 = $1.w2; - break; - } - r.direction = $2; - r.log = $3.log; - r.logif = $3.logif; - r.quick = $3.quick; - r.prob = $9.prob; - r.rtableid = $9.rtableid; - - r.af = $6; - if ($9.tag) - if (strlcpy(r.tagname, $9.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - if (rule_label(&r, $9.label)) - YYERROR; - free($9.label); - r.flags = $9.flags.b1; - r.flagset = $9.flags.b2; - if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { - for (proto = $7; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && $7 != NULL) { - if ($9.flags.b1 || $9.flags.b2) - yyerror( - "flags only apply to tcp"); - if ($8.src_os) - yyerror( - "OS fingerprinting only " - "apply to tcp"); - YYERROR; - } -#if 0 - if (($9.flags.b1 & parse_flags("S")) == 0 && - $8.src_os) { - yyerror("OS fingerprinting requires " - "the SYN TCP flag (flags S/SA)"); - YYERROR; - } -#endif - } - - r.tos = $9.tos; - r.keep_state = $9.keep.action; - o = $9.keep.options; - - /* 'keep state' by default on pass rules. */ - if (!r.keep_state && !r.action && - !($9.marker & FOM_KEEP)) { - r.keep_state = PF_STATE_NORMAL; - o = keep_state_defaults; - defaults = 1; - } - - while (o) { - struct node_state_opt *p = o; - - switch (o->type) { - case PF_STATE_OPT_MAX: - if (r.max_states) { - yyerror("state option 'max' " - "multiple definitions"); - YYERROR; - } - r.max_states = o->data.max_states; - break; - case PF_STATE_OPT_NOSYNC: - if (r.rule_flag & PFRULE_NOSYNC) { - yyerror("state option 'sync' " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_NOSYNC; - break; - case PF_STATE_OPT_SRCTRACK: - if (srctrack) { - yyerror("state option " - "'source-track' " - "multiple definitions"); - YYERROR; - } - srctrack = o->data.src_track; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_STATES: - if (r.max_src_states) { - yyerror("state option " - "'max-src-states' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_states == 0) { - yyerror("'max-src-states' must " - "be > 0"); - YYERROR; - } - r.max_src_states = - o->data.max_src_states; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_OVERLOAD: - if (r.overload_tblname[0]) { - yyerror("multiple 'overload' " - "table definitions"); - YYERROR; - } - if (strlcpy(r.overload_tblname, - o->data.overload.tblname, - PF_TABLE_NAME_SIZE) >= - PF_TABLE_NAME_SIZE) { - yyerror("state option: " - "strlcpy"); - YYERROR; - } - r.flush = o->data.overload.flush; - break; - case PF_STATE_OPT_MAX_SRC_CONN: - if (r.max_src_conn) { - yyerror("state option " - "'max-src-conn' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_conn == 0) { - yyerror("'max-src-conn' " - "must be > 0"); - YYERROR; - } - r.max_src_conn = - o->data.max_src_conn; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_CONN_RATE: - if (r.max_src_conn_rate.limit) { - yyerror("state option " - "'max-src-conn-rate' " - "multiple definitions"); - YYERROR; - } - if (!o->data.max_src_conn_rate.limit || - !o->data.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' " - "values must be > 0"); - YYERROR; - } - if (o->data.max_src_conn_rate.limit > - PF_THRESHOLD_MAX) { - yyerror("'max-src-conn-rate' " - "maximum rate must be < %u", - PF_THRESHOLD_MAX); - YYERROR; - } - r.max_src_conn_rate.limit = - o->data.max_src_conn_rate.limit; - r.max_src_conn_rate.seconds = - o->data.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_NODES: - if (r.max_src_nodes) { - yyerror("state option " - "'max-src-nodes' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_nodes == 0) { - yyerror("'max-src-nodes' must " - "be > 0"); - YYERROR; - } - r.max_src_nodes = - o->data.max_src_nodes; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_STATELOCK: - if (statelock) { - yyerror("state locking option: " - "multiple definitions"); - YYERROR; - } - statelock = 1; - r.rule_flag |= o->data.statelock; - break; - case PF_STATE_OPT_SLOPPY: - if (r.rule_flag & PFRULE_STATESLOPPY) { - yyerror("state sloppy option: " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_STATESLOPPY; - break; - case PF_STATE_OPT_PFLOW: - if (r.rule_flag & PFRULE_PFLOW) { - yyerror("state pflow " - "option: multiple " - "definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_PFLOW; - break; - case PF_STATE_OPT_TIMEOUT: - if (o->data.timeout.number == - PFTM_ADAPTIVE_START || - o->data.timeout.number == - PFTM_ADAPTIVE_END) - adaptive = 1; - if (r.timeout[o->data.timeout.number]) { - yyerror("state timeout %s " - "multiple definitions", - pf_timeouts[o->data. - timeout.number].name); - YYERROR; - } - r.timeout[o->data.timeout.number] = - o->data.timeout.seconds; - } - o = o->next; - if (!defaults) - free(p); - } - - /* 'flags S/SA' by default on stateful rules */ - if (!r.action && !r.flags && !r.flagset && - !$9.fragment && !($9.marker & FOM_FLAGS) && - r.keep_state) { - r.flags = parse_flags("S"); - r.flagset = parse_flags("SA"); - } - if (!adaptive && r.max_states) { - r.timeout[PFTM_ADAPTIVE_START] = - (r.max_states / 10) * 6; - r.timeout[PFTM_ADAPTIVE_END] = - (r.max_states / 10) * 12; - } - if (r.rule_flag & PFRULE_SRCTRACK) { - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_nodes) { - yyerror("'max-src-nodes' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn) { - yyerror("'max-src-conn' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (r.timeout[PFTM_SRC_NODE] < - r.max_src_conn_rate.seconds) - r.timeout[PFTM_SRC_NODE] = - r.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK; - if (srctrack == PF_SRCTRACK_RULE) - r.rule_flag |= PFRULE_RULESRCTRACK; - } - if (r.keep_state && !statelock) - r.rule_flag |= default_statelock; - - if ($9.fragment) - r.rule_flag |= PFRULE_FRAGMENT; - r.allow_opts = $9.allowopts; - - decide_address_family($8.src.host, &r.af); - decide_address_family($8.dst.host, &r.af); - - if ($5.rt) { - if (!r.direction) { - yyerror("direction must be explicit " - "with rules that specify routing"); - YYERROR; - } - r.rt = $5.rt; - r.rpool.opts = $5.pool_opts; - if ($5.key != NULL) - memcpy(&r.rpool.key, $5.key, - sizeof(struct pf_poolhashkey)); - } - if (r.rt && r.rt != PF_FASTROUTE) { - decide_address_family($5.host, &r.af); - remove_invalid_hosts(&$5.host, &r.af); - if ($5.host == NULL) { - yyerror("no routing address with " - "matching address family found."); - YYERROR; - } - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($5.host->next != NULL || - $5.host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($5.host->addr))) - r.rpool.opts |= PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table($5.host, "tables are only " - "supported in round-robin routing pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias($5.host, "interface (%s) " - "is only supported in round-robin " - "routing pools")) - YYERROR; - if ($5.host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("r.rpool.opts must " - "be PF_POOL_ROUNDROBIN"); - YYERROR; - } - } - } - if ($9.queues.qname != NULL) { - if (strlcpy(r.qname, $9.queues.qname, - sizeof(r.qname)) >= sizeof(r.qname)) { - yyerror("rule qname too long (max " - "%d chars)", sizeof(r.qname)-1); - YYERROR; - } - free($9.queues.qname); - } - if ($9.queues.pqname != NULL) { - if (strlcpy(r.pqname, $9.queues.pqname, - sizeof(r.pqname)) >= sizeof(r.pqname)) { - yyerror("rule pqname too long (max " - "%d chars)", sizeof(r.pqname)-1); - YYERROR; - } - free($9.queues.pqname); - } -#ifdef __FreeBSD__ - r.divert.port = $9.divert.port; -#else - if ((r.divert.port = $9.divert.port)) { - if (r.direction == PF_OUT) { - if ($9.divert.addr) { - yyerror("address specified " - "for outgoing divert"); - YYERROR; - } - bzero(&r.divert.addr, - sizeof(r.divert.addr)); - } else { - if (!$9.divert.addr) { - yyerror("no address specified " - "for incoming divert"); - YYERROR; - } - if ($9.divert.addr->af != r.af) { - yyerror("address family " - "mismatch for divert"); - YYERROR; - } - r.divert.addr = - $9.divert.addr->addr.v.a.addr; - } - } -#endif - - expand_rule(&r, $4, $5.host, $7, $8.src_os, - $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - $9.uid, $9.gid, $9.icmpspec, ""); - } - ; - -filter_opts : { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - } - filter_opts_l - { $$ = filter_opts; } - | /* empty */ { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - $$ = filter_opts; - } - ; - -filter_opts_l : filter_opts_l filter_opt - | filter_opt - ; - -filter_opt : USER uids { - if (filter_opts.uid) - $2->tail->next = filter_opts.uid; - filter_opts.uid = $2; - } - | GROUP gids { - if (filter_opts.gid) - $2->tail->next = filter_opts.gid; - filter_opts.gid = $2; - } - | flags { - if (filter_opts.marker & FOM_FLAGS) { - yyerror("flags cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_FLAGS; - filter_opts.flags.b1 |= $1.b1; - filter_opts.flags.b2 |= $1.b2; - filter_opts.flags.w |= $1.w; - filter_opts.flags.w2 |= $1.w2; - } - | icmpspec { - if (filter_opts.marker & FOM_ICMP) { - yyerror("icmp-type cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_ICMP; - filter_opts.icmpspec = $1; - } - | TOS tos { - if (filter_opts.marker & FOM_TOS) { - yyerror("tos cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_TOS; - filter_opts.tos = $2; - } - | keep { - if (filter_opts.marker & FOM_KEEP) { - yyerror("modulate or keep cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_KEEP; - filter_opts.keep.action = $1.action; - filter_opts.keep.options = $1.options; - } - | FRAGMENT { - filter_opts.fragment = 1; - } - | ALLOWOPTS { - filter_opts.allowopts = 1; - } - | label { - if (filter_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - filter_opts.label = $1; - } - | qname { - if (filter_opts.queues.qname) { - yyerror("queue cannot be redefined"); - YYERROR; - } - filter_opts.queues = $1; - } - | TAG string { - filter_opts.tag = $2; - } - | not TAGGED string { - filter_opts.match_tag = $3; - filter_opts.match_tag_not = $1; - } - | PROBABILITY probability { - double p; - - p = floor($2 * UINT_MAX + 0.5); - if (p < 0.0 || p > UINT_MAX) { - yyerror("invalid probability: %lf", p); - YYERROR; - } - filter_opts.prob = (u_int32_t)p; - if (filter_opts.prob == 0) - filter_opts.prob = 1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - filter_opts.rtableid = $2; - } - | DIVERTTO portplain { -#ifdef __FreeBSD__ - filter_opts.divert.port = $2.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs($2.a)); - YYERROR; - } -#endif - } - | DIVERTTO STRING PORT portplain { -#ifndef __FreeBSD__ - if ((filter_opts.divert.addr = host($2)) == NULL) { - yyerror("could not parse divert address: %s", - $2); - free($2); - YYERROR; - } -#else - if ($2) -#endif - free($2); - filter_opts.divert.port = $4.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs($4.a)); - YYERROR; - } - } - | DIVERTREPLY { -#ifdef __FreeBSD__ - yyerror("divert-reply has no meaning in FreeBSD pf(4)"); - YYERROR; -#else - filter_opts.divert.port = 1; /* some random value */ -#endif - } - ; - -probability : STRING { - char *e; - double p = strtod($1, &e); - - if (*e == '%') { - p *= 0.01; - e++; - } - if (*e) { - yyerror("invalid probability: %s", $1); - free($1); - YYERROR; - } - free($1); - $$ = p; - } - | NUMBER { - $$ = (double)$1; - } - ; - - -action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } - | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } - ; - -blockspec : /* empty */ { - $$.b2 = blockpolicy; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | DROP { - $$.b2 = PFRULE_DROP; - $$.w = 0; - $$.w2 = 0; - } - | RETURNRST { - $$.b2 = PFRULE_RETURNRST; - $$.w = 0; - $$.w2 = 0; - } - | RETURNRST '(' TTL NUMBER ')' { - if ($4 < 0 || $4 > 255) { - yyerror("illegal ttl value %d", $4); - YYERROR; - } - $$.b2 = PFRULE_RETURNRST; - $$.w = $4; - $$.w2 = 0; - } - | RETURNICMP { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | RETURNICMP6 { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | RETURNICMP '(' reticmpspec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = $3; - $$.w2 = returnicmpdefault; - } - | RETURNICMP6 '(' reticmp6spec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = $3; - } - | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = $3; - $$.w2 = $5; - } - | RETURN { - $$.b2 = PFRULE_RETURN; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - ; - -reticmpspec : STRING { - if (!($$ = parseicmpspec($1, AF_INET))) { - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - u_int8_t icmptype; - - if ($1 < 0 || $1 > 255) { - yyerror("invalid icmp code %lu", $1); - YYERROR; - } - icmptype = returnicmpdefault >> 8; - $$ = (icmptype << 8 | $1); - } - ; - -reticmp6spec : STRING { - if (!($$ = parseicmpspec($1, AF_INET6))) { - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - u_int8_t icmptype; - - if ($1 < 0 || $1 > 255) { - yyerror("invalid icmp code %lu", $1); - YYERROR; - } - icmptype = returnicmp6default >> 8; - $$ = (icmptype << 8 | $1); - } - ; - -dir : /* empty */ { $$ = PF_INOUT; } - | IN { $$ = PF_IN; } - | OUT { $$ = PF_OUT; } - ; - -quick : /* empty */ { $$.quick = 0; } - | QUICK { $$.quick = 1; } - ; - -logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } - | log { $$ = $1; $$.quick = 0; } - | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } - | log QUICK { $$ = $1; $$.quick = 1; } - | QUICK log { $$ = $2; $$.quick = 1; } - ; - -log : LOG { $$.log = PF_LOG; $$.logif = 0; } - | LOG '(' logopts ')' { - $$.log = PF_LOG | $3.log; - $$.logif = $3.logif; - } - ; - -logopts : logopt { $$ = $1; } - | logopts comma logopt { - $$.log = $1.log | $3.log; - $$.logif = $3.logif; - if ($$.logif == 0) - $$.logif = $1.logif; - } - ; - -logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } - | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } - | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } - | TO string { - const char *errstr; - u_int i; - - $$.log = 0; - if (strncmp($2, "pflog", 5)) { - yyerror("%s: should be a pflog interface", $2); - free($2); - YYERROR; - } - i = strtonum($2 + 5, 0, 255, &errstr); - if (errstr) { - yyerror("%s: %s", $2, errstr); - free($2); - YYERROR; - } - free($2); - $$.logif = i; - } - ; - -interface : /* empty */ { $$ = NULL; } - | ON if_item_not { $$ = $2; } - | ON '{' optnl if_list '}' { $$ = $4; } - ; - -if_list : if_item_not optnl { $$ = $1; } - | if_list comma if_item_not optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -if_item_not : not if_item { $$ = $2; $$->not = $1; } - ; - -if_item : STRING { - struct node_host *n; - - $$ = calloc(1, sizeof(struct node_if)); - if ($$ == NULL) - err(1, "if_item: calloc"); - if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= - sizeof($$->ifname)) { - free($1); - free($$); - yyerror("interface name too long"); - YYERROR; - } - - if ((n = ifa_exists($1)) != NULL) - $$->ifa_flags = n->ifa_flags; - - free($1); - $$->not = 0; - $$->next = NULL; - $$->tail = $$; - } - ; - -af : /* empty */ { $$ = 0; } - | INET { $$ = AF_INET; } - | INET6 { $$ = AF_INET6; } - ; - -proto : /* empty */ { $$ = NULL; } - | PROTO proto_item { $$ = $2; } - | PROTO '{' optnl proto_list '}' { $$ = $4; } - ; - -proto_list : proto_item optnl { $$ = $1; } - | proto_list comma proto_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -proto_item : protoval { - u_int8_t pr; - - pr = (u_int8_t)$1; - if (pr == 0) { - yyerror("proto 0 cannot be used"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_proto)); - if ($$ == NULL) - err(1, "proto_item: calloc"); - $$->proto = pr; - $$->next = NULL; - $$->tail = $$; - } - ; - -protoval : STRING { - struct protoent *p; - - p = getprotobyname($1); - if (p == NULL) { - yyerror("unknown protocol %s", $1); - free($1); - YYERROR; - } - $$ = p->p_proto; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("protocol outside range"); - YYERROR; - } - } - ; - -fromto : ALL { - $$.src.host = NULL; - $$.src.port = NULL; - $$.dst.host = NULL; - $$.dst.port = NULL; - $$.src_os = NULL; - } - | from os to { - $$.src = $1; - $$.src_os = $2; - $$.dst = $3; - } - ; - -os : /* empty */ { $$ = NULL; } - | OS xos { $$ = $2; } - | OS '{' optnl os_list '}' { $$ = $4; } - ; - -xos : STRING { - $$ = calloc(1, sizeof(struct node_os)); - if ($$ == NULL) - err(1, "os: calloc"); - $$->os = $1; - $$->tail = $$; - } - ; - -os_list : xos optnl { $$ = $1; } - | os_list comma xos optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -from : /* empty */ { - $$.host = NULL; - $$.port = NULL; - } - | FROM ipportspec { - $$ = $2; - } - ; - -to : /* empty */ { - $$.host = NULL; - $$.port = NULL; - } - | TO ipportspec { - if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " - "not permitted in a destination address")) - YYERROR; - $$ = $2; - } - ; - -ipportspec : ipspec { - $$.host = $1; - $$.port = NULL; - } - | ipspec PORT portspec { - $$.host = $1; - $$.port = $3; - } - | PORT portspec { - $$.host = NULL; - $$.port = $2; - } - ; - -optnl : '\n' optnl - | - ; - -ipspec : ANY { $$ = NULL; } - | xhost { $$ = $1; } - | '{' optnl host_list '}' { $$ = $3; } - ; - -toipspec : TO ipspec { $$ = $2; } - | /* empty */ { $$ = NULL; } - ; - -host_list : ipspec optnl { $$ = $1; } - | host_list comma ipspec optnl { - if ($3 == NULL) - $$ = $1; - else if ($1 == NULL) - $$ = $3; - else { - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - } - ; - -xhost : not host { - struct node_host *n; - - for (n = $2; n != NULL; n = n->next) - n->not = $1; - $$ = $2; - } - | not NOROUTE { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "xhost: calloc"); - $$->addr.type = PF_ADDR_NOROUTE; - $$->next = NULL; - $$->not = $1; - $$->tail = $$; - } - | not URPFFAILED { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "xhost: calloc"); - $$->addr.type = PF_ADDR_URPFFAILED; - $$->next = NULL; - $$->not = $1; - $$->tail = $$; - } - ; - -host : STRING { - if (($$ = host($1)) == NULL) { - /* error. "any" is handled elsewhere */ - free($1); - yyerror("could not parse host specification"); - YYERROR; - } - free($1); - - } - | STRING '-' STRING { - struct node_host *b, *e; - - if ((b = host($1)) == NULL || (e = host($3)) == NULL) { - free($1); - free($3); - yyerror("could not parse host specification"); - YYERROR; - } - if (b->af != e->af || - b->addr.type != PF_ADDR_ADDRMASK || - e->addr.type != PF_ADDR_ADDRMASK || - unmask(&b->addr.v.a.mask, b->af) != - (b->af == AF_INET ? 32 : 128) || - unmask(&e->addr.v.a.mask, e->af) != - (e->af == AF_INET ? 32 : 128) || - b->next != NULL || b->not || - e->next != NULL || e->not) { - free(b); - free(e); - free($1); - free($3); - yyerror("invalid address range"); - YYERROR; - } - memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, - sizeof(b->addr.v.a.mask)); - b->addr.type = PF_ADDR_RANGE; - $$ = b; - free(e); - free($1); - free($3); - } - | STRING '/' NUMBER { - char *buf; - - if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) - err(1, "host: asprintf"); - free($1); - if (($$ = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } - | NUMBER '/' NUMBER { - char *buf; - - /* ie. for 10/8 parsing */ -#ifdef __FreeBSD__ - if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) -#else - if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) -#endif - err(1, "host: asprintf"); - if (($$ = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } - | dynaddr - | dynaddr '/' NUMBER { - struct node_host *n; - - if ($3 < 0 || $3 > 128) { - yyerror("bit number too big"); - YYERROR; - } - $$ = $1; - for (n = $1; n != NULL; n = n->next) - set_ipmask(n, $3); - } - | '<' STRING '>' { - if (strlen($2) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", $2); - free($2); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "host: calloc"); - $$->addr.type = PF_ADDR_TABLE; - if (strlcpy($$->addr.v.tblname, $2, - sizeof($$->addr.v.tblname)) >= - sizeof($$->addr.v.tblname)) - errx(1, "host: strlcpy"); - free($2); - $$->next = NULL; - $$->tail = $$; - } - | ROUTE STRING { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) { - free($2); - err(1, "host: calloc"); - } - $$->addr.type = PF_ADDR_RTLABEL; - if (strlcpy($$->addr.v.rtlabelname, $2, - sizeof($$->addr.v.rtlabelname)) >= - sizeof($$->addr.v.rtlabelname)) { - yyerror("route label too long, max %u chars", - sizeof($$->addr.v.rtlabelname) - 1); - free($2); - free($$); - YYERROR; - } - $$->next = NULL; - $$->tail = $$; - free($2); - } - ; - -number : NUMBER - | STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - yyerror("%s is not a number", $1); - free($1); - YYERROR; - } else - $$ = ulval; - free($1); - } - ; - -dynaddr : '(' STRING ')' { - int flags = 0; - char *p, *op; - - op = $2; - if (!isalpha(op[0])) { - yyerror("invalid interface name '%s'", op); - free(op); - YYERROR; - } - while ((p = strrchr($2, ':')) != NULL) { - if (!strcmp(p+1, "network")) - flags |= PFI_AFLAG_NETWORK; - else if (!strcmp(p+1, "broadcast")) - flags |= PFI_AFLAG_BROADCAST; - else if (!strcmp(p+1, "peer")) - flags |= PFI_AFLAG_PEER; - else if (!strcmp(p+1, "0")) - flags |= PFI_AFLAG_NOALIAS; - else { - yyerror("interface %s has bad modifier", - $2); - free(op); - YYERROR; - } - *p = '\0'; - } - if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { - free(op); - yyerror("illegal combination of " - "interface modifiers"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "address: calloc"); - $$->af = 0; - set_ipmask($$, 128); - $$->addr.type = PF_ADDR_DYNIFTL; - $$->addr.iflags = flags; - if (strlcpy($$->addr.v.ifname, $2, - sizeof($$->addr.v.ifname)) >= - sizeof($$->addr.v.ifname)) { - free(op); - free($$); - yyerror("interface name too long"); - YYERROR; - } - free(op); - $$->next = NULL; - $$->tail = $$; - } - ; - -portspec : port_item { $$ = $1; } - | '{' optnl port_list '}' { $$ = $3; } - ; - -port_list : port_item optnl { $$ = $1; } - | port_list comma port_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -port_item : portrange { - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $1.a; - $$->port[1] = $1.b; - if ($1.t) - $$->op = PF_OP_RRG; - else - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop portrange { - if ($2.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $2.a; - $$->port[1] = $2.b; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | portrange PORTBINARY portrange { - if ($1.t || $3.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $1.a; - $$->port[1] = $3.a; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -portplain : numberstring { - if (parseport($1, &$$, 0) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -portrange : numberstring { - if (parseport($1, &$$, PPORT_RANGE) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -uids : uid_item { $$ = $1; } - | '{' optnl uid_list '}' { $$ = $3; } - ; - -uid_list : uid_item optnl { $$ = $1; } - | uid_list comma uid_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -uid_item : uid { - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $1; - $$->uid[1] = $1; - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop uid { - if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $2; - $$->uid[1] = $2; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | uid PORTBINARY uid { - if ($1 == UID_MAX || $3 == UID_MAX) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $1; - $$->uid[1] = $3; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -uid : STRING { - if (!strcmp($1, "unknown")) - $$ = UID_MAX; - else { - struct passwd *pw; - - if ((pw = getpwnam($1)) == NULL) { - yyerror("unknown user %s", $1); - free($1); - YYERROR; - } - $$ = pw->pw_uid; - } - free($1); - } - | NUMBER { - if ($1 < 0 || $1 >= UID_MAX) { - yyerror("illegal uid value %lu", $1); - YYERROR; - } - $$ = $1; - } - ; - -gids : gid_item { $$ = $1; } - | '{' optnl gid_list '}' { $$ = $3; } - ; - -gid_list : gid_item optnl { $$ = $1; } - | gid_list comma gid_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -gid_item : gid { - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $1; - $$->gid[1] = $1; - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop gid { - if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $2; - $$->gid[1] = $2; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | gid PORTBINARY gid { - if ($1 == GID_MAX || $3 == GID_MAX) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $1; - $$->gid[1] = $3; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -gid : STRING { - if (!strcmp($1, "unknown")) - $$ = GID_MAX; - else { - struct group *grp; - - if ((grp = getgrnam($1)) == NULL) { - yyerror("unknown group %s", $1); - free($1); - YYERROR; - } - $$ = grp->gr_gid; - } - free($1); - } - | NUMBER { - if ($1 < 0 || $1 >= GID_MAX) { - yyerror("illegal gid value %lu", $1); - YYERROR; - } - $$ = $1; - } - ; - -flag : STRING { - int f; - - if ((f = parse_flags($1)) < 0) { - yyerror("bad flags %s", $1); - free($1); - YYERROR; - } - free($1); - $$.b1 = f; - } - ; - -flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } - | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } - | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } - ; - -icmpspec : ICMPTYPE icmp_item { $$ = $2; } - | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } - | ICMP6TYPE icmp6_item { $$ = $2; } - | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } - ; - -icmp_list : icmp_item optnl { $$ = $1; } - | icmp_list comma icmp_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -icmp6_list : icmp6_item optnl { $$ = $1; } - | icmp6_list comma icmp6_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -icmp_item : icmptype { - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = 0; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - | icmptype CODE STRING { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { - yyerror("unknown icmp-code %s", $3); - free($3); - YYERROR; - } - - free($3); - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = p->code + 1; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - | icmptype CODE NUMBER { - if ($3 < 0 || $3 > 255) { - yyerror("illegal icmp-code %lu", $3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = $3 + 1; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - ; - -icmp6_item : icmp6type { - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = 0; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - | icmp6type CODE STRING { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { - yyerror("unknown icmp6-code %s", $3); - free($3); - YYERROR; - } - free($3); - - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = p->code + 1; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - | icmp6type CODE NUMBER { - if ($3 < 0 || $3 > 255) { - yyerror("illegal icmp-code %lu", $3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = $3 + 1; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - ; - -icmptype : STRING { - const struct icmptypeent *p; - - if ((p = geticmptypebyname($1, AF_INET)) == NULL) { - yyerror("unknown icmp-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("illegal icmp-type %lu", $1); - YYERROR; - } - $$ = $1 + 1; - } - ; - -icmp6type : STRING { - const struct icmptypeent *p; - - if ((p = geticmptypebyname($1, AF_INET6)) == - NULL) { - yyerror("unknown icmp6-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("illegal icmp6-type %lu", $1); - YYERROR; - } - $$ = $1 + 1; - } - ; - -tos : STRING { - if (!strcmp($1, "lowdelay")) - $$ = IPTOS_LOWDELAY; - else if (!strcmp($1, "throughput")) - $$ = IPTOS_THROUGHPUT; - else if (!strcmp($1, "reliability")) - $$ = IPTOS_RELIABILITY; - else if ($1[0] == '0' && $1[1] == 'x') - $$ = strtoul($1, NULL, 16); - else - $$ = 0; /* flag bad argument */ - if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $1); - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - $$ = $1; - if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $1); - YYERROR; - } - } - ; - -sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } - | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } - | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } - ; - -statelock : IFBOUND { - $$ = PFRULE_IFBOUND; - } - | FLOATING { - $$ = 0; - } - ; - -keep : NO STATE { - $$.action = 0; - $$.options = NULL; - } - | KEEP STATE state_opt_spec { - $$.action = PF_STATE_NORMAL; - $$.options = $3; - } - | MODULATE STATE state_opt_spec { - $$.action = PF_STATE_MODULATE; - $$.options = $3; - } - | SYNPROXY STATE state_opt_spec { - $$.action = PF_STATE_SYNPROXY; - $$.options = $3; - } - ; - -flush : /* empty */ { $$ = 0; } - | FLUSH { $$ = PF_FLUSH; } - | FLUSH GLOBAL { - $$ = PF_FLUSH | PF_FLUSH_GLOBAL; - } - ; - -state_opt_spec : '(' state_opt_list ')' { $$ = $2; } - | /* empty */ { $$ = NULL; } - ; - -state_opt_list : state_opt_item { $$ = $1; } - | state_opt_list comma state_opt_item { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -state_opt_item : MAXIMUM NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX; - $$->data.max_states = $2; - $$->next = NULL; - $$->tail = $$; - } - | NOSYNC { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_NOSYNC; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCSTATES NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_STATES; - $$->data.max_src_states = $2; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCCONN NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_CONN; - $$->data.max_src_conn = $2; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCCONNRATE NUMBER '/' NUMBER { - if ($2 < 0 || $2 > UINT_MAX || - $4 < 0 || $4 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; - $$->data.max_src_conn_rate.limit = $2; - $$->data.max_src_conn_rate.seconds = $4; - $$->next = NULL; - $$->tail = $$; - } - | OVERLOAD '<' STRING '>' flush { - if (strlen($3) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", $3); - free($3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - if (strlcpy($$->data.overload.tblname, $3, - PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) - errx(1, "state_opt_item: strlcpy"); - free($3); - $$->type = PF_STATE_OPT_OVERLOAD; - $$->data.overload.flush = $5; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCNODES NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_NODES; - $$->data.max_src_nodes = $2; - $$->next = NULL; - $$->tail = $$; - } - | sourcetrack { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_SRCTRACK; - $$->data.src_track = $1; - $$->next = NULL; - $$->tail = $$; - } - | statelock { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_STATELOCK; - $$->data.statelock = $1; - $$->next = NULL; - $$->tail = $$; - } - | SLOPPY { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_SLOPPY; - $$->next = NULL; - $$->tail = $$; - } - | PFLOW { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_PFLOW; - $$->next = NULL; - $$->tail = $$; - } - | STRING NUMBER { - int i; - - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - for (i = 0; pf_timeouts[i].name && - strcmp(pf_timeouts[i].name, $1); ++i) - ; /* nothing */ - if (!pf_timeouts[i].name) { - yyerror("illegal timeout name %s", $1); - free($1); - YYERROR; - } - if (strchr(pf_timeouts[i].name, '.') == NULL) { - yyerror("illegal state timeout %s", $1); - free($1); - YYERROR; - } - free($1); - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_TIMEOUT; - $$->data.timeout.number = pf_timeouts[i].timeout; - $$->data.timeout.seconds = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -label : LABEL STRING { - $$ = $2; - } - ; - -qname : QUEUE STRING { - $$.qname = $2; - $$.pqname = NULL; - } - | QUEUE '(' STRING ')' { - $$.qname = $3; - $$.pqname = NULL; - } - | QUEUE '(' STRING comma STRING ')' { - $$.qname = $3; - $$.pqname = $5; - } - ; - -no : /* empty */ { $$ = 0; } - | NO { $$ = 1; } - ; - -portstar : numberstring { - if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -redirspec : host { $$ = $1; } - | '{' optnl redir_host_list '}' { $$ = $3; } - ; - -redir_host_list : host optnl { $$ = $1; } - | redir_host_list comma host optnl { - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - ; - -redirpool : /* empty */ { $$ = NULL; } - | ARROW redirspec { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport.a = $$->rport.b = $$->rport.t = 0; - } - | ARROW redirspec PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport = $4; - } - ; - -hashkey : /* empty */ - { - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - $$->key32[0] = arc4random(); - $$->key32[1] = arc4random(); - $$->key32[2] = arc4random(); - $$->key32[3] = arc4random(); - } - | string - { - if (!strncmp($1, "0x", 2)) { - if (strlen($1) != 34) { - free($1); - yyerror("hex key must be 128 bits " - "(32 hex digits) long"); - YYERROR; - } - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - - if (sscanf($1, "0x%8x%8x%8x%8x", - &$$->key32[0], &$$->key32[1], - &$$->key32[2], &$$->key32[3]) != 4) { - free($$); - free($1); - yyerror("invalid hex key"); - YYERROR; - } - } else { - MD5_CTX context; - - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - MD5Init(&context); - MD5Update(&context, (unsigned char *)$1, - strlen($1)); - MD5Final((unsigned char *)$$, &context); - HTONL($$->key32[0]); - HTONL($$->key32[1]); - HTONL($$->key32[2]); - HTONL($$->key32[3]); - } - free($1); - } - ; - -pool_opts : { bzero(&pool_opts, sizeof pool_opts); } - pool_opts_l - { $$ = pool_opts; } - | /* empty */ { - bzero(&pool_opts, sizeof pool_opts); - $$ = pool_opts; - } - ; - -pool_opts_l : pool_opts_l pool_opt - | pool_opt - ; - -pool_opt : BITMASK { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_BITMASK; - } - | RANDOM { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_RANDOM; - } - | SOURCEHASH hashkey { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_SRCHASH; - pool_opts.key = $2; - } - | ROUNDROBIN { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_ROUNDROBIN; - } - | STATICPORT { - if (pool_opts.staticport) { - yyerror("static-port cannot be redefined"); - YYERROR; - } - pool_opts.staticport = 1; - } - | STICKYADDRESS { - if (filter_opts.marker & POM_STICKYADDRESS) { - yyerror("sticky-address cannot be redefined"); - YYERROR; - } - pool_opts.marker |= POM_STICKYADDRESS; - pool_opts.opts |= PF_POOL_STICKYADDR; - } - ; - -redirection : /* empty */ { $$ = NULL; } - | ARROW host { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport.a = $$->rport.b = $$->rport.t = 0; - } - | ARROW host PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport = $4; - } - ; - -natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } - | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } - | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } - | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } - ; - -nataction : no NAT natpasslog { - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - $$.b1 = PF_NONAT; - else - $$.b1 = PF_NAT; - $$.b2 = $3.b1; - $$.w = $3.b2; - $$.w2 = $3.w2; - } - | no RDR natpasslog { - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - $$.b1 = PF_NORDR; - else - $$.b1 = PF_RDR; - $$.b2 = $3.b1; - $$.w = $3.b2; - $$.w2 = $3.w2; - } - ; - -natrule : nataction interface af proto fromto tag tagged rtable - redirpool pool_opts - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - r.natpass = $1.b2; - r.log = $1.w; - r.logif = $1.w2; - r.af = $3; - - if (!r.af) { - if ($5.src.host && $5.src.host->af && - !$5.src.host->ifindex) - r.af = $5.src.host->af; - else if ($5.dst.host && $5.dst.host->af && - !$5.dst.host->ifindex) - r.af = $5.dst.host->af; - } - - if ($6 != NULL) - if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= - PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - - if ($7.name) - if (strlcpy(r.match_tagname, $7.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $7.neg; - r.rtableid = $8; - - if (r.action == PF_NONAT || r.action == PF_NORDR) { - if ($9 != NULL) { - yyerror("translation rule with 'no' " - "does not need '->'"); - YYERROR; - } - } else { - if ($9 == NULL || $9->host == NULL) { - yyerror("translation rule requires '-> " - "address'"); - YYERROR; - } - if (!r.af && ! $9->host->ifindex) - r.af = $9->host->af; - - remove_invalid_hosts(&$9->host, &r.af); - if (invalid_redirect($9->host, r.af)) - YYERROR; - if (check_netmask($9->host, r.af)) - YYERROR; - - r.rpool.proxy_port[0] = ntohs($9->rport.a); - - switch (r.action) { - case PF_RDR: - if (!$9->rport.b && $9->rport.t && - $5.dst.port != NULL) { - r.rpool.proxy_port[1] = - ntohs($9->rport.a) + - (ntohs( - $5.dst.port->port[1]) - - ntohs( - $5.dst.port->port[0])); - } else - r.rpool.proxy_port[1] = - ntohs($9->rport.b); - break; - case PF_NAT: - r.rpool.proxy_port[1] = - ntohs($9->rport.b); - if (!r.rpool.proxy_port[0] && - !r.rpool.proxy_port[1]) { - r.rpool.proxy_port[0] = - PF_NAT_PROXY_PORT_LOW; - r.rpool.proxy_port[1] = - PF_NAT_PROXY_PORT_HIGH; - } else if (!r.rpool.proxy_port[1]) - r.rpool.proxy_port[1] = - r.rpool.proxy_port[0]; - break; - default: - break; - } - - r.rpool.opts = $10.type; - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($9->host->next != NULL || - $9->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($9->host->addr))) - r.rpool.opts = PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table($9->host, "tables are only " - "supported in round-robin redirection " - "pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias($9->host, "interface (%s) " - "is only supported in round-robin " - "redirection pools")) - YYERROR; - if ($9->host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("only round-robin " - "valid for multiple " - "redirection addresses"); - YYERROR; - } - } - } - - if ($10.key != NULL) - memcpy(&r.rpool.key, $10.key, - sizeof(struct pf_poolhashkey)); - - if ($10.opts) - r.rpool.opts |= $10.opts; - - if ($10.staticport) { - if (r.action != PF_NAT) { - yyerror("the 'static-port' option is " - "only valid with nat rules"); - YYERROR; - } - if (r.rpool.proxy_port[0] != - PF_NAT_PROXY_PORT_LOW && - r.rpool.proxy_port[1] != - PF_NAT_PROXY_PORT_HIGH) { - yyerror("the 'static-port' option can't" - " be used when specifying a port" - " range"); - YYERROR; - } - r.rpool.proxy_port[0] = 0; - r.rpool.proxy_port[1] = 0; - } - - expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, - $5.src_os, $5.src.host, $5.src.port, $5.dst.host, - $5.dst.port, 0, 0, 0, ""); - free($9); - } - ; - -binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag - tagged rtable redirection - { - struct pf_rule binat; - struct pf_pooladdr *pa; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - if (disallow_urpf_failed($9, "\"urpf-failed\" is not " - "permitted as a binat destination")) - YYERROR; - - memset(&binat, 0, sizeof(binat)); - - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - binat.action = PF_NOBINAT; - else - binat.action = PF_BINAT; - binat.natpass = $3.b1; - binat.log = $3.b2; - binat.logif = $3.w2; - binat.af = $5; - if (!binat.af && $8 != NULL && $8->af) - binat.af = $8->af; - if (!binat.af && $9 != NULL && $9->af) - binat.af = $9->af; - - if (!binat.af && $13 != NULL && $13->host) - binat.af = $13->host->af; - if (!binat.af) { - yyerror("address family (inet/inet6) " - "undefined"); - YYERROR; - } - - if ($4 != NULL) { - memcpy(binat.ifname, $4->ifname, - sizeof(binat.ifname)); - binat.ifnot = $4->not; - free($4); - } - - if ($10 != NULL) - if (strlcpy(binat.tagname, $10, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($11.name) - if (strlcpy(binat.match_tagname, $11.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - binat.match_tag_not = $11.neg; - binat.rtableid = $12; - - if ($6 != NULL) { - binat.proto = $6->proto; - free($6); - } - - if ($8 != NULL && disallow_table($8, "invalid use of " - "table <%s> as the source address of a binat rule")) - YYERROR; - if ($8 != NULL && disallow_alias($8, "invalid use of " - "interface (%s) as the source address of a binat " - "rule")) - YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_table( - $13->host, "invalid use of table <%s> as the " - "redirect address of a binat rule")) - YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_alias( - $13->host, "invalid use of interface (%s) as the " - "redirect address of a binat rule")) - YYERROR; - - if ($8 != NULL) { - if ($8->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if ($8->addr.type == PF_ADDR_DYNIFTL) - $8->af = binat.af; - if ($8->af != binat.af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask($8, binat.af)) - YYERROR; - memcpy(&binat.src.addr, &$8->addr, - sizeof(binat.src.addr)); - free($8); - } - if ($9 != NULL) { - if ($9->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if ($9->af != binat.af && $9->af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask($9, binat.af)) - YYERROR; - memcpy(&binat.dst.addr, &$9->addr, - sizeof(binat.dst.addr)); - binat.dst.neg = $9->not; - free($9); - } - - if (binat.action == PF_NOBINAT) { - if ($13 != NULL) { - yyerror("'no binat' rule does not need" - " '->'"); - YYERROR; - } - } else { - if ($13 == NULL || $13->host == NULL) { - yyerror("'binat' rule requires" - " '-> address'"); - YYERROR; - } - - remove_invalid_hosts(&$13->host, &binat.af); - if (invalid_redirect($13->host, binat.af)) - YYERROR; - if ($13->host->next != NULL) { - yyerror("binat rule must redirect to " - "a single address"); - YYERROR; - } - if (check_netmask($13->host, binat.af)) - YYERROR; - - if (!PF_AZERO(&binat.src.addr.v.a.mask, - binat.af) && - !PF_AEQ(&binat.src.addr.v.a.mask, - &$13->host->addr.v.a.mask, binat.af)) { - yyerror("'binat' source mask and " - "redirect mask must be the same"); - YYERROR; - } - - TAILQ_INIT(&binat.rpool.list); - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "binat: calloc"); - pa->addr = $13->host->addr; - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&binat.rpool.list, - pa, entries); - - free($13); - } - - pfctl_add_rule(pf, &binat, ""); - } - ; - -tag : /* empty */ { $$ = NULL; } - | TAG STRING { $$ = $2; } - ; - -tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } - | not TAGGED string { $$.neg = $1; $$.name = $3; } - ; - -rtable : /* empty */ { $$ = -1; } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - $$ = $2; - } - ; - -route_host : STRING { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "route_host: calloc"); - $$->ifname = $1; - set_ipmask($$, 128); - $$->next = NULL; - $$->tail = $$; - } - | '(' STRING host ')' { - $$ = $3; - $$->ifname = $2; - } - ; - -route_host_list : route_host optnl { $$ = $1; } - | route_host_list comma route_host optnl { - if ($1->af == 0) - $1->af = $3->af; - if ($1->af != $3->af) { - yyerror("all pool addresses must be in the " - "same address family"); - YYERROR; - } - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - ; - -routespec : route_host { $$ = $1; } - | '{' optnl route_host_list '}' { $$ = $3; } - ; - -route : /* empty */ { - $$.host = NULL; - $$.rt = 0; - $$.pool_opts = 0; - } - | FASTROUTE { - $$.host = NULL; - $$.rt = PF_FASTROUTE; - $$.pool_opts = 0; - } - | ROUTETO routespec pool_opts { - $$.host = $2; - $$.rt = PF_ROUTETO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - | REPLYTO routespec pool_opts { - $$.host = $2; - $$.rt = PF_REPLYTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - | DUPTO routespec pool_opts { - $$.host = $2; - $$.rt = PF_DUPTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - ; - -timeout_spec : STRING NUMBER - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($1); - YYERROR; - } - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { - yyerror("unknown timeout %s", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -timeout_list : timeout_list comma timeout_spec optnl - | timeout_spec optnl - ; - -limit_spec : STRING NUMBER - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($1); - YYERROR; - } - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_limit(pf, $1, $2) != 0) { - yyerror("unable to set limit %s %u", $1, $2); - free($1); - YYERROR; - } - free($1); - } - ; - -limit_list : limit_list comma limit_spec optnl - | limit_spec optnl - ; - -comma : ',' - | /* empty */ - ; - -yesno : NO { $$ = 0; } - | STRING { - if (!strcmp($1, "yes")) - $$ = 1; - else { - yyerror("invalid value '%s', expected 'yes' " - "or 'no'", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -unaryop : '=' { $$ = PF_OP_EQ; } - | '!' '=' { $$ = PF_OP_NE; } - | '<' '=' { $$ = PF_OP_LE; } - | '<' { $$ = PF_OP_LT; } - | '>' '=' { $$ = PF_OP_GE; } - | '>' { $$ = PF_OP_GT; } - ; - -%% - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - - file->errors++; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - return (0); -} - -int -disallow_table(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_TABLE) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -disallow_urpf_failed(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_URPFFAILED) { - yyerror(fmt); - return (1); - } - return (0); -} - -int -disallow_alias(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (DYNIF_MULTIADDR(h->addr)) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -rule_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - switch (r->action) { - case PF_PASS: - case PF_DROP: - case PF_SCRUB: - case PF_NOSCRUB: - problems = filter_consistent(r, anchor_call); - break; - case PF_NAT: - case PF_NONAT: - problems = nat_consistent(r); - break; - case PF_RDR: - case PF_NORDR: - problems = rdr_consistent(r); - break; - case PF_BINAT: - case PF_NOBINAT: - default: - break; - } - return (problems); -} - -int -filter_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && - (r->src.port_op || r->dst.port_op)) { - yyerror("port only applies to tcp/udp"); - problems++; - } - if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && - (r->type || r->code)) { - yyerror("icmp-type/code only applies to icmp"); - problems++; - } - if (!r->af && (r->type || r->code)) { - yyerror("must indicate address family with icmp-type/code"); - problems++; - } - if (r->overload_tblname[0] && - r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { - yyerror("'overload' requires 'max-src-conn' " - "or 'max-src-conn-rate'"); - problems++; - } - if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || - (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { - yyerror("proto %s doesn't match address family %s", - r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", - r->af == AF_INET ? "inet" : "inet6"); - problems++; - } - if (r->allow_opts && r->action != PF_PASS) { - yyerror("allow-opts can only be specified for pass rules"); - problems++; - } - if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || - r->dst.port_op || r->flagset || r->type || r->code)) { - yyerror("fragments can be filtered only on IP header fields"); - problems++; - } - if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { - yyerror("return-rst can only be applied to TCP rules"); - problems++; - } - if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { - yyerror("max-src-nodes requires 'source-track rule'"); - problems++; - } - if (r->action == PF_DROP && r->keep_state) { - yyerror("keep state on block rules doesn't make sense"); - problems++; - } - if (r->rule_flag & PFRULE_STATESLOPPY && - (r->keep_state == PF_STATE_MODULATE || - r->keep_state == PF_STATE_SYNPROXY)) { - yyerror("sloppy state matching cannot be used with " - "synproxy state or modulate state"); - problems++; - } - return (-problems); -} - -int -nat_consistent(struct pf_rule *r) -{ - return (0); /* yeah! */ -} - -int -rdr_consistent(struct pf_rule *r) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { - if (r->src.port_op) { - yyerror("src port only applies to tcp/udp"); - problems++; - } - if (r->dst.port_op) { - yyerror("dst port only applies to tcp/udp"); - problems++; - } - if (r->rpool.proxy_port[0]) { - yyerror("rpool port only applies to tcp/udp"); - problems++; - } - } - if (r->dst.port_op && - r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { - yyerror("invalid port operator for rdr destination port"); - problems++; - } - return (-problems); -} - -int -process_tabledef(char *name, struct table_opts *opts) -{ - struct pfr_buffer ab; - struct node_tinit *ti; - - bzero(&ab, sizeof(ab)); - ab.pfrb_type = PFRB_ADDRS; - SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { - if (ti->file) - if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { - if (errno) - yyerror("cannot load \"%s\": %s", - ti->file, strerror(errno)); - else - yyerror("file \"%s\" contains bad data", - ti->file); - goto _error; - } - if (ti->host) - if (append_addr_host(&ab, ti->host, 0, 0)) { - yyerror("cannot create address buffer: %s", - strerror(errno)); - goto _error; - } - } - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(name, opts->flags, opts->init_addr, - &opts->init_nodes); - if (!(pf->opts & PF_OPT_NOACTION) && - pfctl_define_table(name, opts->flags, opts->init_addr, - pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { - yyerror("cannot define table %s: %s", name, - pfr_strerror(errno)); - goto _error; - } - pf->tdirty = 1; - pfr_buf_clear(&ab); - return (0); -_error: - pfr_buf_clear(&ab); - return (-1); -} - -struct keywords { - const char *k_name; - int k_val; -}; - -/* macro gore, but you should've seen the prior indentation nightmare... */ - -#define FREE_LIST(T,r) \ - do { \ - T *p, *node = r; \ - while (node != NULL) { \ - p = node; \ - node = node->next; \ - free(p); \ - } \ - } while (0) - -#define LOOP_THROUGH(T,n,r,C) \ - do { \ - T *n; \ - if (r == NULL) { \ - r = calloc(1, sizeof(T)); \ - if (r == NULL) \ - err(1, "LOOP: calloc"); \ - r->next = NULL; \ - } \ - n = r; \ - while (n != NULL) { \ - do { \ - C; \ - } while (0); \ - n = n->next; \ - } \ - } while (0) - -void -expand_label_str(char *label, size_t len, const char *srch, const char *repl) -{ - char *tmp; - char *p, *q; - - if ((tmp = calloc(1, len)) == NULL) - err(1, "expand_label_str: calloc"); - p = q = label; - while ((q = strstr(p, srch)) != NULL) { - *q = '\0'; - if ((strlcat(tmp, p, len) >= len) || - (strlcat(tmp, repl, len) >= len)) - errx(1, "expand_label: label too long"); - q += strlen(srch); - p = q; - } - if (strlcat(tmp, p, len) >= len) - errx(1, "expand_label: label too long"); - strlcpy(label, tmp, len); /* always fits */ - free(tmp); -} - -void -expand_label_if(const char *name, char *label, size_t len, const char *ifname) -{ - if (strstr(label, name) != NULL) { - if (!*ifname) - expand_label_str(label, len, name, "any"); - else - expand_label_str(label, len, name, ifname); - } -} - -void -expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, - struct node_host *h) -{ - char tmp[64], tmp_not[66]; - - if (strstr(label, name) != NULL) { - switch (h->addr.type) { - case PF_ADDR_DYNIFTL: - snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); - break; - case PF_ADDR_TABLE: - snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); - break; - case PF_ADDR_NOROUTE: - snprintf(tmp, sizeof(tmp), "no-route"); - break; - case PF_ADDR_URPFFAILED: - snprintf(tmp, sizeof(tmp), "urpf-failed"); - break; - case PF_ADDR_ADDRMASK: - if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && - PF_AZERO(&h->addr.v.a.mask, af))) - snprintf(tmp, sizeof(tmp), "any"); - else { - char a[48]; - int bits; - - if (inet_ntop(af, &h->addr.v.a.addr, a, - sizeof(a)) == NULL) - snprintf(tmp, sizeof(tmp), "?"); - else { - bits = unmask(&h->addr.v.a.mask, af); - if ((af == AF_INET && bits < 32) || - (af == AF_INET6 && bits < 128)) - snprintf(tmp, sizeof(tmp), - "%s/%d", a, bits); - else - snprintf(tmp, sizeof(tmp), - "%s", a); - } - } - break; - default: - snprintf(tmp, sizeof(tmp), "?"); - break; - } - - if (h->not) { - snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); - expand_label_str(label, len, name, tmp_not); - } else - expand_label_str(label, len, name, tmp); - } -} - -void -expand_label_port(const char *name, char *label, size_t len, - struct node_port *port) -{ - char a1[6], a2[6], op[13] = ""; - - if (strstr(label, name) != NULL) { - snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); - snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); - if (!port->op) - ; - else if (port->op == PF_OP_IRG) - snprintf(op, sizeof(op), "%s><%s", a1, a2); - else if (port->op == PF_OP_XRG) - snprintf(op, sizeof(op), "%s<>%s", a1, a2); - else if (port->op == PF_OP_EQ) - snprintf(op, sizeof(op), "%s", a1); - else if (port->op == PF_OP_NE) - snprintf(op, sizeof(op), "!=%s", a1); - else if (port->op == PF_OP_LT) - snprintf(op, sizeof(op), "<%s", a1); - else if (port->op == PF_OP_LE) - snprintf(op, sizeof(op), "<=%s", a1); - else if (port->op == PF_OP_GT) - snprintf(op, sizeof(op), ">%s", a1); - else if (port->op == PF_OP_GE) - snprintf(op, sizeof(op), ">=%s", a1); - expand_label_str(label, len, name, op); - } -} - -void -expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) -{ - struct protoent *pe; - char n[4]; - - if (strstr(label, name) != NULL) { - pe = getprotobynumber(proto); - if (pe != NULL) - expand_label_str(label, len, name, pe->p_name); - else { - snprintf(n, sizeof(n), "%u", proto); - expand_label_str(label, len, name, n); - } - } -} - -void -expand_label_nr(const char *name, char *label, size_t len) -{ - char n[11]; - - if (strstr(label, name) != NULL) { - snprintf(n, sizeof(n), "%u", pf->anchor->match); - expand_label_str(label, len, name, n); - } -} - -void -expand_label(char *label, size_t len, const char *ifname, sa_family_t af, - struct node_host *src_host, struct node_port *src_port, - struct node_host *dst_host, struct node_port *dst_port, - u_int8_t proto) -{ - expand_label_if("$if", label, len, ifname); - expand_label_addr("$srcaddr", label, len, af, src_host); - expand_label_addr("$dstaddr", label, len, af, dst_host); - expand_label_port("$srcport", label, len, src_port); - expand_label_port("$dstport", label, len, dst_port); - expand_label_proto("$proto", label, len, proto); - expand_label_nr("$nr", label, len); -} - -int -expand_altq(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct pf_altq pa, pb; - char qname[PF_QNAME_SIZE]; - struct node_queue *n; - struct node_queue_bw bw; - int errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - memcpy(&pa, a, sizeof(struct pf_altq)); - if (strlcpy(pa.ifname, interface->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_altq: strlcpy"); - - if (interface->not) { - yyerror("altq on ! <interface> is not supported"); - errs++; - } else { - if (eval_pfaltq(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - if (pf->opts & PF_OPT_VERBOSE) { - print_altq(&pf->paltq->altq, 0, - &bwspec, opts); - if (nqueues && nqueues->tail) { - printf("queue { "); - LOOP_THROUGH(struct node_queue, queue, - nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) { - /* now create a root queue */ - memset(&pb, 0, sizeof(struct pf_altq)); - if (strlcpy(qname, "root_", sizeof(qname)) >= - sizeof(qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcat(qname, interface->ifname, - sizeof(qname)) >= sizeof(qname)) - errx(1, "expand_altq: strlcat"); - if (strlcpy(pb.qname, qname, - sizeof(pb.qname)) >= sizeof(pb.qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(pb.ifname, interface->ifname, - sizeof(pb.ifname)) >= sizeof(pb.ifname)) - errx(1, "expand_altq: strlcpy"); - pb.qlimit = pa.qlimit; - pb.scheduler = pa.scheduler; - bw.bw_absolute = pa.ifbandwidth; - bw.bw_percent = 0; - if (eval_pfqueue(pf, &pb, &bw, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pb)) - errs++; - } - - LOOP_THROUGH(struct node_queue, queue, nqueues, - n = calloc(1, sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_altq: calloc"); - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) - if (strlcpy(n->parent, qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->queue, queue->queue, - sizeof(n->queue)) >= sizeof(n->queue)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->ifname, interface->ifname, - sizeof(n->ifname)) >= sizeof(n->ifname)) - errx(1, "expand_altq: strlcpy"); - n->scheduler = pa.scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - ); - } - ); - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - - return (errs); -} - -int -expand_queue(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct node_queue *n, *nq; - struct pf_altq pa; - u_int8_t found = 0; - u_int8_t errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - if (queues == NULL) { - yyerror("queue %s has no parent", a->qname); - FREE_LIST(struct node_queue, nqueues); - return (1); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_queue, tqueue, queues, - if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && - (interface->ifname[0] == 0 || - (!interface->not && !strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)) || - (interface->not && strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)))) { - /* found ourself in queues */ - found++; - - memcpy(&pa, a, sizeof(struct pf_altq)); - - if (pa.scheduler != ALTQT_NONE && - pa.scheduler != tqueue->scheduler) { - yyerror("exactly one scheduler type " - "per interface allowed"); - return (1); - } - pa.scheduler = tqueue->scheduler; - - /* scheduler dependent error checking */ - switch (pa.scheduler) { - case ALTQT_PRIQ: - if (nqueues != NULL) { - yyerror("priq queues cannot " - "have child queues"); - return (1); - } - if (bwspec.bw_absolute > 0 || - bwspec.bw_percent < 100) { - yyerror("priq doesn't take " - "bandwidth"); - return (1); - } - break; - default: - break; - } - - if (strlcpy(pa.ifname, tqueue->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_queue: strlcpy"); - if (strlcpy(pa.parent, tqueue->parent, - sizeof(pa.parent)) >= sizeof(pa.parent)) - errx(1, "expand_queue: strlcpy"); - - if (eval_pfqueue(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - for (nq = nqueues; nq != NULL; nq = nq->next) { - if (!strcmp(a->qname, nq->queue)) { - yyerror("queue cannot have " - "itself as child"); - errs++; - continue; - } - n = calloc(1, - sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_queue: calloc"); - if (strlcpy(n->parent, a->qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->queue, nq->queue, - sizeof(n->queue)) >= - sizeof(n->queue)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->ifname, tqueue->ifname, - sizeof(n->ifname)) >= - sizeof(n->ifname)) - errx(1, "expand_queue strlcpy"); - n->scheduler = tqueue->scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - } - if ((pf->opts & PF_OPT_VERBOSE) && ( - (found == 1 && interface->ifname[0] == 0) || - (found > 0 && interface->ifname[0] != 0))) { - print_queue(&pf->paltq->altq, 0, - &bwspec, interface->ifname[0] != 0, - opts); - if (nqueues && nqueues->tail) { - printf("{ "); - LOOP_THROUGH(struct node_queue, - queue, nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - } - ); - ); - - FREE_LIST(struct node_queue, nqueues); - FREE_LIST(struct node_if, interfaces); - - if (!found) { - yyerror("queue %s has no parent", a->qname); - errs++; - } - - if (errs) - return (1); - else - return (0); -} - -void -expand_rule(struct pf_rule *r, - struct node_if *interfaces, struct node_host *rpool_hosts, - struct node_proto *protos, struct node_os *src_oses, - struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports, - struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, - const char *anchor_call) -{ - sa_family_t af = r->af; - int added = 0, error = 0; - char ifname[IF_NAMESIZE]; - char label[PF_RULE_LABEL_SIZE]; - char tagname[PF_TAG_NAME_SIZE]; - char match_tagname[PF_TAG_NAME_SIZE]; - struct pf_pooladdr *pa; - struct node_host *h; - u_int8_t flags, flagset, keep_state; - - if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= - sizeof(match_tagname)) - errx(1, "expand_rule: strlcpy"); - flags = r->flags; - flagset = r->flagset; - keep_state = r->keep_state; - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_proto, proto, protos, - LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, - LOOP_THROUGH(struct node_host, src_host, src_hosts, - LOOP_THROUGH(struct node_port, src_port, src_ports, - LOOP_THROUGH(struct node_os, src_os, src_oses, - LOOP_THROUGH(struct node_host, dst_host, dst_hosts, - LOOP_THROUGH(struct node_port, dst_port, dst_ports, - LOOP_THROUGH(struct node_uid, uid, uids, - LOOP_THROUGH(struct node_gid, gid, gids, - - r->af = af; - /* for link-local IPv6 address, interface must match up */ - if ((r->af && src_host->af && r->af != src_host->af) || - (r->af && dst_host->af && r->af != dst_host->af) || - (src_host->af && dst_host->af && - src_host->af != dst_host->af) || - (src_host->ifindex && dst_host->ifindex && - src_host->ifindex != dst_host->ifindex) || - (src_host->ifindex && *interface->ifname && - src_host->ifindex != if_nametoindex(interface->ifname)) || - (dst_host->ifindex && *interface->ifname && - dst_host->ifindex != if_nametoindex(interface->ifname))) - continue; - if (!r->af && src_host->af) - r->af = src_host->af; - else if (!r->af && dst_host->af) - r->af = dst_host->af; - - if (*interface->ifname) - strlcpy(r->ifname, interface->ifname, - sizeof(r->ifname)); - else if (if_indextoname(src_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else if (if_indextoname(dst_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else - memset(r->ifname, '\0', sizeof(r->ifname)); - - if (strlcpy(r->label, label, sizeof(r->label)) >= - sizeof(r->label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= - sizeof(r->tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->match_tagname, match_tagname, - sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) - errx(1, "expand_rule: strlcpy"); - expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, - r->af, src_host, src_port, dst_host, dst_port, - proto->proto); - - error += check_netmask(src_host, r->af); - error += check_netmask(dst_host, r->af); - - r->ifnot = interface->not; - r->proto = proto->proto; - r->src.addr = src_host->addr; - r->src.neg = src_host->not; - r->src.port[0] = src_port->port[0]; - r->src.port[1] = src_port->port[1]; - r->src.port_op = src_port->op; - r->dst.addr = dst_host->addr; - r->dst.neg = dst_host->not; - r->dst.port[0] = dst_port->port[0]; - r->dst.port[1] = dst_port->port[1]; - r->dst.port_op = dst_port->op; - r->uid.op = uid->op; - r->uid.uid[0] = uid->uid[0]; - r->uid.uid[1] = uid->uid[1]; - r->gid.op = gid->op; - r->gid.gid[0] = gid->gid[0]; - r->gid.gid[1] = gid->gid[1]; - r->type = icmp_type->type; - r->code = icmp_type->code; - - if ((keep_state == PF_STATE_MODULATE || - keep_state == PF_STATE_SYNPROXY) && - r->proto && r->proto != IPPROTO_TCP) - r->keep_state = PF_STATE_NORMAL; - else - r->keep_state = keep_state; - - if (r->proto && r->proto != IPPROTO_TCP) { - r->flags = 0; - r->flagset = 0; - } else { - r->flags = flags; - r->flagset = flagset; - } - if (icmp_type->proto && r->proto != icmp_type->proto) { - yyerror("icmp-type mismatch"); - error++; - } - - if (src_os && src_os->os) { - r->os_fingerprint = pfctl_get_fingerprint(src_os->os); - if ((pf->opts & PF_OPT_VERBOSE2) && - r->os_fingerprint == PF_OSFP_NOMATCH) - fprintf(stderr, - "warning: unknown '%s' OS fingerprint\n", - src_os->os); - } else { - r->os_fingerprint = PF_OSFP_ANY; - } - - TAILQ_INIT(&r->rpool.list); - for (h = rpool_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); - } - - if (rule_consistent(r, anchor_call[0]) < 0 || error) - yyerror("skipping rule due to errors"); - else { - r->nr = pf->astack[pf->asd]->match++; - pfctl_add_rule(pf, r, anchor_call); - added++; - } - - )))))))))); - - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_proto, protos); - FREE_LIST(struct node_host, src_hosts); - FREE_LIST(struct node_port, src_ports); - FREE_LIST(struct node_os, src_oses); - FREE_LIST(struct node_host, dst_hosts); - FREE_LIST(struct node_port, dst_ports); - FREE_LIST(struct node_uid, uids); - FREE_LIST(struct node_gid, gids); - FREE_LIST(struct node_icmp, icmp_types); - FREE_LIST(struct node_host, rpool_hosts); - - if (!added) - yyerror("rule expands to no valid combination"); -} - -int -expand_skip_interface(struct node_if *interfaces) -{ - int errs = 0; - - if (!interfaces || (!interfaces->next && !interfaces->not && - !strcmp(interfaces->ifname, "none"))) { - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on none\n"); - errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); - return (errs); - } - - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on {"); - LOOP_THROUGH(struct node_if, interface, interfaces, - if (pf->opts & PF_OPT_VERBOSE) - printf(" %s", interface->ifname); - if (interface->not) { - yyerror("skip on ! <interface> is not supported"); - errs++; - } else - errs += pfctl_set_interface_flags(pf, - interface->ifname, PFI_IFLAG_SKIP, 1); - ); - if (pf->opts & PF_OPT_VERBOSE) - printf(" }\n"); - - FREE_LIST(struct node_if, interfaces); - - if (errs) - return (1); - else - return (0); -} - -#undef FREE_LIST -#undef LOOP_THROUGH - -int -check_rulestate(int desired_state) -{ - if (require_order && (rulestate > desired_state)) { - yyerror("Rules must be in order: options, normalization, " - "queueing, translation, filtering"); - return (1); - } - rulestate = desired_state; - return (0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* this has to be sorted always */ - static const struct keywords keywords[] = { - { "all", ALL}, - { "allow-opts", ALLOWOPTS}, - { "altq", ALTQ}, - { "anchor", ANCHOR}, - { "antispoof", ANTISPOOF}, - { "any", ANY}, - { "bandwidth", BANDWIDTH}, - { "binat", BINAT}, - { "binat-anchor", BINATANCHOR}, - { "bitmask", BITMASK}, - { "block", BLOCK}, - { "block-policy", BLOCKPOLICY}, - { "cbq", CBQ}, - { "code", CODE}, - { "crop", FRAGCROP}, - { "debug", DEBUG}, - { "divert-reply", DIVERTREPLY}, - { "divert-to", DIVERTTO}, - { "drop", DROP}, - { "drop-ovl", FRAGDROP}, - { "dup-to", DUPTO}, - { "fastroute", FASTROUTE}, - { "file", FILENAME}, - { "fingerprints", FINGERPRINTS}, - { "flags", FLAGS}, - { "floating", FLOATING}, - { "flush", FLUSH}, - { "for", FOR}, - { "fragment", FRAGMENT}, - { "from", FROM}, - { "global", GLOBAL}, - { "group", GROUP}, - { "hfsc", HFSC}, - { "hostid", HOSTID}, - { "icmp-type", ICMPTYPE}, - { "icmp6-type", ICMP6TYPE}, - { "if-bound", IFBOUND}, - { "in", IN}, - { "include", INCLUDE}, - { "inet", INET}, - { "inet6", INET6}, - { "keep", KEEP}, - { "label", LABEL}, - { "limit", LIMIT}, - { "linkshare", LINKSHARE}, - { "load", LOAD}, - { "log", LOG}, - { "loginterface", LOGINTERFACE}, - { "max", MAXIMUM}, - { "max-mss", MAXMSS}, - { "max-src-conn", MAXSRCCONN}, - { "max-src-conn-rate", MAXSRCCONNRATE}, - { "max-src-nodes", MAXSRCNODES}, - { "max-src-states", MAXSRCSTATES}, - { "min-ttl", MINTTL}, - { "modulate", MODULATE}, - { "nat", NAT}, - { "nat-anchor", NATANCHOR}, - { "no", NO}, - { "no-df", NODF}, - { "no-route", NOROUTE}, - { "no-sync", NOSYNC}, - { "on", ON}, - { "optimization", OPTIMIZATION}, - { "os", OS}, - { "out", OUT}, - { "overload", OVERLOAD}, - { "pass", PASS}, - { "pflow", PFLOW}, - { "port", PORT}, - { "priority", PRIORITY}, - { "priq", PRIQ}, - { "probability", PROBABILITY}, - { "proto", PROTO}, - { "qlimit", QLIMIT}, - { "queue", QUEUE}, - { "quick", QUICK}, - { "random", RANDOM}, - { "random-id", RANDOMID}, - { "rdr", RDR}, - { "rdr-anchor", RDRANCHOR}, - { "realtime", REALTIME}, - { "reassemble", REASSEMBLE}, - { "reply-to", REPLYTO}, - { "require-order", REQUIREORDER}, - { "return", RETURN}, - { "return-icmp", RETURNICMP}, - { "return-icmp6", RETURNICMP6}, - { "return-rst", RETURNRST}, - { "round-robin", ROUNDROBIN}, - { "route", ROUTE}, - { "route-to", ROUTETO}, - { "rtable", RTABLE}, - { "rule", RULE}, - { "ruleset-optimization", RULESET_OPTIMIZATION}, - { "scrub", SCRUB}, - { "set", SET}, - { "set-tos", SETTOS}, - { "skip", SKIP}, - { "sloppy", SLOPPY}, - { "source-hash", SOURCEHASH}, - { "source-track", SOURCETRACK}, - { "state", STATE}, - { "state-defaults", STATEDEFAULTS}, - { "state-policy", STATEPOLICY}, - { "static-port", STATICPORT}, - { "sticky-address", STICKYADDRESS}, - { "synproxy", SYNPROXY}, - { "table", TABLE}, - { "tag", TAG}, - { "tagged", TAGGED}, - { "tbrsize", TBRSIZE}, - { "timeout", TIMEOUT}, - { "to", TO}, - { "tos", TOS}, - { "ttl", TTL}, - { "upperlimit", UPPERLIMIT}, - { "urpf-failed", URPFFAILED}, - { "user", USER}, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) { - if (debug > 1) - fprintf(stderr, "%s: %d\n", s, p->k_val); - return (p->k_val); - } else { - if (debug > 1) - fprintf(stderr, "string: %s\n", s); - return (STRING); - } -} - -#define MAXPUSHBACK 128 - -#ifndef __rtems__ -char *parsebuf; -int parseindex; -char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; -#else /* __rtems__ */ -static char *parsebuf; -static int parseindex; -static char pushback_buffer[MAXPUSHBACK]; -static int pushback_index = 0; -#endif /* __rtems__ */ - -int -lgetc(int quotec) -{ - int c, next; - - if (parsebuf) { - /* Read character from the parsebuffer instead of input. */ - if (parseindex >= 0) { - c = parsebuf[parseindex++]; - if (c != '\0') - return (c); - parsebuf = NULL; - } else - parseindex++; - } - - if (pushback_index) - return (pushback_buffer[--pushback_index]); - - if (quotec) { - if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); - if (popfile() == EOF) - return (EOF); - return (quotec); - } - return (c); - } - - while ((c = getc(file->stream)) == '\\') { - next = getc(file->stream); - if (next != '\n') { - c = next; - break; - } - yylval.lineno = file->lineno; - file->lineno++; - } - - while (c == EOF) { - if (popfile() == EOF) - return (EOF); - c = getc(file->stream); - } - return (c); -} - -int -lungetc(int c) -{ - if (c == EOF) - return (EOF); - if (parsebuf) { - parseindex--; - if (parseindex >= 0) - return (c); - } - if (pushback_index < MAXPUSHBACK-1) - return (pushback_buffer[pushback_index++] = c); - else - return (EOF); -} - -int -findeol(void) -{ - int c; - - parsebuf = NULL; - - /* skip to either EOF or the first real EOL */ - while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; - -top: - p = buf; - while ((c = lgetc(0)) == ' ' || c == '\t') - ; /* nothing */ - - yylval.lineno = file->lineno; - if (c == '#') - while ((c = lgetc(0)) != '\n' && c != EOF) - ; /* nothing */ - if (c == '$' && parsebuf == NULL) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = (char)c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - parsebuf = val; - parseindex = 0; - goto top; - } - - switch (c) { - case '\'': - case '"': - quotec = c; - while (1) { - if ((c = lgetc(quotec)) == EOF) - return (0); - if (c == '\n') { - file->lineno++; - continue; - } else if (c == '\\') { - if ((next = lgetc(quotec)) == EOF) - return (0); - if (next == quotec || c == ' ' || c == '\t') - c = next; - else if (next == '\n') - continue; - else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; - break; - } - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - *p++ = (char)c; - } - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - err(1, "yylex: strdup"); - return (STRING); - case '<': - next = lgetc(0); - if (next == '>') { - yylval.v.i = PF_OP_XRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '>': - next = lgetc(0); - if (next == '<') { - yylval.v.i = PF_OP_IRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '-': - next = lgetc(0); - if (next == '>') - return (ARROW); - lungetc(next); - break; - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && isdigit(c)); - lungetc(c); - if (p == buf + 1 && buf[0] == '-') - goto nodigits; - if (c == EOF || allowed_to_end_number(c)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - return (findeol()); - } - return (NUMBER); - } else { -nodigits: - while (p > buf + 1) - lungetc(*--p); - c = *--p; - if (c == '-') - return (c); - } - } - -#define allowed_in_string(x) \ - (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && x != '<' && x != '>' && \ - x != '!' && x != '=' && x != '/' && x != '#' && \ - x != ',')) - - if (isalnum(c) || c == ':' || c == '_') { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); - lungetc(c); - *p = '\0'; - if ((token = lookup(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - err(1, "yylex: strdup"); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -int -check_file_secrecy(int fd, const char *fname) -{ - struct stat st; - - if (fstat(fd, &st)) { - warn("cannot stat %s", fname); - return (-1); - } - if (st.st_uid != 0 && st.st_uid != getuid()) { - warnx("%s: owner not root or current user", fname); - return (-1); - } - if (st.st_mode & (S_IRWXG | S_IRWXO)) { - warnx("%s: group/world readable/writeable", fname); - return (-1); - } - return (0); -} - -struct file * -pushfile(const char *name, int secret) -{ - struct file *nfile; - - if ((nfile = calloc(1, sizeof(struct file))) == NULL || - (nfile->name = strdup(name)) == NULL) { - warn("malloc"); - return (NULL); - } - if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { - nfile->stream = stdin; - free(nfile->name); - if ((nfile->name = strdup("stdin")) == NULL) { - warn("strdup"); - free(nfile); - return (NULL); - } - } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - warn("%s", nfile->name); - free(nfile->name); - free(nfile); - return (NULL); - } else if (secret && - check_file_secrecy(fileno(nfile->stream), nfile->name)) { - fclose(nfile->stream); - free(nfile->name); - free(nfile); - return (NULL); - } - nfile->lineno = 1; - TAILQ_INSERT_TAIL(&files, nfile, entry); - return (nfile); -} - -int -popfile(void) -{ - struct file *prev; - - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { - prev->errors += file->errors; - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file); - file = prev; - return (0); - } - return (EOF); -} - -int -parse_config(char *filename, struct pfctl *xpf) -{ - int errors = 0; - struct sym *sym; - - pf = xpf; - errors = 0; - rulestate = PFCTL_STATE_NONE; - returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; - returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; - blockpolicy = PFRULE_DROP; - require_order = 1; - - if ((file = pushfile(filename, 0)) == NULL) { - warn("cannot open the main config file!"); - return (-1); - } - - yyparse(); - errors = file->errors; - popfile(); - - /* Free macros and check which have not been used. */ - while ((sym = TAILQ_FIRST(&symhead))) { - if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) - fprintf(stderr, "warning: macro '%s' not " - "used\n", sym->nam); - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - - return (errors ? -1 : 0); -} - -int -symset(const char *nam, const char *val, int persist) -{ - struct sym *sym; - - for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); - sym = TAILQ_NEXT(sym, entry)) - ; /* nothing */ - - if (sym != NULL) { - if (sym->persist == 1) - return (0); - else { - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - } - if ((sym = calloc(1, sizeof(*sym))) == NULL) - return (-1); - - sym->nam = strdup(nam); - if (sym->nam == NULL) { - free(sym); - return (-1); - } - sym->val = strdup(val); - if (sym->val == NULL) { - free(sym->nam); - free(sym); - return (-1); - } - sym->used = 0; - sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entry); - return (0); -} - -int -pfctl_cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - - if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) - err(1, "pfctl_cmdline_symset: malloc"); - - strlcpy(sym, s, strlen(s) - strlen(val) + 1); - - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - -char * -symget(const char *nam) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) - if (strcmp(nam, sym->nam) == 0) { - sym->used = 1; - return (sym->val); - } - return (NULL); -} - -void -mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) -{ - int i; - struct pf_rule *r; - - for (i = 0; i < PF_RULESET_MAX; ++i) { - while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); - dst->anchor->match++; - } - src->anchor->match = 0; - while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, - r, entries); - } - } -} - -void -decide_address_family(struct node_host *n, sa_family_t *af) -{ - if (*af != 0 || n == NULL) - return; - *af = n->af; - while ((n = n->next) != NULL) { - if (n->af != *af) { - *af = 0; - return; - } - } -} - -void -remove_invalid_hosts(struct node_host **nh, sa_family_t *af) -{ - struct node_host *n = *nh, *prev = NULL; - - while (n != NULL) { - if (*af && n->af && n->af != *af) { - /* unlink and free n */ - struct node_host *next = n->next; - - /* adjust tail pointer */ - if (n == (*nh)->tail) - (*nh)->tail = prev; - /* adjust previous node's next pointer */ - if (prev == NULL) - *nh = next; - else - prev->next = next; - /* free node */ - if (n->ifname != NULL) - free(n->ifname); - free(n); - n = next; - } else { - if (n->af && !*af) - *af = n->af; - prev = n; - n = n->next; - } - } -} - -int -invalid_redirect(struct node_host *nh, sa_family_t af) -{ - if (!af) { - struct node_host *n; - - /* tables and dyniftl are ok without an address family */ - for (n = nh; n != NULL; n = n->next) { - if (n->addr.type != PF_ADDR_TABLE && - n->addr.type != PF_ADDR_DYNIFTL) { - yyerror("address family not given and " - "translation address expands to multiple " - "address families"); - return (1); - } - } - } - if (nh == NULL) { - yyerror("no translation address with matching address family " - "found."); - return (1); - } - return (0); -} - -int -atoul(char *s, u_long *ulvalp) -{ - u_long ulval; - char *ep; - - errno = 0; - ulval = strtoul(s, &ep, 0); - if (s[0] == '\0' || *ep != '\0') - return (-1); - if (errno == ERANGE && ulval == ULONG_MAX) - return (-1); - *ulvalp = ulval; - return (0); -} - -int -getservice(char *n) -{ - struct servent *s; - u_long ulval; - - if (atoul(n, &ulval) == 0) { - if (ulval > 65535) { - yyerror("illegal port value %lu", ulval); - return (-1); - } - return (htons(ulval)); - } else { - s = getservbyname(n, "tcp"); - if (s == NULL) - s = getservbyname(n, "udp"); - if (s == NULL) { - yyerror("unknown port %s", n); - return (-1); - } - return (s->s_port); - } -} - -int -rule_label(struct pf_rule *r, char *s) -{ - if (s) { - if (strlcpy(r->label, s, sizeof(r->label)) >= - sizeof(r->label)) { - yyerror("rule label too long (max %d chars)", - sizeof(r->label)-1); - return (-1); - } - } - return (0); -} - -u_int16_t -parseicmpspec(char *w, sa_family_t af) -{ - const struct icmpcodeent *p; - u_long ulval; - u_int8_t icmptype; - - if (af == AF_INET) - icmptype = returnicmpdefault >> 8; - else - icmptype = returnicmp6default >> 8; - - if (atoul(w, &ulval) == -1) { - if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { - yyerror("unknown icmp code %s", w); - return (0); - } - ulval = p->code; - } - if (ulval > 255) { - yyerror("invalid icmp code %lu", ulval); - return (0); - } - return (icmptype << 8 | ulval); -} - -int -parseport(char *port, struct range *r, int extensions) -{ - char *p = strchr(port, ':'); - - if (p == NULL) { - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_NONE; - return (0); - } - if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { - *p = 0; - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_IRG; - return (0); - } - if ((extensions & PPORT_RANGE)) { - *p++ = 0; - if ((r->a = getservice(port)) == -1 || - (r->b = getservice(p)) == -1) - return (-1); - if (r->a == r->b) { - r->b = 0; - r->t = PF_OP_NONE; - } else - r->t = PF_OP_RRG; - return (0); - } - return (-1); -} - -int -pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) -{ - struct loadanchors *la; - - TAILQ_FOREACH(la, &loadanchorshead, entries) { - if (pf->opts & PF_OPT_VERBOSE) - fprintf(stderr, "\nLoading anchor %s from %s\n", - la->anchorname, la->filename); - if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, - la->anchorname, trans) == -1) - return (-1); - } - - return (0); -} - -int -rt_tableid_max(void) -{ -#ifdef __FreeBSD__ - int fibs; - size_t l = sizeof(fibs); - - if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) - fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ - /* - * As the OpenBSD code only compares > and not >= we need to adjust - * here given we only accept values of 0..n and want to avoid #ifdefs - * in the grammer. - */ - return (fibs - 1); -#else - return (RT_TABLEID_MAX); -#endif -} -#ifdef __rtems__ -#include "parse-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pf_print_state.c b/freebsd/contrib/pf/pfctl/pf_print_state.c deleted file mode 100644 index 237b3dea..00000000 --- a/freebsd/contrib/pf/pfctl/pf_print_state.c +++ /dev/null @@ -1,385 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/socket.h> -#ifdef __FreeBSD__ -#include <sys/endian.h> -#define betoh64 be64toh -#endif -#include <net/if.h> -#define TCPSTATES -#include <netinet/tcp_fsm.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <stdio.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void print_name(struct pf_addr *, sa_family_t); - -void -print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) -{ - switch (addr->type) { - case PF_ADDR_DYNIFTL: - printf("(%s", addr->v.ifname); - if (addr->iflags & PFI_AFLAG_NETWORK) - printf(":network"); - if (addr->iflags & PFI_AFLAG_BROADCAST) - printf(":broadcast"); - if (addr->iflags & PFI_AFLAG_PEER) - printf(":peer"); - if (addr->iflags & PFI_AFLAG_NOALIAS) - printf(":0"); - if (verbose) { - if (addr->p.dyncnt <= 0) - printf(":*"); - else - printf(":%d", addr->p.dyncnt); - } - printf(")"); - break; - case PF_ADDR_TABLE: - if (verbose) - if (addr->p.tblcnt == -1) - printf("<%s:*>", addr->v.tblname); - else - printf("<%s:%d>", addr->v.tblname, - addr->p.tblcnt); - else - printf("<%s>", addr->v.tblname); - return; - case PF_ADDR_RANGE: { - char buf[48]; - - if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL) - printf(" - ?"); - else - printf(" - %s", buf); - break; - } - case PF_ADDR_ADDRMASK: - if (PF_AZERO(&addr->v.a.addr, AF_INET6) && - PF_AZERO(&addr->v.a.mask, AF_INET6)) - printf("any"); - else { - char buf[48]; - - if (inet_ntop(af, &addr->v.a.addr, buf, - sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - } - break; - case PF_ADDR_NOROUTE: - printf("no-route"); - return; - case PF_ADDR_URPFFAILED: - printf("urpf-failed"); - return; - case PF_ADDR_RTLABEL: - printf("route \"%s\"", addr->v.rtlabelname); - return; - default: - printf("?"); - return; - } - - /* mask if not _both_ address and mask are zero */ - if (addr->type != PF_ADDR_RANGE && - !(PF_AZERO(&addr->v.a.addr, AF_INET6) && - PF_AZERO(&addr->v.a.mask, AF_INET6))) { - int bits = unmask(&addr->v.a.mask, af); - - if (bits != (af == AF_INET ? 32 : 128)) - printf("/%d", bits); - } -} - -void -print_name(struct pf_addr *addr, sa_family_t af) -{ - char host[NI_MAXHOST]; - - strlcpy(host, "?", sizeof(host)); - switch (af) { - case AF_INET: { - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr = addr->v4; - getnameinfo((struct sockaddr *)&sin, sin.sin_len, - host, sizeof(host), NULL, 0, NI_NOFQDN); - break; - } - case AF_INET6: { - struct sockaddr_in6 sin6; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = addr->v6; - getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - host, sizeof(host), NULL, 0, NI_NOFQDN); - break; - } - } - printf("%s", host); -} - -void -print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) -{ - if (opts & PF_OPT_USEDNS) - print_name(addr, af); - else { - struct pf_addr_wrap aw; - - memset(&aw, 0, sizeof(aw)); - aw.v.a.addr = *addr; - if (af == AF_INET) - aw.v.a.mask.addr32[0] = 0xffffffff; - else { - memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); - af = AF_INET6; - } - print_addr(&aw, af, opts & PF_OPT_VERBOSE2); - } - - if (port) { - if (af == AF_INET) - printf(":%u", ntohs(port)); - else - printf("[%u]", ntohs(port)); - } -} - -void -print_seq(struct pfsync_state_peer *p) -{ - if (p->seqdiff) - printf("[%u + %u](+%u)", ntohl(p->seqlo), - ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); - else - printf("[%u + %u]", ntohl(p->seqlo), - ntohl(p->seqhi) - ntohl(p->seqlo)); -} - -void -print_state(struct pfsync_state *s, int opts) -{ - struct pfsync_state_peer *src, *dst; - struct pfsync_state_key *sk, *nk; - struct protoent *p; - int min, sec; - - if (s->direction == PF_OUT) { - src = &s->src; - dst = &s->dst; - sk = &s->key[PF_SK_STACK]; - nk = &s->key[PF_SK_WIRE]; - if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) - sk->port[0] = nk->port[0]; - } else { - src = &s->dst; - dst = &s->src; - sk = &s->key[PF_SK_WIRE]; - nk = &s->key[PF_SK_STACK]; - if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) - sk->port[1] = nk->port[1]; - } - printf("%s ", s->ifname); - if ((p = getprotobynumber(s->proto)) != NULL) - printf("%s ", p->p_name); - else - printf("%u ", s->proto); - - print_host(&nk->addr[1], nk->port[1], s->af, opts); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || - nk->port[1] != sk->port[1]) { - printf(" ("); - print_host(&sk->addr[1], sk->port[1], s->af, opts); - printf(")"); - } - if (s->direction == PF_OUT) - printf(" -> "); - else - printf(" <- "); - print_host(&nk->addr[0], nk->port[0], s->af, opts); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || - nk->port[0] != sk->port[0]) { - printf(" ("); - print_host(&sk->addr[0], sk->port[0], s->af, opts); - printf(")"); - } - - printf(" "); - if (s->proto == IPPROTO_TCP) { - if (src->state <= TCPS_TIME_WAIT && - dst->state <= TCPS_TIME_WAIT) - printf(" %s:%s\n", tcpstates[src->state], - tcpstates[dst->state]); - else if (src->state == PF_TCPS_PROXY_SRC || - dst->state == PF_TCPS_PROXY_SRC) - printf(" PROXY:SRC\n"); - else if (src->state == PF_TCPS_PROXY_DST || - dst->state == PF_TCPS_PROXY_DST) - printf(" PROXY:DST\n"); - else - printf(" <BAD STATE LEVELS %u:%u>\n", - src->state, dst->state); - if (opts & PF_OPT_VERBOSE) { - printf(" "); - print_seq(src); - if (src->wscale && dst->wscale) - printf(" wscale %u", - src->wscale & PF_WSCALE_MASK); - printf(" "); - print_seq(dst); - if (src->wscale && dst->wscale) - printf(" wscale %u", - dst->wscale & PF_WSCALE_MASK); - printf("\n"); - } - } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && - dst->state < PFUDPS_NSTATES) { - const char *states[] = PFUDPS_NAMES; - - printf(" %s:%s\n", states[src->state], states[dst->state]); - } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && - dst->state < PFOTHERS_NSTATES) { - /* XXX ICMP doesn't really have state levels */ - const char *states[] = PFOTHERS_NAMES; - - printf(" %s:%s\n", states[src->state], states[dst->state]); - } else { - printf(" %u:%u\n", src->state, dst->state); - } - - if (opts & PF_OPT_VERBOSE) { - u_int64_t packets[2]; - u_int64_t bytes[2]; - u_int32_t creation = ntohl(s->creation); - u_int32_t expire = ntohl(s->expire); - - sec = creation % 60; - creation /= 60; - min = creation % 60; - creation /= 60; - printf(" age %.2u:%.2u:%.2u", creation, min, sec); - sec = expire % 60; - expire /= 60; - min = expire % 60; - expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", expire, min, sec); - - bcopy(s->packets[0], &packets[0], sizeof(u_int64_t)); - bcopy(s->packets[1], &packets[1], sizeof(u_int64_t)); - bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t)); - bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t)); - printf(", %llu:%llu pkts, %llu:%llu bytes", -#ifdef __FreeBSD__ - (unsigned long long)betoh64(packets[0]), - (unsigned long long)betoh64(packets[1]), - (unsigned long long)betoh64(bytes[0]), - (unsigned long long)betoh64(bytes[1])); -#else - betoh64(packets[0]), - betoh64(packets[1]), - betoh64(bytes[0]), - betoh64(bytes[1])); -#endif - if (ntohl(s->anchor) != -1) - printf(", anchor %u", ntohl(s->anchor)); - if (ntohl(s->rule) != -1) - printf(", rule %u", ntohl(s->rule)); - if (s->state_flags & PFSTATE_SLOPPY) - printf(", sloppy"); - if (s->state_flags & PFSTATE_PFLOW) - printf(", pflow"); - if (s->sync_flags & PFSYNC_FLAG_SRCNODE) - printf(", source-track"); - if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) - printf(", sticky-address"); - printf("\n"); - } - if (opts & PF_OPT_VERBOSE2) { - u_int64_t id; - - bcopy(&s->id, &id, sizeof(u_int64_t)); - printf(" id: %016llx creatorid: %08x", -#ifdef __FreeBSD__ - (unsigned long long)betoh64(id), ntohl(s->creatorid)); -#else - betoh64(id), ntohl(s->creatorid)); -#endif - printf("\n"); - } -} - -int -unmask(struct pf_addr *m, sa_family_t af) -{ - int i = 31, j = 0, b = 0; - u_int32_t tmp; - - while (j < 4 && m->addr32[j] == 0xffffffff) { - b += 32; - j++; - } - if (j < 4) { - tmp = ntohl(m->addr32[j]); - for (i = 31; tmp & (1 << i); --i) - b++; - } - return (b); -} diff --git a/freebsd/contrib/pf/pfctl/pfctl-data.h b/freebsd/contrib/pf/pfctl/pfctl-data.h deleted file mode 100644 index a7c7e49d..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl-data.h +++ /dev/null @@ -1,26 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int altqsupport); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*anchoropt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *clearopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *debugopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int dev); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int first_title); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*ifaceopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int labels); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int loadopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *optiopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct pf_anchor_global pf_anchors); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *pf_device); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct pf_anchor pf_main_anchor); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*rulesopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *showopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*src_node_kill[2]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int src_node_killers); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*state_kill[2]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int state_killers); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char*tableopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *tblcmdopt); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static const char *tblcmdopt); diff --git a/freebsd/contrib/pf/pfctl/pfctl.c b/freebsd/contrib/pf/pfctl/pfctl.c deleted file mode 100644 index 19bd6c26..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl.c +++ /dev/null @@ -1,2529 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> - -#define __need_getopt_newlib -#include <getopt.h> - -/* We need some functions from kernel space. */ -#define pf_get_ruleset_number _bsd_pf_get_ruleset_number -#define pf_init_ruleset _bsd_pf_init_ruleset - -#include <rtems/linkersets.h> -#include <machine/rtems-bsd-commands.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> - -#ifdef __FreeBSD__ -#include <sys/endian.h> -#endif - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <altq/altq.h> -#include <sys/sysctl.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void usage(void); -int pfctl_enable(int, int); -int pfctl_disable(int, int); -int pfctl_clear_stats(int, int); -int pfctl_clear_interface_flags(int, int); -int pfctl_clear_rules(int, int, char *); -int pfctl_clear_nat(int, int, char *); -int pfctl_clear_altq(int, int); -int pfctl_clear_src_nodes(int, int); -int pfctl_clear_states(int, const char *, int); -void pfctl_addrprefix(char *, struct pf_addr *); -int pfctl_kill_src_nodes(int, const char *, int); -int pfctl_net_kill_states(int, const char *, int); -int pfctl_label_kill_states(int, const char *, int); -int pfctl_id_kill_states(int, const char *, int); -void pfctl_init_options(struct pfctl *); -int pfctl_load_options(struct pfctl *); -int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); -int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); -int pfctl_load_debug(struct pfctl *, unsigned int); -int pfctl_load_logif(struct pfctl *, char *); -#ifndef __rtems__ -int pfctl_load_hostid(struct pfctl *, unsigned int); -#else /* __rtems__ */ -int pfctl_load_hostid(struct pfctl *, u_int32_t); -#endif /* __rtems__ */ -int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, - char *); -void pfctl_print_rule_counters(struct pf_rule *, int); -int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); -int pfctl_show_nat(int, int, char *); -int pfctl_show_src_nodes(int, int); -int pfctl_show_states(int, const char *, int); -int pfctl_show_status(int, int); -int pfctl_show_timeouts(int, int); -int pfctl_show_limits(int, int); -void pfctl_debug(int, u_int32_t, int); -int pfctl_test_altqsupport(int, int); -int pfctl_show_anchors(int, int, char *); -int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *); -int pfctl_load_ruleset(struct pfctl *, char *, - struct pf_ruleset *, int, int); -int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int); -#ifndef __rtems__ -const char *pfctl_lookup_option(char *, const char **); -#else /* __rtems__ */ -const char *pfctl_lookup_option(char *, const char * const *); -#endif /* __rtems__ */ - -#ifndef __rtems__ -struct pf_anchor_global pf_anchors; -struct pf_anchor pf_main_anchor; - -const char *clearopt; -char *rulesopt; -const char *showopt; -const char *debugopt; -char *anchoropt; -const char *optiopt = NULL; -char *pf_device = "/dev/pf"; -char *ifaceopt; -char *tableopt; -const char *tblcmdopt; -int src_node_killers; -char *src_node_kill[2]; -int state_killers; -char *state_kill[2]; -#else /* __rtems__ */ -static struct pf_anchor_global pf_anchors; -static struct pf_anchor pf_main_anchor; - -static const char *clearopt; -static char *rulesopt; -static const char *showopt; -static const char *debugopt; -static char *anchoropt; -static const char *optiopt = NULL; -static const char *pf_device = "/dev/pf"; -static char *ifaceopt; -static char *tableopt; -static const char *tblcmdopt; -static int src_node_killers; -static char *src_node_kill[2]; -static int state_killers; -static char *state_kill[2]; -#endif /* __rtems__ */ -int loadopt; -int altqsupport; - -int dev = -1; -#ifndef __rtems__ -int first_title = 1; -int labels = 0; -#else /* __rtems__ */ -static int first_title = 1; -static int labels = 0; -#endif /* __rtems__ */ - -#define INDENT(d, o) do { \ - if (o) { \ - int i; \ - for (i=0; i < d; i++) \ - printf(" "); \ - } \ - } while (0); \ - - -static const struct { - const char *name; - int index; -} pf_limits[] = { - { "states", PF_LIMIT_STATES }, - { "src-nodes", PF_LIMIT_SRC_NODES }, - { "frags", PF_LIMIT_FRAGS }, - { "tables", PF_LIMIT_TABLES }, - { "table-entries", PF_LIMIT_TABLE_ENTRIES }, - { NULL, 0 } -}; - -struct pf_hint { - const char *name; - int timeout; -}; -static const struct pf_hint pf_hint_normal[] = { - { "tcp.first", 2 * 60 }, - { "tcp.opening", 30 }, - { "tcp.established", 24 * 60 * 60 }, - { "tcp.closing", 15 * 60 }, - { "tcp.finwait", 45 }, - { "tcp.closed", 90 }, - { "tcp.tsdiff", 30 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_satellite[] = { - { "tcp.first", 3 * 60 }, - { "tcp.opening", 30 + 5 }, - { "tcp.established", 24 * 60 * 60 }, - { "tcp.closing", 15 * 60 + 5 }, - { "tcp.finwait", 45 + 5 }, - { "tcp.closed", 90 + 5 }, - { "tcp.tsdiff", 60 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_conservative[] = { - { "tcp.first", 60 * 60 }, - { "tcp.opening", 15 * 60 }, - { "tcp.established", 5 * 24 * 60 * 60 }, - { "tcp.closing", 60 * 60 }, - { "tcp.finwait", 10 * 60 }, - { "tcp.closed", 3 * 60 }, - { "tcp.tsdiff", 60 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_aggressive[] = { - { "tcp.first", 30 }, - { "tcp.opening", 5 }, - { "tcp.established", 5 * 60 * 60 }, - { "tcp.closing", 60 }, - { "tcp.finwait", 30 }, - { "tcp.closed", 30 }, - { "tcp.tsdiff", 10 }, - { NULL, 0 } -}; - -static const struct { - const char *name; - const struct pf_hint *hint; -} pf_hints[] = { - { "normal", pf_hint_normal }, - { "satellite", pf_hint_satellite }, - { "high-latency", pf_hint_satellite }, - { "conservative", pf_hint_conservative }, - { "aggressive", pf_hint_aggressive }, - { NULL, NULL } -}; - -#ifndef __rtems__ -static const char *clearopt_list[] = { -#else /* __rtems__ */ -static const char * const clearopt_list[] = { -#endif /* __rtems__ */ - "nat", "queue", "rules", "Sources", - "states", "info", "Tables", "osfp", "all", NULL -}; - -#ifndef __rtems__ -static const char *showopt_list[] = { -#else /* __rtems__ */ -static const char * const showopt_list[] = { -#endif /* __rtems__ */ - "nat", "queue", "rules", "Anchors", "Sources", "states", "info", - "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", - "all", NULL -}; - -#ifndef __rtems__ -static const char *tblcmdopt_list[] = { -#else /* __rtems__ */ -static const char * const tblcmdopt_list[] = { -#endif /* __rtems__ */ - "kill", "flush", "add", "delete", "load", "replace", "show", - "test", "zero", "expire", NULL -}; - -#ifndef __rtems__ -static const char *debugopt_list[] = { -#else /* __rtems__ */ -static const char * const debugopt_list[] = { -#endif /* __rtems__ */ - "none", "urgent", "misc", "loud", NULL -}; - -#ifndef __rtems__ -static const char *optiopt_list[] = { -#else /* __rtems__ */ -static const char * const optiopt_list[] = { -#endif /* __rtems__ */ - "none", "basic", "profile", NULL -}; -#ifdef __rtems__ - -static const int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; -#endif /* __rtems__ */ - -void -usage(void) -{ -#ifndef __rtems__ - extern char *__progname; -#else /* __rtems__ */ -#define __progname "pfctl" -#endif /* __rtems__ */ - - fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname); - fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n"); - fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n"); - fprintf(stderr, "\t[-k host | network | label | id] "); - fprintf(stderr, "[-o level] [-p device]\n"); - fprintf(stderr, "\t[-s modifier] "); - fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n"); - exit(1); -} - -int -pfctl_enable(int dev, int opts) -{ - if (ioctl(dev, DIOCSTART)) { - if (errno == EEXIST) - errx(1, "pf already enabled"); -#ifdef __FreeBSD__ - else if (errno == ESRCH) - errx(1, "pfil registeration failed"); -#endif - else - err(1, "DIOCSTART"); - } - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf enabled\n"); - - if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) - if (errno != EEXIST) - err(1, "DIOCSTARTALTQ"); - - return (0); -} - -int -pfctl_disable(int dev, int opts) -{ - if (ioctl(dev, DIOCSTOP)) { - if (errno == ENOENT) - errx(1, "pf not enabled"); - else - err(1, "DIOCSTOP"); - } - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf disabled\n"); - - if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) - if (errno != ENOENT) - err(1, "DIOCSTOPALTQ"); - - return (0); -} - -int -pfctl_clear_stats(int dev, int opts) -{ - if (ioctl(dev, DIOCCLRSTATUS)) - err(1, "DIOCCLRSTATUS"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf: statistics cleared\n"); - return (0); -} - -int -pfctl_clear_interface_flags(int dev, int opts) -{ - struct pfioc_iface pi; - - if ((opts & PF_OPT_NOACTION) == 0) { - bzero(&pi, sizeof(pi)); - pi.pfiio_flags = PFI_IFLAG_SKIP; - - if (ioctl(dev, DIOCCLRIFFLAG, &pi)) - err(1, "DIOCCLRIFFLAG"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf: interface flags reset\n"); - } - return (0); -} - -int -pfctl_clear_rules(int dev, int opts, char *anchorname) -{ - struct pfr_buffer t; - - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) || - pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_rules"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "rules cleared\n"); - return (0); -} - -int -pfctl_clear_nat(int dev, int opts, char *anchorname) -{ - struct pfr_buffer t; - - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_nat"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "nat cleared\n"); - return (0); -} - -int -pfctl_clear_altq(int dev, int opts) -{ - struct pfr_buffer t; - - if (!altqsupport) - return (-1); - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_altq"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "altq cleared\n"); - return (0); -} - -int -pfctl_clear_src_nodes(int dev, int opts) -{ - if (ioctl(dev, DIOCCLRSRCNODES)) - err(1, "DIOCCLRSRCNODES"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "source tracking entries cleared\n"); - return (0); -} - -int -pfctl_clear_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - memset(&psk, 0, sizeof(psk)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - if (ioctl(dev, DIOCCLRSTATES, &psk)) - err(1, "DIOCCLRSTATES"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "%d states cleared\n", psk.psk_killed); - return (0); -} - -void -pfctl_addrprefix(char *addr, struct pf_addr *mask) -{ - char *p; - const char *errstr; - int prefix, ret_ga, q, r; - struct addrinfo hints, *res; - - if ((p = strchr(addr, '/')) == NULL) - return; - - *p++ = '\0'; - prefix = strtonum(p, 0, 128, &errstr); - if (errstr) - errx(1, "prefix is %s: %s", errstr, p); - - bzero(&hints, sizeof(hints)); - /* prefix only with numeric addresses */ - hints.ai_flags |= AI_NUMERICHOST; - - if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - - if (res->ai_family == AF_INET && prefix > 32) - errx(1, "prefix too long for AF_INET"); - else if (res->ai_family == AF_INET6 && prefix > 128) - errx(1, "prefix too long for AF_INET6"); - - q = prefix >> 3; - r = prefix & 7; - switch (res->ai_family) { - case AF_INET: - bzero(&mask->v4, sizeof(mask->v4)); - mask->v4.s_addr = htonl((u_int32_t) - (0xffffffffffULL << (32 - prefix))); - break; - case AF_INET6: - bzero(&mask->v6, sizeof(mask->v6)); - if (q > 0) - memset((void *)&mask->v6, 0xff, q); - if (r > 0) - *((u_char *)&mask->v6 + q) = - (0xff00 >> r) & 0xff; - break; - } - freeaddrinfo(res); -} - -int -pfctl_kill_src_nodes(int dev, const char *iface, int opts) -{ - struct pfioc_src_node_kill psnk; - struct addrinfo *res[2], *resp[2]; - struct sockaddr last_src, last_dst; - int killed, sources, dests; - int ret_ga; - - killed = sources = dests = 0; - - memset(&psnk, 0, sizeof(psnk)); - memset(&psnk.psnk_src.addr.v.a.mask, 0xff, - sizeof(psnk.psnk_src.addr.v.a.mask)); - memset(&last_src, 0xff, sizeof(last_src)); - memset(&last_dst, 0xff, sizeof(last_dst)); - - pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); - - if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { - if (resp[0]->ai_addr == NULL) - continue; - /* We get lots of duplicates. Catch the easy ones */ - if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) - continue; - last_src = *(struct sockaddr *)resp[0]->ai_addr; - - psnk.psnk_af = resp[0]->ai_family; - sources++; - - if (psnk.psnk_af == AF_INET) - psnk.psnk_src.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; - else if (psnk.psnk_af == AF_INET6) - psnk.psnk_src.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[0]->ai_addr)-> - sin6_addr; - else - errx(1, "Unknown address family %d", psnk.psnk_af); - - if (src_node_killers > 1) { - dests = 0; - memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, - sizeof(psnk.psnk_dst.addr.v.a.mask)); - memset(&last_dst, 0xff, sizeof(last_dst)); - pfctl_addrprefix(src_node_kill[1], - &psnk.psnk_dst.addr.v.a.mask); - if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, - &res[1]))) { - errx(1, "getaddrinfo: %s", - gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[1] = res[1]; resp[1]; - resp[1] = resp[1]->ai_next) { - if (resp[1]->ai_addr == NULL) - continue; - if (psnk.psnk_af != resp[1]->ai_family) - continue; - - if (memcmp(&last_dst, resp[1]->ai_addr, - sizeof(last_dst)) == 0) - continue; - last_dst = *(struct sockaddr *)resp[1]->ai_addr; - - dests++; - - if (psnk.psnk_af == AF_INET) - psnk.psnk_dst.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[1]-> - ai_addr)->sin_addr; - else if (psnk.psnk_af == AF_INET6) - psnk.psnk_dst.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[1]-> - ai_addr)->sin6_addr; - else - errx(1, "Unknown address family %d", - psnk.psnk_af); - - if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) - err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_killed; - } - freeaddrinfo(res[1]); - } else { - if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) - err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_killed; - } - } - - freeaddrinfo(res[0]); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d src nodes from %d sources and %d " - "destinations\n", killed, sources, dests); - return (0); -} - -int -pfctl_net_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - struct addrinfo *res[2], *resp[2]; - struct sockaddr last_src, last_dst; - int killed, sources, dests; - int ret_ga; - - killed = sources = dests = 0; - - memset(&psk, 0, sizeof(psk)); - memset(&psk.psk_src.addr.v.a.mask, 0xff, - sizeof(psk.psk_src.addr.v.a.mask)); - memset(&last_src, 0xff, sizeof(last_src)); - memset(&last_dst, 0xff, sizeof(last_dst)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); - - if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { - if (resp[0]->ai_addr == NULL) - continue; - /* We get lots of duplicates. Catch the easy ones */ - if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) - continue; - last_src = *(struct sockaddr *)resp[0]->ai_addr; - - psk.psk_af = resp[0]->ai_family; - sources++; - - if (psk.psk_af == AF_INET) - psk.psk_src.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; - else if (psk.psk_af == AF_INET6) - psk.psk_src.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[0]->ai_addr)-> - sin6_addr; - else - errx(1, "Unknown address family %d", psk.psk_af); - - if (state_killers > 1) { - dests = 0; - memset(&psk.psk_dst.addr.v.a.mask, 0xff, - sizeof(psk.psk_dst.addr.v.a.mask)); - memset(&last_dst, 0xff, sizeof(last_dst)); - pfctl_addrprefix(state_kill[1], - &psk.psk_dst.addr.v.a.mask); - if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, - &res[1]))) { - errx(1, "getaddrinfo: %s", - gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[1] = res[1]; resp[1]; - resp[1] = resp[1]->ai_next) { - if (resp[1]->ai_addr == NULL) - continue; - if (psk.psk_af != resp[1]->ai_family) - continue; - - if (memcmp(&last_dst, resp[1]->ai_addr, - sizeof(last_dst)) == 0) - continue; - last_dst = *(struct sockaddr *)resp[1]->ai_addr; - - dests++; - - if (psk.psk_af == AF_INET) - psk.psk_dst.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[1]-> - ai_addr)->sin_addr; - else if (psk.psk_af == AF_INET6) - psk.psk_dst.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[1]-> - ai_addr)->sin6_addr; - else - errx(1, "Unknown address family %d", - psk.psk_af); - - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - killed += psk.psk_killed; - } - freeaddrinfo(res[1]); - } else { - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - killed += psk.psk_killed; - } - } - - freeaddrinfo(res[0]); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states from %d sources and %d " - "destinations\n", killed, sources, dests); - return (0); -} - -int -pfctl_label_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { - warnx("no label specified"); - usage(); - } - memset(&psk, 0, sizeof(psk)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >= - sizeof(psk.psk_label)) - errx(1, "label too long: %s", state_kill[1]); - - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states\n", psk.psk_killed); - - return (0); -} - -int -pfctl_id_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { - warnx("no id specified"); - usage(); - } - - memset(&psk, 0, sizeof(psk)); - if ((sscanf(state_kill[1], "%jx/%x", - &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) - HTONL(psk.psk_pfcmp.creatorid); - else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) { - psk.psk_pfcmp.creatorid = 0; - } else { - warnx("wrong id format specified"); - usage(); - } - if (psk.psk_pfcmp.id == 0) { - warnx("cannot kill id 0"); - usage(); - } - - psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id); - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states\n", psk.psk_killed); - - return (0); -} - -int -pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, - u_int32_t ticket, int r_action, char *anchorname) -{ - struct pfioc_pooladdr pp; - struct pf_pooladdr *pa; - u_int32_t pnr, mpnr; - - memset(&pp, 0, sizeof(pp)); - memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); - pp.r_action = r_action; - pp.r_num = nr; - pp.ticket = ticket; - if (ioctl(dev, DIOCGETADDRS, &pp)) { - warn("DIOCGETADDRS"); - return (-1); - } - mpnr = pp.nr; - TAILQ_INIT(&pool->list); - for (pnr = 0; pnr < mpnr; ++pnr) { - pp.nr = pnr; - if (ioctl(dev, DIOCGETADDR, &pp)) { - warn("DIOCGETADDR"); - return (-1); - } - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "calloc"); - bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); - TAILQ_INSERT_TAIL(&pool->list, pa, entries); - } - - return (0); -} - -void -pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst) -{ - struct pf_pooladdr *pa; - - while ((pa = TAILQ_FIRST(&src->list)) != NULL) { - TAILQ_REMOVE(&src->list, pa, entries); - TAILQ_INSERT_TAIL(&dst->list, pa, entries); - } -} - -void -pfctl_clear_pool(struct pf_pool *pool) -{ - struct pf_pooladdr *pa; - - while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { - TAILQ_REMOVE(&pool->list, pa, entries); - free(pa); - } -} - -void -pfctl_print_rule_counters(struct pf_rule *rule, int opts) -{ - if (opts & PF_OPT_DEBUG) { - const char *t[PF_SKIP_COUNT] = { "i", "d", "f", - "p", "sa", "sp", "da", "dp" }; - int i; - - printf(" [ Skip steps: "); - for (i = 0; i < PF_SKIP_COUNT; ++i) { - if (rule->skip[i].nr == rule->nr + 1) - continue; - printf("%s=", t[i]); - if (rule->skip[i].nr == -1) - printf("end "); - else - printf("%u ", rule->skip[i].nr); - } - printf("]\n"); - - printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", - rule->qname, rule->qid, rule->pqname, rule->pqid); - } - if (opts & PF_OPT_VERBOSE) { - printf(" [ Evaluations: %-8llu Packets: %-8llu " - "Bytes: %-10llu States: %-6u]\n", - (unsigned long long)rule->evaluations, - (unsigned long long)(rule->packets[0] + - rule->packets[1]), - (unsigned long long)(rule->bytes[0] + - rule->bytes[1]), rule->states_cur); - if (!(opts & PF_OPT_DEBUG)) - printf(" [ Inserted: uid %u pid %u " - "State Creations: %-6u]\n", - (unsigned)rule->cuid, (unsigned)rule->cpid, - rule->states_tot); - } -} - -void -pfctl_print_title(char *title) -{ - if (!first_title) - printf("\n"); - first_title = 0; - printf("%s\n", title); -} - -int -pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, - char *anchorname, int depth) -{ - struct pfioc_rule pr; - u_int32_t nr, mnr, header = 0; - int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); - int numeric = opts & PF_OPT_NUMERIC; - int len = strlen(path); - int brace; - char *p; - - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); - else - snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, path, sizeof(pr.anchor)); - if (opts & PF_OPT_SHOWALL) { - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - header++; - } - pr.rule.action = PF_SCRUB; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - if (opts & PF_OPT_SHOWALL) { - if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) - pfctl_print_title("FILTER RULES:"); - else if (format == PFCTL_SHOW_LABELS && labels) - pfctl_print_title("LABEL COUNTERS:"); - } - mnr = pr.nr; - if (opts & PF_OPT_CLRRULECTRS) - pr.action = PF_GET_CLR_CNTR; - - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - goto error; - } - - if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_SCRUB, path) != 0) - goto error; - - switch (format) { - case PFCTL_SHOW_LABELS: - break; - case PFCTL_SHOW_RULES: - if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) - labels = 1; - print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric); - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - break; - case PFCTL_SHOW_NOTHING: - break; - } - pfctl_clear_pool(&pr.rule.rpool); - } - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - goto error; - } - - if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_PASS, path) != 0) - goto error; - - switch (format) { - case PFCTL_SHOW_LABELS: - if (pr.rule.label[0]) { - printf("%s %llu %llu %llu %llu" - " %llu %llu %llu %llu\n", - pr.rule.label, - (unsigned long long)pr.rule.evaluations, - (unsigned long long)(pr.rule.packets[0] + - pr.rule.packets[1]), - (unsigned long long)(pr.rule.bytes[0] + - pr.rule.bytes[1]), - (unsigned long long)pr.rule.packets[0], - (unsigned long long)pr.rule.bytes[0], - (unsigned long long)pr.rule.packets[1], - (unsigned long long)pr.rule.bytes[1], - (unsigned long long)pr.rule.states_tot); - } - break; - case PFCTL_SHOW_RULES: - brace = 0; - if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) - labels = 1; - INDENT(depth, !(opts & PF_OPT_VERBOSE)); - if (pr.anchor_call[0] && - ((((p = strrchr(pr.anchor_call, '_')) != NULL) && - ((void *)p == (void *)pr.anchor_call || - *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { - brace++; - if ((p = strrchr(pr.anchor_call, '/')) != - NULL) - p++; - else - p = &pr.anchor_call[0]; - } else - p = &pr.anchor_call[0]; - - print_rule(&pr.rule, p, rule_numbers, numeric); - if (brace) - printf(" {\n"); - else - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - if (brace) { - pfctl_show_rules(dev, path, opts, format, - p, depth + 1); - INDENT(depth, !(opts & PF_OPT_VERBOSE)); - printf("}\n"); - } - break; - case PFCTL_SHOW_NOTHING: - break; - } - pfctl_clear_pool(&pr.rule.rpool); - } - path[len] = '\0'; - return (0); - - error: - path[len] = '\0'; - return (-1); -} - -int -pfctl_show_nat(int dev, int opts, char *anchorname) -{ - struct pfioc_rule pr; - u_int32_t mnr, nr; -#ifndef __rtems__ - static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; -#endif /* __rtems__ */ - int i, dotitle = opts & PF_OPT_SHOWALL; - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); - for (i = 0; i < 3; i++) { - pr.rule.action = nattype[i]; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - return (-1); - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - return (-1); - } - if (pfctl_get_pool(dev, &pr.rule.rpool, nr, - pr.ticket, nattype[i], anchorname) != 0) - return (-1); - if (dotitle) { - pfctl_print_title("TRANSLATION RULES:"); - dotitle = 0; - } - print_rule(&pr.rule, pr.anchor_call, - opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - pfctl_clear_pool(&pr.rule.rpool); - } - } - return (0); -} - -int -pfctl_show_src_nodes(int dev, int opts) -{ - struct pfioc_src_nodes psn; - struct pf_src_node *p; - char *inbuf = NULL, *newinbuf = NULL; - unsigned int len = 0; - int i; - - memset(&psn, 0, sizeof(psn)); - for (;;) { - psn.psn_len = len; - if (len) { - newinbuf = realloc(inbuf, len); - if (newinbuf == NULL) - err(1, "realloc"); - psn.psn_buf = inbuf = newinbuf; - } - if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { - warn("DIOCGETSRCNODES"); - free(inbuf); - return (-1); - } - if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) - break; - if (len == 0 && psn.psn_len == 0) - goto done; - if (len == 0 && psn.psn_len != 0) - len = psn.psn_len; - if (psn.psn_len == 0) - goto done; /* no src_nodes */ - len *= 2; - } - p = psn.psn_src_nodes; - if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) - pfctl_print_title("SOURCE TRACKING NODES:"); - for (i = 0; i < psn.psn_len; i += sizeof(*p)) { - print_src_node(p, opts); - p++; - } -done: - free(inbuf); - return (0); -} - -int -pfctl_show_states(int dev, const char *iface, int opts) -{ - struct pfioc_states ps; - struct pfsync_state *p; - char *inbuf = NULL, *newinbuf = NULL; - unsigned int len = 0; - int i, dotitle = (opts & PF_OPT_SHOWALL); - - memset(&ps, 0, sizeof(ps)); - for (;;) { - ps.ps_len = len; - if (len) { - newinbuf = realloc(inbuf, len); - if (newinbuf == NULL) - err(1, "realloc"); - ps.ps_buf = inbuf = newinbuf; - } - if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { - warn("DIOCGETSTATES"); - free(inbuf); - return (-1); - } - if (ps.ps_len + sizeof(struct pfioc_states) < len) - break; - if (len == 0 && ps.ps_len == 0) - goto done; - if (len == 0 && ps.ps_len != 0) - len = ps.ps_len; - if (ps.ps_len == 0) - goto done; /* no states */ - len *= 2; - } - p = ps.ps_states; - for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { - if (iface != NULL && strcmp(p->ifname, iface)) - continue; - if (dotitle) { - pfctl_print_title("STATES:"); - dotitle = 0; - } - print_state(p, opts); - } -done: - free(inbuf); - return (0); -} - -int -pfctl_show_status(int dev, int opts) -{ - struct pf_status status; - - if (ioctl(dev, DIOCGETSTATUS, &status)) { - warn("DIOCGETSTATUS"); - return (-1); - } - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("INFO:"); - print_status(&status, opts); - return (0); -} - -int -pfctl_show_timeouts(int dev, int opts) -{ - struct pfioc_tm pt; - int i; - - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("TIMEOUTS:"); - memset(&pt, 0, sizeof(pt)); - for (i = 0; pf_timeouts[i].name; i++) { - pt.timeout = pf_timeouts[i].timeout; - if (ioctl(dev, DIOCGETTIMEOUT, &pt)) - err(1, "DIOCGETTIMEOUT"); - printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); - if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && - pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) - printf(" states"); - else - printf("s"); - printf("\n"); - } - return (0); - -} - -int -pfctl_show_limits(int dev, int opts) -{ - struct pfioc_limit pl; - int i; - - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("LIMITS:"); - memset(&pl, 0, sizeof(pl)); - for (i = 0; pf_limits[i].name; i++) { - pl.index = pf_limits[i].index; - if (ioctl(dev, DIOCGETLIMIT, &pl)) - err(1, "DIOCGETLIMIT"); - printf("%-13s ", pf_limits[i].name); - if (pl.limit == UINT_MAX) - printf("unlimited\n"); - else - printf("hard limit %8u\n", pl.limit); - } - return (0); -} - -/* callbacks for rule/nat/rdr/addr */ -int -pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) -{ - struct pf_pooladdr *pa; - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) - err(1, "DIOCBEGINADDRS"); - } - - pf->paddr.af = af; - TAILQ_FOREACH(pa, &p->list, entries) { - memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) - err(1, "DIOCADDADDR"); - } - } - return (0); -} - -int -pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) -{ - u_int8_t rs_num; - struct pf_rule *rule; - struct pf_ruleset *rs; - char *p; - - rs_num = pf_get_ruleset_number(r->action); - if (rs_num == PF_RULESET_MAX) - errx(1, "Invalid rule type %d", r->action); - - rs = &pf->anchor->ruleset; - - if (anchor_call[0] && r->anchor == NULL) { - /* - * Don't make non-brace anchors part of the main anchor pool. - */ - if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) - err(1, "pfctl_add_rule: calloc"); - - pf_init_ruleset(&r->anchor->ruleset); - r->anchor->ruleset.anchor = r->anchor; - if (strlcpy(r->anchor->path, anchor_call, - sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) - errx(1, "pfctl_add_rule: strlcpy"); - if ((p = strrchr(anchor_call, '/')) != NULL) { - if (!strlen(p)) - err(1, "pfctl_add_rule: bad anchor name %s", - anchor_call); - } else - p = (char *)anchor_call; - if (strlcpy(r->anchor->name, p, - sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); - } - - if ((rule = calloc(1, sizeof(*rule))) == NULL) - err(1, "calloc"); - bcopy(r, rule, sizeof(*rule)); - TAILQ_INIT(&rule->rpool.list); - pfctl_move_pool(&r->rpool, &rule->rpool); - - TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); - return (0); -} - -int -pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) -{ - int osize = pf->trans->pfrb_size; - - if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { - if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || - pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || - pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) - return (1); - } - if (a == pf->astack[0] && ((altqsupport && - (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { - if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) - return (2); - } - if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { - if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || - pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) - return (3); - } - if (pf->loadopt & PFCTL_FLAG_TABLE) - if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) - return (4); - if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) - return (5); - - return (0); -} - -int -pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs, - int rs_num, int depth) -{ - struct pf_rule *r; - int error, len = strlen(path); - int brace = 0; - - pf->anchor = rs->anchor; - - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); - else - snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); - - if (depth) { - if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { - brace++; - if (pf->opts & PF_OPT_VERBOSE) - printf(" {\n"); - if ((pf->opts & PF_OPT_NOACTION) == 0 && - (error = pfctl_ruleset_trans(pf, - path, rs->anchor))) { - printf("pfctl_load_rulesets: " - "pfctl_ruleset_trans %d\n", error); - goto error; - } - } else if (pf->opts & PF_OPT_VERBOSE) - printf("\n"); - - } - - if (pf->optimize && rs_num == PF_RULESET_FILTER) - pfctl_optimize_ruleset(pf, rs); - - while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { - TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); - if ((error = pfctl_load_rule(pf, path, r, depth))) - goto error; - if (r->anchor) { - if ((error = pfctl_load_ruleset(pf, path, - &r->anchor->ruleset, rs_num, depth + 1))) - goto error; - } else if (pf->opts & PF_OPT_VERBOSE) - printf("\n"); - free(r); - } - if (brace && pf->opts & PF_OPT_VERBOSE) { - INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); - printf("}\n"); - } - path[len] = '\0'; - return (0); - - error: - path[len] = '\0'; - return (error); - -} - -int -pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) -{ - u_int8_t rs_num = pf_get_ruleset_number(r->action); - char *name; - struct pfioc_rule pr; - int len = strlen(path); - - bzero(&pr, sizeof(pr)); - /* set up anchor before adding to path for anchor_call */ - if ((pf->opts & PF_OPT_NOACTION) == 0) - pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path); - if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) - errx(1, "pfctl_load_rule: strlcpy"); - - if (r->anchor) { - if (r->anchor->match) { - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, - "/%s", r->anchor->name); - else - snprintf(&path[len], MAXPATHLEN - len, - "%s", r->anchor->name); - name = path; - } else - name = r->anchor->path; - } else - name = ""; - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (pfctl_add_pool(pf, &r->rpool, r->af)) - return (1); - pr.pool_ticket = pf->paddr.ticket; - memcpy(&pr.rule, r, sizeof(pr.rule)); - if (r->anchor && strlcpy(pr.anchor_call, name, - sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call)) - errx(1, "pfctl_load_rule: strlcpy"); - if (ioctl(pf->dev, DIOCADDRULE, &pr)) - err(1, "DIOCADDRULE"); - } - - if (pf->opts & PF_OPT_VERBOSE) { - INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); - print_rule(r, r->anchor ? r->anchor->name : "", - pf->opts & PF_OPT_VERBOSE2, - pf->opts & PF_OPT_NUMERIC); - } - path[len] = '\0'; - pfctl_clear_pool(&r->rpool); - return (0); -} - -int -pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) -{ - if (altqsupport && - (loadopt & PFCTL_FLAG_ALTQ) != 0) { - memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { - if (errno == ENXIO) - errx(1, "qtype not configured"); - else if (errno == ENODEV) - errx(1, "%s: driver does not support " - "altq", a->ifname); - else - err(1, "DIOCADDALTQ"); - } - } - pfaltq_store(&pf->paltq->altq); - } - return (0); -} - -int -pfctl_rules(int dev, char *filename, int opts, int optimize, - char *anchorname, struct pfr_buffer *trans) -{ -#define ERR(x) do { warn(x); goto _error; } while(0) -#define ERRX(x) do { warnx(x); goto _error; } while(0) - - struct pfr_buffer *t, buf; - struct pfioc_altq pa; - struct pfctl pf; - struct pf_ruleset *rs; - struct pfr_table trs; - char *path; - int osize; - - RB_INIT(&pf_anchors); - memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); - pf_init_ruleset(&pf_main_anchor.ruleset); - pf_main_anchor.ruleset.anchor = &pf_main_anchor; - if (trans == NULL) { - bzero(&buf, sizeof(buf)); - buf.pfrb_type = PFRB_TRANS; - t = &buf; - osize = 0; - } else { - t = trans; - osize = t->pfrb_size; - } - - memset(&pa, 0, sizeof(pa)); - memset(&pf, 0, sizeof(pf)); - memset(&trs, 0, sizeof(trs)); - if ((path = calloc(1, MAXPATHLEN)) == NULL) - ERRX("pfctl_rules: calloc"); - if (strlcpy(trs.pfrt_anchor, anchorname, - sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) - ERRX("pfctl_rules: strlcpy"); - pf.dev = dev; - pf.opts = opts; - pf.optimize = optimize; - pf.loadopt = loadopt; - - /* non-brace anchor, create without resolving the path */ - if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) - ERRX("pfctl_rules: calloc"); - rs = &pf.anchor->ruleset; - pf_init_ruleset(rs); - rs->anchor = pf.anchor; - if (strlcpy(pf.anchor->path, anchorname, - sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) - errx(1, "pfctl_add_rule: strlcpy"); - if (strlcpy(pf.anchor->name, anchorname, - sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); - - - pf.astack[0] = pf.anchor; - pf.asd = 0; - if (anchorname[0]) - pf.loadopt &= ~PFCTL_FLAG_ALTQ; - pf.paltq = &pa; - pf.trans = t; - pfctl_init_options(&pf); - - if ((opts & PF_OPT_NOACTION) == 0) { - /* - * XXX For the time being we need to open transactions for - * the main ruleset before parsing, because tables are still - * loaded at parse time. - */ - if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) - ERRX("pfctl_rules"); - if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) - pa.ticket = - pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); - if (pf.loadopt & PFCTL_FLAG_TABLE) - pf.astack[0]->ruleset.tticket = - pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); - } - - if (parse_config(filename, &pf) < 0) { - if ((opts & PF_OPT_NOACTION) == 0) - ERRX("Syntax error in config file: " - "pf rules not loaded"); - else - goto _error; - } - - if ((pf.loadopt & PFCTL_FLAG_FILTER && - (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || - (pf.loadopt & PFCTL_FLAG_NAT && - (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || - (pf.loadopt & PFCTL_FLAG_FILTER && - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { - if ((opts & PF_OPT_NOACTION) == 0) - ERRX("Unable to load rules into kernel"); - else - goto _error; - } - - if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) - if (check_commit_altq(dev, opts) != 0) - ERRX("errors in altq config"); - - /* process "load anchor" directives */ - if (!anchorname[0]) - if (pfctl_load_anchors(dev, &pf, t) == -1) - ERRX("load anchors"); - - if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { - if (!anchorname[0]) - if (pfctl_load_options(&pf)) - goto _error; - if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) - ERR("DIOCXCOMMIT"); - } - return (0); - -_error: - if (trans == NULL) { /* main ruleset */ - if ((opts & PF_OPT_NOACTION) == 0) - if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) - err(1, "DIOCXROLLBACK"); - exit(1); - } else { /* sub ruleset */ - return (-1); - } - -#undef ERR -#undef ERRX -} - -FILE * -pfctl_fopen(const char *name, const char *mode) -{ - struct stat st; - FILE *fp; - - fp = fopen(name, mode); - if (fp == NULL) - return (NULL); - if (fstat(fileno(fp), &st)) { - fclose(fp); - return (NULL); - } - if (S_ISDIR(st.st_mode)) { - fclose(fp); - errno = EISDIR; - return (NULL); - } - return (fp); -} - -void -pfctl_init_options(struct pfctl *pf) -{ - int64_t mem; - int mib[2]; - size_t size; - - pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; - pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; - pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; - pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; - pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; - pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; - pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; - pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; - pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; - pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; - pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; - pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; - pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; - pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; - pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; - pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; - pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; - pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; - pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; - pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; - - pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; - pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; - pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; - pf->limit[PF_LIMIT_TABLES] = PFR_KTABLE_HIWAT; - pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; - -#ifndef __rtems__ - mib[0] = CTL_HW; -#ifdef __FreeBSD__ - mib[1] = HW_PHYSMEM; -#else - mib[1] = HW_PHYSMEM64; -#endif - size = sizeof(mem); - if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) - err(1, "sysctl"); - if (mem <= 100*1024*1024) -#endif /* __rtems__ */ - pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; - - pf->debug = PF_DEBUG_URGENT; -} - -int -pfctl_load_options(struct pfctl *pf) -{ - int i, error = 0; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - /* load limits */ - for (i = 0; i < PF_LIMIT_MAX; i++) { - if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i]) - continue; - if (pfctl_load_limit(pf, i, pf->limit[i])) - error = 1; - } - - /* - * If we've set the limit, but haven't explicitly set adaptive - * timeouts, do it now with a start of 60% and end of 120%. - */ - if (pf->limit_set[PF_LIMIT_STATES] && - !pf->timeout_set[PFTM_ADAPTIVE_START] && - !pf->timeout_set[PFTM_ADAPTIVE_END]) { - pf->timeout[PFTM_ADAPTIVE_START] = - (pf->limit[PF_LIMIT_STATES] / 10) * 6; - pf->timeout_set[PFTM_ADAPTIVE_START] = 1; - pf->timeout[PFTM_ADAPTIVE_END] = - (pf->limit[PF_LIMIT_STATES] / 10) * 12; - pf->timeout_set[PFTM_ADAPTIVE_END] = 1; - } - - /* load timeouts */ - for (i = 0; i < PFTM_MAX; i++) { - if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) - continue; - if (pfctl_load_timeout(pf, i, pf->timeout[i])) - error = 1; - } - - /* load debug */ - if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set) - if (pfctl_load_debug(pf, pf->debug)) - error = 1; - - /* load logif */ - if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set) - if (pfctl_load_logif(pf, pf->ifname)) - error = 1; - - /* load hostid */ - if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set) - if (pfctl_load_hostid(pf, pf->hostid)) - error = 1; - - return (error); -} - -int -pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) -{ - int i; - - - for (i = 0; pf_limits[i].name; i++) { - if (strcasecmp(opt, pf_limits[i].name) == 0) { - pf->limit[pf_limits[i].index] = limit; - pf->limit_set[pf_limits[i].index] = 1; - break; - } - } - if (pf_limits[i].name == NULL) { - warnx("Bad pool name."); - return (1); - } - - if (pf->opts & PF_OPT_VERBOSE) - printf("set limit %s %d\n", opt, limit); - - return (0); -} - -int -pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) -{ - struct pfioc_limit pl; - - memset(&pl, 0, sizeof(pl)); - pl.index = index; - pl.limit = limit; - if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { - if (errno == EBUSY) - warnx("Current pool size exceeds requested hard limit"); - else - warnx("DIOCSETLIMIT"); - return (1); - } - return (0); -} - -int -pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) -{ - int i; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - for (i = 0; pf_timeouts[i].name; i++) { - if (strcasecmp(opt, pf_timeouts[i].name) == 0) { - pf->timeout[pf_timeouts[i].timeout] = seconds; - pf->timeout_set[pf_timeouts[i].timeout] = 1; - break; - } - } - - if (pf_timeouts[i].name == NULL) { - warnx("Bad timeout name."); - return (1); - } - - - if (pf->opts & PF_OPT_VERBOSE && ! quiet) - printf("set timeout %s %d\n", opt, seconds); - - return (0); -} - -int -pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) -{ - struct pfioc_tm pt; - - memset(&pt, 0, sizeof(pt)); - pt.timeout = timeout; - pt.seconds = seconds; - if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { - warnx("DIOCSETTIMEOUT"); - return (1); - } - return (0); -} - -int -pfctl_set_optimization(struct pfctl *pf, const char *opt) -{ - const struct pf_hint *hint; - int i, r; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - for (i = 0; pf_hints[i].name; i++) - if (strcasecmp(opt, pf_hints[i].name) == 0) - break; - - hint = pf_hints[i].hint; - if (hint == NULL) { - warnx("invalid state timeouts optimization"); - return (1); - } - - for (i = 0; hint[i].name; i++) - if ((r = pfctl_set_timeout(pf, hint[i].name, - hint[i].timeout, 1))) - return (r); - - if (pf->opts & PF_OPT_VERBOSE) - printf("set optimization %s\n", opt); - - return (0); -} - -int -pfctl_set_logif(struct pfctl *pf, char *ifname) -{ - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - if (!strcmp(ifname, "none")) { - free(pf->ifname); - pf->ifname = NULL; - } else { - pf->ifname = strdup(ifname); - if (!pf->ifname) - errx(1, "pfctl_set_logif: strdup"); - } - pf->ifname_set = 1; - - if (pf->opts & PF_OPT_VERBOSE) - printf("set loginterface %s\n", ifname); - - return (0); -} - -int -pfctl_load_logif(struct pfctl *pf, char *ifname) -{ - struct pfioc_if pi; - - memset(&pi, 0, sizeof(pi)); - if (ifname && strlcpy(pi.ifname, ifname, - sizeof(pi.ifname)) >= sizeof(pi.ifname)) { - warnx("pfctl_load_logif: strlcpy"); - return (1); - } - if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { - warnx("DIOCSETSTATUSIF"); - return (1); - } - return (0); -} - -int -pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) -{ - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - HTONL(hostid); - - pf->hostid = hostid; - pf->hostid_set = 1; - - if (pf->opts & PF_OPT_VERBOSE) - printf("set hostid 0x%08x\n", ntohl(hostid)); - - return (0); -} - -int -pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) -{ - if (ioctl(dev, DIOCSETHOSTID, &hostid)) { - warnx("DIOCSETHOSTID"); - return (1); - } - return (0); -} - -int -pfctl_set_debug(struct pfctl *pf, char *d) -{ - u_int32_t level; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - if (!strcmp(d, "none")) - pf->debug = PF_DEBUG_NONE; - else if (!strcmp(d, "urgent")) - pf->debug = PF_DEBUG_URGENT; - else if (!strcmp(d, "misc")) - pf->debug = PF_DEBUG_MISC; - else if (!strcmp(d, "loud")) - pf->debug = PF_DEBUG_NOISY; - else { - warnx("unknown debug level \"%s\"", d); - return (-1); - } - - pf->debug_set = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0) - if (ioctl(dev, DIOCSETDEBUG, &level)) - err(1, "DIOCSETDEBUG"); - - if (pf->opts & PF_OPT_VERBOSE) - printf("set debug %s\n", d); - - return (0); -} - -int -pfctl_load_debug(struct pfctl *pf, unsigned int level) -{ - if (ioctl(pf->dev, DIOCSETDEBUG, &level)) { - warnx("DIOCSETDEBUG"); - return (1); - } - return (0); -} - -int -pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) -{ - struct pfioc_iface pi; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - bzero(&pi, sizeof(pi)); - - pi.pfiio_flags = flags; - - if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= - sizeof(pi.pfiio_name)) - errx(1, "pfctl_set_interface_flags: strlcpy"); - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (how == 0) { - if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) - err(1, "DIOCCLRIFFLAG"); - } else { - if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) - err(1, "DIOCSETIFFLAG"); - } - } - return (0); -} - -void -pfctl_debug(int dev, u_int32_t level, int opts) -{ - if (ioctl(dev, DIOCSETDEBUG, &level)) - err(1, "DIOCSETDEBUG"); - if ((opts & PF_OPT_QUIET) == 0) { - fprintf(stderr, "debug level set to '"); - switch (level) { - case PF_DEBUG_NONE: - fprintf(stderr, "none"); - break; - case PF_DEBUG_URGENT: - fprintf(stderr, "urgent"); - break; - case PF_DEBUG_MISC: - fprintf(stderr, "misc"); - break; - case PF_DEBUG_NOISY: - fprintf(stderr, "loud"); - break; - default: - fprintf(stderr, "<invalid>"); - break; - } - fprintf(stderr, "'\n"); - } -} - -int -pfctl_test_altqsupport(int dev, int opts) -{ - struct pfioc_altq pa; - - if (ioctl(dev, DIOCGETALTQS, &pa)) { - if (errno == ENODEV) { - if (!(opts & PF_OPT_QUIET)) - fprintf(stderr, "No ALTQ support in kernel\n" - "ALTQ related functions disabled\n"); - return (0); - } else - err(1, "DIOCGETALTQS"); - } - return (1); -} - -int -pfctl_show_anchors(int dev, int opts, char *anchorname) -{ - struct pfioc_ruleset pr; - u_int32_t mnr, nr; - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.path, anchorname, sizeof(pr.path)); - if (ioctl(dev, DIOCGETRULESETS, &pr)) { - if (errno == EINVAL) - fprintf(stderr, "Anchor '%s' not found.\n", - anchorname); - else - err(1, "DIOCGETRULESETS"); - return (-1); - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - char sub[MAXPATHLEN]; - - pr.nr = nr; - if (ioctl(dev, DIOCGETRULESET, &pr)) - err(1, "DIOCGETRULESET"); - if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) - continue; - sub[0] = 0; - if (pr.path[0]) { - strlcat(sub, pr.path, sizeof(sub)); - strlcat(sub, "/", sizeof(sub)); - } - strlcat(sub, pr.name, sizeof(sub)); - if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) - printf(" %s\n", sub); - if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) - return (-1); - } - return (0); -} - -const char * -#ifndef __rtems__ -pfctl_lookup_option(char *cmd, const char **list) -#else /* __rtems__ */ -pfctl_lookup_option(char *cmd, const char * const *list) -#endif /* __rtems__ */ -{ - if (cmd != NULL && *cmd) - for (; *list; list++) - if (!strncmp(cmd, *list, strlen(cmd))) - return (*list); - return (NULL); -} - -#ifdef __rtems__ -static int main(int argc, char *argv[]); - -RTEMS_LINKER_RWSET(bsd_prog_pfctl, char); - -int -rtems_bsd_command_pfctl(int argc, char *argv[]) -{ - int exit_code; - const void *data_begin; - size_t data_size; - - data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_pfctl); - data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_pfctl); - - rtems_bsd_program_lock(); - exit_code = rtems_bsd_program_call_main_with_data_restore("pfctl", - main, argc, argv, data_begin, data_size); - rtems_bsd_program_unlock(); - - return exit_code; -} - -#endif /* __rtems__ */ -int -main(int argc, char *argv[]) -{ - int error = 0; - int ch; - int mode = O_RDONLY; - int opts = 0; - int optimize = PF_OPTIMIZE_BASIC; - char anchorname[MAXPATHLEN]; - char *path; - -#ifdef __rtems__ - struct getopt_data getopt_data; - memset(&getopt_data, 0, sizeof(getopt_data)); -#define optind getopt_data.optind -#define optarg getopt_data.optarg -#define opterr getopt_data.opterr -#define optopt getopt_data.optopt -#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data) -#endif /* __rtems__ */ - - if (argc < 2) - usage(); - - while ((ch = getopt(argc, argv, - "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) { - switch (ch) { - case 'a': - anchoropt = optarg; - break; - case 'd': - opts |= PF_OPT_DISABLE; - mode = O_RDWR; - break; - case 'D': - if (pfctl_cmdline_symset(optarg) < 0) - warnx("could not parse macro definition %s", - optarg); - break; - case 'e': - opts |= PF_OPT_ENABLE; - mode = O_RDWR; - break; - case 'q': - opts |= PF_OPT_QUIET; - break; - case 'F': - clearopt = pfctl_lookup_option(optarg, clearopt_list); - if (clearopt == NULL) { - warnx("Unknown flush modifier '%s'", optarg); - usage(); - } - mode = O_RDWR; - break; - case 'i': - ifaceopt = optarg; - break; - case 'k': - if (state_killers >= 2) { - warnx("can only specify -k twice"); - usage(); - /* NOTREACHED */ - } - state_kill[state_killers++] = optarg; - mode = O_RDWR; - break; - case 'K': - if (src_node_killers >= 2) { - warnx("can only specify -K twice"); - usage(); - /* NOTREACHED */ - } - src_node_kill[src_node_killers++] = optarg; - mode = O_RDWR; - break; - case 'm': - opts |= PF_OPT_MERGE; - break; - case 'n': - opts |= PF_OPT_NOACTION; - break; - case 'N': - loadopt |= PFCTL_FLAG_NAT; - break; - case 'r': - opts |= PF_OPT_USEDNS; - break; - case 'f': - rulesopt = optarg; - mode = O_RDWR; - break; - case 'g': - opts |= PF_OPT_DEBUG; - break; - case 'A': - loadopt |= PFCTL_FLAG_ALTQ; - break; - case 'R': - loadopt |= PFCTL_FLAG_FILTER; - break; - case 'o': - optiopt = pfctl_lookup_option(optarg, optiopt_list); - if (optiopt == NULL) { - warnx("Unknown optimization '%s'", optarg); - usage(); - } - opts |= PF_OPT_OPTIMIZE; - break; - case 'O': - loadopt |= PFCTL_FLAG_OPTION; - break; - case 'p': - pf_device = optarg; - break; - case 'P': - opts |= PF_OPT_NUMERIC; - break; - case 's': - showopt = pfctl_lookup_option(optarg, showopt_list); - if (showopt == NULL) { - warnx("Unknown show modifier '%s'", optarg); - usage(); - } - break; - case 't': - tableopt = optarg; - break; - case 'T': - tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); - if (tblcmdopt == NULL) { - warnx("Unknown table command '%s'", optarg); - usage(); - } - break; - case 'v': - if (opts & PF_OPT_VERBOSE) - opts |= PF_OPT_VERBOSE2; - opts |= PF_OPT_VERBOSE; - break; - case 'x': - debugopt = pfctl_lookup_option(optarg, debugopt_list); - if (debugopt == NULL) { - warnx("Unknown debug level '%s'", optarg); - usage(); - } - mode = O_RDWR; - break; - case 'z': - opts |= PF_OPT_CLRRULECTRS; - mode = O_RDWR; - break; - case 'h': - /* FALLTHROUGH */ - default: - usage(); - /* NOTREACHED */ - } - } - - if (tblcmdopt != NULL) { - argc -= optind; - argv += optind; - ch = *tblcmdopt; - if (ch == 'l') { - loadopt |= PFCTL_FLAG_TABLE; - tblcmdopt = NULL; - } else - mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; - } else if (argc != optind) { - warnx("unknown command line argument: %s ...", argv[optind]); - usage(); - /* NOTREACHED */ - } - if (loadopt == 0) - loadopt = ~0; - - if ((path = calloc(1, MAXPATHLEN)) == NULL) - errx(1, "pfctl: calloc"); - memset(anchorname, 0, sizeof(anchorname)); - if (anchoropt != NULL) { - int len = strlen(anchoropt); - - if (anchoropt[len - 1] == '*') { - if (len >= 2 && anchoropt[len - 2] == '/') - anchoropt[len - 2] = '\0'; - else - anchoropt[len - 1] = '\0'; - opts |= PF_OPT_RECURSE; - } - if (strlcpy(anchorname, anchoropt, - sizeof(anchorname)) >= sizeof(anchorname)) - errx(1, "anchor name '%s' too long", - anchoropt); - loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; - } - - if ((opts & PF_OPT_NOACTION) == 0) { - dev = open(pf_device, mode); - if (dev == -1) - err(1, "%s", pf_device); - altqsupport = pfctl_test_altqsupport(dev, opts); - } else { - dev = open(pf_device, O_RDONLY); - if (dev >= 0) - opts |= PF_OPT_DUMMYACTION; - /* turn off options */ - opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); - clearopt = showopt = debugopt = NULL; -#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) - altqsupport = 0; -#else - altqsupport = 1; -#endif - } - - if (opts & PF_OPT_DISABLE) - if (pfctl_disable(dev, opts)) - error = 1; - - if (showopt != NULL) { - switch (*showopt) { - case 'A': - pfctl_show_anchors(dev, opts, anchorname); - break; - case 'r': - pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, - anchorname, 0); - break; - case 'l': - pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, - anchorname, 0); - break; - case 'n': - pfctl_load_fingerprints(dev, opts); - pfctl_show_nat(dev, opts, anchorname); - break; - case 'q': - pfctl_show_altq(dev, ifaceopt, opts, - opts & PF_OPT_VERBOSE2); - break; - case 's': - pfctl_show_states(dev, ifaceopt, opts); - break; - case 'S': - pfctl_show_src_nodes(dev, opts); - break; - case 'i': - pfctl_show_status(dev, opts); - break; - case 't': - pfctl_show_timeouts(dev, opts); - break; - case 'm': - pfctl_show_limits(dev, opts); - break; - case 'a': - opts |= PF_OPT_SHOWALL; - pfctl_load_fingerprints(dev, opts); - - pfctl_show_nat(dev, opts, anchorname); - pfctl_show_rules(dev, path, opts, 0, anchorname, 0); - pfctl_show_altq(dev, ifaceopt, opts, 0); - pfctl_show_states(dev, ifaceopt, opts); - pfctl_show_src_nodes(dev, opts); - pfctl_show_status(dev, opts); - pfctl_show_rules(dev, path, opts, 1, anchorname, 0); - pfctl_show_timeouts(dev, opts); - pfctl_show_limits(dev, opts); - pfctl_show_tables(anchorname, opts); - pfctl_show_fingerprints(opts); - break; - case 'T': - pfctl_show_tables(anchorname, opts); - break; - case 'o': - pfctl_load_fingerprints(dev, opts); - pfctl_show_fingerprints(opts); - break; - case 'I': - pfctl_show_ifaces(ifaceopt, opts); - break; - } - } - - if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, - anchorname, 0); - - if (clearopt != NULL) { - if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) - errx(1, "anchor names beginning with '_' cannot " - "be modified from the command line"); - - switch (*clearopt) { - case 'r': - pfctl_clear_rules(dev, opts, anchorname); - break; - case 'n': - pfctl_clear_nat(dev, opts, anchorname); - break; - case 'q': - pfctl_clear_altq(dev, opts); - break; - case 's': - pfctl_clear_states(dev, ifaceopt, opts); - break; - case 'S': - pfctl_clear_src_nodes(dev, opts); - break; - case 'i': - pfctl_clear_stats(dev, opts); - break; - case 'a': - pfctl_clear_rules(dev, opts, anchorname); - pfctl_clear_nat(dev, opts, anchorname); - pfctl_clear_tables(anchorname, opts); - if (!*anchorname) { - pfctl_clear_altq(dev, opts); - pfctl_clear_states(dev, ifaceopt, opts); - pfctl_clear_src_nodes(dev, opts); - pfctl_clear_stats(dev, opts); - pfctl_clear_fingerprints(dev, opts); - pfctl_clear_interface_flags(dev, opts); - } - break; - case 'o': - pfctl_clear_fingerprints(dev, opts); - break; - case 'T': - pfctl_clear_tables(anchorname, opts); - break; - } - } - if (state_killers) { - if (!strcmp(state_kill[0], "label")) - pfctl_label_kill_states(dev, ifaceopt, opts); - else if (!strcmp(state_kill[0], "id")) - pfctl_id_kill_states(dev, ifaceopt, opts); - else - pfctl_net_kill_states(dev, ifaceopt, opts); - } - - if (src_node_killers) - pfctl_kill_src_nodes(dev, ifaceopt, opts); - - if (tblcmdopt != NULL) { - error = pfctl_command_tables(argc, argv, tableopt, - tblcmdopt, rulesopt, anchorname, opts); - rulesopt = NULL; - } - if (optiopt != NULL) { - switch (*optiopt) { - case 'n': - optimize = 0; - break; - case 'b': - optimize |= PF_OPTIMIZE_BASIC; - break; - case 'o': - case 'p': - optimize |= PF_OPTIMIZE_PROFILE; - break; - } - } - - if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && - !anchorname[0]) - if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) - error = 1; - - if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) && - !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) - if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) - error = 1; - - if (rulesopt != NULL) { - if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) - errx(1, "anchor names beginning with '_' cannot " - "be modified from the command line"); - if (pfctl_rules(dev, rulesopt, opts, optimize, - anchorname, NULL)) - error = 1; - else if (!(opts & PF_OPT_NOACTION) && - (loadopt & PFCTL_FLAG_TABLE)) - warn_namespace_collision(NULL); - } - - if (opts & PF_OPT_ENABLE) - if (pfctl_enable(dev, opts)) - error = 1; - - if (debugopt != NULL) { - switch (*debugopt) { - case 'n': - pfctl_debug(dev, PF_DEBUG_NONE, opts); - break; - case 'u': - pfctl_debug(dev, PF_DEBUG_URGENT, opts); - break; - case 'm': - pfctl_debug(dev, PF_DEBUG_MISC, opts); - break; - case 'l': - pfctl_debug(dev, PF_DEBUG_NOISY, opts); - break; - } - } - - exit(error); -} -#ifdef __rtems__ -#include "pfctl-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl.h b/freebsd/contrib/pf/pfctl/pfctl.h deleted file mode 100644 index 2c69bc20..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl.h +++ /dev/null @@ -1,130 +0,0 @@ -/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _PFCTL_H_ -#define _PFCTL_H_ - -enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING }; - -enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, - PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; -struct pfr_buffer { - int pfrb_type; /* type of content, see enum above */ - int pfrb_size; /* number of objects in buffer */ - int pfrb_msize; /* maximum number of objects in buffer */ - void *pfrb_caddr; /* malloc'ated memory area */ -}; -#define PFRB_FOREACH(var, buf) \ - for ((var) = pfr_buf_next((buf), NULL); \ - (var) != NULL; \ - (var) = pfr_buf_next((buf), (var))) - -int pfr_get_fd(void); -int pfr_clr_tables(struct pfr_table *, int *, int); -int pfr_add_tables(struct pfr_table *, int, int *, int); -int pfr_del_tables(struct pfr_table *, int, int *, int); -int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); -int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); -int pfr_clr_tstats(struct pfr_table *, int, int *, int); -int pfr_clr_addrs(struct pfr_table *, int *, int); -int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int *, int *, int); -int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int); -int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int); -int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int, int); -void pfr_buf_clear(struct pfr_buffer *); -int pfr_buf_add(struct pfr_buffer *, const void *); -void *pfr_buf_next(struct pfr_buffer *, const void *); -int pfr_buf_grow(struct pfr_buffer *, int); -int pfr_buf_load(struct pfr_buffer *, char *, int, - int (*)(struct pfr_buffer *, char *, int)); -char *pfr_strerror(int); -int pfi_get_ifaces(const char *, struct pfi_kif *, int *); -int pfi_clr_istats(const char *, int *, int); - -void pfctl_print_title(char *); -int pfctl_clear_tables(const char *, int); -int pfctl_show_tables(const char *, int); -int pfctl_command_tables(int, char *[], char *, const char *, char *, - const char *, int); -int pfctl_show_altq(int, const char *, int, int); -void warn_namespace_collision(const char *); -int pfctl_show_ifaces(const char *, int); -FILE *pfctl_fopen(const char *, const char *); - -#ifdef __FreeBSD__ -extern int altqsupport; -extern int dummynetsupport; -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - -#ifndef DEFAULT_PRIORITY -#define DEFAULT_PRIORITY 1 -#endif - -#ifndef DEFAULT_QLIMIT -#define DEFAULT_QLIMIT 50 -#endif - -/* - * generalized service curve used for admission control - */ -struct segment { - LIST_ENTRY(segment) _next; - double x, y, d, m; -}; - -extern int loadopt; - -int check_commit_altq(int, int); -void pfaltq_store(struct pf_altq *); -struct pf_altq *pfaltq_lookup(const char *); -char *rate2str(double); - -void print_addr(struct pf_addr_wrap *, sa_family_t, int); -void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int); -void print_seq(struct pfsync_state_peer *); -void print_state(struct pfsync_state *, int); -int unmask(struct pf_addr *, sa_family_t); - -int pfctl_cmdline_symset(char *); -int pfctl_add_trans(struct pfr_buffer *, int, const char *); -u_int32_t - pfctl_get_ticket(struct pfr_buffer *, int, const char *); -int pfctl_trans(int, struct pfr_buffer *, u_long, int); - -#endif /* _PFCTL_H_ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_altq-data.h b/freebsd/contrib/pf/pfctl/pfctl_altq-data.h deleted file mode 100644 index 49898bc7..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_altq-data.h +++ /dev/null @@ -1,8 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct altqs altqs); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc rtsc); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc lssc); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static char r2sbuf[R2S_BUFS][RATESTR_MAX]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int r2sidx); diff --git a/freebsd/contrib/pf/pfctl/pfctl_altq.c b/freebsd/contrib/pf/pfctl/pfctl_altq.c deleted file mode 100644 index a5dea13f..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_altq.c +++ /dev/null @@ -1,1284 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ - -/* - * Copyright (c) 2002 - * Sony Computer Science Laboratories Inc. - * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> - -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) - -#ifndef __rtems__ -TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); -LIST_HEAD(gen_sc, segment) rtsc, lssc; -#else /* __rtems__ */ -static TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); -static LIST_HEAD(gen_sc, segment) rtsc, lssc; -#endif /* __rtems__ */ - -struct pf_altq *qname_to_pfaltq(const char *, const char *); -u_int32_t qname_to_qid(const char *); - -static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *); -static int cbq_compute_idletime(struct pfctl *, struct pf_altq *); -static int check_commit_cbq(int, int, struct pf_altq *); -static int print_cbq_opts(const struct pf_altq *); - -static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *); -static int check_commit_priq(int, int, struct pf_altq *); -static int print_priq_opts(const struct pf_altq *); - -static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *); -static int check_commit_hfsc(int, int, struct pf_altq *); -static int print_hfsc_opts(const struct pf_altq *, - const struct node_queue_opt *); - -static void gsc_add_sc(struct gen_sc *, struct service_curve *); -static int is_gsc_under_sc(struct gen_sc *, - struct service_curve *); -static void gsc_destroy(struct gen_sc *); -static struct segment *gsc_getentry(struct gen_sc *, double); -static int gsc_add_seg(struct gen_sc *, double, double, double, - double); -static double sc_x2y(struct service_curve *, double); - -#ifdef __FreeBSD__ -u_int32_t getifspeed(int, char *); -#else -u_int32_t getifspeed(char *); -#endif -u_long getifmtu(char *); -int eval_queue_opts(struct pf_altq *, struct node_queue_opt *, - u_int32_t); -u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); -void print_hfsc_sc(const char *, u_int, u_int, u_int, - const struct node_hfsc_sc *); - -void -pfaltq_store(struct pf_altq *a) -{ - struct pf_altq *altq; - - if ((altq = malloc(sizeof(*altq))) == NULL) - err(1, "malloc"); - memcpy(altq, a, sizeof(struct pf_altq)); - TAILQ_INSERT_TAIL(&altqs, altq, entries); -} - -struct pf_altq * -pfaltq_lookup(const char *ifname) -{ - struct pf_altq *altq; - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && - altq->qname[0] == 0) - return (altq); - } - return (NULL); -} - -struct pf_altq * -qname_to_pfaltq(const char *qname, const char *ifname) -{ - struct pf_altq *altq; - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && - strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) - return (altq); - } - return (NULL); -} - -u_int32_t -qname_to_qid(const char *qname) -{ - struct pf_altq *altq; - - /* - * We guarantee that same named queues on different interfaces - * have the same qid, so we do NOT need to limit matching on - * one interface! - */ - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) - return (altq->qid); - } - return (0); -} - -void -print_altq(const struct pf_altq *a, unsigned int level, - struct node_queue_bw *bw, struct node_queue_opt *qopts) -{ - if (a->qname[0] != 0) { - print_queue(a, level, bw, 1, qopts); - return; - } - -#ifdef __FreeBSD__ - if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) - printf("INACTIVE "); -#endif - - printf("altq on %s ", a->ifname); - - switch (a->scheduler) { - case ALTQT_CBQ: - if (!print_cbq_opts(a)) - printf("cbq "); - break; - case ALTQT_PRIQ: - if (!print_priq_opts(a)) - printf("priq "); - break; - case ALTQT_HFSC: - if (!print_hfsc_opts(a, qopts)) - printf("hfsc "); - break; - } - - if (bw != NULL && bw->bw_percent > 0) { - if (bw->bw_percent < 100) - printf("bandwidth %u%% ", bw->bw_percent); - } else - printf("bandwidth %s ", rate2str((double)a->ifbandwidth)); - - if (a->qlimit != DEFAULT_QLIMIT) - printf("qlimit %u ", a->qlimit); - printf("tbrsize %u ", a->tbrsize); -} - -void -print_queue(const struct pf_altq *a, unsigned int level, - struct node_queue_bw *bw, int print_interface, - struct node_queue_opt *qopts) -{ - unsigned int i; - -#ifdef __FreeBSD__ - if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) - printf("INACTIVE "); -#endif - printf("queue "); - for (i = 0; i < level; ++i) - printf(" "); - printf("%s ", a->qname); - if (print_interface) - printf("on %s ", a->ifname); - if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC) { - if (bw != NULL && bw->bw_percent > 0) { - if (bw->bw_percent < 100) - printf("bandwidth %u%% ", bw->bw_percent); - } else - printf("bandwidth %s ", rate2str((double)a->bandwidth)); - } - if (a->priority != DEFAULT_PRIORITY) - printf("priority %u ", a->priority); - if (a->qlimit != DEFAULT_QLIMIT) - printf("qlimit %u ", a->qlimit); - switch (a->scheduler) { - case ALTQT_CBQ: - print_cbq_opts(a); - break; - case ALTQT_PRIQ: - print_priq_opts(a); - break; - case ALTQT_HFSC: - print_hfsc_opts(a, qopts); - break; - } -} - -/* - * eval_pfaltq computes the discipline parameters. - */ -int -eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, - struct node_queue_opt *opts) -{ - u_int rate, size, errors = 0; - - if (bw->bw_absolute > 0) - pa->ifbandwidth = bw->bw_absolute; - else -#ifdef __FreeBSD__ - if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) { -#else - if ((rate = getifspeed(pa->ifname)) == 0) { -#endif - fprintf(stderr, "interface %s does not know its bandwidth, " - "please specify an absolute bandwidth\n", - pa->ifname); - errors++; - } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) - pa->ifbandwidth = rate; - - errors += eval_queue_opts(pa, opts, pa->ifbandwidth); - - /* if tbrsize is not specified, use heuristics */ - if (pa->tbrsize == 0) { - rate = pa->ifbandwidth; - if (rate <= 1 * 1000 * 1000) - size = 1; - else if (rate <= 10 * 1000 * 1000) - size = 4; - else if (rate <= 200 * 1000 * 1000) - size = 8; - else - size = 24; - size = size * getifmtu(pa->ifname); - if (size > 0xffff) - size = 0xffff; - pa->tbrsize = size; - } - return (errors); -} - -/* - * check_commit_altq does consistency check for each interface - */ -int -check_commit_altq(int dev, int opts) -{ - struct pf_altq *altq; - int error = 0; - - /* call the discipline check for each interface. */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (altq->qname[0] == 0) { - switch (altq->scheduler) { - case ALTQT_CBQ: - error = check_commit_cbq(dev, opts, altq); - break; - case ALTQT_PRIQ: - error = check_commit_priq(dev, opts, altq); - break; - case ALTQT_HFSC: - error = check_commit_hfsc(dev, opts, altq); - break; - default: - break; - } - } - } - return (error); -} - -/* - * eval_pfqueue computes the queue parameters. - */ -int -eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, - struct node_queue_opt *opts) -{ - /* should be merged with expand_queue */ - struct pf_altq *if_pa, *parent, *altq; - u_int32_t bwsum; - int error = 0; - - /* find the corresponding interface and copy fields used by queues */ - if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) { - fprintf(stderr, "altq not defined on %s\n", pa->ifname); - return (1); - } - pa->scheduler = if_pa->scheduler; - pa->ifbandwidth = if_pa->ifbandwidth; - - if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) { - fprintf(stderr, "queue %s already exists on interface %s\n", - pa->qname, pa->ifname); - return (1); - } - pa->qid = qname_to_qid(pa->qname); - - parent = NULL; - if (pa->parent[0] != 0) { - parent = qname_to_pfaltq(pa->parent, pa->ifname); - if (parent == NULL) { - fprintf(stderr, "parent %s not found for %s\n", - pa->parent, pa->qname); - return (1); - } - pa->parent_qid = parent->qid; - } - if (pa->qlimit == 0) - pa->qlimit = DEFAULT_QLIMIT; - - if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC) { - pa->bandwidth = eval_bwspec(bw, - parent == NULL ? 0 : parent->bandwidth); - - if (pa->bandwidth > pa->ifbandwidth) { - fprintf(stderr, "bandwidth for %s higher than " - "interface\n", pa->qname); - return (1); - } - /* check the sum of the child bandwidth is under parent's */ - if (parent != NULL) { - if (pa->bandwidth > parent->bandwidth) { - warnx("bandwidth for %s higher than parent", - pa->qname); - return (1); - } - bwsum = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, - IFNAMSIZ) == 0 && - altq->qname[0] != 0 && - strncmp(altq->parent, pa->parent, - PF_QNAME_SIZE) == 0) - bwsum += altq->bandwidth; - } - bwsum += pa->bandwidth; - if (bwsum > parent->bandwidth) { - warnx("the sum of the child bandwidth higher" - " than parent \"%s\"", parent->qname); - } - } - } - - if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth)) - return (1); - - switch (pa->scheduler) { - case ALTQT_CBQ: - error = eval_pfqueue_cbq(pf, pa); - break; - case ALTQT_PRIQ: - error = eval_pfqueue_priq(pf, pa); - break; - case ALTQT_HFSC: - error = eval_pfqueue_hfsc(pf, pa); - break; - default: - break; - } - return (error); -} - -/* - * CBQ support functions - */ -#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */ -#define RM_NS_PER_SEC (1000000000) - -static int -eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) -{ - struct cbq_opts *opts; - u_int ifmtu; - - if (pa->priority >= CBQ_MAXPRI) { - warnx("priority out of range: max %d", CBQ_MAXPRI - 1); - return (-1); - } - - ifmtu = getifmtu(pa->ifname); - opts = &pa->pq_u.cbq_opts; - - if (opts->pktsize == 0) { /* use default */ - opts->pktsize = ifmtu; - if (opts->pktsize > MCLBYTES) /* do what TCP does */ - opts->pktsize &= ~MCLBYTES; - } else if (opts->pktsize > ifmtu) - opts->pktsize = ifmtu; - if (opts->maxpktsize == 0) /* use default */ - opts->maxpktsize = ifmtu; - else if (opts->maxpktsize > ifmtu) - opts->pktsize = ifmtu; - - if (opts->pktsize > opts->maxpktsize) - opts->pktsize = opts->maxpktsize; - - if (pa->parent[0] == 0) - opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); - - cbq_compute_idletime(pf, pa); - return (0); -} - -/* - * compute ns_per_byte, maxidle, minidle, and offtime - */ -static int -cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) -{ - struct cbq_opts *opts; - double maxidle_s, maxidle, minidle; - double offtime, nsPerByte, ifnsPerByte, ptime, cptime; - double z, g, f, gton, gtom; - u_int minburst, maxburst; - - opts = &pa->pq_u.cbq_opts; - ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8; - minburst = opts->minburst; - maxburst = opts->maxburst; - - if (pa->bandwidth == 0) - f = 0.0001; /* small enough? */ - else - f = ((double) pa->bandwidth / (double) pa->ifbandwidth); - - nsPerByte = ifnsPerByte / f; - ptime = (double)opts->pktsize * ifnsPerByte; - cptime = ptime * (1.0 - f) / f; - - if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) { - /* - * this causes integer overflow in kernel! - * (bandwidth < 6Kbps when max_pkt_size=1500) - */ - if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) - warnx("queue bandwidth must be larger than %s", - rate2str(ifnsPerByte * (double)opts->maxpktsize / - (double)INT_MAX * (double)pa->ifbandwidth)); - fprintf(stderr, "cbq: queue %s is too slow!\n", - pa->qname); - nsPerByte = (double)(INT_MAX / opts->maxpktsize); - } - - if (maxburst == 0) { /* use default */ - if (cptime > 10.0 * 1000000) - maxburst = 4; - else - maxburst = 16; - } - if (minburst == 0) /* use default */ - minburst = 2; - if (minburst > maxburst) - minburst = maxburst; - - z = (double)(1 << RM_FILTER_GAIN); - g = (1.0 - 1.0 / z); - gton = pow(g, (double)maxburst); - gtom = pow(g, (double)(minburst-1)); - maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); - maxidle_s = (1.0 - g); - if (maxidle > maxidle_s) - maxidle = ptime * maxidle; - else - maxidle = ptime * maxidle_s; - offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); - minidle = -((double)opts->maxpktsize * (double)nsPerByte); - - /* scale parameters */ - maxidle = ((maxidle * 8.0) / nsPerByte) * - pow(2.0, (double)RM_FILTER_GAIN); - offtime = (offtime * 8.0) / nsPerByte * - pow(2.0, (double)RM_FILTER_GAIN); - minidle = ((minidle * 8.0) / nsPerByte) * - pow(2.0, (double)RM_FILTER_GAIN); - - maxidle = maxidle / 1000.0; - offtime = offtime / 1000.0; - minidle = minidle / 1000.0; - - opts->minburst = minburst; - opts->maxburst = maxburst; - opts->ns_per_byte = (u_int)nsPerByte; - opts->maxidle = (u_int)fabs(maxidle); - opts->minidle = (int)minidle; - opts->offtime = (u_int)fabs(offtime); - - return (0); -} - -static int -check_commit_cbq(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq; - int root_class, default_class; - int error = 0; - - /* - * check if cbq has one root queue and one default queue - * for this interface - */ - root_class = default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) - root_class++; - if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) - default_class++; - } - if (root_class != 1) { - warnx("should have one root queue on %s", pa->ifname); - error++; - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - error++; - } - return (error); -} - -static int -print_cbq_opts(const struct pf_altq *a) -{ - const struct cbq_opts *opts; - - opts = &a->pq_u.cbq_opts; - if (opts->flags) { - printf("cbq("); - if (opts->flags & CBQCLF_RED) - printf(" red"); - if (opts->flags & CBQCLF_ECN) - printf(" ecn"); - if (opts->flags & CBQCLF_RIO) - printf(" rio"); - if (opts->flags & CBQCLF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & CBQCLF_FLOWVALVE) - printf(" flowvalve"); - if (opts->flags & CBQCLF_BORROW) - printf(" borrow"); - if (opts->flags & CBQCLF_WRR) - printf(" wrr"); - if (opts->flags & CBQCLF_EFFICIENT) - printf(" efficient"); - if (opts->flags & CBQCLF_ROOTCLASS) - printf(" root"); - if (opts->flags & CBQCLF_DEFCLASS) - printf(" default"); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * PRIQ support functions - */ -static int -eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) -{ - struct pf_altq *altq; - - if (pa->priority >= PRIQ_MAXPRI) { - warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); - return (-1); - } - /* the priority should be unique for the interface */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && - altq->qname[0] != 0 && altq->priority == pa->priority) { - warnx("%s and %s have the same priority", - altq->qname, pa->qname); - return (-1); - } - } - - return (0); -} - -static int -check_commit_priq(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq; - int default_class; - int error = 0; - - /* - * check if priq has one default class for this interface - */ - default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) - default_class++; - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - error++; - } - return (error); -} - -static int -print_priq_opts(const struct pf_altq *a) -{ - const struct priq_opts *opts; - - opts = &a->pq_u.priq_opts; - - if (opts->flags) { - printf("priq("); - if (opts->flags & PRCF_RED) - printf(" red"); - if (opts->flags & PRCF_ECN) - printf(" ecn"); - if (opts->flags & PRCF_RIO) - printf(" rio"); - if (opts->flags & PRCF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & PRCF_DEFAULTCLASS) - printf(" default"); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * HFSC support functions - */ -static int -eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) -{ - struct pf_altq *altq, *parent; - struct hfsc_opts *opts; - struct service_curve sc; - - opts = &pa->pq_u.hfsc_opts; - - if (pa->parent[0] == 0) { - /* root queue */ - opts->lssc_m1 = pa->ifbandwidth; - opts->lssc_m2 = pa->ifbandwidth; - opts->lssc_d = 0; - return (0); - } - - LIST_INIT(&rtsc); - LIST_INIT(&lssc); - - /* if link_share is not specified, use bandwidth */ - if (opts->lssc_m2 == 0) - opts->lssc_m2 = pa->bandwidth; - - if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || - (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || - (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { - warnx("m2 is zero for %s", pa->qname); - return (-1); - } - - if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || - (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || - (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { - warnx("m1 must be zero for convex curve: %s", pa->qname); - return (-1); - } - - /* - * admission control: - * for the real-time service curve, the sum of the service curves - * should not exceed 80% of the interface bandwidth. 20% is reserved - * not to over-commit the actual interface bandwidth. - * for the linkshare service curve, the sum of the child service - * curve should not exceed the parent service curve. - * for the upper-limit service curve, the assigned bandwidth should - * be smaller than the interface bandwidth, and the upper-limit should - * be larger than the real-time service curve when both are defined. - */ - parent = qname_to_pfaltq(pa->parent, pa->ifname); - if (parent == NULL) - errx(1, "parent %s not found for %s", pa->parent, pa->qname); - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - - /* if the class has a real-time service curve, add it. */ - if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { - sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; - sc.d = altq->pq_u.hfsc_opts.rtsc_d; - sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; - gsc_add_sc(&rtsc, &sc); - } - - if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) - continue; - - /* if the class has a linkshare service curve, add it. */ - if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { - sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; - sc.d = altq->pq_u.hfsc_opts.lssc_d; - sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; - gsc_add_sc(&lssc, &sc); - } - } - - /* check the real-time service curve. reserve 20% of interface bw */ - if (opts->rtsc_m2 != 0) { - /* add this queue to the sum */ - sc.m1 = opts->rtsc_m1; - sc.d = opts->rtsc_d; - sc.m2 = opts->rtsc_m2; - gsc_add_sc(&rtsc, &sc); - /* compare the sum with 80% of the interface */ - sc.m1 = 0; - sc.d = 0; - sc.m2 = pa->ifbandwidth / 100 * 80; - if (!is_gsc_under_sc(&rtsc, &sc)) { - warnx("real-time sc exceeds 80%% of the interface " - "bandwidth (%s)", rate2str((double)sc.m2)); - goto err_ret; - } - } - - /* check the linkshare service curve. */ - if (opts->lssc_m2 != 0) { - /* add this queue to the child sum */ - sc.m1 = opts->lssc_m1; - sc.d = opts->lssc_d; - sc.m2 = opts->lssc_m2; - gsc_add_sc(&lssc, &sc); - /* compare the sum of the children with parent's sc */ - sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; - sc.d = parent->pq_u.hfsc_opts.lssc_d; - sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; - if (!is_gsc_under_sc(&lssc, &sc)) { - warnx("linkshare sc exceeds parent's sc"); - goto err_ret; - } - } - - /* check the upper-limit service curve. */ - if (opts->ulsc_m2 != 0) { - if (opts->ulsc_m1 > pa->ifbandwidth || - opts->ulsc_m2 > pa->ifbandwidth) { - warnx("upper-limit larger than interface bandwidth"); - goto err_ret; - } - if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { - warnx("upper-limit sc smaller than real-time sc"); - goto err_ret; - } - } - - gsc_destroy(&rtsc); - gsc_destroy(&lssc); - - return (0); - -err_ret: - gsc_destroy(&rtsc); - gsc_destroy(&lssc); - return (-1); -} - -static int -check_commit_hfsc(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq, *def = NULL; - int default_class; - int error = 0; - - /* check if hfsc has one default queue for this interface */ - default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->parent[0] == 0) /* dummy root */ - continue; - if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { - default_class++; - def = altq; - } - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - return (1); - } - /* make sure the default queue is a leaf */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { - warnx("default queue is not a leaf"); - error++; - } - } - return (error); -} - -static int -print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) -{ - const struct hfsc_opts *opts; - const struct node_hfsc_sc *rtsc, *lssc, *ulsc; - - opts = &a->pq_u.hfsc_opts; - if (qopts == NULL) - rtsc = lssc = ulsc = NULL; - else { - rtsc = &qopts->data.hfsc_opts.realtime; - lssc = &qopts->data.hfsc_opts.linkshare; - ulsc = &qopts->data.hfsc_opts.upperlimit; - } - - if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || - (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || - opts->lssc_d != 0))) { - printf("hfsc("); - if (opts->flags & HFCF_RED) - printf(" red"); - if (opts->flags & HFCF_ECN) - printf(" ecn"); - if (opts->flags & HFCF_RIO) - printf(" rio"); - if (opts->flags & HFCF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & HFCF_DEFAULTCLASS) - printf(" default"); - if (opts->rtsc_m2 != 0) - print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, - opts->rtsc_m2, rtsc); - if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || - opts->lssc_d != 0)) - print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, - opts->lssc_m2, lssc); - if (opts->ulsc_m2 != 0) - print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, - opts->ulsc_m2, ulsc); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * admission control using generalized service curve - */ - -/* add a new service curve to a generalized service curve */ -static void -gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) -{ - if (is_sc_null(sc)) - return; - if (sc->d != 0) - gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); - gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); -} - -/* - * check whether all points of a generalized service curve have - * their y-coordinates no larger than a given two-piece linear - * service curve. - */ -static int -is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) -{ - struct segment *s, *last, *end; - double y; - - if (is_sc_null(sc)) { - if (LIST_EMPTY(gsc)) - return (1); - LIST_FOREACH(s, gsc, _next) { - if (s->m != 0) - return (0); - } - return (1); - } - /* - * gsc has a dummy entry at the end with x = INFINITY. - * loop through up to this dummy entry. - */ - end = gsc_getentry(gsc, INFINITY); - if (end == NULL) - return (1); - last = NULL; - for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { - if (s->y > sc_x2y(sc, s->x)) - return (0); - last = s; - } - /* last now holds the real last segment */ - if (last == NULL) - return (1); - if (last->m > sc->m2) - return (0); - if (last->x < sc->d && last->m > sc->m1) { - y = last->y + (sc->d - last->x) * last->m; - if (y > sc_x2y(sc, sc->d)) - return (0); - } - return (1); -} - -static void -gsc_destroy(struct gen_sc *gsc) -{ - struct segment *s; - - while ((s = LIST_FIRST(gsc)) != NULL) { - LIST_REMOVE(s, _next); - free(s); - } -} - -/* - * return a segment entry starting at x. - * if gsc has no entry starting at x, a new entry is created at x. - */ -static struct segment * -gsc_getentry(struct gen_sc *gsc, double x) -{ - struct segment *new, *prev, *s; - - prev = NULL; - LIST_FOREACH(s, gsc, _next) { - if (s->x == x) - return (s); /* matching entry found */ - else if (s->x < x) - prev = s; - else - break; - } - - /* we have to create a new entry */ - if ((new = calloc(1, sizeof(struct segment))) == NULL) - return (NULL); - - new->x = x; - if (x == INFINITY || s == NULL) - new->d = 0; - else if (s->x == INFINITY) - new->d = INFINITY; - else - new->d = s->x - x; - if (prev == NULL) { - /* insert the new entry at the head of the list */ - new->y = 0; - new->m = 0; - LIST_INSERT_HEAD(gsc, new, _next); - } else { - /* - * the start point intersects with the segment pointed by - * prev. divide prev into 2 segments - */ - if (x == INFINITY) { - prev->d = INFINITY; - if (prev->m == 0) - new->y = prev->y; - else - new->y = INFINITY; - } else { - prev->d = x - prev->x; - new->y = prev->d * prev->m + prev->y; - } - new->m = prev->m; - LIST_INSERT_AFTER(prev, new, _next); - } - return (new); -} - -/* add a segment to a generalized service curve */ -static int -gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) -{ - struct segment *start, *end, *s; - double x2; - - if (d == INFINITY) - x2 = INFINITY; - else - x2 = x + d; - start = gsc_getentry(gsc, x); - end = gsc_getentry(gsc, x2); - if (start == NULL || end == NULL) - return (-1); - - for (s = start; s != end; s = LIST_NEXT(s, _next)) { - s->m += m; - s->y += y + (s->x - x) * m; - } - - end = gsc_getentry(gsc, INFINITY); - for (; s != end; s = LIST_NEXT(s, _next)) { - s->y += m * d; - } - - return (0); -} - -/* get y-projection of a service curve */ -static double -sc_x2y(struct service_curve *sc, double x) -{ - double y; - - if (x <= (double)sc->d) - /* y belongs to the 1st segment */ - y = x * (double)sc->m1; - else - /* y belongs to the 2nd segment */ - y = (double)sc->d * (double)sc->m1 - + (x - (double)sc->d) * (double)sc->m2; - return (y); -} - -/* - * misc utilities - */ -#define R2S_BUFS 8 -#define RATESTR_MAX 16 - -#ifdef __rtems__ -static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ -static int r2sidx = 0; - -#endif /* __rtems__ */ -char * -rate2str(double rate) -{ - char *buf; -#ifndef __rtems__ - static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ - static int idx = 0; -#endif /* __rtems__ */ - int i; - static const char unit[] = " KMG"; - -#ifndef __rtems__ - buf = r2sbuf[idx++]; - if (idx == R2S_BUFS) - idx = 0; -#else /* __rtems__ */ - buf = r2sbuf[r2sidx++]; - if (r2sidx == R2S_BUFS) - r2sidx = 0; -#endif /* __rtems__ */ - - for (i = 0; rate >= 1000 && i <= 3; i++) - rate /= 1000; - - if ((int)(rate * 100) % 100) - snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); - else - snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); - - return (buf); -} - -#ifdef __FreeBSD__ -/* - * XXX - * FreeBSD does not have SIOCGIFDATA. - * To emulate this, DIOCGIFSPEED ioctl added to pf. - */ -u_int32_t -getifspeed(int pfdev, char *ifname) -{ - struct pf_ifspeed io; - - bzero(&io, sizeof io); - if (strlcpy(io.ifname, ifname, IFNAMSIZ) >= - sizeof(io.ifname)) - errx(1, "getifspeed: strlcpy"); - if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1) - err(1, "DIOCGIFSPEED"); - return ((u_int32_t)io.baudrate); -} -#else -u_int32_t -getifspeed(char *ifname) -{ - int s; - struct ifreq ifr; - struct if_data ifrdat; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - bzero(&ifr, sizeof(ifr)); - if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= - sizeof(ifr.ifr_name)) - errx(1, "getifspeed: strlcpy"); - ifr.ifr_data = (caddr_t)&ifrdat; - if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) - err(1, "SIOCGIFDATA"); - if (close(s)) - err(1, "close"); - return ((u_int32_t)ifrdat.ifi_baudrate); -} -#endif - -u_long -getifmtu(char *ifname) -{ - int s; - struct ifreq ifr; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - bzero(&ifr, sizeof(ifr)); - if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= - sizeof(ifr.ifr_name)) - errx(1, "getifmtu: strlcpy"); - if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) -#ifdef __FreeBSD__ - ifr.ifr_mtu = 1500; -#else - err(1, "SIOCGIFMTU"); -#endif - if (close(s)) - err(1, "close"); - if (ifr.ifr_mtu > 0) - return (ifr.ifr_mtu); - else { - warnx("could not get mtu for %s, assuming 1500", ifname); - return (1500); - } -} - -int -eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, - u_int32_t ref_bw) -{ - int errors = 0; - - switch (pa->scheduler) { - case ALTQT_CBQ: - pa->pq_u.cbq_opts = opts->data.cbq_opts; - break; - case ALTQT_PRIQ: - pa->pq_u.priq_opts = opts->data.priq_opts; - break; - case ALTQT_HFSC: - pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; - if (opts->data.hfsc_opts.linkshare.used) { - pa->pq_u.hfsc_opts.lssc_m1 = - eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, - ref_bw); - pa->pq_u.hfsc_opts.lssc_m2 = - eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, - ref_bw); - pa->pq_u.hfsc_opts.lssc_d = - opts->data.hfsc_opts.linkshare.d; - } - if (opts->data.hfsc_opts.realtime.used) { - pa->pq_u.hfsc_opts.rtsc_m1 = - eval_bwspec(&opts->data.hfsc_opts.realtime.m1, - ref_bw); - pa->pq_u.hfsc_opts.rtsc_m2 = - eval_bwspec(&opts->data.hfsc_opts.realtime.m2, - ref_bw); - pa->pq_u.hfsc_opts.rtsc_d = - opts->data.hfsc_opts.realtime.d; - } - if (opts->data.hfsc_opts.upperlimit.used) { - pa->pq_u.hfsc_opts.ulsc_m1 = - eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, - ref_bw); - pa->pq_u.hfsc_opts.ulsc_m2 = - eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, - ref_bw); - pa->pq_u.hfsc_opts.ulsc_d = - opts->data.hfsc_opts.upperlimit.d; - } - break; - default: - warnx("eval_queue_opts: unknown scheduler type %u", - opts->qtype); - errors++; - break; - } - - return (errors); -} - -u_int32_t -eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) -{ - if (bw->bw_absolute > 0) - return (bw->bw_absolute); - - if (bw->bw_percent > 0) - return (ref_bw / 100 * bw->bw_percent); - - return (0); -} - -void -print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, - const struct node_hfsc_sc *sc) -{ - printf(" %s", scname); - - if (d != 0) { - printf("("); - if (sc != NULL && sc->m1.bw_percent > 0) - printf("%u%%", sc->m1.bw_percent); - else - printf("%s", rate2str((double)m1)); - printf(" %u", d); - } - - if (sc != NULL && sc->m2.bw_percent > 0) - printf(" %u%%", sc->m2.bw_percent); - else - printf(" %s", rate2str((double)m2)); - - if (d != 0) - printf(")"); -} -#ifdef __rtems__ -#include "pfctl_altq-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_optimize-data.h b/freebsd/contrib/pf/pfctl/pfctl_optimize-data.h deleted file mode 100644 index 1d55415a..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_optimize-data.h +++ /dev/null @@ -1,13 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int add_opt_table_num); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pf_opt_create_table_num); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct pf_rule_field pf_rule_desc[]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int - (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, struct pf_rule *)); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static const char *skip_comparitors_names[PF_SKIP_COUNT]); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, - static struct pfr_buffer table_buffer); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int table_identifier); diff --git a/freebsd/contrib/pf/pfctl/pfctl_optimize.c b/freebsd/contrib/pf/pfctl/pfctl_optimize.c deleted file mode 100644 index b62359f3..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_optimize.c +++ /dev/null @@ -1,1703 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */ - -/* - * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> - -/* We need some functions from kernel space. */ -#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <assert.h> -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -/* The size at which a table becomes faster than individual rules */ -#define TABLE_THRESHOLD 6 - - -/* #define OPT_DEBUG 1 */ -#ifdef OPT_DEBUG -# define DEBUG(str, v...) \ - printf("%s: " str "\n", __FUNCTION__ , ## v) -#else -# define DEBUG(str, v...) ((void)0) -#endif - - -/* - * A container that lets us sort a superblock to optimize the skip step jumps - */ -struct pf_skip_step { - int ps_count; /* number of items */ - TAILQ_HEAD( , pf_opt_rule) ps_rules; - TAILQ_ENTRY(pf_skip_step) ps_entry; -}; - - -/* - * A superblock is a block of adjacent rules of similar action. If there - * are five PASS rules in a row, they all become members of a superblock. - * Once we have a superblock, we are free to re-order any rules within it - * in order to improve performance; if a packet is passed, it doesn't matter - * who passed it. - */ -struct superblock { - TAILQ_HEAD( , pf_opt_rule) sb_rules; - TAILQ_ENTRY(superblock) sb_entry; - struct superblock *sb_profiled_block; - TAILQ_HEAD(skiplist, pf_skip_step) sb_skipsteps[PF_SKIP_COUNT]; -}; -TAILQ_HEAD(superblocks, superblock); - - -/* - * Description of the PF rule structure. - */ -enum { - BARRIER, /* the presence of the field puts the rule in it's own block */ - BREAK, /* the field may not differ between rules in a superblock */ - NOMERGE, /* the field may not differ between rules when combined */ - COMBINED, /* the field may itself be combined with other rules */ - DC, /* we just don't care about the field */ - NEVER}; /* we should never see this field set?!? */ -#ifndef __rtems__ -struct pf_rule_field { -#else /* __rtems__ */ -static struct pf_rule_field { -#endif /* __rtems__ */ - const char *prf_name; - int prf_type; - size_t prf_offset; - size_t prf_size; -} pf_rule_desc[] = { -#define PF_RULE_FIELD(field, ty) \ - {#field, \ - ty, \ - offsetof(struct pf_rule, field), \ - sizeof(((struct pf_rule *)0)->field)} - - - /* - * The presence of these fields in a rule put the rule in it's own - * superblock. Thus it will not be optimized. It also prevents the - * rule from being re-ordered at all. - */ - PF_RULE_FIELD(label, BARRIER), - PF_RULE_FIELD(prob, BARRIER), - PF_RULE_FIELD(max_states, BARRIER), - PF_RULE_FIELD(max_src_nodes, BARRIER), - PF_RULE_FIELD(max_src_states, BARRIER), - PF_RULE_FIELD(max_src_conn, BARRIER), - PF_RULE_FIELD(max_src_conn_rate, BARRIER), - PF_RULE_FIELD(anchor, BARRIER), /* for now */ - - /* - * These fields must be the same between all rules in the same superblock. - * These rules are allowed to be re-ordered but only among like rules. - * For instance we can re-order all 'tag "foo"' rules because they have the - * same tag. But we can not re-order between a 'tag "foo"' and a - * 'tag "bar"' since that would change the meaning of the ruleset. - */ - PF_RULE_FIELD(tagname, BREAK), - PF_RULE_FIELD(keep_state, BREAK), - PF_RULE_FIELD(qname, BREAK), - PF_RULE_FIELD(pqname, BREAK), - PF_RULE_FIELD(rt, BREAK), - PF_RULE_FIELD(allow_opts, BREAK), - PF_RULE_FIELD(rule_flag, BREAK), - PF_RULE_FIELD(action, BREAK), - PF_RULE_FIELD(log, BREAK), - PF_RULE_FIELD(quick, BREAK), - PF_RULE_FIELD(return_ttl, BREAK), - PF_RULE_FIELD(overload_tblname, BREAK), - PF_RULE_FIELD(flush, BREAK), - PF_RULE_FIELD(rpool, BREAK), - PF_RULE_FIELD(logif, BREAK), - - /* - * Any fields not listed in this structure act as BREAK fields - */ - - - /* - * These fields must not differ when we merge two rules together but - * their difference isn't enough to put the rules in different superblocks. - * There are no problems re-ordering any rules with these fields. - */ - PF_RULE_FIELD(af, NOMERGE), - PF_RULE_FIELD(ifnot, NOMERGE), - PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */ - PF_RULE_FIELD(match_tag_not, NOMERGE), - PF_RULE_FIELD(match_tagname, NOMERGE), - PF_RULE_FIELD(os_fingerprint, NOMERGE), - PF_RULE_FIELD(timeout, NOMERGE), - PF_RULE_FIELD(return_icmp, NOMERGE), - PF_RULE_FIELD(return_icmp6, NOMERGE), - PF_RULE_FIELD(uid, NOMERGE), - PF_RULE_FIELD(gid, NOMERGE), - PF_RULE_FIELD(direction, NOMERGE), - PF_RULE_FIELD(proto, NOMERGE), - PF_RULE_FIELD(type, NOMERGE), - PF_RULE_FIELD(code, NOMERGE), - PF_RULE_FIELD(flags, NOMERGE), - PF_RULE_FIELD(flagset, NOMERGE), - PF_RULE_FIELD(tos, NOMERGE), - PF_RULE_FIELD(src.port, NOMERGE), - PF_RULE_FIELD(dst.port, NOMERGE), - PF_RULE_FIELD(src.port_op, NOMERGE), - PF_RULE_FIELD(dst.port_op, NOMERGE), - PF_RULE_FIELD(src.neg, NOMERGE), - PF_RULE_FIELD(dst.neg, NOMERGE), - - /* These fields can be merged */ - PF_RULE_FIELD(src.addr, COMBINED), - PF_RULE_FIELD(dst.addr, COMBINED), - - /* We just don't care about these fields. They're set by the kernel */ - PF_RULE_FIELD(skip, DC), - PF_RULE_FIELD(evaluations, DC), - PF_RULE_FIELD(packets, DC), - PF_RULE_FIELD(bytes, DC), - PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(states_cur, DC), - PF_RULE_FIELD(states_tot, DC), - PF_RULE_FIELD(src_nodes, DC), - PF_RULE_FIELD(nr, DC), - PF_RULE_FIELD(entries, DC), - PF_RULE_FIELD(qid, DC), - PF_RULE_FIELD(pqid, DC), - PF_RULE_FIELD(anchor_relative, DC), - PF_RULE_FIELD(anchor_wildcard, DC), - PF_RULE_FIELD(tag, DC), - PF_RULE_FIELD(match_tag, DC), - PF_RULE_FIELD(overload_tbl, DC), - - /* These fields should never be set in a PASS/BLOCK rule */ - PF_RULE_FIELD(natpass, NEVER), - PF_RULE_FIELD(max_mss, NEVER), - PF_RULE_FIELD(min_ttl, NEVER), - PF_RULE_FIELD(set_tos, NEVER), -}; -#ifdef __rtems__ -static int pf_opt_create_table_num; -static int add_opt_table_num = 0; -#endif /* __rtems__ */ - - - -int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t, - struct pf_rule_addr *); -int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *); -int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *); -int block_feedback(struct pfctl *, struct superblock *); -int combine_rules(struct pfctl *, struct superblock *); -void comparable_rule(struct pf_rule *, const struct pf_rule *, int); -int construct_superblocks(struct pfctl *, struct pf_opt_queue *, - struct superblocks *); -void exclude_supersets(struct pf_rule *, struct pf_rule *); -int interface_group(const char *); -int load_feedback_profile(struct pfctl *, struct superblocks *); -int optimize_superblock(struct pfctl *, struct superblock *); -int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *); -void remove_from_skipsteps(struct skiplist *, struct superblock *, - struct pf_opt_rule *, struct pf_skip_step *); -int remove_identical_rules(struct pfctl *, struct superblock *); -int reorder_rules(struct pfctl *, struct superblock *, int); -int rules_combineable(struct pf_rule *, struct pf_rule *); -void skip_append(struct superblock *, int, struct pf_skip_step *, - struct pf_opt_rule *); -int skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *); -void skip_init(void); -int skip_cmp_af(struct pf_rule *, struct pf_rule *); -int skip_cmp_dir(struct pf_rule *, struct pf_rule *); -int skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *); -int skip_cmp_dst_port(struct pf_rule *, struct pf_rule *); -int skip_cmp_ifp(struct pf_rule *, struct pf_rule *); -int skip_cmp_proto(struct pf_rule *, struct pf_rule *); -int skip_cmp_src_addr(struct pf_rule *, struct pf_rule *); -int skip_cmp_src_port(struct pf_rule *, struct pf_rule *); -int superblock_inclusive(struct superblock *, struct pf_opt_rule *); -void superblock_free(struct pfctl *, struct superblock *); - - -#ifndef __rtems__ -int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, struct pf_rule *); -const char *skip_comparitors_names[PF_SKIP_COUNT]; -#else /* __rtems__ */ -static int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, - struct pf_rule *); -static const char *skip_comparitors_names[PF_SKIP_COUNT]; -#endif /* __rtems__ */ -#define PF_SKIP_COMPARITORS { \ - { "ifp", PF_SKIP_IFP, skip_cmp_ifp }, \ - { "dir", PF_SKIP_DIR, skip_cmp_dir }, \ - { "af", PF_SKIP_AF, skip_cmp_af }, \ - { "proto", PF_SKIP_PROTO, skip_cmp_proto }, \ - { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr }, \ - { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port }, \ - { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr }, \ - { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \ -} - -#ifndef __rtems__ -struct pfr_buffer table_buffer; -int table_identifier; -#else /* __rtems__ */ -static struct pfr_buffer table_buffer; -static int table_identifier; -#endif /* __rtems__ */ - - -int -pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs) -{ - struct superblocks superblocks; - struct pf_opt_queue opt_queue; - struct superblock *block; - struct pf_opt_rule *por; - struct pf_rule *r; - struct pf_rulequeue *old_rules; - - DEBUG("optimizing ruleset"); - memset(&table_buffer, 0, sizeof(table_buffer)); - skip_init(); - TAILQ_INIT(&opt_queue); - - old_rules = rs->rules[PF_RULESET_FILTER].active.ptr; - rs->rules[PF_RULESET_FILTER].active.ptr = - rs->rules[PF_RULESET_FILTER].inactive.ptr; - rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules; - - /* - * XXX expanding the pf_opt_rule format throughout pfctl might allow - * us to avoid all this copying. - */ - while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r, - entries); - if ((por = calloc(1, sizeof(*por))) == NULL) - err(1, "calloc"); - memcpy(&por->por_rule, r, sizeof(*r)); - if (TAILQ_FIRST(&r->rpool.list) != NULL) { - TAILQ_INIT(&por->por_rule.rpool.list); - pfctl_move_pool(&r->rpool, &por->por_rule.rpool); - } else - bzero(&por->por_rule.rpool, - sizeof(por->por_rule.rpool)); - - - TAILQ_INSERT_TAIL(&opt_queue, por, por_entry); - } - - TAILQ_INIT(&superblocks); - if (construct_superblocks(pf, &opt_queue, &superblocks)) - goto error; - - if (pf->optimize & PF_OPTIMIZE_PROFILE) { - if (load_feedback_profile(pf, &superblocks)) - goto error; - } - - TAILQ_FOREACH(block, &superblocks, sb_entry) { - if (optimize_superblock(pf, block)) - goto error; - } - - rs->anchor->refcnt = 0; - while ((block = TAILQ_FIRST(&superblocks))) { - TAILQ_REMOVE(&superblocks, block, sb_entry); - - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - por->por_rule.nr = rs->anchor->refcnt++; - if ((r = calloc(1, sizeof(*r))) == NULL) - err(1, "calloc"); - memcpy(r, &por->por_rule, sizeof(*r)); - TAILQ_INIT(&r->rpool.list); - pfctl_move_pool(&por->por_rule.rpool, &r->rpool); - TAILQ_INSERT_TAIL( - rs->rules[PF_RULESET_FILTER].active.ptr, - r, entries); - free(por); - } - free(block); - } - - return (0); - -error: - while ((por = TAILQ_FIRST(&opt_queue))) { - TAILQ_REMOVE(&opt_queue, por, por_entry); - if (por->por_src_tbl) { - pfr_buf_clear(por->por_src_tbl->pt_buf); - free(por->por_src_tbl->pt_buf); - free(por->por_src_tbl); - } - if (por->por_dst_tbl) { - pfr_buf_clear(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl); - } - free(por); - } - while ((block = TAILQ_FIRST(&superblocks))) { - TAILQ_REMOVE(&superblocks, block, sb_entry); - superblock_free(pf, block); - } - return (1); -} - - -/* - * Go ahead and optimize a superblock - */ -int -optimize_superblock(struct pfctl *pf, struct superblock *block) -{ -#ifdef OPT_DEBUG - struct pf_opt_rule *por; -#endif /* OPT_DEBUG */ - - /* We have a few optimization passes: - * 1) remove duplicate rules or rules that are a subset of other - * rules - * 2) combine otherwise identical rules with different IP addresses - * into a single rule and put the addresses in a table. - * 3) re-order the rules to improve kernel skip steps - * 4) re-order the 'quick' rules based on feedback from the - * active ruleset statistics - * - * XXX combine_rules() doesn't combine v4 and v6 rules. would just - * have to keep af in the table container, make af 'COMBINE' and - * twiddle the af on the merged rule - * XXX maybe add a weighting to the metric on skipsteps when doing - * reordering. sometimes two sequential tables will be better - * that four consecutive interfaces. - * XXX need to adjust the skipstep count of everything after PROTO, - * since they aren't actually checked on a proto mismatch in - * pf_test_{tcp, udp, icmp}() - * XXX should i treat proto=0, af=0 or dir=0 special in skepstep - * calculation since they are a DC? - * XXX keep last skiplist of last superblock to influence this - * superblock. '5 inet6 log' should make '3 inet6' come before '4 - * inet' in the next superblock. - * XXX would be useful to add tables for ports - * XXX we can also re-order some mutually exclusive superblocks to - * try merging superblocks before any of these optimization passes. - * for instance a single 'log in' rule in the middle of non-logging - * out rules. - */ - - /* shortcut. there will be a lot of 1-rule superblocks */ - if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry)) - return (0); - -#ifdef OPT_DEBUG - printf("--- Superblock ---\n"); - TAILQ_FOREACH(por, &block->sb_rules, por_entry) { - printf(" "); - print_rule(&por->por_rule, por->por_rule.anchor ? - por->por_rule.anchor->name : "", 1, 0); - } -#endif /* OPT_DEBUG */ - - - if (remove_identical_rules(pf, block)) - return (1); - if (combine_rules(pf, block)) - return (1); - if ((pf->optimize & PF_OPTIMIZE_PROFILE) && - TAILQ_FIRST(&block->sb_rules)->por_rule.quick && - block->sb_profiled_block) { - if (block_feedback(pf, block)) - return (1); - } else if (reorder_rules(pf, block, 0)) { - return (1); - } - - /* - * Don't add any optimization passes below reorder_rules(). It will - * have divided superblocks into smaller blocks for further refinement - * and doesn't put them back together again. What once was a true - * superblock might have been split into multiple superblocks. - */ - -#ifdef OPT_DEBUG - printf("--- END Superblock ---\n"); -#endif /* OPT_DEBUG */ - return (0); -} - - -/* - * Optimization pass #1: remove identical rules - */ -int -remove_identical_rules(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *por1, *por2, *por_next, *por2_next; - struct pf_rule a, a2, b, b2; - - for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) { - por_next = TAILQ_NEXT(por1, por_entry); - for (por2 = por_next; por2; por2 = por2_next) { - por2_next = TAILQ_NEXT(por2, por_entry); - comparable_rule(&a, &por1->por_rule, DC); - comparable_rule(&b, &por2->por_rule, DC); - memcpy(&a2, &a, sizeof(a2)); - memcpy(&b2, &b, sizeof(b2)); - - exclude_supersets(&a, &b); - exclude_supersets(&b2, &a2); - if (memcmp(&a, &b, sizeof(a)) == 0) { - DEBUG("removing identical rule nr%d = *nr%d*", - por1->por_rule.nr, por2->por_rule.nr); - TAILQ_REMOVE(&block->sb_rules, por2, por_entry); - if (por_next == por2) - por_next = TAILQ_NEXT(por1, por_entry); - free(por2); - } else if (memcmp(&a2, &b2, sizeof(a2)) == 0) { - DEBUG("removing identical rule *nr%d* = nr%d", - por1->por_rule.nr, por2->por_rule.nr); - TAILQ_REMOVE(&block->sb_rules, por1, por_entry); - free(por1); - break; - } - } - } - - return (0); -} - - -/* - * Optimization pass #2: combine similar rules with different addresses - * into a single rule and a table - */ -int -combine_rules(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *p1, *p2, *por_next; - int src_eq, dst_eq; - - if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) { - warnx("Must enable table loading for optimizations"); - return (1); - } - - /* First we make a pass to combine the rules. O(n log n) */ - TAILQ_FOREACH(p1, &block->sb_rules, por_entry) { - for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) { - por_next = TAILQ_NEXT(p2, por_entry); - - src_eq = addrs_equal(&p1->por_rule.src, - &p2->por_rule.src); - dst_eq = addrs_equal(&p1->por_rule.dst, - &p2->por_rule.dst); - - if (src_eq && !dst_eq && p1->por_src_tbl == NULL && - p2->por_dst_tbl == NULL && - p2->por_src_tbl == NULL && - rules_combineable(&p1->por_rule, &p2->por_rule) && - addrs_combineable(&p1->por_rule.dst, - &p2->por_rule.dst)) { - DEBUG("can combine rules nr%d = nr%d", - p1->por_rule.nr, p2->por_rule.nr); - if (p1->por_dst_tbl == NULL && - add_opt_table(pf, &p1->por_dst_tbl, - p1->por_rule.af, &p1->por_rule.dst)) - return (1); - if (add_opt_table(pf, &p1->por_dst_tbl, - p1->por_rule.af, &p2->por_rule.dst)) - return (1); - p2->por_dst_tbl = p1->por_dst_tbl; - if (p1->por_dst_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - TAILQ_REMOVE(&block->sb_rules, p2, - por_entry); - free(p2); - } - } else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL - && p2->por_src_tbl == NULL && - p2->por_dst_tbl == NULL && - rules_combineable(&p1->por_rule, &p2->por_rule) && - addrs_combineable(&p1->por_rule.src, - &p2->por_rule.src)) { - DEBUG("can combine rules nr%d = nr%d", - p1->por_rule.nr, p2->por_rule.nr); - if (p1->por_src_tbl == NULL && - add_opt_table(pf, &p1->por_src_tbl, - p1->por_rule.af, &p1->por_rule.src)) - return (1); - if (add_opt_table(pf, &p1->por_src_tbl, - p1->por_rule.af, &p2->por_rule.src)) - return (1); - p2->por_src_tbl = p1->por_src_tbl; - if (p1->por_src_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - TAILQ_REMOVE(&block->sb_rules, p2, - por_entry); - free(p2); - } - } - } - } - - - /* - * Then we make a final pass to create a valid table name and - * insert the name into the rules. - */ - for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) { - por_next = TAILQ_NEXT(p1, por_entry); - assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL); - - if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - if (p1->por_src_tbl->pt_generated) { - /* This rule is included in a table */ - TAILQ_REMOVE(&block->sb_rules, p1, por_entry); - free(p1); - continue; - } - p1->por_src_tbl->pt_generated = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0 && - pf_opt_create_table(pf, p1->por_src_tbl)) - return (1); - - pf->tdirty = 1; - - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(p1->por_src_tbl->pt_name, - PFR_TFLAG_CONST, 1, - &p1->por_src_tbl->pt_nodes); - - memset(&p1->por_rule.src.addr, 0, - sizeof(p1->por_rule.src.addr)); - p1->por_rule.src.addr.type = PF_ADDR_TABLE; - strlcpy(p1->por_rule.src.addr.v.tblname, - p1->por_src_tbl->pt_name, - sizeof(p1->por_rule.src.addr.v.tblname)); - - pfr_buf_clear(p1->por_src_tbl->pt_buf); - free(p1->por_src_tbl->pt_buf); - p1->por_src_tbl->pt_buf = NULL; - } - if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - if (p1->por_dst_tbl->pt_generated) { - /* This rule is included in a table */ - TAILQ_REMOVE(&block->sb_rules, p1, por_entry); - free(p1); - continue; - } - p1->por_dst_tbl->pt_generated = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0 && - pf_opt_create_table(pf, p1->por_dst_tbl)) - return (1); - pf->tdirty = 1; - - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(p1->por_dst_tbl->pt_name, - PFR_TFLAG_CONST, 1, - &p1->por_dst_tbl->pt_nodes); - - memset(&p1->por_rule.dst.addr, 0, - sizeof(p1->por_rule.dst.addr)); - p1->por_rule.dst.addr.type = PF_ADDR_TABLE; - strlcpy(p1->por_rule.dst.addr.v.tblname, - p1->por_dst_tbl->pt_name, - sizeof(p1->por_rule.dst.addr.v.tblname)); - - pfr_buf_clear(p1->por_dst_tbl->pt_buf); - free(p1->por_dst_tbl->pt_buf); - p1->por_dst_tbl->pt_buf = NULL; - } - } - - return (0); -} - - -/* - * Optimization pass #3: re-order rules to improve skip steps - */ -int -reorder_rules(struct pfctl *pf, struct superblock *block, int depth) -{ - struct superblock *newblock; - struct pf_skip_step *skiplist; - struct pf_opt_rule *por; - int i, largest, largest_list, rule_count = 0; - TAILQ_HEAD( , pf_opt_rule) head; - - /* - * Calculate the best-case skip steps. We put each rule in a list - * of other rules with common fields - */ - for (i = 0; i < PF_SKIP_COUNT; i++) { - TAILQ_FOREACH(por, &block->sb_rules, por_entry) { - TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i], - ps_entry) { - if (skip_compare(i, skiplist, por) == 0) - break; - } - if (skiplist == NULL) { - if ((skiplist = calloc(1, sizeof(*skiplist))) == - NULL) - err(1, "calloc"); - TAILQ_INIT(&skiplist->ps_rules); - TAILQ_INSERT_TAIL(&block->sb_skipsteps[i], - skiplist, ps_entry); - } - skip_append(block, i, skiplist, por); - } - } - - TAILQ_FOREACH(por, &block->sb_rules, por_entry) - rule_count++; - - /* - * Now we're going to ignore any fields that are identical between - * all of the rules in the superblock and those fields which differ - * between every rule in the superblock. - */ - largest = 0; - for (i = 0; i < PF_SKIP_COUNT; i++) { - skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (skiplist->ps_count == rule_count) { - DEBUG("(%d) original skipstep '%s' is all rules", - depth, skip_comparitors_names[i]); - skiplist->ps_count = 0; - } else if (skiplist->ps_count == 1) { - skiplist->ps_count = 0; - } else { - DEBUG("(%d) original skipstep '%s' largest jump is %d", - depth, skip_comparitors_names[i], - skiplist->ps_count); - if (skiplist->ps_count > largest) - largest = skiplist->ps_count; - } - } - if (largest == 0) { - /* Ugh. There is NO commonality in the superblock on which - * optimize the skipsteps optimization. - */ - goto done; - } - - /* - * Now we're going to empty the superblock rule list and re-create - * it based on a more optimal skipstep order. - */ - TAILQ_INIT(&head); - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - TAILQ_INSERT_TAIL(&head, por, por_entry); - } - - - while (!TAILQ_EMPTY(&head)) { - largest = 1; - - /* - * Find the most useful skip steps remaining - */ - for (i = 0; i < PF_SKIP_COUNT; i++) { - skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (skiplist->ps_count > largest) { - largest = skiplist->ps_count; - largest_list = i; - } - } - - if (largest <= 1) { - /* - * Nothing useful left. Leave remaining rules in order. - */ - DEBUG("(%d) no more commonality for skip steps", depth); - while ((por = TAILQ_FIRST(&head))) { - TAILQ_REMOVE(&head, por, por_entry); - TAILQ_INSERT_TAIL(&block->sb_rules, por, - por_entry); - } - } else { - /* - * There is commonality. Extract those common rules - * and place them in the ruleset adjacent to each - * other. - */ - skiplist = TAILQ_FIRST(&block->sb_skipsteps[ - largest_list]); - DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d", - depth, skip_comparitors_names[largest_list], - largest, TAILQ_FIRST(&TAILQ_FIRST(&block-> - sb_skipsteps [largest_list])->ps_rules)-> - por_rule.nr); - TAILQ_REMOVE(&block->sb_skipsteps[largest_list], - skiplist, ps_entry); - - - /* - * There may be further commonality inside these - * rules. So we'll split them off into they're own - * superblock and pass it back into the optimizer. - */ - if (skiplist->ps_count > 2) { - if ((newblock = calloc(1, sizeof(*newblock))) - == NULL) { - warn("calloc"); - return (1); - } - TAILQ_INIT(&newblock->sb_rules); - for (i = 0; i < PF_SKIP_COUNT; i++) - TAILQ_INIT(&newblock->sb_skipsteps[i]); - TAILQ_INSERT_BEFORE(block, newblock, sb_entry); - DEBUG("(%d) splitting off %d rules from superblock @ #%d", - depth, skiplist->ps_count, - TAILQ_FIRST(&skiplist->ps_rules)-> - por_rule.nr); - } else { - newblock = block; - } - - while ((por = TAILQ_FIRST(&skiplist->ps_rules))) { - TAILQ_REMOVE(&head, por, por_entry); - TAILQ_REMOVE(&skiplist->ps_rules, por, - por_skip_entry[largest_list]); - TAILQ_INSERT_TAIL(&newblock->sb_rules, por, - por_entry); - - /* Remove this rule from all other skiplists */ - remove_from_skipsteps(&block->sb_skipsteps[ - largest_list], block, por, skiplist); - } - free(skiplist); - if (newblock != block) - if (reorder_rules(pf, newblock, depth + 1)) - return (1); - } - } - -done: - for (i = 0; i < PF_SKIP_COUNT; i++) { - while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) { - TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist, - ps_entry); - free(skiplist); - } - } - - return (0); -} - - -/* - * Optimization pass #4: re-order 'quick' rules based on feedback from the - * currently running ruleset - */ -int -block_feedback(struct pfctl *pf, struct superblock *block) -{ - TAILQ_HEAD( , pf_opt_rule) queue; - struct pf_opt_rule *por1, *por2; - u_int64_t total_count = 0; - struct pf_rule a, b; - - - /* - * Walk through all of the profiled superblock's rules and copy - * the counters onto our rules. - */ - TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) { - comparable_rule(&a, &por1->por_rule, DC); - total_count += por1->por_rule.packets[0] + - por1->por_rule.packets[1]; - TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { - if (por2->por_profile_count) - continue; - comparable_rule(&b, &por2->por_rule, DC); - if (memcmp(&a, &b, sizeof(a)) == 0) { - por2->por_profile_count = - por1->por_rule.packets[0] + - por1->por_rule.packets[1]; - break; - } - } - } - superblock_free(pf, block->sb_profiled_block); - block->sb_profiled_block = NULL; - - /* - * Now we pull all of the rules off the superblock and re-insert them - * in sorted order. - */ - - TAILQ_INIT(&queue); - while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) { - TAILQ_REMOVE(&block->sb_rules, por1, por_entry); - TAILQ_INSERT_TAIL(&queue, por1, por_entry); - } - - while ((por1 = TAILQ_FIRST(&queue)) != NULL) { - TAILQ_REMOVE(&queue, por1, por_entry); -/* XXX I should sort all of the unused rules based on skip steps */ - TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { - if (por1->por_profile_count > por2->por_profile_count) { - TAILQ_INSERT_BEFORE(por2, por1, por_entry); - break; - } - } -#ifdef __FreeBSD__ - if (por2 == NULL) -#else - if (por2 == TAILQ_END(&block->sb_rules)) -#endif - TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry); - } - - return (0); -} - - -/* - * Load the current ruleset from the kernel and try to associate them with - * the ruleset we're optimizing. - */ -int -load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) -{ - struct superblock *block, *blockcur; - struct superblocks prof_superblocks; - struct pf_opt_rule *por; - struct pf_opt_queue queue; - struct pfioc_rule pr; - struct pf_rule a, b; - int nr, mnr; - - TAILQ_INIT(&queue); - TAILQ_INIT(&prof_superblocks); - - memset(&pr, 0, sizeof(pr)); - pr.rule.action = PF_PASS; - if (ioctl(pf->dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - return (1); - } - mnr = pr.nr; - - DEBUG("Loading %d active rules for a feedback profile", mnr); - for (nr = 0; nr < mnr; ++nr) { - struct pf_ruleset *rs; - if ((por = calloc(1, sizeof(*por))) == NULL) { - warn("calloc"); - return (1); - } - pr.nr = nr; - if (ioctl(pf->dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULES"); - return (1); - } - memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule)); - rs = pf_find_or_create_ruleset(pr.anchor_call); - por->por_rule.anchor = rs->anchor; - if (TAILQ_EMPTY(&por->por_rule.rpool.list)) - memset(&por->por_rule.rpool, 0, - sizeof(por->por_rule.rpool)); - TAILQ_INSERT_TAIL(&queue, por, por_entry); - - /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket, - * PF_PASS, pf->anchor) ??? - * ... pfctl_clear_pool(&pr.rule.rpool) - */ - } - - if (construct_superblocks(pf, &queue, &prof_superblocks)) - return (1); - - - /* - * Now we try to associate the active ruleset's superblocks with - * the superblocks we're compiling. - */ - block = TAILQ_FIRST(superblocks); - blockcur = TAILQ_FIRST(&prof_superblocks); - while (block && blockcur) { - comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, - BREAK); - comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule, - BREAK); - if (memcmp(&a, &b, sizeof(a)) == 0) { - /* The two superblocks lined up */ - block->sb_profiled_block = blockcur; - } else { - DEBUG("superblocks don't line up between #%d and #%d", - TAILQ_FIRST(&block->sb_rules)->por_rule.nr, - TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr); - break; - } - block = TAILQ_NEXT(block, sb_entry); - blockcur = TAILQ_NEXT(blockcur, sb_entry); - } - - - - /* Free any superblocks we couldn't link */ - while (blockcur) { - block = TAILQ_NEXT(blockcur, sb_entry); - superblock_free(pf, blockcur); - blockcur = block; - } - return (0); -} - - -/* - * Compare a rule to a skiplist to see if the rule is a member - */ -int -skip_compare(int skipnum, struct pf_skip_step *skiplist, - struct pf_opt_rule *por) -{ - struct pf_rule *a, *b; - if (skipnum >= PF_SKIP_COUNT || skipnum < 0) - errx(1, "skip_compare() out of bounds"); - a = &por->por_rule; - b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule; - - return ((skip_comparitors[skipnum])(a, b)); -} - - -/* - * Add a rule to a skiplist - */ -void -skip_append(struct superblock *superblock, int skipnum, - struct pf_skip_step *skiplist, struct pf_opt_rule *por) -{ - struct pf_skip_step *prev; - - skiplist->ps_count++; - TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]); - - /* Keep the list of skiplists sorted by whichever is larger */ - while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) && - prev->ps_count < skiplist->ps_count) { - TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum], - skiplist, ps_entry); - TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry); - } -} - - -/* - * Remove a rule from the other skiplist calculations. - */ -void -remove_from_skipsteps(struct skiplist *head, struct superblock *block, - struct pf_opt_rule *por, struct pf_skip_step *active_list) -{ - struct pf_skip_step *sk, *next; - struct pf_opt_rule *p2; - int i, found; - - for (i = 0; i < PF_SKIP_COUNT; i++) { - sk = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (sk == NULL || sk == active_list || sk->ps_count <= 1) - continue; - found = 0; - do { - TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i]) - if (p2 == por) { - TAILQ_REMOVE(&sk->ps_rules, p2, - por_skip_entry[i]); - found = 1; - sk->ps_count--; - break; - } - } while (!found && (sk = TAILQ_NEXT(sk, ps_entry))); - if (found && sk) { - /* Does this change the sorting order? */ - while ((next = TAILQ_NEXT(sk, ps_entry)) && - next->ps_count > sk->ps_count) { - TAILQ_REMOVE(head, sk, ps_entry); - TAILQ_INSERT_AFTER(head, next, sk, ps_entry); - } -#ifdef OPT_DEBUG - next = TAILQ_NEXT(sk, ps_entry); - assert(next == NULL || next->ps_count <= sk->ps_count); -#endif /* OPT_DEBUG */ - } - } -} - - -/* Compare two rules AF field for skiplist construction */ -int -skip_cmp_af(struct pf_rule *a, struct pf_rule *b) -{ - if (a->af != b->af || a->af == 0) - return (1); - return (0); -} - -/* Compare two rules DIRECTION field for skiplist construction */ -int -skip_cmp_dir(struct pf_rule *a, struct pf_rule *b) -{ - if (a->direction == 0 || a->direction != b->direction) - return (1); - return (0); -} - -/* Compare two rules DST Address field for skiplist construction */ -int -skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b) -{ - if (a->dst.neg != b->dst.neg || - a->dst.addr.type != b->dst.addr.type) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - switch (a->dst.addr.type) { - case PF_ADDR_ADDRMASK: - if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr, - sizeof(a->dst.addr.v.a.addr)) || - memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, - sizeof(a->dst.addr.v.a.mask)) || - (a->dst.addr.v.a.addr.addr32[0] == 0 && - a->dst.addr.v.a.addr.addr32[1] == 0 && - a->dst.addr.v.a.addr.addr32[2] == 0 && - a->dst.addr.v.a.addr.addr32[3] == 0)) - return (1); - return (0); - case PF_ADDR_DYNIFTL: - if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 || - a->dst.addr.iflags != a->dst.addr.iflags || - memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, - sizeof(a->dst.addr.v.a.mask))) - return (1); - return (0); - case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: - return (0); - case PF_ADDR_TABLE: - return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname)); - } - return (1); -} - -/* Compare two rules DST port field for skiplist construction */ -int -skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b) -{ - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op || - a->dst.port[0] != b->dst.port[0] || - a->dst.port[1] != b->dst.port[1]) - return (1); - return (0); -} - -/* Compare two rules IFP field for skiplist construction */ -int -skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b) -{ - if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0') - return (1); - return (a->ifnot != b->ifnot); -} - -/* Compare two rules PROTO field for skiplist construction */ -int -skip_cmp_proto(struct pf_rule *a, struct pf_rule *b) -{ - return (a->proto != b->proto || a->proto == 0); -} - -/* Compare two rules SRC addr field for skiplist construction */ -int -skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b) -{ - if (a->src.neg != b->src.neg || - a->src.addr.type != b->src.addr.type) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - switch (a->src.addr.type) { - case PF_ADDR_ADDRMASK: - if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr, - sizeof(a->src.addr.v.a.addr)) || - memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, - sizeof(a->src.addr.v.a.mask)) || - (a->src.addr.v.a.addr.addr32[0] == 0 && - a->src.addr.v.a.addr.addr32[1] == 0 && - a->src.addr.v.a.addr.addr32[2] == 0 && - a->src.addr.v.a.addr.addr32[3] == 0)) - return (1); - return (0); - case PF_ADDR_DYNIFTL: - if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 || - a->src.addr.iflags != a->src.addr.iflags || - memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, - sizeof(a->src.addr.v.a.mask))) - return (1); - return (0); - case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: - return (0); - case PF_ADDR_TABLE: - return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname)); - } - return (1); -} - -/* Compare two rules SRC port field for skiplist construction */ -int -skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b) -{ - if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op || - a->src.port[0] != b->src.port[0] || - a->src.port[1] != b->src.port[1]) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - return (0); -} - - -void -skip_init(void) -{ - struct { - char *name; - int skipnum; - int (*func)(struct pf_rule *, struct pf_rule *); - } comps[] = PF_SKIP_COMPARITORS; - int skipnum, i; - - for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) { - for (i = 0; i < sizeof(comps)/sizeof(*comps); i++) - if (comps[i].skipnum == skipnum) { - skip_comparitors[skipnum] = comps[i].func; - skip_comparitors_names[skipnum] = comps[i].name; - } - } - for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) - if (skip_comparitors[skipnum] == NULL) - errx(1, "Need to add skip step comparitor to pfctl?!"); -} - -/* - * Add a host/netmask to a table - */ -int -add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af, - struct pf_rule_addr *addr) -{ -#ifdef OPT_DEBUG - char buf[128]; -#endif /* OPT_DEBUG */ -#ifndef __rtems__ - static int tablenum = 0; -#endif /* __rtems__ */ - struct node_host node_host; - - if (*tbl == NULL) { - if ((*tbl = calloc(1, sizeof(**tbl))) == NULL || - ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) == - NULL) - err(1, "calloc"); - (*tbl)->pt_buf->pfrb_type = PFRB_ADDRS; - SIMPLEQ_INIT(&(*tbl)->pt_nodes); - - /* This is just a temporary table name */ - snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d", -#ifndef __rtems__ - PF_OPT_TABLE_PREFIX, tablenum++); -#else /* __rtems__ */ - PF_OPT_TABLE_PREFIX, add_opt_table_num++); -#endif /* __rtems__ */ - DEBUG("creating table <%s>", (*tbl)->pt_name); - } - - memset(&node_host, 0, sizeof(node_host)); - node_host.af = af; - node_host.addr = addr->addr; - -#ifdef OPT_DEBUG - DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af, - &node_host.addr.v.a.addr, buf, sizeof(buf)), - unmask(&node_host.addr.v.a.mask, af)); -#endif /* OPT_DEBUG */ - - if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) { - warn("failed to add host"); - return (1); - } - if (pf->opts & PF_OPT_VERBOSE) { - struct node_tinit *ti; - - if ((ti = calloc(1, sizeof(*ti))) == NULL) - err(1, "malloc"); - if ((ti->host = malloc(sizeof(*ti->host))) == NULL) - err(1, "malloc"); - memcpy(ti->host, &node_host, sizeof(*ti->host)); - SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries); - } - - (*tbl)->pt_rulecount++; - if ((*tbl)->pt_rulecount == TABLE_THRESHOLD) - DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name); - - return (0); -} - -/* - * Do the dirty work of choosing an unused table name and creating it. - * (be careful with the table name, it might already be used in another anchor) - */ -int -pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl) -{ -#ifndef __rtems__ - static int tablenum; -#endif /* __rtems__ */ - struct pfr_table *t; - - if (table_buffer.pfrb_type == 0) { - /* Initialize the list of tables */ - table_buffer.pfrb_type = PFRB_TABLES; - for (;;) { - pfr_buf_grow(&table_buffer, table_buffer.pfrb_size); - table_buffer.pfrb_size = table_buffer.pfrb_msize; - if (pfr_get_tables(NULL, table_buffer.pfrb_caddr, - &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS)) - err(1, "pfr_get_tables"); - if (table_buffer.pfrb_size <= table_buffer.pfrb_msize) - break; - } - table_identifier = arc4random(); - } - - /* XXX would be *really* nice to avoid duplicating identical tables */ - - /* Now we have to pick a table name that isn't used */ -again: - DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name, -#ifndef __rtems__ - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); -#else /* __rtems__ */ - PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_table_num); -#endif /* __rtems__ */ - snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d", -#ifndef __rtems__ - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); -#else /* __rtems__ */ - PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_table_num); -#endif /* __rtems__ */ - PFRB_FOREACH(t, &table_buffer) { - if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) { - /* Collision. Try again */ - DEBUG("wow, table <%s> in use. trying again", - tbl->pt_name); - table_identifier = arc4random(); - goto again; - } - } -#ifndef __rtems__ - tablenum++; -#else /* __rtems__ */ - pf_opt_create_table_num++; -#endif /* __rtems__ */ - - - if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, - pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) { - warn("failed to create table %s in %s", - tbl->pt_name, pf->astack[0]->name); - return (1); - } - return (0); -} - -/* - * Partition the flat ruleset into a list of distinct superblocks - */ -int -construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue, - struct superblocks *superblocks) -{ - struct superblock *block = NULL; - struct pf_opt_rule *por; - int i; - - while (!TAILQ_EMPTY(opt_queue)) { - por = TAILQ_FIRST(opt_queue); - TAILQ_REMOVE(opt_queue, por, por_entry); - if (block == NULL || !superblock_inclusive(block, por)) { - if ((block = calloc(1, sizeof(*block))) == NULL) { - warn("calloc"); - return (1); - } - TAILQ_INIT(&block->sb_rules); - for (i = 0; i < PF_SKIP_COUNT; i++) - TAILQ_INIT(&block->sb_skipsteps[i]); - TAILQ_INSERT_TAIL(superblocks, block, sb_entry); - } - TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry); - } - - return (0); -} - - -/* - * Compare two rule addresses - */ -int -addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b) -{ - if (a->neg != b->neg) - return (0); - return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0); -} - - -/* - * The addresses are not equal, but can we combine them into one table? - */ -int -addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b) -{ - if (a->addr.type != PF_ADDR_ADDRMASK || - b->addr.type != PF_ADDR_ADDRMASK) - return (0); - if (a->neg != b->neg || a->port_op != b->port_op || - a->port[0] != b->port[0] || a->port[1] != b->port[1]) - return (0); - return (1); -} - - -/* - * Are we allowed to combine these two rules - */ -int -rules_combineable(struct pf_rule *p1, struct pf_rule *p2) -{ - struct pf_rule a, b; - - comparable_rule(&a, p1, COMBINED); - comparable_rule(&b, p2, COMBINED); - return (memcmp(&a, &b, sizeof(a)) == 0); -} - - -/* - * Can a rule be included inside a superblock - */ -int -superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) -{ - struct pf_rule a, b; - int i, j; - - /* First check for hard breaks */ - for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) { - if (pf_rule_desc[i].prf_type == BARRIER) { - for (j = 0; j < pf_rule_desc[i].prf_size; j++) - if (((char *)&por->por_rule)[j + - pf_rule_desc[i].prf_offset] != 0) - return (0); - } - } - - /* per-rule src-track is also a hard break */ - if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK) - return (0); - - /* - * Have to handle interface groups separately. Consider the following - * rules: - * block on EXTIFS to any port 22 - * pass on em0 to any port 22 - * (where EXTIFS is an arbitrary interface group) - * The optimizer may decide to re-order the pass rule in front of the - * block rule. But what if EXTIFS includes em0??? Such a reordering - * would change the meaning of the ruleset. - * We can't just lookup the EXTIFS group and check if em0 is a member - * because the user is allowed to add interfaces to a group during - * runtime. - * Ergo interface groups become a defacto superblock break :-( - */ - if (interface_group(por->por_rule.ifname) || - interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) { - if (strcasecmp(por->por_rule.ifname, - TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0) - return (0); - } - - comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE); - comparable_rule(&b, &por->por_rule, NOMERGE); - if (memcmp(&a, &b, sizeof(a)) == 0) - return (1); - -#ifdef OPT_DEBUG - for (i = 0; i < sizeof(por->por_rule); i++) { - int closest = -1; - if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) { - for (j = 0; j < sizeof(pf_rule_desc) / - sizeof(*pf_rule_desc); j++) { - if (i >= pf_rule_desc[j].prf_offset && - i < pf_rule_desc[j].prf_offset + - pf_rule_desc[j].prf_size) { - DEBUG("superblock break @ %d due to %s", - por->por_rule.nr, - pf_rule_desc[j].prf_name); - return (0); - } - if (i > pf_rule_desc[j].prf_offset) { - if (closest == -1 || - i-pf_rule_desc[j].prf_offset < - i-pf_rule_desc[closest].prf_offset) - closest = j; - } - } - - if (closest >= 0) - DEBUG("superblock break @ %d on %s+%xh", - por->por_rule.nr, - pf_rule_desc[closest].prf_name, - i - pf_rule_desc[closest].prf_offset - - pf_rule_desc[closest].prf_size); - else - DEBUG("superblock break @ %d on field @ %d", - por->por_rule.nr, i); - return (0); - } - } -#endif /* OPT_DEBUG */ - - return (0); -} - - -/* - * Figure out if an interface name is an actual interface or actually a - * group of interfaces. - */ -int -interface_group(const char *ifname) -{ - if (ifname == NULL || !ifname[0]) - return (0); - - /* Real interfaces must end in a number, interface groups do not */ - if (isdigit(ifname[strlen(ifname) - 1])) - return (0); - else - return (1); -} - - -/* - * Make a rule that can directly compared by memcmp() - */ -void -comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type) -{ - int i; - /* - * To simplify the comparison, we just zero out the fields that are - * allowed to be different and then do a simple memcmp() - */ - memcpy(dst, src, sizeof(*dst)); - for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) - if (pf_rule_desc[i].prf_type >= type) { -#ifdef OPT_DEBUG - assert(pf_rule_desc[i].prf_type != NEVER || - *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0); -#endif /* OPT_DEBUG */ - memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0, - pf_rule_desc[i].prf_size); - } -} - - -/* - * Remove superset information from two rules so we can directly compare them - * with memcmp() - */ -void -exclude_supersets(struct pf_rule *super, struct pf_rule *sub) -{ - if (super->ifname[0] == '\0') - memset(sub->ifname, 0, sizeof(sub->ifname)); - if (super->direction == PF_INOUT) - sub->direction = PF_INOUT; - if ((super->proto == 0 || super->proto == sub->proto) && - super->flags == 0 && super->flagset == 0 && (sub->flags || - sub->flagset)) { - sub->flags = super->flags; - sub->flagset = super->flagset; - } - if (super->proto == 0) - sub->proto = 0; - - if (super->src.port_op == 0) { - sub->src.port_op = 0; - sub->src.port[0] = 0; - sub->src.port[1] = 0; - } - if (super->dst.port_op == 0) { - sub->dst.port_op = 0; - sub->dst.port[0] = 0; - sub->dst.port[1] = 0; - } - - if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg && - !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 && - super->src.addr.v.a.mask.addr32[1] == 0 && - super->src.addr.v.a.mask.addr32[2] == 0 && - super->src.addr.v.a.mask.addr32[3] == 0) - memset(&sub->src.addr, 0, sizeof(sub->src.addr)); - else if (super->src.addr.type == PF_ADDR_ADDRMASK && - sub->src.addr.type == PF_ADDR_ADDRMASK && - super->src.neg == sub->src.neg && - super->af == sub->af && - unmask(&super->src.addr.v.a.mask, super->af) < - unmask(&sub->src.addr.v.a.mask, sub->af) && - super->src.addr.v.a.addr.addr32[0] == - (sub->src.addr.v.a.addr.addr32[0] & - super->src.addr.v.a.mask.addr32[0]) && - super->src.addr.v.a.addr.addr32[1] == - (sub->src.addr.v.a.addr.addr32[1] & - super->src.addr.v.a.mask.addr32[1]) && - super->src.addr.v.a.addr.addr32[2] == - (sub->src.addr.v.a.addr.addr32[2] & - super->src.addr.v.a.mask.addr32[2]) && - super->src.addr.v.a.addr.addr32[3] == - (sub->src.addr.v.a.addr.addr32[3] & - super->src.addr.v.a.mask.addr32[3])) { - /* sub->src.addr is a subset of super->src.addr/mask */ - memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr)); - } - - if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg && - !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 && - super->dst.addr.v.a.mask.addr32[1] == 0 && - super->dst.addr.v.a.mask.addr32[2] == 0 && - super->dst.addr.v.a.mask.addr32[3] == 0) - memset(&sub->dst.addr, 0, sizeof(sub->dst.addr)); - else if (super->dst.addr.type == PF_ADDR_ADDRMASK && - sub->dst.addr.type == PF_ADDR_ADDRMASK && - super->dst.neg == sub->dst.neg && - super->af == sub->af && - unmask(&super->dst.addr.v.a.mask, super->af) < - unmask(&sub->dst.addr.v.a.mask, sub->af) && - super->dst.addr.v.a.addr.addr32[0] == - (sub->dst.addr.v.a.addr.addr32[0] & - super->dst.addr.v.a.mask.addr32[0]) && - super->dst.addr.v.a.addr.addr32[1] == - (sub->dst.addr.v.a.addr.addr32[1] & - super->dst.addr.v.a.mask.addr32[1]) && - super->dst.addr.v.a.addr.addr32[2] == - (sub->dst.addr.v.a.addr.addr32[2] & - super->dst.addr.v.a.mask.addr32[2]) && - super->dst.addr.v.a.addr.addr32[3] == - (sub->dst.addr.v.a.addr.addr32[3] & - super->dst.addr.v.a.mask.addr32[3])) { - /* sub->dst.addr is a subset of super->dst.addr/mask */ - memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr)); - } - - if (super->af == 0) - sub->af = 0; -} - - -void -superblock_free(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *por; - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - if (por->por_src_tbl) { - if (por->por_src_tbl->pt_buf) { - pfr_buf_clear(por->por_src_tbl->pt_buf); - free(por->por_src_tbl->pt_buf); - } - free(por->por_src_tbl); - } - if (por->por_dst_tbl) { - if (por->por_dst_tbl->pt_buf) { - pfr_buf_clear(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl->pt_buf); - } - free(por->por_dst_tbl); - } - free(por); - } - if (block->sb_profiled_block) - superblock_free(pf, block->sb_profiled_block); - free(block); -} -#ifdef __rtems__ -#include "pfctl_optimize-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_osfp-data.h b/freebsd/contrib/pf/pfctl/pfctl_osfp-data.h deleted file mode 100644 index 1ac0ee31..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_osfp-data.h +++ /dev/null @@ -1,7 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int class_count); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct name_list classes); -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int fingerprint_count); -/* There is also one static buffer called "buf". But this can be ignored. See - * comment in source file. */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_osfp.c b/freebsd/contrib/pf/pfctl/pfctl_osfp.c deleted file mode 100644 index cc9d86e8..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_osfp.c +++ /dev/null @@ -1,1133 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ - -/* - * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -#ifndef MIN -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif /* MIN */ -#ifndef MAX -# define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif /* MAX */ - - -#if 0 -# define DEBUG(fp, str, v...) \ - fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \ - (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v); -#else -# define DEBUG(fp, str, v...) ((void)0) -#endif - - -struct name_entry; -LIST_HEAD(name_list, name_entry); -struct name_entry { - LIST_ENTRY(name_entry) nm_entry; - int nm_num; - char nm_name[PF_OSFP_LEN]; - - struct name_list nm_sublist; - int nm_sublist_num; -}; -#ifndef __rtems__ -struct name_list classes = LIST_HEAD_INITIALIZER(&classes); -int class_count; -int fingerprint_count; -#else /* __rtems__ */ -static struct name_list classes = LIST_HEAD_INITIALIZER(&classes); -static int class_count; -static int fingerprint_count; -#endif /* __rtems__ */ - -void add_fingerprint(int, int, struct pf_osfp_ioctl *); -struct name_entry *fingerprint_name_entry(struct name_list *, char *); -void pfctl_flush_my_fingerprints(struct name_list *); -char *get_field(char **, size_t *, int *); -int get_int(char **, size_t *, int *, int *, const char *, - int, int, const char *, int); -int get_str(char **, size_t *, char **, const char *, int, - const char *, int); -int get_tcpopts(const char *, int, const char *, - pf_tcpopts_t *, int *, int *, int *, int *, int *, - int *); -void import_fingerprint(struct pf_osfp_ioctl *); -const char *print_ioctl(struct pf_osfp_ioctl *); -void print_name_list(int, struct name_list *, const char *); -void sort_name_list(int, struct name_list *); -struct name_entry *lookup_name_list(struct name_list *, const char *); - -/* Load fingerprints from a file */ -int -pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) -{ - FILE *in; - char *line; - size_t len; - int i, lineno = 0; - int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale, - wscale_mod, optcnt, ts0; - pf_tcpopts_t packed_tcpopts; - char *class, *version, *subtype, *desc, *tcpopts; - struct pf_osfp_ioctl fp; - - pfctl_flush_my_fingerprints(&classes); - - if ((in = pfctl_fopen(fp_filename, "r")) == NULL) { - warn("%s", fp_filename); - return (1); - } - class = version = subtype = desc = tcpopts = NULL; - - if ((opts & PF_OPT_NOACTION) == 0) - pfctl_clear_fingerprints(dev, opts); - - while ((line = fgetln(in, &len)) != NULL) { - lineno++; - if (class) - free(class); - if (version) - free(version); - if (subtype) - free(subtype); - if (desc) - free(desc); - if (tcpopts) - free(tcpopts); - class = version = subtype = desc = tcpopts = NULL; - memset(&fp, 0, sizeof(fp)); - - /* Chop off comment */ - for (i = 0; i < len; i++) - if (line[i] == '#') { - len = i; - break; - } - /* Chop off whitespace */ - while (len > 0 && isspace(line[len - 1])) - len--; - while (len > 0 && isspace(line[0])) { - len--; - line++; - } - if (len == 0) - continue; - -#define T_DC 0x01 /* Allow don't care */ -#define T_MSS 0x02 /* Allow MSS multiple */ -#define T_MTU 0x04 /* Allow MTU multiple */ -#define T_MOD 0x08 /* Allow modulus */ - -#define GET_INT(v, mod, n, ty, mx) \ - get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno) -#define GET_STR(v, n, mn) \ - get_str(&line, &len, &v, n, mn, fp_filename, lineno) - - if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU| - T_MOD, 0xffff) || - GET_INT(ttl, NULL, "ttl", 0, 0xff) || - GET_INT(df, NULL, "don't fragment frag", 0, 1) || - GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC, - 8192) || - GET_STR(tcpopts, "TCP Options", 1) || - GET_STR(class, "OS class", 1) || - GET_STR(version, "OS version", 0) || - GET_STR(subtype, "OS subtype", 0) || - GET_STR(desc, "OS description", 2)) - continue; - if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts, - &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0)) - continue; - if (len != 0) { - fprintf(stderr, "%s:%d excess field\n", fp_filename, - lineno); - continue; - } - - fp.fp_ttl = ttl; - if (df) - fp.fp_flags |= PF_OSFP_DF; - switch (w_mod) { - case 0: - break; - case T_DC: - fp.fp_flags |= PF_OSFP_WSIZE_DC; - break; - case T_MSS: - fp.fp_flags |= PF_OSFP_WSIZE_MSS; - break; - case T_MTU: - fp.fp_flags |= PF_OSFP_WSIZE_MTU; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_WSIZE_MOD; - break; - } - fp.fp_wsize = window; - - switch (p_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_PSIZE_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_PSIZE_MOD; - } - fp.fp_psize = psize; - - - switch (wscale_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_WSCALE_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_WSCALE_MOD; - } - fp.fp_wscale = wscale; - - switch (mss_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_MSS_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_MSS_MOD; - break; - } - fp.fp_mss = mss; - - fp.fp_tcpopts = packed_tcpopts; - fp.fp_optcnt = optcnt; - if (ts0) - fp.fp_flags |= PF_OSFP_TS0; - - if (class[0] == '@') - fp.fp_os.fp_enflags |= PF_OSFP_GENERIC; - if (class[0] == '*') - fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL; - - if (class[0] == '@' || class[0] == '*') - strlcpy(fp.fp_os.fp_class_nm, class + 1, - sizeof(fp.fp_os.fp_class_nm)); - else - strlcpy(fp.fp_os.fp_class_nm, class, - sizeof(fp.fp_os.fp_class_nm)); - strlcpy(fp.fp_os.fp_version_nm, version, - sizeof(fp.fp_os.fp_version_nm)); - strlcpy(fp.fp_os.fp_subtype_nm, subtype, - sizeof(fp.fp_os.fp_subtype_nm)); - - add_fingerprint(dev, opts, &fp); - - fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6); - fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip); - add_fingerprint(dev, opts, &fp); - } - - if (class) - free(class); - if (version) - free(version); - if (subtype) - free(subtype); - if (desc) - free(desc); - if (tcpopts) - free(tcpopts); - - fclose(in); - - if (opts & PF_OPT_VERBOSE2) - printf("Loaded %d passive OS fingerprints\n", - fingerprint_count); - return (0); -} - -/* flush the kernel's fingerprints */ -void -pfctl_clear_fingerprints(int dev, int opts) -{ - if (ioctl(dev, DIOCOSFPFLUSH)) - err(1, "DIOCOSFPFLUSH"); -} - -/* flush pfctl's view of the fingerprints */ -void -pfctl_flush_my_fingerprints(struct name_list *list) -{ - struct name_entry *nm; - - while ((nm = LIST_FIRST(list)) != NULL) { - LIST_REMOVE(nm, nm_entry); - pfctl_flush_my_fingerprints(&nm->nm_sublist); - free(nm); - } - fingerprint_count = 0; - class_count = 0; -} - -/* Fetch the active fingerprints from the kernel */ -int -pfctl_load_fingerprints(int dev, int opts) -{ - struct pf_osfp_ioctl io; - int i; - - pfctl_flush_my_fingerprints(&classes); - - for (i = 0; i >= 0; i++) { - memset(&io, 0, sizeof(io)); - io.fp_getnum = i; - if (ioctl(dev, DIOCOSFPGET, &io)) { - if (errno == EBUSY) - break; - warn("DIOCOSFPGET"); - return (1); - } - import_fingerprint(&io); - } - return (0); -} - -/* List the fingerprints */ -void -pfctl_show_fingerprints(int opts) -{ - if (LIST_FIRST(&classes) != NULL) { - if (opts & PF_OPT_SHOWALL) { - pfctl_print_title("OS FINGERPRINTS:"); - printf("%u fingerprints loaded\n", fingerprint_count); - } else { - printf("Class\tVersion\tSubtype(subversion)\n"); - printf("-----\t-------\t-------------------\n"); - sort_name_list(opts, &classes); - print_name_list(opts, &classes, ""); - } - } -} - -/* Lookup a fingerprint */ -pf_osfp_t -pfctl_get_fingerprint(const char *name) -{ - struct name_entry *nm, *class_nm, *version_nm, *subtype_nm; - pf_osfp_t ret = PF_OSFP_NOMATCH; - int class, version, subtype; - int unp_class, unp_version, unp_subtype; - int wr_len, version_len, subtype_len; - char *ptr, *wr_name; - - if (strcasecmp(name, "unknown") == 0) - return (PF_OSFP_UNKNOWN); - - /* Try most likely no version and no subtype */ - if ((nm = lookup_name_list(&classes, name))) { - class = nm->nm_num; - version = PF_OSFP_ANY; - subtype = PF_OSFP_ANY; - goto found; - } else { - - /* Chop it up into class/version/subtype */ - - if ((wr_name = strdup(name)) == NULL) - err(1, "malloc"); - if ((ptr = strchr(wr_name, ' ')) == NULL) { - free(wr_name); - return (PF_OSFP_NOMATCH); - } - *ptr++ = '\0'; - - /* The class is easy to find since it is delimited by a space */ - if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) { - free(wr_name); - return (PF_OSFP_NOMATCH); - } - class = class_nm->nm_num; - - /* Try no subtype */ - if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr))) - { - version = version_nm->nm_num; - subtype = PF_OSFP_ANY; - free(wr_name); - goto found; - } - - - /* - * There must be a version and a subtype. - * We'll do some fuzzy matching to pick up things like: - * Linux 2.2.14 (version=2.2 subtype=14) - * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE) - * Windows 2000 SP2 (version=2000 subtype=SP2) - */ -#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-') - wr_len = strlen(ptr); - LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) { - version_len = strlen(version_nm->nm_name); - if (wr_len < version_len + 2 || - !CONNECTOR(ptr[version_len])) - continue; - /* first part of the string must be version */ - if (strncasecmp(ptr, version_nm->nm_name, - version_len)) - continue; - - LIST_FOREACH(subtype_nm, &version_nm->nm_sublist, - nm_entry) { - subtype_len = strlen(subtype_nm->nm_name); - if (wr_len != version_len + subtype_len + 1) - continue; - - /* last part of the string must be subtype */ - if (strcasecmp(&ptr[version_len+1], - subtype_nm->nm_name) != 0) - continue; - - /* Found it!! */ - version = version_nm->nm_num; - subtype = subtype_nm->nm_num; - free(wr_name); - goto found; - } - } - - free(wr_name); - return (PF_OSFP_NOMATCH); - } - -found: - PF_OSFP_PACK(ret, class, version, subtype); - if (ret != PF_OSFP_NOMATCH) { - PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype); - if (class != unp_class) { - fprintf(stderr, "warning: fingerprint table overflowed " - "classes\n"); - return (PF_OSFP_NOMATCH); - } - if (version != unp_version) { - fprintf(stderr, "warning: fingerprint table overflowed " - "versions\n"); - return (PF_OSFP_NOMATCH); - } - if (subtype != unp_subtype) { - fprintf(stderr, "warning: fingerprint table overflowed " - "subtypes\n"); - return (PF_OSFP_NOMATCH); - } - } - if (ret == PF_OSFP_ANY) { - /* should never happen */ - fprintf(stderr, "warning: fingerprint packed to 'any'\n"); - return (PF_OSFP_NOMATCH); - } - - return (ret); -} - -/* Lookup a fingerprint name by ID */ -char * -pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len) -{ - int class, version, subtype; - struct name_list *list; - struct name_entry *nm; - - char *class_name, *version_name, *subtype_name; - class_name = version_name = subtype_name = NULL; - - if (fp == PF_OSFP_UNKNOWN) { - strlcpy(buf, "unknown", len); - return (buf); - } - if (fp == PF_OSFP_ANY) { - strlcpy(buf, "any", len); - return (buf); - } - - PF_OSFP_UNPACK(fp, class, version, subtype); - if (class >= (1 << _FP_CLASS_BITS) || - version >= (1 << _FP_VERSION_BITS) || - subtype >= (1 << _FP_SUBTYPE_BITS)) { - warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp); - strlcpy(buf, "nomatch", len); - return (buf); - } - - LIST_FOREACH(nm, &classes, nm_entry) { - if (nm->nm_num == class) { - class_name = nm->nm_name; - if (version == PF_OSFP_ANY) - goto found; - list = &nm->nm_sublist; - LIST_FOREACH(nm, list, nm_entry) { - if (nm->nm_num == version) { - version_name = nm->nm_name; - if (subtype == PF_OSFP_ANY) - goto found; - list = &nm->nm_sublist; - LIST_FOREACH(nm, list, nm_entry) { - if (nm->nm_num == subtype) { - subtype_name = - nm->nm_name; - goto found; - } - } /* foreach subtype */ - strlcpy(buf, "nomatch", len); - return (buf); - } - } /* foreach version */ - strlcpy(buf, "nomatch", len); - return (buf); - } - } /* foreach class */ - - strlcpy(buf, "nomatch", len); - return (buf); - -found: - snprintf(buf, len, "%s", class_name); - if (version_name) { - strlcat(buf, " ", len); - strlcat(buf, version_name, len); - if (subtype_name) { - if (strchr(version_name, ' ')) - strlcat(buf, " ", len); - else if (strchr(version_name, '.') && - isdigit(*subtype_name)) - strlcat(buf, ".", len); - else - strlcat(buf, " ", len); - strlcat(buf, subtype_name, len); - } - } - return (buf); -} - -/* lookup a name in a list */ -struct name_entry * -lookup_name_list(struct name_list *list, const char *name) -{ - struct name_entry *nm; - LIST_FOREACH(nm, list, nm_entry) - if (strcasecmp(name, nm->nm_name) == 0) - return (nm); - - return (NULL); -} - - -void -add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp) -{ - struct pf_osfp_ioctl fptmp; - struct name_entry *nm_class, *nm_version, *nm_subtype; - int class, version, subtype; - -/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */ -#define EXPAND(field) do { \ - int _dot = -1, _start = -1, _end = -1, _i = 0; \ - /* pick major version out of #.# */ \ - if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \ - _dot = fp->field[_i] - '0'; \ - _i += 2; \ - } \ - if (isdigit(fp->field[_i])) \ - _start = fp->field[_i++] - '0'; \ - else \ - break; \ - if (isdigit(fp->field[_i])) \ - _start = (_start * 10) + fp->field[_i++] - '0'; \ - if (fp->field[_i++] != '-') \ - break; \ - if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \ - fp->field[_i] - '0' == _dot) \ - _i += 2; \ - else if (_dot != -1) \ - break; \ - if (isdigit(fp->field[_i])) \ - _end = fp->field[_i++] - '0'; \ - else \ - break; \ - if (isdigit(fp->field[_i])) \ - _end = (_end * 10) + fp->field[_i++] - '0'; \ - if (isdigit(fp->field[_i])) \ - _end = (_end * 10) + fp->field[_i++] - '0'; \ - if (fp->field[_i] != '\0') \ - break; \ - memcpy(&fptmp, fp, sizeof(fptmp)); \ - for (;_start <= _end; _start++) { \ - memset(fptmp.field, 0, sizeof(fptmp.field)); \ - fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \ - if (_dot == -1) \ - snprintf(fptmp.field, sizeof(fptmp.field), \ - "%d", _start); \ - else \ - snprintf(fptmp.field, sizeof(fptmp.field), \ - "%d.%d", _dot, _start); \ - add_fingerprint(dev, opts, &fptmp); \ - } \ -} while(0) - - /* We allow "#-#" as a version or subtype and we'll expand it */ - EXPAND(fp_os.fp_version_nm); - EXPAND(fp_os.fp_subtype_nm); - - if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0) - errx(1, "fingerprint class \"nomatch\" is reserved"); - - version = PF_OSFP_ANY; - subtype = PF_OSFP_ANY; - - nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); - if (nm_class->nm_num == 0) - nm_class->nm_num = ++class_count; - class = nm_class->nm_num; - - nm_version = fingerprint_name_entry(&nm_class->nm_sublist, - fp->fp_os.fp_version_nm); - if (nm_version) { - if (nm_version->nm_num == 0) - nm_version->nm_num = ++nm_class->nm_sublist_num; - version = nm_version->nm_num; - nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, - fp->fp_os.fp_subtype_nm); - if (nm_subtype) { - if (nm_subtype->nm_num == 0) - nm_subtype->nm_num = - ++nm_version->nm_sublist_num; - subtype = nm_subtype->nm_num; - } - } - - - DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype, - print_ioctl(fp)); - - PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype); - fingerprint_count++; - -#ifdef FAKE_PF_KERNEL - /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */ - if ((errno = pf_osfp_add(fp))) -#else - if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp)) -#endif /* FAKE_PF_KERNEL */ - { - if (errno == EEXIST) { - warn("Duplicate signature for %s %s %s", - fp->fp_os.fp_class_nm, - fp->fp_os.fp_version_nm, - fp->fp_os.fp_subtype_nm); - - } else { - err(1, "DIOCOSFPADD"); - } - } -} - -/* import a fingerprint from the kernel */ -void -import_fingerprint(struct pf_osfp_ioctl *fp) -{ - struct name_entry *nm_class, *nm_version, *nm_subtype; - int class, version, subtype; - - PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype); - - nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); - if (nm_class->nm_num == 0) { - nm_class->nm_num = class; - class_count = MAX(class_count, class); - } - - nm_version = fingerprint_name_entry(&nm_class->nm_sublist, - fp->fp_os.fp_version_nm); - if (nm_version) { - if (nm_version->nm_num == 0) { - nm_version->nm_num = version; - nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num, - version); - } - nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, - fp->fp_os.fp_subtype_nm); - if (nm_subtype) { - if (nm_subtype->nm_num == 0) { - nm_subtype->nm_num = subtype; - nm_version->nm_sublist_num = - MAX(nm_version->nm_sublist_num, subtype); - } - } - } - - - fingerprint_count++; - DEBUG(fp, "import signature %d:%d:%d", class, version, subtype); -} - -/* Find an entry for a fingerprints class/version/subtype */ -struct name_entry * -fingerprint_name_entry(struct name_list *list, char *name) -{ - struct name_entry *nm_entry; - - if (name == NULL || strlen(name) == 0) - return (NULL); - - LIST_FOREACH(nm_entry, list, nm_entry) { - if (strcasecmp(nm_entry->nm_name, name) == 0) { - /* We'll move this to the front of the list later */ - LIST_REMOVE(nm_entry, nm_entry); - break; - } - } - if (nm_entry == NULL) { - nm_entry = calloc(1, sizeof(*nm_entry)); - if (nm_entry == NULL) - err(1, "calloc"); - LIST_INIT(&nm_entry->nm_sublist); - strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name)); - } - LIST_INSERT_HEAD(list, nm_entry, nm_entry); - return (nm_entry); -} - - -void -print_name_list(int opts, struct name_list *nml, const char *prefix) -{ - char newprefix[32]; - struct name_entry *nm; - - LIST_FOREACH(nm, nml, nm_entry) { - snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix, - nm->nm_name); - printf("%s\n", newprefix); - print_name_list(opts, &nm->nm_sublist, newprefix); - } -} - -void -sort_name_list(int opts, struct name_list *nml) -{ - struct name_list new; - struct name_entry *nm, *nmsearch, *nmlast; - - /* yes yes, it's a very slow sort. so sue me */ - - LIST_INIT(&new); - - while ((nm = LIST_FIRST(nml)) != NULL) { - LIST_REMOVE(nm, nm_entry); - nmlast = NULL; - LIST_FOREACH(nmsearch, &new, nm_entry) { - if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) { - LIST_INSERT_BEFORE(nmsearch, nm, nm_entry); - break; - } - nmlast = nmsearch; - } - if (nmsearch == NULL) { - if (nmlast) - LIST_INSERT_AFTER(nmlast, nm, nm_entry); - else - LIST_INSERT_HEAD(&new, nm, nm_entry); - } - - sort_name_list(opts, &nm->nm_sublist); - } - nmlast = NULL; - while ((nm = LIST_FIRST(&new)) != NULL) { - LIST_REMOVE(nm, nm_entry); - if (nmlast == NULL) - LIST_INSERT_HEAD(nml, nm, nm_entry); - else - LIST_INSERT_AFTER(nmlast, nm, nm_entry); - nmlast = nm; - } -} - -/* parse the next integer in a formatted config file line */ -int -get_int(char **line, size_t *len, int *var, int *mod, - const char *name, int flags, int max, const char *filename, int lineno) -{ - int fieldlen, i; - char *field; - long val = 0; - - if (mod) - *mod = 0; - *var = 0; - - field = get_field(line, len, &fieldlen); - if (field == NULL) - return (1); - if (fieldlen == 0) { - fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name); - return (1); - } - - i = 0; - if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*') - && fieldlen >= 1) { - switch (*field) { - case 'S': - if (mod && (flags & T_MSS)) - *mod = T_MSS; - if (fieldlen == 1) - return (0); - break; - case 'T': - if (mod && (flags & T_MTU)) - *mod = T_MTU; - if (fieldlen == 1) - return (0); - break; - case '*': - if (fieldlen != 1) { - fprintf(stderr, "%s:%d long '%c' %s\n", - filename, lineno, *field, name); - return (1); - } - if (mod && (flags & T_DC)) { - *mod = T_DC; - return (0); - } - case '%': - if (mod && (flags & T_MOD)) - *mod = T_MOD; - if (fieldlen == 1) { - fprintf(stderr, "%s:%d modulus %s must have a " - "value\n", filename, lineno, name); - return (1); - } - break; - } - if (mod == NULL || *mod == 0) { - fprintf(stderr, "%s:%d does not allow %c' %s\n", - filename, lineno, *field, name); - return (1); - } - i++; - } - - for (; i < fieldlen; i++) { - if (field[i] < '0' || field[i] > '9') { - fprintf(stderr, "%s:%d non-digit character in %s\n", - filename, lineno, name); - return (1); - } - val = val * 10 + field[i] - '0'; - if (val < 0) { - fprintf(stderr, "%s:%d %s overflowed\n", filename, - lineno, name); - return (1); - } - } - - if (val > max) { - fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno, - name, val, max); - return (1); - } - *var = (int)val; - - return (0); -} - -/* parse the next string in a formatted config file line */ -int -get_str(char **line, size_t *len, char **v, const char *name, int minlen, - const char *filename, int lineno) -{ - int fieldlen; - char *ptr; - - ptr = get_field(line, len, &fieldlen); - if (ptr == NULL) - return (1); - if (fieldlen < minlen) { - fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name); - return (1); - } - if ((*v = malloc(fieldlen + 1)) == NULL) { - perror("malloc()"); - return (1); - } - memcpy(*v, ptr, fieldlen); - (*v)[fieldlen] = '\0'; - - return (0); -} - -/* Parse out the TCP opts */ -int -get_tcpopts(const char *filename, int lineno, const char *tcpopts, - pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale, - int *wscale_mod, int *ts0) -{ - int i, opt; - - *packed = 0; - *optcnt = 0; - *wscale = 0; - *wscale_mod = T_DC; - *mss = 0; - *mss_mod = T_DC; - *ts0 = 0; - if (strcmp(tcpopts, ".") == 0) - return (0); - - for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) { - switch ((opt = toupper(tcpopts[i++]))) { - case 'N': /* FALLTHROUGH */ - case 'S': - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - (opt == 'N' ? PF_OSFP_TCPOPT_NOP : - PF_OSFP_TCPOPT_SACK); - break; - case 'W': /* FALLTHROUGH */ - case 'M': { - int *this_mod, *this; - - if (opt == 'W') { - this = wscale; - this_mod = wscale_mod; - } else { - this = mss; - this_mod = mss_mod; - } - *this = 0; - *this_mod = 0; - - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE : - PF_OSFP_TCPOPT_MSS); - if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' || - tcpopts[i + 1] == ',')) { - *this_mod = T_DC; - i++; - break; - } - - if (tcpopts[i] == '%') { - *this_mod = T_MOD; - i++; - } - do { - if (!isdigit(tcpopts[i])) { - fprintf(stderr, "%s:%d unknown " - "character '%c' in %c TCP opt\n", - filename, lineno, tcpopts[i], opt); - return (1); - } - *this = (*this * 10) + tcpopts[i++] - '0'; - } while(tcpopts[i] != ',' && tcpopts[i] != '\0'); - break; - } - case 'T': - if (tcpopts[i] == '0') { - *ts0 = 1; - i++; - } - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - PF_OSFP_TCPOPT_TS; - break; - } - (*optcnt) ++; - if (tcpopts[i] == '\0') - break; - if (tcpopts[i] != ',') { - fprintf(stderr, "%s:%d unknown option to %c TCP opt\n", - filename, lineno, opt); - return (1); - } - i++; - } - - return (0); -} - -/* rip the next field ouf of a formatted config file line */ -char * -get_field(char **line, size_t *len, int *fieldlen) -{ - char *ret, *ptr = *line; - size_t plen = *len; - - - while (plen && isspace(*ptr)) { - plen--; - ptr++; - } - ret = ptr; - *fieldlen = 0; - - for (; plen > 0 && *ptr != ':'; plen--, ptr++) - (*fieldlen)++; - if (plen) { - *line = ptr + 1; - *len = plen - 1; - } else { - *len = 0; - } - while (*fieldlen && isspace(ret[*fieldlen - 1])) - (*fieldlen)--; - return (ret); -} - - -const char * -print_ioctl(struct pf_osfp_ioctl *fp) -{ -#ifndef __rtems__ - static char buf[1024]; -#else /* __rtems__ */ - /* Note on RTEMS port: - * This buffer is static. So normally it would have to be initialized to - * zero every time the program starts. But in this special case it is - * set to zero inside the function. Therefore it is not necessary to - * move it. If it would be moved out of the function, the name would - * have to be changed. This would be a lot of change in this function! - */ - static char buf[1024]; -#endif /* __rtems__ */ - char tmp[32]; - int i, opt; - - *buf = '\0'; - if (fp->fp_flags & PF_OSFP_WSIZE_DC) - strlcat(buf, "*", sizeof(buf)); - else if (fp->fp_flags & PF_OSFP_WSIZE_MSS) - strlcat(buf, "S", sizeof(buf)); - else if (fp->fp_flags & PF_OSFP_WSIZE_MTU) - strlcat(buf, "T", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_WSIZE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize); - strlcat(buf, tmp, sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl); - strlcat(buf, tmp, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_flags & PF_OSFP_DF) - strlcat(buf, "1", sizeof(buf)); - else - strlcat(buf, "0", sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_flags & PF_OSFP_PSIZE_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_PSIZE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize); - strlcat(buf, tmp, sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_optcnt == 0) - strlcat(buf, ".", sizeof(buf)); - for (i = fp->fp_optcnt - 1; i >= 0; i--) { - opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS); - opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1; - switch (opt) { - case PF_OSFP_TCPOPT_NOP: - strlcat(buf, "N", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_SACK: - strlcat(buf, "S", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_TS: - strlcat(buf, "T", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_TS0) - strlcat(buf, "0", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_MSS: - strlcat(buf, "M", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_MSS_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_MSS_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss); - strlcat(buf, tmp, sizeof(buf)); - } - break; - case PF_OSFP_TCPOPT_WSCALE: - strlcat(buf, "W", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_WSCALE_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_WSCALE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale); - strlcat(buf, tmp, sizeof(buf)); - } - break; - } - - if (i != 0) - strlcat(buf, ",", sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt, - (long long int)fp->fp_tcpopts); - strlcat(buf, tmp, sizeof(buf)); - - return (buf); -} -#ifdef __rtems__ -#include "pfctl_osfp-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_parser-data.h b/freebsd/contrib/pf/pfctl/pfctl_parser-data.h deleted file mode 100644 index 5e9ff5c1..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_parser-data.h +++ /dev/null @@ -1,3 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab); diff --git a/freebsd/contrib/pf/pfctl/pfctl_parser.c b/freebsd/contrib/pf/pfctl/pfctl_parser.c deleted file mode 100644 index 0efdaad9..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_parser.c +++ /dev/null @@ -1,1778 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <rtems/bsd/sys/param.h> -#ifdef __rtems__ -#include <rtems/bsd/sys/errno.h> -#endif /* __rtems__ */ -#include <sys/proc.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <netdb.h> -#include <stdarg.h> -#include <errno.h> -#include <err.h> -#include <ifaddrs.h> -#include <unistd.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void print_op (u_int8_t, const char *, const char *); -void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); -void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); -void print_flags (u_int8_t); -void print_fromto(struct pf_rule_addr *, pf_osfp_t, - struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); -int ifa_skip_if(const char *filter, struct node_host *p); - -struct node_host *ifa_grouplookup(const char *, int); -struct node_host *host_if(const char *, int); -struct node_host *host_v4(const char *, int); -struct node_host *host_v6(const char *, int); -struct node_host *host_dns(const char *, int, int); - -#ifndef __rtems__ -const char *tcpflags = "FSRPAUEW"; -#else /* __rtems__ */ -const char * const tcpflags = "FSRPAUEW"; -#endif /* __rtems__ */ - -static const struct icmptypeent icmp_type[] = { - { "echoreq", ICMP_ECHO }, - { "echorep", ICMP_ECHOREPLY }, - { "unreach", ICMP_UNREACH }, - { "squench", ICMP_SOURCEQUENCH }, - { "redir", ICMP_REDIRECT }, - { "althost", ICMP_ALTHOSTADDR }, - { "routeradv", ICMP_ROUTERADVERT }, - { "routersol", ICMP_ROUTERSOLICIT }, - { "timex", ICMP_TIMXCEED }, - { "paramprob", ICMP_PARAMPROB }, - { "timereq", ICMP_TSTAMP }, - { "timerep", ICMP_TSTAMPREPLY }, - { "inforeq", ICMP_IREQ }, - { "inforep", ICMP_IREQREPLY }, - { "maskreq", ICMP_MASKREQ }, - { "maskrep", ICMP_MASKREPLY }, - { "trace", ICMP_TRACEROUTE }, - { "dataconv", ICMP_DATACONVERR }, - { "mobredir", ICMP_MOBILE_REDIRECT }, - { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, - { "ipv6-here", ICMP_IPV6_IAMHERE }, - { "mobregreq", ICMP_MOBILE_REGREQUEST }, - { "mobregrep", ICMP_MOBILE_REGREPLY }, - { "skip", ICMP_SKIP }, - { "photuris", ICMP_PHOTURIS } -}; - -static const struct icmptypeent icmp6_type[] = { - { "unreach", ICMP6_DST_UNREACH }, - { "toobig", ICMP6_PACKET_TOO_BIG }, - { "timex", ICMP6_TIME_EXCEEDED }, - { "paramprob", ICMP6_PARAM_PROB }, - { "echoreq", ICMP6_ECHO_REQUEST }, - { "echorep", ICMP6_ECHO_REPLY }, - { "groupqry", ICMP6_MEMBERSHIP_QUERY }, - { "listqry", MLD_LISTENER_QUERY }, - { "grouprep", ICMP6_MEMBERSHIP_REPORT }, - { "listenrep", MLD_LISTENER_REPORT }, - { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, - { "listendone", MLD_LISTENER_DONE }, - { "routersol", ND_ROUTER_SOLICIT }, - { "routeradv", ND_ROUTER_ADVERT }, - { "neighbrsol", ND_NEIGHBOR_SOLICIT }, - { "neighbradv", ND_NEIGHBOR_ADVERT }, - { "redir", ND_REDIRECT }, - { "routrrenum", ICMP6_ROUTER_RENUMBERING }, - { "wrureq", ICMP6_WRUREQUEST }, - { "wrurep", ICMP6_WRUREPLY }, - { "fqdnreq", ICMP6_FQDN_QUERY }, - { "fqdnrep", ICMP6_FQDN_REPLY }, - { "niqry", ICMP6_NI_QUERY }, - { "nirep", ICMP6_NI_REPLY }, - { "mtraceresp", MLD_MTRACE_RESP }, - { "mtrace", MLD_MTRACE } -}; - -static const struct icmpcodeent icmp_code[] = { - { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, - { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, - { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, - { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, - { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, - { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, - { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, - { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, - { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, - { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, - { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, - { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, - { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, - { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, - { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, - { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, - { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, - { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, - { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, - { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, - { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, - { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, - { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, - { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, - { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, - { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, - { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, - { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, - { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, - { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } -}; - -static const struct icmpcodeent icmp6_code[] = { - { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, - { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, - { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, - { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, - { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, - { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, - { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, - { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, - { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, - { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, - { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, - { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } -}; - -const struct pf_timeout pf_timeouts[] = { - { "tcp.first", PFTM_TCP_FIRST_PACKET }, - { "tcp.opening", PFTM_TCP_OPENING }, - { "tcp.established", PFTM_TCP_ESTABLISHED }, - { "tcp.closing", PFTM_TCP_CLOSING }, - { "tcp.finwait", PFTM_TCP_FIN_WAIT }, - { "tcp.closed", PFTM_TCP_CLOSED }, - { "tcp.tsdiff", PFTM_TS_DIFF }, - { "udp.first", PFTM_UDP_FIRST_PACKET }, - { "udp.single", PFTM_UDP_SINGLE }, - { "udp.multiple", PFTM_UDP_MULTIPLE }, - { "icmp.first", PFTM_ICMP_FIRST_PACKET }, - { "icmp.error", PFTM_ICMP_ERROR_REPLY }, - { "other.first", PFTM_OTHER_FIRST_PACKET }, - { "other.single", PFTM_OTHER_SINGLE }, - { "other.multiple", PFTM_OTHER_MULTIPLE }, - { "frag", PFTM_FRAG }, - { "interval", PFTM_INTERVAL }, - { "adaptive.start", PFTM_ADAPTIVE_START }, - { "adaptive.end", PFTM_ADAPTIVE_END }, - { "src.track", PFTM_SRC_NODE }, - { NULL, 0 } -}; - -const struct icmptypeent * -geticmptypebynumber(u_int8_t type, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); - i++) { - if (type == icmp_type[i].type) - return (&icmp_type[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_type) / - sizeof(icmp6_type[0])); i++) { - if (type == icmp6_type[i].type) - return (&icmp6_type[i]); - } - } - return (NULL); -} - -const struct icmptypeent * -geticmptypebyname(char *w, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); - i++) { - if (!strcmp(w, icmp_type[i].name)) - return (&icmp_type[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_type) / - sizeof(icmp6_type[0])); i++) { - if (!strcmp(w, icmp6_type[i].name)) - return (&icmp6_type[i]); - } - } - return (NULL); -} - -const struct icmpcodeent * -geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); - i++) { - if (type == icmp_code[i].type && - code == icmp_code[i].code) - return (&icmp_code[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_code) / - sizeof(icmp6_code[0])); i++) { - if (type == icmp6_code[i].type && - code == icmp6_code[i].code) - return (&icmp6_code[i]); - } - } - return (NULL); -} - -const struct icmpcodeent * -geticmpcodebyname(u_long type, char *w, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); - i++) { - if (type == icmp_code[i].type && - !strcmp(w, icmp_code[i].name)) - return (&icmp_code[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_code) / - sizeof(icmp6_code[0])); i++) { - if (type == icmp6_code[i].type && - !strcmp(w, icmp6_code[i].name)) - return (&icmp6_code[i]); - } - } - return (NULL); -} - -void -print_op(u_int8_t op, const char *a1, const char *a2) -{ - if (op == PF_OP_IRG) - printf(" %s >< %s", a1, a2); - else if (op == PF_OP_XRG) - printf(" %s <> %s", a1, a2); - else if (op == PF_OP_EQ) - printf(" = %s", a1); - else if (op == PF_OP_NE) - printf(" != %s", a1); - else if (op == PF_OP_LT) - printf(" < %s", a1); - else if (op == PF_OP_LE) - printf(" <= %s", a1); - else if (op == PF_OP_GT) - printf(" > %s", a1); - else if (op == PF_OP_GE) - printf(" >= %s", a1); - else if (op == PF_OP_RRG) - printf(" %s:%s", a1, a2); -} - -void -print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric) -{ - char a1[6], a2[6]; - struct servent *s; - - if (!numeric) - s = getservbyport(p1, proto); - else - s = NULL; - p1 = ntohs(p1); - p2 = ntohs(p2); - snprintf(a1, sizeof(a1), "%u", p1); - snprintf(a2, sizeof(a2), "%u", p2); - printf(" port"); - if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) - print_op(op, s->s_name, a2); - else - print_op(op, a1, a2); -} - -void -print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) -{ - char a1[11], a2[11]; - - snprintf(a1, sizeof(a1), "%u", u1); - snprintf(a2, sizeof(a2), "%u", u2); - printf(" %s", t); - if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) - print_op(op, "unknown", a2); - else - print_op(op, a1, a2); -} - -void -print_flags(u_int8_t f) -{ - int i; - - for (i = 0; tcpflags[i]; ++i) - if (f & (1 << i)) - printf("%c", tcpflags[i]); -} - -void -print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, - sa_family_t af, u_int8_t proto, int verbose, int numeric) -{ - char buf[PF_OSFP_LEN*3]; - if (src->addr.type == PF_ADDR_ADDRMASK && - dst->addr.type == PF_ADDR_ADDRMASK && - PF_AZERO(&src->addr.v.a.addr, AF_INET6) && - PF_AZERO(&src->addr.v.a.mask, AF_INET6) && - PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && - PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && - !src->neg && !dst->neg && - !src->port_op && !dst->port_op && - osfp == PF_OSFP_ANY) - printf(" all"); - else { - printf(" from "); - if (src->neg) - printf("! "); - print_addr(&src->addr, af, verbose); - if (src->port_op) - print_port(src->port_op, src->port[0], - src->port[1], - proto == IPPROTO_TCP ? "tcp" : "udp", - numeric); - if (osfp != PF_OSFP_ANY) - printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf, - sizeof(buf))); - - printf(" to "); - if (dst->neg) - printf("! "); - print_addr(&dst->addr, af, verbose); - if (dst->port_op) - print_port(dst->port_op, dst->port[0], - dst->port[1], - proto == IPPROTO_TCP ? "tcp" : "udp", - numeric); - } -} - -void -print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, - sa_family_t af, int id) -{ - struct pf_pooladdr *pooladdr; - - if ((TAILQ_FIRST(&pool->list) != NULL) && - TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) - printf("{ "); - TAILQ_FOREACH(pooladdr, &pool->list, entries){ - switch (id) { - case PF_NAT: - case PF_RDR: - case PF_BINAT: - print_addr(&pooladdr->addr, af, 0); - break; - case PF_PASS: - if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) - printf("%s", pooladdr->ifname); - else { - printf("(%s ", pooladdr->ifname); - print_addr(&pooladdr->addr, af, 0); - printf(")"); - } - break; - default: - break; - } - if (TAILQ_NEXT(pooladdr, entries) != NULL) - printf(", "); - else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) - printf(" }"); - } - switch (id) { - case PF_NAT: - if ((p1 != PF_NAT_PROXY_PORT_LOW || - p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { - if (p1 == p2) - printf(" port %u", p1); - else - printf(" port %u:%u", p1, p2); - } - break; - case PF_RDR: - if (p1) { - printf(" port %u", p1); - if (p2 && (p2 != p1)) - printf(":%u", p2); - } - break; - default: - break; - } - switch (pool->opts & PF_POOL_TYPEMASK) { - case PF_POOL_NONE: - break; - case PF_POOL_BITMASK: - printf(" bitmask"); - break; - case PF_POOL_RANDOM: - printf(" random"); - break; - case PF_POOL_SRCHASH: - printf(" source-hash 0x%08x%08x%08x%08x", - pool->key.key32[0], pool->key.key32[1], - pool->key.key32[2], pool->key.key32[3]); - break; - case PF_POOL_ROUNDROBIN: - printf(" round-robin"); - break; - } - if (pool->opts & PF_POOL_STICKYADDR) - printf(" sticky-address"); - if (id == PF_NAT && p1 == 0 && p2 == 0) - printf(" static-port"); -} - -#ifndef __rtems__ -const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; -const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; -const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; -const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; -#else /* __rtems__ */ -const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES; -const char * const pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; -const char * const pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; -const char * const pf_scounters[FCNT_MAX+1] = FCNT_NAMES; -#endif /* __rtems__ */ - -void -print_status(struct pf_status *s, int opts) -{ - char statline[80], *running; - time_t runtime; - int i; - char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; - static const char hex[] = "0123456789abcdef"; - - runtime = time(NULL) - s->since; - running = s->running ? "Enabled" : "Disabled"; - - if (s->since) { - unsigned int sec, min, hrs, day = runtime; - - sec = day % 60; - day /= 60; - min = day % 60; - day /= 60; - hrs = day % 24; - day /= 24; - snprintf(statline, sizeof(statline), - "Status: %s for %u days %.2u:%.2u:%.2u", - running, day, hrs, min, sec); - } else - snprintf(statline, sizeof(statline), "Status: %s", running); - printf("%-44s", statline); - switch (s->debug) { - case PF_DEBUG_NONE: - printf("%15s\n\n", "Debug: None"); - break; - case PF_DEBUG_URGENT: - printf("%15s\n\n", "Debug: Urgent"); - break; - case PF_DEBUG_MISC: - printf("%15s\n\n", "Debug: Misc"); - break; - case PF_DEBUG_NOISY: - printf("%15s\n\n", "Debug: Loud"); - break; - } - - if (opts & PF_OPT_VERBOSE) { - printf("Hostid: 0x%08x\n", ntohl(s->hostid)); - - for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { - buf[i + i] = hex[s->pf_chksum[i] >> 4]; - buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; - } - buf[i + i] = '\0'; - printf("Checksum: 0x%s\n\n", buf); - } - - if (s->ifname[0] != 0) { - printf("Interface Stats for %-16s %5s %16s\n", - s->ifname, "IPv4", "IPv6"); - printf(" %-25s %14llu %16llu\n", "Bytes In", - (unsigned long long)s->bcounters[0][0], - (unsigned long long)s->bcounters[1][0]); - printf(" %-25s %14llu %16llu\n", "Bytes Out", - (unsigned long long)s->bcounters[0][1], - (unsigned long long)s->bcounters[1][1]); - printf(" Packets In\n"); - printf(" %-23s %14llu %16llu\n", "Passed", - (unsigned long long)s->pcounters[0][0][PF_PASS], - (unsigned long long)s->pcounters[1][0][PF_PASS]); - printf(" %-23s %14llu %16llu\n", "Blocked", - (unsigned long long)s->pcounters[0][0][PF_DROP], - (unsigned long long)s->pcounters[1][0][PF_DROP]); - printf(" Packets Out\n"); - printf(" %-23s %14llu %16llu\n", "Passed", - (unsigned long long)s->pcounters[0][1][PF_PASS], - (unsigned long long)s->pcounters[1][1][PF_PASS]); - printf(" %-23s %14llu %16llu\n\n", "Blocked", - (unsigned long long)s->pcounters[0][1][PF_DROP], - (unsigned long long)s->pcounters[1][1][PF_DROP]); - } - printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); - printf(" %-25s %14u %14s\n", "current entries", s->states, ""); - for (i = 0; i < FCNT_MAX; i++) { - printf(" %-25s %14llu ", pf_fcounters[i], - (unsigned long long)s->fcounters[i]); - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->fcounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - if (opts & PF_OPT_VERBOSE) { - printf("Source Tracking Table\n"); - printf(" %-25s %14u %14s\n", "current entries", - s->src_nodes, ""); - for (i = 0; i < SCNT_MAX; i++) { - printf(" %-25s %14lld ", pf_scounters[i], -#ifdef __FreeBSD__ - (long long)s->scounters[i]); -#else - s->scounters[i]); -#endif - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->scounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - } - printf("Counters\n"); - for (i = 0; i < PFRES_MAX; i++) { - printf(" %-25s %14llu ", pf_reasons[i], - (unsigned long long)s->counters[i]); - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->counters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - if (opts & PF_OPT_VERBOSE) { - printf("Limit Counters\n"); - for (i = 0; i < LCNT_MAX; i++) { - printf(" %-25s %14lld ", pf_lcounters[i], -#ifdef __FreeBSD__ - (unsigned long long)s->lcounters[i]); -#else - s->lcounters[i]); -#endif - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->lcounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - } -} - -void -print_src_node(struct pf_src_node *sn, int opts) -{ - struct pf_addr_wrap aw; - int min, sec; - - memset(&aw, 0, sizeof(aw)); - if (sn->af == AF_INET) - aw.v.a.mask.addr32[0] = 0xffffffff; - else - memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); - - aw.v.a.addr = sn->addr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); - printf(" -> "); - aw.v.a.addr = sn->raddr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); - printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, - sn->conn, sn->conn_rate.count / 1000, - (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); - if (opts & PF_OPT_VERBOSE) { - sec = sn->creation % 60; - sn->creation /= 60; - min = sn->creation % 60; - sn->creation /= 60; - printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); - if (sn->states == 0) { - sec = sn->expire % 60; - sn->expire /= 60; - min = sn->expire % 60; - sn->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", - sn->expire, min, sec); - } - printf(", %llu pkts, %llu bytes", -#ifdef __FreeBSD__ - (unsigned long long)(sn->packets[0] + sn->packets[1]), - (unsigned long long)(sn->bytes[0] + sn->bytes[1])); -#else - sn->packets[0] + sn->packets[1], - sn->bytes[0] + sn->bytes[1]); -#endif - switch (sn->ruletype) { - case PF_NAT: - if (sn->rule.nr != -1) - printf(", nat rule %u", sn->rule.nr); - break; - case PF_RDR: - if (sn->rule.nr != -1) - printf(", rdr rule %u", sn->rule.nr); - break; - case PF_PASS: - if (sn->rule.nr != -1) - printf(", filter rule %u", sn->rule.nr); - break; - } - printf("\n"); - } -} - -void -print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) -{ - static const char *actiontypes[] = { "pass", "block", "scrub", - "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" }; - static const char *anchortypes[] = { "anchor", "anchor", "anchor", - "anchor", "nat-anchor", "nat-anchor", "binat-anchor", - "binat-anchor", "rdr-anchor", "rdr-anchor" }; - int i, opts; - - if (verbose) - printf("@%d ", r->nr); - if (r->action > PF_NORDR) - printf("action(%d)", r->action); - else if (anchor_call[0]) { - if (anchor_call[0] == '_') { - printf("%s", anchortypes[r->action]); - } else - printf("%s \"%s\"", anchortypes[r->action], - anchor_call); - } else { - printf("%s", actiontypes[r->action]); - if (r->natpass) - printf(" pass"); - } - if (r->action == PF_DROP) { - if (r->rule_flag & PFRULE_RETURN) - printf(" return"); - else if (r->rule_flag & PFRULE_RETURNRST) { - if (!r->return_ttl) - printf(" return-rst"); - else - printf(" return-rst(ttl %d)", r->return_ttl); - } else if (r->rule_flag & PFRULE_RETURNICMP) { - const struct icmpcodeent *ic, *ic6; - - ic = geticmpcodebynumber(r->return_icmp >> 8, - r->return_icmp & 255, AF_INET); - ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, - r->return_icmp6 & 255, AF_INET6); - - switch (r->af) { - case AF_INET: - printf(" return-icmp"); - if (ic == NULL) - printf("(%u)", r->return_icmp & 255); - else - printf("(%s)", ic->name); - break; - case AF_INET6: - printf(" return-icmp6"); - if (ic6 == NULL) - printf("(%u)", r->return_icmp6 & 255); - else - printf("(%s)", ic6->name); - break; - default: - printf(" return-icmp"); - if (ic == NULL) - printf("(%u, ", r->return_icmp & 255); - else - printf("(%s, ", ic->name); - if (ic6 == NULL) - printf("%u)", r->return_icmp6 & 255); - else - printf("%s)", ic6->name); - break; - } - } else - printf(" drop"); - } - if (r->direction == PF_IN) - printf(" in"); - else if (r->direction == PF_OUT) - printf(" out"); - if (r->log) { - printf(" log"); - if (r->log & ~PF_LOG || r->logif) { - int count = 0; - - printf(" ("); - if (r->log & PF_LOG_ALL) - printf("%sall", count++ ? ", " : ""); - if (r->log & PF_LOG_SOCKET_LOOKUP) - printf("%suser", count++ ? ", " : ""); - if (r->logif) - printf("%sto pflog%u", count++ ? ", " : "", - r->logif); - printf(")"); - } - } - if (r->quick) - printf(" quick"); - if (r->ifname[0]) { - if (r->ifnot) - printf(" on ! %s", r->ifname); - else - printf(" on %s", r->ifname); - } - if (r->rt) { - if (r->rt == PF_ROUTETO) - printf(" route-to"); - else if (r->rt == PF_REPLYTO) - printf(" reply-to"); - else if (r->rt == PF_DUPTO) - printf(" dup-to"); - else if (r->rt == PF_FASTROUTE) - printf(" fastroute"); - if (r->rt != PF_FASTROUTE) { - printf(" "); - print_pool(&r->rpool, 0, 0, r->af, PF_PASS); - } - } - if (r->af) { - if (r->af == AF_INET) - printf(" inet"); - else - printf(" inet6"); - } - if (r->proto) { - struct protoent *p; - - if ((p = getprotobynumber(r->proto)) != NULL) - printf(" proto %s", p->p_name); - else - printf(" proto %u", r->proto); - } - print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, - verbose, numeric); - if (r->uid.op) - print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", - UID_MAX); - if (r->gid.op) - print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", - GID_MAX); - if (r->flags || r->flagset) { - printf(" flags "); - print_flags(r->flags); - printf("/"); - print_flags(r->flagset); - } else if (r->action == PF_PASS && - (!r->proto || r->proto == IPPROTO_TCP) && - !(r->rule_flag & PFRULE_FRAGMENT) && - !anchor_call[0] && r->keep_state) - printf(" flags any"); - if (r->type) { - const struct icmptypeent *it; - - it = geticmptypebynumber(r->type-1, r->af); - if (r->af != AF_INET6) - printf(" icmp-type"); - else - printf(" icmp6-type"); - if (it != NULL) - printf(" %s", it->name); - else - printf(" %u", r->type-1); - if (r->code) { - const struct icmpcodeent *ic; - - ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); - if (ic != NULL) - printf(" code %s", ic->name); - else - printf(" code %u", r->code-1); - } - } - if (r->tos) - printf(" tos 0x%2.2x", r->tos); - if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) - printf(" no state"); - else if (r->keep_state == PF_STATE_NORMAL) - printf(" keep state"); - else if (r->keep_state == PF_STATE_MODULATE) - printf(" modulate state"); - else if (r->keep_state == PF_STATE_SYNPROXY) - printf(" synproxy state"); - if (r->prob) { - char buf[20]; - - snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0)); - for (i = strlen(buf)-1; i > 0; i--) { - if (buf[i] == '0') - buf[i] = '\0'; - else { - if (buf[i] == '.') - buf[i] = '\0'; - break; - } - } - printf(" probability %s%%", buf); - } - opts = 0; - if (r->max_states || r->max_src_nodes || r->max_src_states) - opts = 1; - if (r->rule_flag & PFRULE_NOSYNC) - opts = 1; - if (r->rule_flag & PFRULE_SRCTRACK) - opts = 1; - if (r->rule_flag & PFRULE_IFBOUND) - opts = 1; - if (r->rule_flag & PFRULE_STATESLOPPY) - opts = 1; - for (i = 0; !opts && i < PFTM_MAX; ++i) - if (r->timeout[i]) - opts = 1; - if (opts) { - printf(" ("); - if (r->max_states) { - printf("max %u", r->max_states); - opts = 0; - } - if (r->rule_flag & PFRULE_NOSYNC) { - if (!opts) - printf(", "); - printf("no-sync"); - opts = 0; - } - if (r->rule_flag & PFRULE_SRCTRACK) { - if (!opts) - printf(", "); - printf("source-track"); - if (r->rule_flag & PFRULE_RULESRCTRACK) - printf(" rule"); - else - printf(" global"); - opts = 0; - } - if (r->max_src_states) { - if (!opts) - printf(", "); - printf("max-src-states %u", r->max_src_states); - opts = 0; - } - if (r->max_src_conn) { - if (!opts) - printf(", "); - printf("max-src-conn %u", r->max_src_conn); - opts = 0; - } - if (r->max_src_conn_rate.limit) { - if (!opts) - printf(", "); - printf("max-src-conn-rate %u/%u", - r->max_src_conn_rate.limit, - r->max_src_conn_rate.seconds); - opts = 0; - } - if (r->max_src_nodes) { - if (!opts) - printf(", "); - printf("max-src-nodes %u", r->max_src_nodes); - opts = 0; - } - if (r->overload_tblname[0]) { - if (!opts) - printf(", "); - printf("overload <%s>", r->overload_tblname); - if (r->flush) - printf(" flush"); - if (r->flush & PF_FLUSH_GLOBAL) - printf(" global"); - } - if (r->rule_flag & PFRULE_IFBOUND) { - if (!opts) - printf(", "); - printf("if-bound"); - opts = 0; - } - if (r->rule_flag & PFRULE_STATESLOPPY) { - if (!opts) - printf(", "); - printf("sloppy"); - opts = 0; - } - if (r->rule_flag & PFRULE_PFLOW) { - if (!opts) - printf(", "); - printf("pflow"); - opts = 0; - } - for (i = 0; i < PFTM_MAX; ++i) - if (r->timeout[i]) { - int j; - - if (!opts) - printf(", "); - opts = 0; - for (j = 0; pf_timeouts[j].name != NULL; - ++j) - if (pf_timeouts[j].timeout == i) - break; - printf("%s %u", pf_timeouts[j].name == NULL ? - "inv.timeout" : pf_timeouts[j].name, - r->timeout[i]); - } - printf(")"); - } - if (r->rule_flag & PFRULE_FRAGMENT) - printf(" fragment"); - if (r->rule_flag & PFRULE_NODF) - printf(" no-df"); - if (r->rule_flag & PFRULE_RANDOMID) - printf(" random-id"); - if (r->min_ttl) - printf(" min-ttl %d", r->min_ttl); - if (r->max_mss) - printf(" max-mss %d", r->max_mss); - if (r->rule_flag & PFRULE_SET_TOS) - printf(" set-tos 0x%2.2x", r->set_tos); - if (r->allow_opts) - printf(" allow-opts"); - if (r->action == PF_SCRUB) { - if (r->rule_flag & PFRULE_REASSEMBLE_TCP) - printf(" reassemble tcp"); - - if (r->rule_flag & PFRULE_FRAGDROP) - printf(" fragment drop-ovl"); - else if (r->rule_flag & PFRULE_FRAGCROP) - printf(" fragment crop"); - else - printf(" fragment reassemble"); - } - if (r->label[0]) - printf(" label \"%s\"", r->label); - if (r->qname[0] && r->pqname[0]) - printf(" queue(%s, %s)", r->qname, r->pqname); - else if (r->qname[0]) - printf(" queue %s", r->qname); - if (r->tagname[0]) - printf(" tag %s", r->tagname); - if (r->match_tagname[0]) { - if (r->match_tag_not) - printf(" !"); - printf(" tagged %s", r->match_tagname); - } - if (r->rtableid != -1) - printf(" rtable %u", r->rtableid); - if (r->divert.port) { -#ifdef __FreeBSD__ - printf(" divert-to %u", ntohs(r->divert.port)); -#else - if (PF_AZERO(&r->divert.addr, r->af)) { - printf(" divert-reply"); - } else { - /* XXX cut&paste from print_addr */ - char buf[48]; - - printf(" divert-to "); - if (inet_ntop(r->af, &r->divert.addr, buf, - sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - printf(" port %u", ntohs(r->divert.port)); - } -#endif - } - if (!anchor_call[0] && (r->action == PF_NAT || - r->action == PF_BINAT || r->action == PF_RDR)) { - printf(" -> "); - print_pool(&r->rpool, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], r->af, r->action); - } -} - -void -print_tabledef(const char *name, int flags, int addrs, - struct node_tinithead *nodes) -{ - struct node_tinit *ti, *nti; - struct node_host *h; - - printf("table <%s>", name); - if (flags & PFR_TFLAG_CONST) - printf(" const"); - if (flags & PFR_TFLAG_PERSIST) - printf(" persist"); - if (flags & PFR_TFLAG_COUNTERS) - printf(" counters"); - SIMPLEQ_FOREACH(ti, nodes, entries) { - if (ti->file) { - printf(" file \"%s\"", ti->file); - continue; - } - printf(" {"); - for (;;) { - for (h = ti->host; h != NULL; h = h->next) { - printf(h->not ? " !" : " "); - print_addr(&h->addr, h->af, 0); - } - nti = SIMPLEQ_NEXT(ti, entries); - if (nti != NULL && nti->file == NULL) - ti = nti; /* merge lists */ - else - break; - } - printf(" }"); - } - if (addrs && SIMPLEQ_EMPTY(nodes)) - printf(" { }"); - printf("\n"); -} - -int -parse_flags(char *s) -{ - char *p, *q; - u_int8_t f = 0; - - for (p = s; *p; p++) { - if ((q = strchr(tcpflags, *p)) == NULL) - return -1; - else - f |= 1 << (q - tcpflags); - } - return (f ? f : PF_TH_ALL); -} - -void -set_ipmask(struct node_host *h, u_int8_t b) -{ - struct pf_addr *m, *n; - int i, j = 0; - - m = &h->addr.v.a.mask; - memset(m, 0, sizeof(*m)); - - while (b >= 32) { - m->addr32[j++] = 0xffffffff; - b -= 32; - } - for (i = 31; i > 31-b; --i) - m->addr32[j] |= (1 << i); - if (b) - m->addr32[j] = htonl(m->addr32[j]); - - /* Mask off bits of the address that will never be used. */ - n = &h->addr.v.a.addr; - if (h->addr.type == PF_ADDR_ADDRMASK) - for (i = 0; i < 4; i++) - n->addr32[i] = n->addr32[i] & m->addr32[i]; -} - -int -check_netmask(struct node_host *h, sa_family_t af) -{ - struct node_host *n = NULL; - struct pf_addr *m; - - for (n = h; n != NULL; n = n->next) { - if (h->addr.type == PF_ADDR_TABLE) - continue; - m = &h->addr.v.a.mask; - /* fix up netmask for dynaddr */ - if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && - unmask(m, AF_INET6) > 32) - set_ipmask(n, 32); - /* netmasks > 32 bit are invalid on v4 */ - if (af == AF_INET && - (m->addr32[1] || m->addr32[2] || m->addr32[3])) { - fprintf(stderr, "netmask %u invalid for IPv4 address\n", - unmask(m, AF_INET6)); - return (1); - } - } - return (0); -} - -/* interface lookup routines */ - -#ifndef __rtems__ -struct node_host *iftab; -#else /* __rtems__ */ -static struct node_host *iftab; -#endif /* __rtems__ */ - -void -ifa_load(void) -{ - struct ifaddrs *ifap, *ifa; - struct node_host *n = NULL, *h = NULL; - - if (getifaddrs(&ifap) < 0) - err(1, "getifaddrs"); - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (!(ifa->ifa_addr->sa_family == AF_INET || - ifa->ifa_addr->sa_family == AF_INET6 || - ifa->ifa_addr->sa_family == AF_LINK)) - continue; - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "address: calloc"); - n->af = ifa->ifa_addr->sa_family; - n->ifa_flags = ifa->ifa_flags; -#ifdef __KAME__ - if (n->af == AF_INET6 && - IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_addr) && - ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == - 0) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | - sin6->sin6_addr.s6_addr[3]; - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - } -#endif - n->ifindex = 0; - if (n->af == AF_INET) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) - ifa->ifa_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) - ifa->ifa_netmask)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in *) - ifa->ifa_broadaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in *) - ifa->ifa_dstaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - } else if (n->af == AF_INET6) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) - ifa->ifa_netmask)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in6 *) - ifa->ifa_broadaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in6 *) - ifa->ifa_dstaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - n->ifindex = ((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_scope_id; - } - if ((n->ifname = strdup(ifa->ifa_name)) == NULL) - err(1, "ifa_load: strdup"); - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - - iftab = h; - freeifaddrs(ifap); -} - -struct node_host * -ifa_exists(const char *ifa_name) -{ - struct node_host *n; - struct ifgroupreq ifgr; - int s; - - if (iftab == NULL) - ifa_load(); - - /* check wether this is a group */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - err(1, "socket"); - bzero(&ifgr, sizeof(ifgr)); - strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { - /* fake a node_host */ - if ((n = calloc(1, sizeof(*n))) == NULL) - err(1, "calloc"); - if ((n->ifname = strdup(ifa_name)) == NULL) - err(1, "strdup"); - close(s); - return (n); - } - close(s); - - for (n = iftab; n; n = n->next) { - if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) - return (n); - } - - return (NULL); -} - -struct node_host * -ifa_grouplookup(const char *ifa_name, int flags) -{ - struct ifg_req *ifg; - struct ifgroupreq ifgr; - int s, len; - struct node_host *n, *h = NULL; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - err(1, "socket"); - bzero(&ifgr, sizeof(ifgr)); - strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { - close(s); - return (NULL); - } - - len = ifgr.ifgr_len; - if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) - err(1, "calloc"); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) - err(1, "SIOCGIFGMEMB"); - - for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); - ifg++) { - len -= sizeof(struct ifg_req); - if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) - continue; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n->tail; - } - } - free(ifgr.ifgr_groups); - close(s); - - return (h); -} - -struct node_host * -ifa_lookup(const char *ifa_name, int flags) -{ - struct node_host *p = NULL, *h = NULL, *n = NULL; - int got4 = 0, got6 = 0; - const char *last_if = NULL; - - if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) - return (h); - - if (!strncmp(ifa_name, "self", IFNAMSIZ)) - ifa_name = NULL; - - if (iftab == NULL) - ifa_load(); - - for (p = iftab; p; p = p->next) { - if (ifa_skip_if(ifa_name, p)) - continue; - if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) - continue; - if ((flags & PFI_AFLAG_BROADCAST) && - !(p->ifa_flags & IFF_BROADCAST)) - continue; - if ((flags & PFI_AFLAG_PEER) && - !(p->ifa_flags & IFF_POINTOPOINT)) - continue; - if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) - continue; - if (last_if == NULL || strcmp(last_if, p->ifname)) - got4 = got6 = 0; - last_if = p->ifname; - if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) - continue; - if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) - continue; - if (p->af == AF_INET) - got4 = 1; - else - got6 = 1; - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "address: calloc"); - n->af = p->af; - if (flags & PFI_AFLAG_BROADCAST) - memcpy(&n->addr.v.a.addr, &p->bcast, - sizeof(struct pf_addr)); - else if (flags & PFI_AFLAG_PEER) - memcpy(&n->addr.v.a.addr, &p->peer, - sizeof(struct pf_addr)); - else - memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, - sizeof(struct pf_addr)); - if (flags & PFI_AFLAG_NETWORK) - set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); - else { - if (n->af == AF_INET) { - if (p->ifa_flags & IFF_LOOPBACK && - p->ifa_flags & IFF_LINK1) - memcpy(&n->addr.v.a.mask, - &p->addr.v.a.mask, - sizeof(struct pf_addr)); - else - set_ipmask(n, 32); - } else - set_ipmask(n, 128); - } - n->ifindex = p->ifindex; - - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - return (h); -} - -int -ifa_skip_if(const char *filter, struct node_host *p) -{ - int n; - - if (p->af != AF_INET && p->af != AF_INET6) - return (1); - if (filter == NULL || !*filter) - return (0); - if (!strcmp(p->ifname, filter)) - return (0); /* exact match */ - n = strlen(filter); - if (n < 1 || n >= IFNAMSIZ) - return (1); /* sanity check */ - if (filter[n-1] >= '0' && filter[n-1] <= '9') - return (1); /* only do exact match in that case */ - if (strncmp(p->ifname, filter, n)) - return (1); /* prefix doesn't match */ - return (p->ifname[n] < '0' || p->ifname[n] > '9'); -} - - -struct node_host * -host(const char *s) -{ - struct node_host *h = NULL; - int mask, v4mask, v6mask, cont = 1; - char *p, *q, *ps; - - if ((p = strrchr(s, '/')) != NULL) { - mask = strtol(p+1, &q, 0); - if (!q || *q || mask > 128 || q == (p+1)) { - fprintf(stderr, "invalid netmask '%s'\n", p); - return (NULL); - } - if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) - err(1, "host: malloc"); - strlcpy(ps, s, strlen(s) - strlen(p) + 1); - v4mask = v6mask = mask; - } else { - if ((ps = strdup(s)) == NULL) - err(1, "host: strdup"); - v4mask = 32; - v6mask = 128; - mask = -1; - } - - /* interface with this name exists? */ - if (cont && (h = host_if(ps, mask)) != NULL) - cont = 0; - - /* IPv4 address? */ - if (cont && (h = host_v4(s, mask)) != NULL) - cont = 0; - - /* IPv6 address? */ - if (cont && (h = host_v6(ps, v6mask)) != NULL) - cont = 0; - - /* dns lookup */ - if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) - cont = 0; - free(ps); - - if (h == NULL || cont == 1) { - fprintf(stderr, "no IP address found for %s\n", s); - return (NULL); - } - return (h); -} - -struct node_host * -host_if(const char *s, int mask) -{ - struct node_host *n, *h = NULL; - char *p, *ps; - int flags = 0; - - if ((ps = strdup(s)) == NULL) - err(1, "host_if: strdup"); - while ((p = strrchr(ps, ':')) != NULL) { - if (!strcmp(p+1, "network")) - flags |= PFI_AFLAG_NETWORK; - else if (!strcmp(p+1, "broadcast")) - flags |= PFI_AFLAG_BROADCAST; - else if (!strcmp(p+1, "peer")) - flags |= PFI_AFLAG_PEER; - else if (!strcmp(p+1, "0")) - flags |= PFI_AFLAG_NOALIAS; - else { - free(ps); - return (NULL); - } - *p = '\0'; - } - if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ - fprintf(stderr, "illegal combination of interface modifiers\n"); - free(ps); - return (NULL); - } - if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { - fprintf(stderr, "network or broadcast lookup, but " - "extra netmask given\n"); - free(ps); - return (NULL); - } - if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { - /* interface with this name exists */ - h = ifa_lookup(ps, flags); - for (n = h; n != NULL && mask > -1; n = n->next) - set_ipmask(n, mask); - } - - free(ps); - return (h); -} - -struct node_host * -host_v4(const char *s, int mask) -{ - struct node_host *h = NULL; - struct in_addr ina; - int bits = 32; - - memset(&ina, 0, sizeof(struct in_addr)); - if (strrchr(s, '/') != NULL) { - if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) - return (NULL); - } else { - if (inet_pton(AF_INET, s, &ina) != 1) - return (NULL); - } - - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET; - h->addr.v.a.addr.addr32[0] = ina.s_addr; - set_ipmask(h, bits); - h->next = NULL; - h->tail = h; - - return (h); -} - -struct node_host * -host_v6(const char *s, int mask) -{ - struct addrinfo hints, *res; - struct node_host *h = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(s, "0", &hints, &res) == 0) { - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET6; - memcpy(&h->addr.v.a.addr, - &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, - sizeof(h->addr.v.a.addr)); - h->ifindex = - ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; - set_ipmask(h, mask); - freeaddrinfo(res); - h->next = NULL; - h->tail = h; - } - - return (h); -} - -struct node_host * -host_dns(const char *s, int v4mask, int v6mask) -{ - struct addrinfo hints, *res0, *res; - struct node_host *n, *h = NULL; - int error, noalias = 0; - int got4 = 0, got6 = 0; - char *p, *ps; - - if ((ps = strdup(s)) == NULL) - err(1, "host_dns: strdup"); - if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { - noalias = 1; - *p = '\0'; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; /* DUMMY */ - error = getaddrinfo(ps, NULL, &hints, &res0); - if (error) { - free(ps); - return (h); - } - - for (res = res0; res; res = res->ai_next) { - if (res->ai_family != AF_INET && - res->ai_family != AF_INET6) - continue; - if (noalias) { - if (res->ai_family == AF_INET) { - if (got4) - continue; - got4 = 1; - } else { - if (got6) - continue; - got6 = 1; - } - } - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "host_dns: calloc"); - n->ifname = NULL; - n->af = res->ai_family; - if (res->ai_family == AF_INET) { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in *) - res->ai_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - set_ipmask(n, v4mask); - } else { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in6 *) - res->ai_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - n->ifindex = - ((struct sockaddr_in6 *) - res->ai_addr)->sin6_scope_id; - set_ipmask(n, v6mask); - } - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - freeaddrinfo(res0); - free(ps); - - return (h); -} - -/* - * convert a hostname to a list of addresses and put them in the given buffer. - * test: - * if set to 1, only simple addresses are accepted (no netblock, no "!"). - */ -int -append_addr(struct pfr_buffer *b, char *s, int test) -{ - char *r; - struct node_host *h, *n; - int rv, not = 0; - - for (r = s; *r == '!'; r++) - not = !not; - if ((n = host(r)) == NULL) { - errno = 0; - return (-1); - } - rv = append_addr_host(b, n, test, not); - do { - h = n; - n = n->next; - free(h); - } while (n != NULL); - return (rv); -} - -/* - * same as previous function, but with a pre-parsed input and the ability - * to "negate" the result. Does not free the node_host list. - * not: - * setting it to 1 is equivalent to adding "!" in front of parameter s. - */ -int -append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) -{ - int bits; - struct pfr_addr addr; - - do { - bzero(&addr, sizeof(addr)); - addr.pfra_not = n->not ^ not; - addr.pfra_af = n->af; - addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); - switch (n->af) { - case AF_INET: - addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; - bits = 32; - break; - case AF_INET6: - memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, - sizeof(struct in6_addr)); - bits = 128; - break; - default: - errno = EINVAL; - return (-1); - } - if ((test && (not || addr.pfra_net != bits)) || - addr.pfra_net > bits) { - errno = EINVAL; - return (-1); - } - if (pfr_buf_add(b, &addr)) - return (-1); - } while ((n = n->next) != NULL); - - return (0); -} - -int -pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor) -{ - struct pfioc_trans_e trans; - - bzero(&trans, sizeof(trans)); - trans.rs_num = rs_num; - if (strlcpy(trans.anchor, anchor, - sizeof(trans.anchor)) >= sizeof(trans.anchor)) - errx(1, "pfctl_add_trans: strlcpy"); - - return pfr_buf_add(buf, &trans); -} - -u_int32_t -pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor) -{ - struct pfioc_trans_e *p; - - PFRB_FOREACH(p, buf) - if (rs_num == p->rs_num && !strcmp(anchor, p->anchor)) - return (p->ticket); - errx(1, "pfctl_get_ticket: assertion failed"); -} - -int -pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) -{ - struct pfioc_trans trans; - - bzero(&trans, sizeof(trans)); - trans.size = buf->pfrb_size - from; - trans.esize = sizeof(struct pfioc_trans_e); - trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; - return ioctl(dev, cmd, &trans); -} -#ifdef __rtems__ -#include "pfctl_parser-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_parser.h b/freebsd/contrib/pf/pfctl/pfctl_parser.h deleted file mode 100644 index 4560d66b..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_parser.h +++ /dev/null @@ -1,305 +0,0 @@ -/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _PFCTL_PARSER_H_ -#define _PFCTL_PARSER_H_ - -#define PF_OSFP_FILE "/etc/pf.os" - -#define PF_OPT_DISABLE 0x0001 -#define PF_OPT_ENABLE 0x0002 -#define PF_OPT_VERBOSE 0x0004 -#define PF_OPT_NOACTION 0x0008 -#define PF_OPT_QUIET 0x0010 -#define PF_OPT_CLRRULECTRS 0x0020 -#define PF_OPT_USEDNS 0x0040 -#define PF_OPT_VERBOSE2 0x0080 -#define PF_OPT_DUMMYACTION 0x0100 -#define PF_OPT_DEBUG 0x0200 -#define PF_OPT_SHOWALL 0x0400 -#define PF_OPT_OPTIMIZE 0x0800 -#define PF_OPT_NUMERIC 0x1000 -#define PF_OPT_MERGE 0x2000 -#define PF_OPT_RECURSE 0x4000 - -#define PF_TH_ALL 0xFF - -#define PF_NAT_PROXY_PORT_LOW 50001 -#define PF_NAT_PROXY_PORT_HIGH 65535 - -#define PF_OPTIMIZE_BASIC 0x0001 -#define PF_OPTIMIZE_PROFILE 0x0002 - -#define FCNT_NAMES { \ - "searches", \ - "inserts", \ - "removals", \ - NULL \ -} - -struct pfr_buffer; /* forward definition */ - - -struct pfctl { - int dev; - int opts; - int optimize; - int loadopt; - int asd; /* anchor stack depth */ - int bn; /* brace number */ - int brace; - int tdirty; /* kernel dirty */ -#define PFCTL_ANCHOR_STACK_DEPTH 64 - struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH]; - struct pfioc_pooladdr paddr; - struct pfioc_altq *paltq; - struct pfioc_queue *pqueue; - struct pfr_buffer *trans; - struct pf_anchor *anchor, *alast; - const char *ruleset; - - /* 'set foo' options */ - u_int32_t timeout[PFTM_MAX]; - u_int32_t limit[PF_LIMIT_MAX]; - u_int32_t debug; - u_int32_t hostid; - char *ifname; - - u_int8_t timeout_set[PFTM_MAX]; - u_int8_t limit_set[PF_LIMIT_MAX]; - u_int8_t debug_set; - u_int8_t hostid_set; - u_int8_t ifname_set; -}; - -struct node_if { - char ifname[IFNAMSIZ]; - u_int8_t not; - u_int8_t dynamic; /* antispoof */ - u_int ifa_flags; - struct node_if *next; - struct node_if *tail; -}; - -struct node_host { - struct pf_addr_wrap addr; - struct pf_addr bcast; - struct pf_addr peer; - sa_family_t af; - u_int8_t not; - u_int32_t ifindex; /* link-local IPv6 addrs */ - char *ifname; - u_int ifa_flags; - struct node_host *next; - struct node_host *tail; -}; - -struct node_os { - char *os; - pf_osfp_t fingerprint; - struct node_os *next; - struct node_os *tail; -}; - -struct node_queue_bw { - u_int32_t bw_absolute; - u_int16_t bw_percent; -}; - -struct node_hfsc_sc { - struct node_queue_bw m1; /* slope of 1st segment; bps */ - u_int d; /* x-projection of m1; msec */ - struct node_queue_bw m2; /* slope of 2nd segment; bps */ - u_int8_t used; -}; - -struct node_hfsc_opts { - struct node_hfsc_sc realtime; - struct node_hfsc_sc linkshare; - struct node_hfsc_sc upperlimit; - int flags; -}; - -struct node_queue_opt { - int qtype; - union { - struct cbq_opts cbq_opts; - struct priq_opts priq_opts; - struct node_hfsc_opts hfsc_opts; - } data; -}; - -#ifdef __FreeBSD__ -/* - * XXX - * Absolutely this is not correct location to define this. - * Should we use an another sperate header file? - */ -#define SIMPLEQ_HEAD STAILQ_HEAD -#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER -#define SIMPLEQ_ENTRY STAILQ_ENTRY -#define SIMPLEQ_FIRST STAILQ_FIRST -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY STAILQ_EMPTY -#define SIMPLEQ_NEXT STAILQ_NEXT -/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/ -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) -#define SIMPLEQ_INIT STAILQ_INIT -#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD -#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL -#define SIMPLEQ_INSERT_AFTER STAILQ_INSERT_AFTER -#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD -#endif -SIMPLEQ_HEAD(node_tinithead, node_tinit); -struct node_tinit { /* table initializer */ - SIMPLEQ_ENTRY(node_tinit) entries; - struct node_host *host; - char *file; -}; - - -/* optimizer created tables */ -struct pf_opt_tbl { - char pt_name[PF_TABLE_NAME_SIZE]; - int pt_rulecount; - int pt_generated; - struct node_tinithead pt_nodes; - struct pfr_buffer *pt_buf; -}; -#define PF_OPT_TABLE_PREFIX "__automatic_" - -/* optimizer pf_rule container */ -struct pf_opt_rule { - struct pf_rule por_rule; - struct pf_opt_tbl *por_src_tbl; - struct pf_opt_tbl *por_dst_tbl; - u_int64_t por_profile_count; - TAILQ_ENTRY(pf_opt_rule) por_entry; - TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT]; -}; - -TAILQ_HEAD(pf_opt_queue, pf_opt_rule); - -int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); -int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *); - -int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); -int pfctl_add_altq(struct pfctl *, struct pf_altq *); -int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); -void pfctl_move_pool(struct pf_pool *, struct pf_pool *); -void pfctl_clear_pool(struct pf_pool *); - -int pfctl_set_timeout(struct pfctl *, const char *, int, int); -int pfctl_set_optimization(struct pfctl *, const char *); -int pfctl_set_limit(struct pfctl *, const char *, unsigned int); -int pfctl_set_logif(struct pfctl *, char *); -int pfctl_set_hostid(struct pfctl *, u_int32_t); -int pfctl_set_debug(struct pfctl *, char *); -int pfctl_set_interface_flags(struct pfctl *, char *, int, int); - -int parse_config(char *, struct pfctl *); -int parse_flags(char *); -int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); - -void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); -void print_src_node(struct pf_src_node *, int); -void print_rule(struct pf_rule *, const char *, int, int); -void print_tabledef(const char *, int, int, struct node_tinithead *); -void print_status(struct pf_status *, int); - -int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *, - struct node_queue_opt *); -int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *, - struct node_queue_opt *); - -void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *, - struct node_queue_opt *); -void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, - int, struct node_queue_opt *); - -int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *, - u_int32_t); - -void pfctl_clear_fingerprints(int, int); -int pfctl_file_fingerprints(int, int, const char *); -pf_osfp_t pfctl_get_fingerprint(const char *); -int pfctl_load_fingerprints(int, int); -char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t); -void pfctl_show_fingerprints(int); - - -struct icmptypeent { - const char *name; - u_int8_t type; -}; - -struct icmpcodeent { - const char *name; - u_int8_t type; - u_int8_t code; -}; - -const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t); -const struct icmptypeent *geticmptypebyname(char *, u_int8_t); -const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t); -const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t); - -struct pf_timeout { - const char *name; - int timeout; -}; - -#define PFCTL_FLAG_FILTER 0x02 -#define PFCTL_FLAG_NAT 0x04 -#define PFCTL_FLAG_OPTION 0x08 -#define PFCTL_FLAG_ALTQ 0x10 -#define PFCTL_FLAG_TABLE 0x20 - -extern const struct pf_timeout pf_timeouts[]; - -void set_ipmask(struct node_host *, u_int8_t); -int check_netmask(struct node_host *, sa_family_t); -int unmask(struct pf_addr *, sa_family_t); -void ifa_load(void); -struct node_host *ifa_exists(const char *); -struct node_host *ifa_lookup(const char *, int); -struct node_host *host(const char *); - -int append_addr(struct pfr_buffer *, char *, int); -int append_addr_host(struct pfr_buffer *, - struct node_host *, int, int); - -#endif /* _PFCTL_PARSER_H_ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_qstats-data.h b/freebsd/contrib/pf/pfctl/pfctl_qstats-data.h deleted file mode 100644 index 275a184c..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_qstats-data.h +++ /dev/null @@ -1,3 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int32_t last_ticket); diff --git a/freebsd/contrib/pf/pfctl/pfctl_qstats.c b/freebsd/contrib/pf/pfctl/pfctl_qstats.c deleted file mode 100644 index 91bdb86c..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_qstats.c +++ /dev/null @@ -1,463 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */ - -/* - * Copyright (c) Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include "pfctl.h" -#include "pfctl_parser.h" - -union class_stats { - class_stats_t cbq_stats; - struct priq_classstats priq_stats; - struct hfsc_classstats hfsc_stats; -}; - -#define AVGN_MAX 8 -#define STAT_INTERVAL 5 - -struct queue_stats { - union class_stats data; - int avgn; - double avg_bytes; - double avg_packets; - u_int64_t prev_bytes; - u_int64_t prev_packets; -}; - -struct pf_altq_node { - struct pf_altq altq; - struct pf_altq_node *next; - struct pf_altq_node *children; - struct queue_stats qstats; -}; - -#ifdef __rtems__ -static u_int32_t last_ticket; - -#endif /* __rtems__ */ -int pfctl_update_qstats(int, struct pf_altq_node **); -void pfctl_insert_altq_node(struct pf_altq_node **, - const struct pf_altq, const struct queue_stats); -struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *, - const char *, const char *); -void pfctl_print_altq_node(int, const struct pf_altq_node *, - unsigned, int); -void print_cbqstats(struct queue_stats); -void print_priqstats(struct queue_stats); -void print_hfscstats(struct queue_stats); -void pfctl_free_altq_node(struct pf_altq_node *); -void pfctl_print_altq_nodestat(int, - const struct pf_altq_node *); - -void update_avg(struct pf_altq_node *); - -int -pfctl_show_altq(int dev, const char *iface, int opts, int verbose2) -{ - struct pf_altq_node *root = NULL, *node; - int nodes, dotitle = (opts & PF_OPT_SHOWALL); - -#ifdef __FreeBSD__ - if (!altqsupport) - return (-1); -#endif - - if ((nodes = pfctl_update_qstats(dev, &root)) < 0) - return (-1); - - if (nodes == 0) - printf("No queue in use\n"); - for (node = root; node != NULL; node = node->next) { - if (iface != NULL && strcmp(node->altq.ifname, iface)) - continue; - if (dotitle) { - pfctl_print_title("ALTQ:"); - dotitle = 0; - } - pfctl_print_altq_node(dev, node, 0, opts); - } - - while (verbose2 && nodes > 0) { - printf("\n"); - fflush(stdout); - sleep(STAT_INTERVAL); - if ((nodes = pfctl_update_qstats(dev, &root)) == -1) - return (-1); - for (node = root; node != NULL; node = node->next) { - if (iface != NULL && strcmp(node->altq.ifname, iface)) - continue; -#ifdef __FreeBSD__ - if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) - continue; -#endif - pfctl_print_altq_node(dev, node, 0, opts); - } - } - pfctl_free_altq_node(root); - return (0); -} - -int -pfctl_update_qstats(int dev, struct pf_altq_node **root) -{ - struct pf_altq_node *node; - struct pfioc_altq pa; - struct pfioc_qstats pq; - u_int32_t mnr, nr; - struct queue_stats qstats; -#ifndef __rtems__ - static u_int32_t last_ticket; -#endif /* __rtems__ */ - - memset(&pa, 0, sizeof(pa)); - memset(&pq, 0, sizeof(pq)); - memset(&qstats, 0, sizeof(qstats)); - if (ioctl(dev, DIOCGETALTQS, &pa)) { - warn("DIOCGETALTQS"); - return (-1); - } - - /* if a new set is found, start over */ - if (pa.ticket != last_ticket && *root != NULL) { - pfctl_free_altq_node(*root); - *root = NULL; - } - last_ticket = pa.ticket; - - mnr = pa.nr; - for (nr = 0; nr < mnr; ++nr) { - pa.nr = nr; - if (ioctl(dev, DIOCGETALTQ, &pa)) { - warn("DIOCGETALTQ"); - return (-1); - } -#ifdef __FreeBSD__ - if (pa.altq.qid > 0 && - !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { -#else - if (pa.altq.qid > 0) { -#endif - pq.nr = nr; - pq.ticket = pa.ticket; - pq.buf = &qstats.data; - pq.nbytes = sizeof(qstats.data); - if (ioctl(dev, DIOCGETQSTATS, &pq)) { - warn("DIOCGETQSTATS"); - return (-1); - } - if ((node = pfctl_find_altq_node(*root, pa.altq.qname, - pa.altq.ifname)) != NULL) { - memcpy(&node->qstats.data, &qstats.data, - sizeof(qstats.data)); - update_avg(node); - } else { - pfctl_insert_altq_node(root, pa.altq, qstats); - } - } -#ifdef __FreeBSD__ - else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { - memset(&qstats.data, 0, sizeof(qstats.data)); - if ((node = pfctl_find_altq_node(*root, pa.altq.qname, - pa.altq.ifname)) != NULL) { - memcpy(&node->qstats.data, &qstats.data, - sizeof(qstats.data)); - update_avg(node); - } else { - pfctl_insert_altq_node(root, pa.altq, qstats); - } - } -#endif - } - return (mnr); -} - -void -pfctl_insert_altq_node(struct pf_altq_node **root, - const struct pf_altq altq, const struct queue_stats qstats) -{ - struct pf_altq_node *node; - - node = calloc(1, sizeof(struct pf_altq_node)); - if (node == NULL) - err(1, "pfctl_insert_altq_node: calloc"); - memcpy(&node->altq, &altq, sizeof(struct pf_altq)); - memcpy(&node->qstats, &qstats, sizeof(qstats)); - node->next = node->children = NULL; - - if (*root == NULL) - *root = node; - else if (!altq.parent[0]) { - struct pf_altq_node *prev = *root; - - while (prev->next != NULL) - prev = prev->next; - prev->next = node; - } else { - struct pf_altq_node *parent; - - parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname); - if (parent == NULL) - errx(1, "parent %s not found", altq.parent); - if (parent->children == NULL) - parent->children = node; - else { - struct pf_altq_node *prev = parent->children; - - while (prev->next != NULL) - prev = prev->next; - prev->next = node; - } - } - update_avg(node); -} - -struct pf_altq_node * -pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, - const char *ifname) -{ - struct pf_altq_node *node, *child; - - for (node = root; node != NULL; node = node->next) { - if (!strcmp(node->altq.qname, qname) - && !(strcmp(node->altq.ifname, ifname))) - return (node); - if (node->children != NULL) { - child = pfctl_find_altq_node(node->children, qname, - ifname); - if (child != NULL) - return (child); - } - } - return (NULL); -} - -void -pfctl_print_altq_node(int dev, const struct pf_altq_node *node, - unsigned int level, int opts) -{ - const struct pf_altq_node *child; - - if (node == NULL) - return; - - print_altq(&node->altq, level, NULL, NULL); - - if (node->children != NULL) { - printf("{"); - for (child = node->children; child != NULL; - child = child->next) { - printf("%s", child->altq.qname); - if (child->next != NULL) - printf(", "); - } - printf("}"); - } - printf("\n"); - - if (opts & PF_OPT_VERBOSE) - pfctl_print_altq_nodestat(dev, node); - - if (opts & PF_OPT_DEBUG) - printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", - node->altq.qid, node->altq.ifname, - rate2str((double)(node->altq.ifbandwidth))); - - for (child = node->children; child != NULL; - child = child->next) - pfctl_print_altq_node(dev, child, level + 1, opts); -} - -void -pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) -{ - if (a->altq.qid == 0) - return; - -#ifdef __FreeBSD__ - if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) - return; -#endif - switch (a->altq.scheduler) { - case ALTQT_CBQ: - print_cbqstats(a->qstats); - break; - case ALTQT_PRIQ: - print_priqstats(a->qstats); - break; - case ALTQT_HFSC: - print_hfscstats(a->qstats); - break; - } -} - -void -print_cbqstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets, - (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes, - (unsigned long long)cur.data.cbq_stats.drop_cnt.packets, - (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes); - printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n", - cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax, - cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -print_priqstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.priq_stats.xmitcnt.packets, - (unsigned long long)cur.data.priq_stats.xmitcnt.bytes, - (unsigned long long)cur.data.priq_stats.dropcnt.packets, - (unsigned long long)cur.data.priq_stats.dropcnt.bytes); - printf(" [ qlength: %3d/%3d ]\n", - cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -print_hfscstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets, - (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes, - (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets, - (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes); - printf(" [ qlength: %3d/%3d ]\n", - cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -pfctl_free_altq_node(struct pf_altq_node *node) -{ - while (node != NULL) { - struct pf_altq_node *prev; - - if (node->children != NULL) - pfctl_free_altq_node(node->children); - prev = node; - node = node->next; - free(prev); - } -} - -void -update_avg(struct pf_altq_node *a) -{ - struct queue_stats *qs; - u_int64_t b, p; - int n; - - if (a->altq.qid == 0) - return; - - qs = &a->qstats; - n = qs->avgn; - - switch (a->altq.scheduler) { - case ALTQT_CBQ: - b = qs->data.cbq_stats.xmit_cnt.bytes; - p = qs->data.cbq_stats.xmit_cnt.packets; - break; - case ALTQT_PRIQ: - b = qs->data.priq_stats.xmitcnt.bytes; - p = qs->data.priq_stats.xmitcnt.packets; - break; - case ALTQT_HFSC: - b = qs->data.hfsc_stats.xmit_cnt.bytes; - p = qs->data.hfsc_stats.xmit_cnt.packets; - break; - default: - b = 0; - p = 0; - break; - } - - if (n == 0) { - qs->prev_bytes = b; - qs->prev_packets = p; - qs->avgn++; - return; - } - - if (b >= qs->prev_bytes) - qs->avg_bytes = ((qs->avg_bytes * (n - 1)) + - (b - qs->prev_bytes)) / n; - - if (p >= qs->prev_packets) - qs->avg_packets = ((qs->avg_packets * (n - 1)) + - (p - qs->prev_packets)) / n; - - qs->prev_bytes = b; - qs->prev_packets = p; - if (n < AVGN_MAX) - qs->avgn++; -} -#ifdef __rtems__ -#include "pfctl_qstats-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_radix-data.h b/freebsd/contrib/pf/pfctl/pfctl_radix-data.h deleted file mode 100644 index bcb5f3bb..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_radix-data.h +++ /dev/null @@ -1,3 +0,0 @@ -#include <rtems/linkersets.h> - -RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char next_ch); diff --git a/freebsd/contrib/pf/pfctl/pfctl_radix.c b/freebsd/contrib/pf/pfctl/pfctl_radix.c deleted file mode 100644 index cc5b0acd..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_radix.c +++ /dev/null @@ -1,602 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */ - -/* - * Copyright (c) 2002 Cedric Berger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <err.h> - -#include "pfctl.h" - -#define BUF_SIZE 256 - -extern int dev; - -static int pfr_next_token(char buf[], FILE *); - - -int -pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) -{ - struct pfioc_table io; - - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - if (ioctl(dev, DIOCRCLRTABLES, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRADDTABLES, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - return (0); -} - -int -pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRDELTABLES, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, - int flags) -{ - struct pfioc_table io; - - if (size == NULL || *size < 0 || (*size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETTABLES, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, - int flags) -{ - struct pfioc_table io; - - if (size == NULL || *size < 0 || (*size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETTSTATS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - if (ioctl(dev, DIOCRCLRADDRS, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nadd, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRADDADDRS, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - return (0); -} - -int -pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *ndel, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRDELADDRS, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *size2, int *nadd, int *ndel, int *nchange, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; - if (ioctl(dev, DIOCRSETADDRS, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - if (ndel != NULL) - *ndel = io.pfrio_ndel; - if (nchange != NULL) - *nchange = io.pfrio_nchange; - if (size2 != NULL) - *size2 = io.pfrio_size2; - return (0); -} - -int -pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, - int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size == NULL || *size < 0 || - (*size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETADDRS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, - int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size == NULL || *size < 0 || - (*size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETASTATS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && !tbl)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRCLRTSTATS, &io)) - return (-1); - if (nzero) - *nzero = io.pfrio_nzero; - return (0); -} - -int -pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nmatch, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRTSTADDRS, &io)) - return (-1); - if (nmatch) - *nmatch = io.pfrio_nmatch; - return (0); -} - -int -pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nadd, int *naddr, int ticket, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - io.pfrio_ticket = ticket; - if (ioctl(dev, DIOCRINADEFINE, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - if (naddr != NULL) - *naddr = io.pfrio_naddr; - return (0); -} - -/* interface management code */ - -int -pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) -{ - struct pfioc_iface io; - - if (size == NULL || *size < 0 || (*size && buf == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - if (filter != NULL) - if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= - sizeof(io.pfiio_name)) { - errno = EINVAL; - return (-1); - } - io.pfiio_buffer = buf; - io.pfiio_esize = sizeof(*buf); - io.pfiio_size = *size; - if (ioctl(dev, DIOCIGETIFACES, &io)) - return (-1); - *size = io.pfiio_size; - return (0); -} - -/* buffer management code */ - -#ifndef __rtems__ -size_t buf_esize[PFRB_MAX] = { 0, -#else /* __rtems__ */ -const size_t buf_esize[PFRB_MAX] = { 0, -#endif /* __rtems__ */ - sizeof(struct pfr_table), sizeof(struct pfr_tstats), - sizeof(struct pfr_addr), sizeof(struct pfr_astats), - sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) -}; - -/* - * add one element to the buffer - */ -int -pfr_buf_add(struct pfr_buffer *b, const void *e) -{ - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || - e == NULL) { - errno = EINVAL; - return (-1); - } - bs = buf_esize[b->pfrb_type]; - if (b->pfrb_size == b->pfrb_msize) - if (pfr_buf_grow(b, 0)) - return (-1); - memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); - b->pfrb_size++; - return (0); -} - -/* - * return next element of the buffer (or first one if prev is NULL) - * see PFRB_FOREACH macro - */ -void * -pfr_buf_next(struct pfr_buffer *b, const void *prev) -{ - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) - return (NULL); - if (b->pfrb_size == 0) - return (NULL); - if (prev == NULL) - return (b->pfrb_caddr); - bs = buf_esize[b->pfrb_type]; - if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) - return (NULL); - return (((caddr_t)prev) + bs); -} - -/* - * minsize: - * 0: make the buffer somewhat bigger - * n: make room for "n" entries in the buffer - */ -int -pfr_buf_grow(struct pfr_buffer *b, int minsize) -{ - caddr_t p; - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { - errno = EINVAL; - return (-1); - } - if (minsize != 0 && minsize <= b->pfrb_msize) - return (0); - bs = buf_esize[b->pfrb_type]; - if (!b->pfrb_msize) { - if (minsize < 64) - minsize = 64; - b->pfrb_caddr = calloc(bs, minsize); - if (b->pfrb_caddr == NULL) - return (-1); - b->pfrb_msize = minsize; - } else { - if (minsize == 0) - minsize = b->pfrb_msize * 2; - if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { - /* msize overflow */ - errno = ENOMEM; - return (-1); - } - p = realloc(b->pfrb_caddr, minsize * bs); - if (p == NULL) - return (-1); - bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); - b->pfrb_caddr = p; - b->pfrb_msize = minsize; - } - return (0); -} - -/* - * reset buffer and free memory. - */ -void -pfr_buf_clear(struct pfr_buffer *b) -{ - if (b == NULL) - return; - if (b->pfrb_caddr != NULL) - free(b->pfrb_caddr); - b->pfrb_caddr = NULL; - b->pfrb_size = b->pfrb_msize = 0; -} - -int -pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, - int (*append_addr)(struct pfr_buffer *, char *, int)) -{ - FILE *fp; - char buf[BUF_SIZE]; - int rv; - - if (file == NULL) - return (0); - if (!strcmp(file, "-")) - fp = stdin; - else { - fp = pfctl_fopen(file, "r"); - if (fp == NULL) - return (-1); - } - while ((rv = pfr_next_token(buf, fp)) == 1) - if (append_addr(b, buf, nonetwork)) { - rv = -1; - break; - } - if (fp != stdin) - fclose(fp); - return (rv); -} - -#ifdef __rtems__ -static char next_ch = ' '; -#endif /* __rtems__ */ -int -pfr_next_token(char buf[BUF_SIZE], FILE *fp) -{ -#ifndef __rtems__ - static char next_ch = ' '; -#endif /* __rtems__ */ - int i = 0; - - for (;;) { - /* skip spaces */ - while (isspace(next_ch) && !feof(fp)) - next_ch = fgetc(fp); - /* remove from '#' until end of line */ - if (next_ch == '#') - while (!feof(fp)) { - next_ch = fgetc(fp); - if (next_ch == '\n') - break; - } - else - break; - } - if (feof(fp)) { - next_ch = ' '; - return (0); - } - do { - if (i < BUF_SIZE) - buf[i++] = next_ch; - next_ch = fgetc(fp); - } while (!feof(fp) && !isspace(next_ch)); - if (i >= BUF_SIZE) { - errno = EINVAL; - return (-1); - } - buf[i] = '\0'; - return (1); -} - -char * -pfr_strerror(int errnum) -{ - switch (errnum) { - case ESRCH: - return "Table does not exist"; - case ENOENT: - return "Anchor or Ruleset does not exist"; - default: - return strerror(errnum); - } -} -#ifdef __rtems__ -#include "pfctl_radix-data.h" -#endif /* __rtems__ */ diff --git a/freebsd/contrib/pf/pfctl/pfctl_table.c b/freebsd/contrib/pf/pfctl/pfctl_table.c deleted file mode 100644 index 6fad082d..00000000 --- a/freebsd/contrib/pf/pfctl/pfctl_table.c +++ /dev/null @@ -1,644 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ - -/* - * Copyright (c) 2002 Cedric Berger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifdef __rtems__ -#include <machine/rtems-bsd-program.h> -#endif /* __rtems__ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <netdb.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -extern void usage(void); -static int pfctl_table(int, char *[], char *, const char *, char *, - const char *, int); -static void print_table(struct pfr_table *, int, int); -static void print_tstats(struct pfr_tstats *, int); -static int load_addr(struct pfr_buffer *, int, char *[], char *, int); -static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); -static void print_astats(struct pfr_astats *, int); -static void radix_perror(void); -static void xprintf(int, const char *, ...); -static void print_iface(struct pfi_kif *, int); - -static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { - { "In/Block:", "In/Pass:", "In/XPass:" }, - { "Out/Block:", "Out/Pass:", "Out/XPass:" } -}; - -static const char *istats_text[2][2][2] = { - { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, - { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } -}; - -#define RVTEST(fct) do { \ - if ((!(opts & PF_OPT_NOACTION) || \ - (opts & PF_OPT_DUMMYACTION)) && \ - (fct)) { \ - radix_perror(); \ - goto _error; \ - } \ - } while (0) - -#define CREATE_TABLE do { \ - table.pfrt_flags |= PFR_TFLAG_PERSIST; \ - if ((!(opts & PF_OPT_NOACTION) || \ - (opts & PF_OPT_DUMMYACTION)) && \ - (pfr_add_tables(&table, 1, &nadd, flags)) && \ - (errno != EPERM)) { \ - radix_perror(); \ - goto _error; \ - } \ - if (nadd) { \ - warn_namespace_collision(table.pfrt_name); \ - xprintf(opts, "%d table created", nadd); \ - if (opts & PF_OPT_NOACTION) \ - return (0); \ - } \ - table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ - } while(0) - -int -pfctl_clear_tables(const char *anchor, int opts) -{ - return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts); -} - -int -pfctl_show_tables(const char *anchor, int opts) -{ - return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts); -} - -int -pfctl_command_tables(int argc, char *argv[], char *tname, - const char *command, char *file, const char *anchor, int opts) -{ - if (tname == NULL || command == NULL) - usage(); - return pfctl_table(argc, argv, tname, command, file, anchor, opts); -} - -int -pfctl_table(int argc, char *argv[], char *tname, const char *command, - char *file, const char *anchor, int opts) -{ - struct pfr_table table; - struct pfr_buffer b, b2; - struct pfr_addr *a, *a2; - int nadd = 0, ndel = 0, nchange = 0, nzero = 0; - int rv = 0, flags = 0, nmatch = 0; - void *p; - - if (command == NULL) - usage(); - if (opts & PF_OPT_NOACTION) - flags |= PFR_FLAG_DUMMY; - - bzero(&b, sizeof(b)); - bzero(&b2, sizeof(b2)); - bzero(&table, sizeof(table)); - if (tname != NULL) { - if (strlen(tname) >= PF_TABLE_NAME_SIZE) - usage(); - if (strlcpy(table.pfrt_name, tname, - sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) - errx(1, "pfctl_table: strlcpy"); - } - if (strlcpy(table.pfrt_anchor, anchor, - sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor)) - errx(1, "pfctl_table: strlcpy"); - - if (!strcmp(command, "-F")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_clr_tables(&table, &ndel, flags)); - xprintf(opts, "%d tables deleted", ndel); - } else if (!strcmp(command, "-s")) { - b.pfrb_type = (opts & PF_OPT_VERBOSE2) ? - PFRB_TSTATS : PFRB_TABLES; - if (argc || file != NULL) - usage(); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (opts & PF_OPT_VERBOSE2) - RVTEST(pfr_get_tstats(&table, - b.pfrb_caddr, &b.pfrb_size, flags)); - else - RVTEST(pfr_get_tables(&table, - b.pfrb_caddr, &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - - if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) - pfctl_print_title("TABLES:"); - - PFRB_FOREACH(p, &b) - if (opts & PF_OPT_VERBOSE2) - print_tstats(p, opts & PF_OPT_DEBUG); - else - print_table(p, opts & PF_OPT_VERBOSE, - opts & PF_OPT_DEBUG); - } else if (!strcmp(command, "kill")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_del_tables(&table, 1, &ndel, flags)); - xprintf(opts, "%d table deleted", ndel); - } else if (!strcmp(command, "flush")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_clr_addrs(&table, &ndel, flags)); - xprintf(opts, "%d addresses deleted", ndel); - } else if (!strcmp(command, "add")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - CREATE_TABLE; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &nadd, flags)); - xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "delete")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &ndel, flags)); - xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "replace")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - CREATE_TABLE; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - for (;;) { - int sz2 = b.pfrb_msize; - - RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &sz2, &nadd, &ndel, &nchange, flags)); - if (sz2 <= b.pfrb_msize) { - b.pfrb_size = sz2; - break; - } else - pfr_buf_grow(&b, sz2); - } - if (nadd) - xprintf(opts, "%d addresses added", nadd); - if (ndel) - xprintf(opts, "%d addresses deleted", ndel); - if (nchange) - xprintf(opts, "%d addresses changed", nchange); - if (!nadd && !ndel && !nchange) - xprintf(opts, "no changes"); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "expire")) { - const char *errstr; - u_int lifetime; - - b.pfrb_type = PFRB_ASTATS; - b2.pfrb_type = PFRB_ADDRS; - if (argc != 1 || file != NULL) - usage(); - lifetime = strtonum(*argv, 0, UINT_MAX, &errstr); - if (errstr) - errx(1, "expiry time: %s", errstr); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - RVTEST(pfr_get_astats(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(p, &b) { - ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; - if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > - lifetime) - if (pfr_buf_add(&b2, - &((struct pfr_astats *)p)->pfras_a)) - err(1, "duplicate buffer"); - } - - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, - &ndel, flags)); - xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b2) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "show")) { - b.pfrb_type = (opts & PF_OPT_VERBOSE) ? - PFRB_ASTATS : PFRB_ADDRS; - if (argc || file != NULL) - usage(); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (opts & PF_OPT_VERBOSE) - RVTEST(pfr_get_astats(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - else - RVTEST(pfr_get_addrs(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(p, &b) - if (opts & PF_OPT_VERBOSE) - print_astats(p, opts & PF_OPT_USEDNS); - else - print_addrx(p, NULL, opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "test")) { - b.pfrb_type = PFRB_ADDRS; - b2.pfrb_type = PFRB_ADDRS; - - if (load_addr(&b, argc, argv, file, 1)) - goto _error; - if (opts & PF_OPT_VERBOSE2) { - flags |= PFR_FLAG_REPLACE; - PFRB_FOREACH(a, &b) - if (pfr_buf_add(&b2, a)) - err(1, "duplicate buffer"); - } - RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &nmatch, flags)); - xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); - if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2)) - PFRB_FOREACH(a, &b) - if (a->pfra_fback == PFR_FB_MATCH) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - if (opts & PF_OPT_VERBOSE2) { - a2 = NULL; - PFRB_FOREACH(a, &b) { - a2 = pfr_buf_next(&b2, a2); - print_addrx(a2, a, opts & PF_OPT_USEDNS); - } - } - if (nmatch < b.pfrb_size) - rv = 2; - } else if (!strcmp(command, "zero")) { - if (argc || file != NULL) - usage(); - flags |= PFR_FLAG_ADDRSTOO; - RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags)); - xprintf(opts, "%d table/stats cleared", nzero); - } else - warnx("pfctl_table: unknown command '%s'", command); - goto _cleanup; - -_error: - rv = -1; -_cleanup: - pfr_buf_clear(&b); - pfr_buf_clear(&b2); - return (rv); -} - -void -print_table(struct pfr_table *ta, int verbose, int debug) -{ - if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) - return; - if (verbose) { - printf("%c%c%c%c%c%c%c\t%s", - (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', - (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', - (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', - (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', - (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', - (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', - (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', - ta->pfrt_name); - if (ta->pfrt_anchor[0]) - printf("\t%s", ta->pfrt_anchor); - puts(""); - } else - puts(ta->pfrt_name); -} - -void -print_tstats(struct pfr_tstats *ts, int debug) -{ - time_t time = ts->pfrts_tzero; - int dir, op; - - if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) - return; - print_table(&ts->pfrts_t, 1, debug); - printf("\tAddresses: %d\n", ts->pfrts_cnt); - printf("\tCleared: %s", ctime(&time)); - printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n", - ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], - ts->pfrts_refcnt[PFR_REFCNT_RULE]); - printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", - (unsigned long long)ts->pfrts_nomatch, - (unsigned long long)ts->pfrts_match); - for (dir = 0; dir < PFR_DIR_MAX; dir++) - for (op = 0; op < PFR_OP_TABLE_MAX; op++) - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - stats_text[dir][op], - (unsigned long long)ts->pfrts_packets[dir][op], - (unsigned long long)ts->pfrts_bytes[dir][op]); -} - -int -load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file, - int nonetwork) -{ - while (argc--) - if (append_addr(b, *argv++, nonetwork)) { - if (errno) - warn("cannot decode %s", argv[-1]); - return (-1); - } - if (pfr_buf_load(b, file, nonetwork, append_addr)) { - warn("cannot load %s", file); - return (-1); - } - return (0); -} - -void -print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) -{ - char ch, buf[256] = "{error}"; - char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; - unsigned int fback, hostnet; - - fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; - ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?'; - hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32; - inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf)); - printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf); - if (ad->pfra_net < hostnet) - printf("/%d", ad->pfra_net); - if (rad != NULL && fback != PFR_FB_NONE) { - if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf)) - errx(1, "print_addrx: strlcpy"); - inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf)); - printf("\t%c%s", (rad->pfra_not?'!':' '), buf); - if (rad->pfra_net < hostnet) - printf("/%d", rad->pfra_net); - } - if (rad != NULL && fback == PFR_FB_NONE) - printf("\t nomatch"); - if (dns && ad->pfra_net == hostnet) { - char host[NI_MAXHOST]; - union sockaddr_union sa; - - strlcpy(host, "?", sizeof(host)); - bzero(&sa, sizeof(sa)); - sa.sa.sa_family = ad->pfra_af; - if (sa.sa.sa_family == AF_INET) { - sa.sa.sa_len = sizeof(sa.sin); - sa.sin.sin_addr = ad->pfra_ip4addr; - } else { - sa.sa.sa_len = sizeof(sa.sin6); - sa.sin6.sin6_addr = ad->pfra_ip6addr; - } - if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host), - NULL, 0, NI_NAMEREQD) == 0) - printf("\t(%s)", host); - } - printf("\n"); -} - -void -print_astats(struct pfr_astats *as, int dns) -{ - time_t time = as->pfras_tzero; - int dir, op; - - print_addrx(&as->pfras_a, NULL, dns); - printf("\tCleared: %s", ctime(&time)); - if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) - return; - for (dir = 0; dir < PFR_DIR_MAX; dir++) - for (op = 0; op < PFR_OP_ADDR_MAX; op++) - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - stats_text[dir][op], - (unsigned long long)as->pfras_packets[dir][op], - (unsigned long long)as->pfras_bytes[dir][op]); -} - -void -radix_perror(void) -{ -#ifndef __rtems__ - extern char *__progname; -#else /* __rtems__ */ -#define __progname "pfctl" -#endif /* __rtems__ */ - fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno)); -} - -int -pfctl_define_table(char *name, int flags, int addrs, const char *anchor, - struct pfr_buffer *ab, u_int32_t ticket) -{ - struct pfr_table tbl; - - bzero(&tbl, sizeof(tbl)); - if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= - sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, - sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) - errx(1, "pfctl_define_table: strlcpy"); - tbl.pfrt_flags = flags; - - return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, - NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); -} - -void -warn_namespace_collision(const char *filter) -{ - struct pfr_buffer b; - struct pfr_table *t; - const char *name = NULL, *lastcoll; - int coll = 0; - - bzero(&b, sizeof(b)); - b.pfrb_type = PFRB_TABLES; - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (pfr_get_tables(NULL, b.pfrb_caddr, - &b.pfrb_size, PFR_FLAG_ALLRSETS)) - err(1, "pfr_get_tables"); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(t, &b) { - if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE)) - continue; - if (filter != NULL && strcmp(filter, t->pfrt_name)) - continue; - if (!t->pfrt_anchor[0]) - name = t->pfrt_name; - else if (name != NULL && !strcmp(name, t->pfrt_name)) { - coll++; - lastcoll = name; - name = NULL; - } - } - if (coll == 1) - warnx("warning: namespace collision with <%s> global table.", - lastcoll); - else if (coll > 1) - warnx("warning: namespace collisions with %d global tables.", - coll); - pfr_buf_clear(&b); -} - -void -xprintf(int opts, const char *fmt, ...) -{ - va_list args; - - if (opts & PF_OPT_QUIET) - return; - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - if (opts & PF_OPT_DUMMYACTION) - fprintf(stderr, " (dummy).\n"); - else if (opts & PF_OPT_NOACTION) - fprintf(stderr, " (syntax only).\n"); - else - fprintf(stderr, ".\n"); -} - - -/* interface stuff */ - -int -pfctl_show_ifaces(const char *filter, int opts) -{ - struct pfr_buffer b; - struct pfi_kif *p; - int i = 0; - - bzero(&b, sizeof(b)); - b.pfrb_type = PFRB_IFACES; - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { - radix_perror(); - return (1); - } - if (b.pfrb_size <= b.pfrb_msize) - break; - i++; - } - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("INTERFACES:"); - PFRB_FOREACH(p, &b) - print_iface(p, opts); - return (0); -} - -void -print_iface(struct pfi_kif *p, int opts) -{ - time_t tzero = p->pfik_tzero; - int i, af, dir, act; - - printf("%s", p->pfik_name); - if (opts & PF_OPT_VERBOSE) { - if (p->pfik_flags & PFI_IFLAG_SKIP) - printf(" (skip)"); - } - printf("\n"); - - if (!(opts & PF_OPT_VERBOSE2)) - return; - printf("\tCleared: %s", ctime(&tzero)); - printf("\tReferences: [ States: %-18d Rules: %-18d ]\n", - p->pfik_states, p->pfik_rules); - for (i = 0; i < 8; i++) { - af = (i>>2) & 1; - dir = (i>>1) &1; - act = i & 1; - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - istats_text[af][dir][act], - (unsigned long long)p->pfik_packets[af][dir][act], - (unsigned long long)p->pfik_bytes[af][dir][act]); - } -} |