summaryrefslogtreecommitdiffstats
path: root/freebsd/contrib
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/contrib
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/contrib')
-rw-r--r--freebsd/contrib/libxo/libxo/libxo.c8080
-rw-r--r--freebsd/contrib/libxo/libxo/xo.h666
-rw-r--r--freebsd/contrib/libxo/libxo/xo_buf.h158
-rw-r--r--freebsd/contrib/libxo/libxo/xo_config.h254
-rw-r--r--freebsd/contrib/libxo/libxo/xo_encoder.c435
-rw-r--r--freebsd/contrib/libxo/libxo/xo_encoder.h116
-rw-r--r--freebsd/contrib/libxo/libxo/xo_humanize.h169
-rw-r--r--freebsd/contrib/libxo/libxo/xo_wcwidth.h313
-rw-r--r--freebsd/contrib/pf/pfctl/parse-data.h42
-rw-r--r--freebsd/contrib/pf/pfctl/parse.c9013
-rw-r--r--freebsd/contrib/pf/pfctl/parse.y6139
-rw-r--r--freebsd/contrib/pf/pfctl/pf_print_state.c385
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl-data.h26
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl.c2529
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl.h130
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_altq-data.h8
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_altq.c1284
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_optimize-data.h13
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_optimize.c1703
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_osfp-data.h7
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_osfp.c1133
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_parser-data.h3
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_parser.c1778
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_parser.h305
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_qstats-data.h3
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_qstats.c463
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_radix-data.h3
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_radix.c602
-rw-r--r--freebsd/contrib/pf/pfctl/pfctl_table.c644
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[] = "&amp;";
+static char xo_xml_lt[] = "&lt;";
+static char xo_xml_gt[] = "&gt;";
+static char xo_xml_quot[] = "&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]);
- }
-}