summaryrefslogtreecommitdiffstats
path: root/contrib/pf
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2012-09-14 11:51:49 +0000
committerglebius <glebius@FreeBSD.org>2012-09-14 11:51:49 +0000
commit0ccf4838d7a8b4da2c3beaac7ea1fd977aa0ed11 (patch)
treeec60da6e90cde2e87aa91ac9450c84ce3446233a /contrib/pf
parentf99fc207edf21e7c05c1147864077ce3fe1f3e2c (diff)
downloadFreeBSD-src-0ccf4838d7a8b4da2c3beaac7ea1fd977aa0ed11.zip
FreeBSD-src-0ccf4838d7a8b4da2c3beaac7ea1fd977aa0ed11.tar.gz
o Create directory sys/netpfil, where all packet filters should
reside, and move there ipfw(4) and pf(4). o Move most modified parts of pf out of contrib. Actual movements: sys/contrib/pf/net/*.c -> sys/netpfil/pf/ sys/contrib/pf/net/*.h -> sys/net/ contrib/pf/pfctl/*.c -> sbin/pfctl contrib/pf/pfctl/*.h -> sbin/pfctl contrib/pf/pfctl/pfctl.8 -> sbin/pfctl contrib/pf/pfctl/*.4 -> share/man/man4 contrib/pf/pfctl/*.5 -> share/man/man5 sys/netinet/ipfw -> sys/netpfil/ipfw The arguable movement is pf/net/*.h -> sys/net. There are future plans to refactor pf includes, so I decided not to break things twice. Not modified bits of pf left in contrib: authpf, ftp-proxy, tftp-proxy, pflogd. The ipfw(4) movement is planned to be merged to stable/9, to make head and stable match. Discussed with: bz, luigi
Diffstat (limited to 'contrib/pf')
-rw-r--r--contrib/pf/man/pf.41175
-rw-r--r--contrib/pf/man/pf.conf.53066
-rw-r--r--contrib/pf/man/pf.os.5223
-rw-r--r--contrib/pf/man/pflog.4107
-rw-r--r--contrib/pf/man/pfsync.4229
-rw-r--r--contrib/pf/pfctl/parse.y6038
-rw-r--r--contrib/pf/pfctl/pf_print_state.c375
-rw-r--r--contrib/pf/pfctl/pfctl.8687
-rw-r--r--contrib/pf/pfctl/pfctl.c2391
-rw-r--r--contrib/pf/pfctl/pfctl.h130
-rw-r--r--contrib/pf/pfctl/pfctl_altq.c1258
-rw-r--r--contrib/pf/pfctl/pfctl_optimize.c1655
-rw-r--r--contrib/pf/pfctl/pfctl_osfp.c1108
-rw-r--r--contrib/pf/pfctl/pfctl_parser.c1746
-rw-r--r--contrib/pf/pfctl/pfctl_parser.h305
-rw-r--r--contrib/pf/pfctl/pfctl_qstats.c449
-rw-r--r--contrib/pf/pfctl/pfctl_radix.c585
-rw-r--r--contrib/pf/pfctl/pfctl_table.c634
18 files changed, 0 insertions, 22161 deletions
diff --git a/contrib/pf/man/pf.4 b/contrib/pf/man/pf.4
deleted file mode 100644
index 635078d..0000000
--- a/contrib/pf/man/pf.4
+++ /dev/null
@@ -1,1175 +0,0 @@
-.\" $OpenBSD: pf.4,v 1.62 2008/09/10 14:57:37 jmc Exp $
-.\"
-.\" Copyright (C) 2001, Kjell Wooding. 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.
-.\" 3. Neither the name of the project 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 PROJECT 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 PROJECT 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$
-.\"
-.Dd June 29 2012
-.Dt PF 4
-.Os
-.Sh NAME
-.Nm pf
-.Nd packet filter
-.Sh SYNOPSIS
-.Cd "device pf"
-.Sh DESCRIPTION
-Packet filtering takes place in the kernel.
-A pseudo-device,
-.Pa /dev/pf ,
-allows userland processes to control the
-behavior of the packet filter through an
-.Xr ioctl 2
-interface.
-There are commands to enable and disable the filter, load rulesets,
-add and remove individual rules or state table entries,
-and retrieve statistics.
-The most commonly used functions are covered by
-.Xr pfctl 8 .
-.Pp
-Manipulations like loading a ruleset that involve more than a single
-.Xr ioctl 2
-call require a so-called
-.Em ticket ,
-which prevents the occurrence of
-multiple concurrent manipulations.
-.Pp
-Fields of
-.Xr ioctl 2
-parameter structures that refer to packet data (like
-addresses and ports) are generally expected in network byte-order.
-.Pp
-Rules and address tables are contained in so-called
-.Em anchors .
-When servicing an
-.Xr ioctl 2
-request, if the anchor field of the argument structure is empty,
-the kernel will use the default anchor (i.e., the main ruleset)
-in operations.
-Anchors are specified by name and may be nested, with components
-separated by
-.Sq /
-characters, similar to how file system hierarchies are laid out.
-The final component of the anchor path is the anchor under which
-operations will be performed.
-.Sh SYSCTL VARIABLES AND LOADER TUNABLES
-The following
-.Xr loader 8
-tunables are available.
-.Bl -tag -width indent
-.It Va net.pf.states_hashsize
-Size of hash tables that store states.
-Should be power of 2.
-Default value is 32768.
-.It Va net.pf.source_nodes_hashsize
-Size of hash table that store source nodes.
-Should be power of 2.
-Default value is 8192.
-.El
-.Pp
-Read only
-.Xr sysctl 8
-variables with matching names are provided to obtain current values
-at runtime.
-.Sh IOCTL INTERFACE
-.Nm
-supports the following
-.Xr ioctl 2
-commands, available through
-.Aq Pa net/pfvar.h :
-.Bl -tag -width xxxxxx
-.It Dv DIOCSTART
-Start the packet filter.
-.It Dv DIOCSTOP
-Stop the packet filter.
-.It Dv DIOCSTARTALTQ
-Start the ALTQ bandwidth control system (see
-.Xr altq 9 ) .
-.It Dv DIOCSTOPALTQ
-Stop the ALTQ bandwidth control system.
-.It Dv DIOCBEGINADDRS Fa "struct pfioc_pooladdr *pp"
-.Bd -literal
-struct pfioc_pooladdr {
- u_int32_t action;
- u_int32_t ticket;
- u_int32_t nr;
- u_int32_t r_num;
- u_int8_t r_action;
- u_int8_t r_last;
- u_int8_t af;
- char anchor[MAXPATHLEN];
- struct pf_pooladdr addr;
-};
-.Ed
-.Pp
-Clear the buffer address pool and get a
-.Va ticket
-for subsequent
-.Dv DIOCADDADDR ,
-.Dv DIOCADDRULE ,
-and
-.Dv DIOCCHANGERULE
-calls.
-.It Dv DIOCADDADDR Fa "struct pfioc_pooladdr *pp"
-.Pp
-Add the pool address
-.Va addr
-to the buffer address pool to be used in the following
-.Dv DIOCADDRULE
-or
-.Dv DIOCCHANGERULE
-call.
-All other members of the structure are ignored.
-.It Dv DIOCADDRULE Fa "struct pfioc_rule *pr"
-.Bd -literal
-struct pfioc_rule {
- u_int32_t action;
- u_int32_t ticket;
- u_int32_t pool_ticket;
- u_int32_t nr;
- char anchor[MAXPATHLEN];
- char anchor_call[MAXPATHLEN];
- struct pf_rule rule;
-};
-.Ed
-.Pp
-Add
-.Va rule
-at the end of the inactive ruleset.
-This call requires a
-.Va ticket
-obtained through a preceding
-.Dv DIOCXBEGIN
-call and a
-.Va pool_ticket
-obtained through a
-.Dv DIOCBEGINADDRS
-call.
-.Dv DIOCADDADDR
-must also be called if any pool addresses are required.
-The optional
-.Va anchor
-name indicates the anchor in which to append the rule.
-.Va nr
-and
-.Va action
-are ignored.
-.It Dv DIOCADDALTQ Fa "struct pfioc_altq *pa"
-Add an ALTQ discipline or queue.
-.Bd -literal
-struct pfioc_altq {
- u_int32_t action;
- u_int32_t ticket;
- u_int32_t nr;
- struct pf_altq altq;
-};
-.Ed
-.It Dv DIOCGETRULES Fa "struct pfioc_rule *pr"
-Get a
-.Va ticket
-for subsequent
-.Dv DIOCGETRULE
-calls and the number
-.Va nr
-of rules in the active ruleset.
-.It Dv DIOCGETRULE Fa "struct pfioc_rule *pr"
-Get a
-.Va rule
-by its number
-.Va nr
-using the
-.Va ticket
-obtained through a preceding
-.Dv DIOCGETRULES
-call.
-If
-.Va action
-is set to
-.Dv PF_GET_CLR_CNTR ,
-the per-rule statistics on the requested rule are cleared.
-.It Dv DIOCGETADDRS Fa "struct pfioc_pooladdr *pp"
-Get a
-.Va ticket
-for subsequent
-.Dv DIOCGETADDR
-calls and the number
-.Va nr
-of pool addresses in the rule specified with
-.Va r_action ,
-.Va r_num ,
-and
-.Va anchor .
-.It Dv DIOCGETADDR Fa "struct pfioc_pooladdr *pp"
-Get the pool address
-.Va addr
-by its number
-.Va nr
-from the rule specified with
-.Va r_action ,
-.Va r_num ,
-and
-.Va anchor
-using the
-.Va ticket
-obtained through a preceding
-.Dv DIOCGETADDRS
-call.
-.It Dv DIOCGETALTQS Fa "struct pfioc_altq *pa"
-Get a
-.Va ticket
-for subsequent
-.Dv DIOCGETALTQ
-calls and the number
-.Va nr
-of queues in the active list.
-.It Dv DIOCGETALTQ Fa "struct pfioc_altq *pa"
-Get the queueing discipline
-.Va altq
-by its number
-.Va nr
-using the
-.Va ticket
-obtained through a preceding
-.Dv DIOCGETALTQS
-call.
-.It Dv DIOCGETQSTATS Fa "struct pfioc_qstats *pq"
-Get the statistics on a queue.
-.Bd -literal
-struct pfioc_qstats {
- u_int32_t ticket;
- u_int32_t nr;
- void *buf;
- int nbytes;
- u_int8_t scheduler;
-};
-.Ed
-.Pp
-This call fills in a pointer to the buffer of statistics
-.Va buf ,
-of length
-.Va nbytes ,
-for the queue specified by
-.Va nr .
-.It Dv DIOCGETRULESETS Fa "struct pfioc_ruleset *pr"
-.Bd -literal
-struct pfioc_ruleset {
- u_int32_t nr;
- char path[MAXPATHLEN];
- char name[PF_ANCHOR_NAME_SIZE];
-};
-.Ed
-.Pp
-Get the number
-.Va nr
-of rulesets (i.e., anchors) directly attached to the anchor named by
-.Va path
-for use in subsequent
-.Dv DIOCGETRULESET
-calls.
-Nested anchors, since they are not directly attached to the given
-anchor, will not be included.
-This ioctl returns
-.Er EINVAL
-if the given anchor does not exist.
-.It Dv DIOCGETRULESET Fa "struct pfioc_ruleset *pr"
-Get a ruleset (i.e., an anchor)
-.Va name
-by its number
-.Va nr
-from the given anchor
-.Va path ,
-the maximum number of which can be obtained from a preceding
-.Dv DIOCGETRULESETS
-call.
-This ioctl returns
-.Er EINVAL
-if the given anchor does not exist or
-.Er EBUSY
-if another process is concurrently updating a ruleset.
-.It Dv DIOCADDSTATE Fa "struct pfioc_state *ps"
-Add a state entry.
-.Bd -literal
-struct pfioc_state {
- struct pfsync_state state;
-};
-.Ed
-.It Dv DIOCGETSTATE Fa "struct pfioc_state *ps"
-Extract the entry identified by the
-.Va id
-and
-.Va creatorid
-fields of the
-.Va state
-structure from the state table.
-.It Dv DIOCKILLSTATES Fa "struct pfioc_state_kill *psk"
-Remove matching entries from the state table.
-This ioctl returns the number of killed states in
-.Va psk_killed .
-.Bd -literal
-struct pfioc_state_kill {
- struct pf_state_cmp psk_pfcmp;
- sa_family_t psk_af;
- int psk_proto;
- struct pf_rule_addr psk_src;
- struct pf_rule_addr psk_dst;
- char psk_ifname[IFNAMSIZ];
- char psk_label[PF_RULE_LABEL_SIZE];
- u_int psk_killed;
-};
-.Ed
-.It Dv DIOCCLRSTATES Fa "struct pfioc_state_kill *psk"
-Clear all states.
-It works like
-.Dv DIOCKILLSTATES ,
-but ignores the
-.Va psk_af ,
-.Va psk_proto ,
-.Va psk_src ,
-and
-.Va psk_dst
-fields of the
-.Vt pfioc_state_kill
-structure.
-.It Dv DIOCSETSTATUSIF Fa "struct pfioc_if *pi"
-Specify the interface for which statistics are accumulated.
-.Bd -literal
-struct pfioc_if {
- char ifname[IFNAMSIZ];
-};
-.Ed
-.It Dv DIOCGETSTATUS Fa "struct pf_status *s"
-Get the internal packet filter statistics.
-.Bd -literal
-struct pf_status {
- u_int64_t counters[PFRES_MAX];
- u_int64_t lcounters[LCNT_MAX];
- u_int64_t fcounters[FCNT_MAX];
- u_int64_t scounters[SCNT_MAX];
- u_int64_t pcounters[2][2][3];
- u_int64_t bcounters[2][2];
- u_int32_t running;
- u_int32_t states;
- u_int32_t src_nodes;
- u_int32_t since;
- u_int32_t debug;
- u_int32_t hostid;
- char ifname[IFNAMSIZ];
- u_int8_t pf_chksum[MD5_DIGEST_LENGTH];
-};
-.Ed
-.It Dv DIOCCLRSTATUS
-Clear the internal packet filter statistics.
-.It Dv DIOCNATLOOK Fa "struct pfioc_natlook *pnl"
-Look up a state table entry by source and destination addresses and ports.
-.Bd -literal
-struct pfioc_natlook {
- struct pf_addr saddr;
- struct pf_addr daddr;
- struct pf_addr rsaddr;
- struct pf_addr rdaddr;
- u_int16_t sport;
- u_int16_t dport;
- u_int16_t rsport;
- u_int16_t rdport;
- sa_family_t af;
- u_int8_t proto;
- u_int8_t direction;
-};
-.Ed
-.It Dv DIOCSETDEBUG Fa "u_int32_t *level"
-Set the debug level.
-.Bd -literal
-enum { PF_DEBUG_NONE, PF_DEBUG_URGENT, PF_DEBUG_MISC,
- PF_DEBUG_NOISY };
-.Ed
-.It Dv DIOCGETSTATES Fa "struct pfioc_states *ps"
-Get state table entries.
-.Bd -literal
-struct pfioc_states {
- int ps_len;
- union {
- caddr_t psu_buf;
- struct pf_state *psu_states;
- } ps_u;
-#define ps_buf ps_u.psu_buf
-#define ps_states ps_u.psu_states
-};
-.Ed
-.Pp
-If
-.Va ps_len
-is non-zero on entry, as many states as possible that can fit into this
-size will be copied into the supplied buffer
-.Va ps_states .
-On exit,
-.Va ps_len
-is always set to the total size required to hold all state table entries
-(i.e., it is set to
-.Li sizeof(struct pf_state) * nr ) .
-.It Dv DIOCCHANGERULE Fa "struct pfioc_rule *pcr"
-Add or remove the
-.Va rule
-in the ruleset specified by
-.Va rule.action .
-.Pp
-The type of operation to be performed is indicated by
-.Va action ,
-which can be any of the following:
-.Bd -literal
-enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL,
- PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER,
- PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET };
-.Ed
-.Pp
-.Va ticket
-must be set to the value obtained with
-.Dv PF_CHANGE_GET_TICKET
-for all actions except
-.Dv PF_CHANGE_GET_TICKET .
-.Va pool_ticket
-must be set to the value obtained with the
-.Dv DIOCBEGINADDRS
-call for all actions except
-.Dv PF_CHANGE_REMOVE
-and
-.Dv PF_CHANGE_GET_TICKET .
-.Va anchor
-indicates to which anchor the operation applies.
-.Va nr
-indicates the rule number against which
-.Dv PF_CHANGE_ADD_BEFORE ,
-.Dv PF_CHANGE_ADD_AFTER ,
-or
-.Dv PF_CHANGE_REMOVE
-actions are applied.
-.\" It Dv DIOCCHANGEALTQ Fa "struct pfioc_altq *pcr"
-.It Dv DIOCCHANGEADDR Fa "struct pfioc_pooladdr *pca"
-Add or remove the pool address
-.Va addr
-from the rule specified by
-.Va r_action ,
-.Va r_num ,
-and
-.Va anchor .
-.It Dv DIOCSETTIMEOUT Fa "struct pfioc_tm *pt"
-.Bd -literal
-struct pfioc_tm {
- int timeout;
- int seconds;
-};
-.Ed
-.Pp
-Set the state timeout of
-.Va timeout
-to
-.Va seconds .
-The old value will be placed into
-.Va seconds .
-For possible values of
-.Va timeout ,
-consult the
-.Dv PFTM_*
-values in
-.Aq Pa net/pfvar.h .
-.It Dv DIOCGETTIMEOUT Fa "struct pfioc_tm *pt"
-Get the state timeout of
-.Va timeout .
-The value will be placed into the
-.Va seconds
-field.
-.It Dv DIOCCLRRULECTRS
-Clear per-rule statistics.
-.It Dv DIOCSETLIMIT Fa "struct pfioc_limit *pl"
-Set the hard limits on the memory pools used by the packet filter.
-.Bd -literal
-struct pfioc_limit {
- int index;
- unsigned limit;
-};
-
-enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
- PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
-.Ed
-.It Dv DIOCGETLIMIT Fa "struct pfioc_limit *pl"
-Get the hard
-.Va limit
-for the memory pool indicated by
-.Va index .
-.It Dv DIOCRCLRTABLES Fa "struct pfioc_table *io"
-Clear all tables.
-All the ioctls that manipulate radix tables
-use the same structure described below.
-For
-.Dv DIOCRCLRTABLES ,
-.Va pfrio_ndel
-contains on exit the number of tables deleted.
-.Bd -literal
-struct pfioc_table {
- struct pfr_table pfrio_table;
- void *pfrio_buffer;
- int pfrio_esize;
- int pfrio_size;
- int pfrio_size2;
- int pfrio_nadd;
- int pfrio_ndel;
- int pfrio_nchange;
- int pfrio_flags;
- u_int32_t pfrio_ticket;
-};
-#define pfrio_exists pfrio_nadd
-#define pfrio_nzero pfrio_nadd
-#define pfrio_nmatch pfrio_nadd
-#define pfrio_naddr pfrio_size2
-#define pfrio_setflag pfrio_size2
-#define pfrio_clrflag pfrio_nadd
-.Ed
-.It Dv DIOCRADDTABLES Fa "struct pfioc_table *io"
-Create one or more tables.
-On entry,
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_table
-containing at least
-.Vt pfrio_size
-elements.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_table .
-On exit,
-.Va pfrio_nadd
-contains the number of tables effectively created.
-.Bd -literal
-struct pfr_table {
- char pfrt_anchor[MAXPATHLEN];
- char pfrt_name[PF_TABLE_NAME_SIZE];
- u_int32_t pfrt_flags;
- u_int8_t pfrt_fback;
-};
-.Ed
-.It Dv DIOCRDELTABLES Fa "struct pfioc_table *io"
-Delete one or more tables.
-On entry,
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_table
-containing at least
-.Vt pfrio_size
-elements.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_table .
-On exit,
-.Va pfrio_ndel
-contains the number of tables effectively deleted.
-.It Dv DIOCRGETTABLES Fa "struct pfioc_table *io"
-Get the list of all tables.
-On entry,
-.Va pfrio_buffer[pfrio_size]
-contains a valid writeable buffer for
-.Vt pfr_table
-structures.
-On exit,
-.Va pfrio_size
-contains the number of tables written into the buffer.
-If the buffer is too small, the kernel does not store anything but just
-returns the required buffer size, without error.
-.It Dv DIOCRGETTSTATS Fa "struct pfioc_table *io"
-This call is like
-.Dv DIOCRGETTABLES
-but is used to get an array of
-.Vt pfr_tstats
-structures.
-.Bd -literal
-struct pfr_tstats {
- struct pfr_table pfrts_t;
- u_int64_t pfrts_packets
- [PFR_DIR_MAX][PFR_OP_TABLE_MAX];
- u_int64_t pfrts_bytes
- [PFR_DIR_MAX][PFR_OP_TABLE_MAX];
- u_int64_t pfrts_match;
- u_int64_t pfrts_nomatch;
- long pfrts_tzero;
- int pfrts_cnt;
- int pfrts_refcnt[PFR_REFCNT_MAX];
-};
-#define pfrts_name pfrts_t.pfrt_name
-#define pfrts_flags pfrts_t.pfrt_flags
-.Ed
-.It Dv DIOCRCLRTSTATS Fa "struct pfioc_table *io"
-Clear the statistics of one or more tables.
-On entry,
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_table
-containing at least
-.Vt pfrio_size
-elements.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_table .
-On exit,
-.Va pfrio_nzero
-contains the number of tables effectively cleared.
-.It Dv DIOCRCLRADDRS Fa "struct pfioc_table *io"
-Clear all addresses in a table.
-On entry,
-.Va pfrio_table
-contains the table to clear.
-On exit,
-.Va pfrio_ndel
-contains the number of addresses removed.
-.It Dv DIOCRADDADDRS Fa "struct pfioc_table *io"
-Add one or more addresses to a table.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_addr
-containing at least
-.Vt pfrio_size
-elements to add to the table.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_addr .
-On exit,
-.Va pfrio_nadd
-contains the number of addresses effectively added.
-.Bd -literal
-struct pfr_addr {
- union {
- struct in_addr _pfra_ip4addr;
- struct in6_addr _pfra_ip6addr;
- } pfra_u;
- u_int8_t pfra_af;
- u_int8_t pfra_net;
- u_int8_t pfra_not;
- u_int8_t pfra_fback;
-};
-#define pfra_ip4addr pfra_u._pfra_ip4addr
-#define pfra_ip6addr pfra_u._pfra_ip6addr
-.Ed
-.It Dv DIOCRDELADDRS Fa "struct pfioc_table *io"
-Delete one or more addresses from a table.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_addr
-containing at least
-.Vt pfrio_size
-elements to delete from the table.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_addr .
-On exit,
-.Va pfrio_ndel
-contains the number of addresses effectively deleted.
-.It Dv DIOCRSETADDRS Fa "struct pfioc_table *io"
-Replace the content of a table by a new address list.
-This is the most complicated command, which uses all the structure members.
-.Pp
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_addr
-containing at least
-.Vt pfrio_size
-elements which become the new contents of the table.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_addr .
-Additionally, if
-.Va pfrio_size2
-is non-zero,
-.Va pfrio_buffer[pfrio_size..pfrio_size2]
-must be a writeable buffer, into which the kernel can copy the
-addresses that have been deleted during the replace operation.
-On exit,
-.Va pfrio_ndel ,
-.Va pfrio_nadd ,
-and
-.Va pfrio_nchange
-contain the number of addresses deleted, added, and changed by the
-kernel.
-If
-.Va pfrio_size2
-was set on entry,
-.Va pfrio_size2
-will point to the size of the buffer used, exactly like
-.Dv DIOCRGETADDRS .
-.It Dv DIOCRGETADDRS Fa "struct pfioc_table *io"
-Get all the addresses of a table.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer[pfrio_size]
-contains a valid writeable buffer for
-.Vt pfr_addr
-structures.
-On exit,
-.Va pfrio_size
-contains the number of addresses written into the buffer.
-If the buffer was too small, the kernel does not store anything but just
-returns the required buffer size, without returning an error.
-.It Dv DIOCRGETASTATS Fa "struct pfioc_table *io"
-This call is like
-.Dv DIOCRGETADDRS
-but is used to get an array of
-.Vt pfr_astats
-structures.
-.Bd -literal
-struct pfr_astats {
- struct pfr_addr pfras_a;
- u_int64_t pfras_packets
- [PFR_DIR_MAX][PFR_OP_ADDR_MAX];
- u_int64_t pfras_bytes
- [PFR_DIR_MAX][PFR_OP_ADDR_MAX];
- long pfras_tzero;
-};
-.Ed
-.It Dv DIOCRCLRASTATS Fa "struct pfioc_table *io"
-Clear the statistics of one or more addresses.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_addr
-containing at least
-.Vt pfrio_size
-elements to be cleared from the table.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_addr .
-On exit,
-.Va pfrio_nzero
-contains the number of addresses effectively cleared.
-.It Dv DIOCRTSTADDRS Fa "struct pfioc_table *io"
-Test if the given addresses match a table.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_addr
-containing at least
-.Vt pfrio_size
-elements, each of which will be tested for a match in the table.
-.Vt pfrio_esize
-must be the size of
-.Vt struct pfr_addr .
-On exit, the kernel updates the
-.Vt pfr_addr
-array by setting the
-.Va pfra_fback
-member appropriately.
-.It Dv DIOCRSETTFLAGS Fa "struct pfioc_table *io"
-Change the
-.Dv PFR_TFLAG_CONST
-or
-.Dv PFR_TFLAG_PERSIST
-flags of a table.
-On entry,
-.Va pfrio_buffer
-must point to an array of
-.Vt struct pfr_table
-containing at least
-.Vt pfrio_size
-elements.
-.Va pfrio_esize
-must be the size of
-.Vt struct pfr_table .
-.Va pfrio_setflag
-must contain the flags to add, while
-.Va pfrio_clrflag
-must contain the flags to remove.
-On exit,
-.Va pfrio_nchange
-and
-.Va pfrio_ndel
-contain the number of tables altered or deleted by the kernel.
-Yes, tables can be deleted if one removes the
-.Dv PFR_TFLAG_PERSIST
-flag of an unreferenced table.
-.It Dv DIOCRINADEFINE Fa "struct pfioc_table *io"
-Defines a table in the inactive set.
-On entry,
-.Va pfrio_table
-contains the table ID and
-.Va pfrio_buffer[pfrio_size]
-contains an array of
-.Vt pfr_addr
-structures to put in the table.
-A valid ticket must also be supplied to
-.Va pfrio_ticket .
-On exit,
-.Va pfrio_nadd
-contains 0 if the table was already defined in the inactive list
-or 1 if a new table has been created.
-.Va pfrio_naddr
-contains the number of addresses effectively put in the table.
-.It Dv DIOCXBEGIN Fa "struct pfioc_trans *io"
-.Bd -literal
-struct pfioc_trans {
- int size; /* number of elements */
- int esize; /* size of each element in bytes */
- struct pfioc_trans_e {
- int rs_num;
- char anchor[MAXPATHLEN];
- u_int32_t ticket;
- } *array;
-};
-.Ed
-.Pp
-Clear all the inactive rulesets specified in the
-.Vt pfioc_trans_e
-array.
-For each ruleset, a ticket is returned for subsequent "add rule" ioctls,
-as well as for the
-.Dv DIOCXCOMMIT
-and
-.Dv DIOCXROLLBACK
-calls.
-.Pp
-Ruleset types, identified by
-.Va rs_num ,
-include the following:
-.Pp
-.Bl -tag -width PF_RULESET_FILTER -offset ind -compact
-.It Dv PF_RULESET_SCRUB
-Scrub (packet normalization) rules.
-.It Dv PF_RULESET_FILTER
-Filter rules.
-.It Dv PF_RULESET_NAT
-NAT (Network Address Translation) rules.
-.It Dv PF_RULESET_BINAT
-Bidirectional NAT rules.
-.It Dv PF_RULESET_RDR
-Redirect rules.
-.It Dv PF_RULESET_ALTQ
-ALTQ disciplines.
-.It Dv PF_RULESET_TABLE
-Address tables.
-.El
-.It Dv DIOCXCOMMIT Fa "struct pfioc_trans *io"
-Atomically switch a vector of inactive rulesets to the active rulesets.
-This call is implemented as a standard two-phase commit, which will either
-fail for all rulesets or completely succeed.
-All tickets need to be valid.
-This ioctl returns
-.Er EBUSY
-if another process is concurrently updating some of the same rulesets.
-.It Dv DIOCXROLLBACK Fa "struct pfioc_trans *io"
-Clean up the kernel by undoing all changes that have taken place on the
-inactive rulesets since the last
-.Dv DIOCXBEGIN .
-.Dv DIOCXROLLBACK
-will silently ignore rulesets for which the ticket is invalid.
-.It Dv DIOCSETHOSTID Fa "u_int32_t *hostid"
-Set the host ID, which is used by
-.Xr pfsync 4
-to identify which host created state table entries.
-.It Dv DIOCOSFPFLUSH
-Flush the passive OS fingerprint table.
-.It Dv DIOCOSFPADD Fa "struct pf_osfp_ioctl *io"
-.Bd -literal
-struct pf_osfp_ioctl {
- struct pf_osfp_entry {
- SLIST_ENTRY(pf_osfp_entry) fp_entry;
- pf_osfp_t fp_os;
- char fp_class_nm[PF_OSFP_LEN];
- char fp_version_nm[PF_OSFP_LEN];
- char fp_subtype_nm[PF_OSFP_LEN];
- } fp_os;
- pf_tcpopts_t fp_tcpopts;
- u_int16_t fp_wsize;
- u_int16_t fp_psize;
- u_int16_t fp_mss;
- u_int16_t fp_flags;
- u_int8_t fp_optcnt;
- u_int8_t fp_wscale;
- u_int8_t fp_ttl;
- int fp_getnum;
-};
-.Ed
-.Pp
-Add a passive OS fingerprint to the table.
-Set
-.Va fp_os.fp_os
-to the packed fingerprint,
-.Va fp_os.fp_class_nm
-to the name of the class (Linux, Windows, etc),
-.Va fp_os.fp_version_nm
-to the name of the version (NT, 95, 98), and
-.Va fp_os.fp_subtype_nm
-to the name of the subtype or patchlevel.
-The members
-.Va fp_mss ,
-.Va fp_wsize ,
-.Va fp_psize ,
-.Va fp_ttl ,
-.Va fp_optcnt ,
-and
-.Va fp_wscale
-are set to the TCP MSS, the TCP window size, the IP length, the IP TTL,
-the number of TCP options, and the TCP window scaling constant of the
-TCP SYN packet, respectively.
-.Pp
-The
-.Va fp_flags
-member is filled according to the
-.Aq Pa net/pfvar.h
-include file
-.Dv PF_OSFP_*
-defines.
-The
-.Va fp_tcpopts
-member contains packed TCP options.
-Each option uses
-.Dv PF_OSFP_TCPOPT_BITS
-bits in the packed value.
-Options include any of
-.Dv PF_OSFP_TCPOPT_NOP ,
-.Dv PF_OSFP_TCPOPT_SACK ,
-.Dv PF_OSFP_TCPOPT_WSCALE ,
-.Dv PF_OSFP_TCPOPT_MSS ,
-or
-.Dv PF_OSFP_TCPOPT_TS .
-.Pp
-The
-.Va fp_getnum
-member is not used with this ioctl.
-.Pp
-The structure's slack space must be zeroed for correct operation;
-.Xr memset 3
-the whole structure to zero before filling and sending to the kernel.
-.It Dv DIOCOSFPGET Fa "struct pf_osfp_ioctl *io"
-Get the passive OS fingerprint number
-.Va fp_getnum
-from the kernel's fingerprint list.
-The rest of the structure members will come back filled.
-Get the whole list by repeatedly incrementing the
-.Va fp_getnum
-number until the ioctl returns
-.Er EBUSY .
-.It Dv DIOCGETSRCNODES Fa "struct pfioc_src_nodes *psn"
-.Bd -literal
-struct pfioc_src_nodes {
- int psn_len;
- union {
- caddr_t psu_buf;
- struct pf_src_node *psu_src_nodes;
- } psn_u;
-#define psn_buf psn_u.psu_buf
-#define psn_src_nodes psn_u.psu_src_nodes
-};
-.Ed
-.Pp
-Get the list of source nodes kept by sticky addresses and source
-tracking.
-The ioctl must be called once with
-.Va psn_len
-set to 0.
-If the ioctl returns without error,
-.Va psn_len
-will be set to the size of the buffer required to hold all the
-.Va pf_src_node
-structures held in the table.
-A buffer of this size should then be allocated, and a pointer to this buffer
-placed in
-.Va psn_buf .
-The ioctl must then be called again to fill this buffer with the actual
-source node data.
-After that call,
-.Va psn_len
-will be set to the length of the buffer actually used.
-.It Dv DIOCCLRSRCNODES
-Clear the tree of source tracking nodes.
-.It Dv DIOCIGETIFACES Fa "struct pfioc_iface *io"
-Get the list of interfaces and interface drivers known to
-.Nm .
-All the ioctls that manipulate interfaces
-use the same structure described below:
-.Bd -literal
-struct pfioc_iface {
- char pfiio_name[IFNAMSIZ];
- void *pfiio_buffer;
- int pfiio_esize;
- int pfiio_size;
- int pfiio_nzero;
- int pfiio_flags;
-};
-.Ed
-.Pp
-If not empty,
-.Va pfiio_name
-can be used to restrict the search to a specific interface or driver.
-.Va pfiio_buffer[pfiio_size]
-is the user-supplied buffer for returning the data.
-On entry,
-.Va pfiio_size
-contains the number of
-.Vt pfi_kif
-entries that can fit into the buffer.
-The kernel will replace this value by the real number of entries it wants
-to return.
-.Va pfiio_esize
-should be set to
-.Li sizeof(struct pfi_kif) .
-.Pp
-The data is returned in the
-.Vt pfi_kif
-structure described below:
-.Bd -literal
-struct pfi_kif {
- RB_ENTRY(pfi_kif) pfik_tree;
- char pfik_name[IFNAMSIZ];
- u_int64_t pfik_packets[2][2][2];
- u_int64_t pfik_bytes[2][2][2];
- u_int32_t pfik_tzero;
- int pfik_flags;
- struct pf_state_tree_lan_ext pfik_lan_ext;
- struct pf_state_tree_ext_gwy pfik_ext_gwy;
- TAILQ_ENTRY(pfi_kif) pfik_w_states;
- void *pfik_ah_cookie;
- struct ifnet *pfik_ifp;
- struct ifg_group *pfik_group;
- int pfik_states;
- int pfik_rules;
- TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
-};
-.Ed
-.It Dv DIOCSETIFFLAG Fa "struct pfioc_iface *io"
-Set the user setable flags (described above) of the
-.Nm
-internal interface description.
-The filtering process is the same as for
-.Dv DIOCIGETIFACES .
-.Bd -literal
-#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
-.Ed
-.It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io"
-Works as
-.Dv DIOCSETIFFLAG
-above but clears the flags.
-.It Dv DIOCKILLSRCNODES Fa "struct pfioc_iface *io"
-Explicitly remove source tracking nodes.
-.El
-.Sh FILES
-.Bl -tag -width /dev/pf -compact
-.It Pa /dev/pf
-packet filtering device.
-.El
-.Sh EXAMPLES
-The following example demonstrates how to use the
-.Dv DIOCNATLOOK
-command to find the internal host/port of a NATed connection:
-.Bd -literal
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/fcntl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <net/pfvar.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-u_int32_t
-read_address(const char *s)
-{
- int a, b, c, d;
-
- sscanf(s, "%i.%i.%i.%i", &a, &b, &c, &d);
- return htonl(a << 24 | b << 16 | c << 8 | d);
-}
-
-void
-print_address(u_int32_t a)
-{
- a = ntohl(a);
- printf("%d.%d.%d.%d", a >> 24 & 255, a >> 16 & 255,
- a >> 8 & 255, a & 255);
-}
-
-int
-main(int argc, char *argv[])
-{
- struct pfioc_natlook nl;
- int dev;
-
- if (argc != 5) {
- printf("%s <gwy addr> <gwy port> <ext addr> <ext port>\\n",
- argv[0]);
- return 1;
- }
-
- dev = open("/dev/pf", O_RDWR);
- if (dev == -1)
- err(1, "open(\\"/dev/pf\\") failed");
-
- memset(&nl, 0, sizeof(struct pfioc_natlook));
- nl.saddr.v4.s_addr = read_address(argv[1]);
- nl.sport = htons(atoi(argv[2]));
- nl.daddr.v4.s_addr = read_address(argv[3]);
- nl.dport = htons(atoi(argv[4]));
- nl.af = AF_INET;
- nl.proto = IPPROTO_TCP;
- nl.direction = PF_IN;
-
- if (ioctl(dev, DIOCNATLOOK, &nl))
- err(1, "DIOCNATLOOK");
-
- printf("internal host ");
- print_address(nl.rsaddr.v4.s_addr);
- printf(":%u\\n", ntohs(nl.rsport));
- return 0;
-}
-.Ed
-.Sh SEE ALSO
-.Xr ioctl 2 ,
-.Xr altq 4 ,
-.Xr if_bridge 4 ,
-.Xr pflog 4 ,
-.Xr pflow 4 ,
-.Xr pfsync 4 ,
-.Xr pfctl 8 ,
-.Xr altq 9
-.Sh HISTORY
-The
-.Nm
-packet filtering mechanism first appeared in
-.Ox 3.0
-and then
-.Fx 5.2 .
-.Pp
-This implementation matches
-.Ox 4.5 .
diff --git a/contrib/pf/man/pf.conf.5 b/contrib/pf/man/pf.conf.5
deleted file mode 100644
index fc86111..0000000
--- a/contrib/pf/man/pf.conf.5
+++ /dev/null
@@ -1,3066 +0,0 @@
-.\" $FreeBSD$
-.\" $OpenBSD: pf.conf.5,v 1.406 2009/01/31 19:37:12 sobrado Exp $
-.\"
-.\" Copyright (c) 2002, 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.
-.\"
-.Dd June 29 2012
-.Dt PF.CONF 5
-.Os
-.Sh NAME
-.Nm pf.conf
-.Nd packet filter configuration file
-.Sh DESCRIPTION
-The
-.Xr pf 4
-packet filter modifies, drops or passes packets according to rules or
-definitions specified in
-.Nm pf.conf .
-.Sh STATEMENT ORDER
-There are seven types of statements in
-.Nm pf.conf :
-.Bl -tag -width xxxx
-.It Cm Macros
-User-defined variables may be defined and used later, simplifying
-the configuration file.
-Macros must be defined before they are referenced in
-.Nm pf.conf .
-.It Cm Tables
-Tables provide a mechanism for increasing the performance and flexibility of
-rules with large numbers of source or destination addresses.
-.It Cm Options
-Options tune the behaviour of the packet filtering engine.
-.It Cm Traffic Normalization Li (e.g. Em scrub )
-Traffic normalization protects internal machines against inconsistencies
-in Internet protocols and implementations.
-.It Cm Queueing
-Queueing provides rule-based bandwidth control.
-.It Cm Translation Li (Various forms of NAT)
-Translation rules specify how addresses are to be mapped or redirected to
-other addresses.
-.It Cm Packet Filtering
-Packet filtering provides rule-based blocking or passing of packets.
-.El
-.Pp
-With the exception of
-.Cm macros
-and
-.Cm tables ,
-the types of statements should be grouped and appear in
-.Nm pf.conf
-in the order shown above, as this matches the operation of the underlying
-packet filtering engine.
-By default
-.Xr pfctl 8
-enforces this order (see
-.Ar set require-order
-below).
-.Pp
-Comments can be put anywhere in the file using a hash mark
-.Pq Sq # ,
-and extend to the end of the current line.
-.Pp
-Additional configuration files can be included with the
-.Ic include
-keyword, for example:
-.Bd -literal -offset indent
-include "/etc/pf/sub.filter.conf"
-.Ed
-.Sh MACROS
-Macros can be defined that will later be expanded in context.
-Macro names must start with a letter, and may contain letters, digits
-and underscores.
-Macro names may not be reserved words (for example
-.Ar pass ,
-.Ar in ,
-.Ar out ) .
-Macros are not expanded inside quotes.
-.Pp
-For example,
-.Bd -literal -offset indent
-ext_if = \&"kue0\&"
-all_ifs = \&"{\&" $ext_if lo0 \&"}\&"
-pass out on $ext_if from any to any
-pass in on $ext_if proto tcp from any to any port 25
-.Ed
-.Sh TABLES
-Tables are named structures which can hold a collection of addresses and
-networks.
-Lookups against tables in
-.Xr pf 4
-are relatively fast, making a single rule with tables much more efficient,
-in terms of
-processor usage and memory consumption, than a large number of rules which
-differ only in IP address (either created explicitly or automatically by rule
-expansion).
-.Pp
-Tables can be used as the source or destination of filter rules,
-.Ar scrub
-rules
-or
-translation rules such as
-.Ar nat
-or
-.Ar rdr
-(see below for details on the various rule types).
-Tables can also be used for the redirect address of
-.Ar nat
-and
-.Ar rdr
-rules and in the routing options of filter rules, but only for
-.Ar round-robin
-pools.
-.Pp
-Tables can be defined with any of the following
-.Xr pfctl 8
-mechanisms.
-As with macros, reserved words may not be used as table names.
-.Bl -tag -width "manually"
-.It Ar manually
-Persistent tables can be manually created with the
-.Ar add
-or
-.Ar replace
-option of
-.Xr pfctl 8 ,
-before or after the ruleset has been loaded.
-.It Pa pf.conf
-Table definitions can be placed directly in this file, and loaded at the
-same time as other rules are loaded, atomically.
-Table definitions inside
-.Nm pf.conf
-use the
-.Ar table
-statement, and are especially useful to define non-persistent tables.
-The contents of a pre-existing table defined without a list of addresses
-to initialize it is not altered when
-.Nm pf.conf
-is loaded.
-A table initialized with the empty list,
-.Li { } ,
-will be cleared on load.
-.El
-.Pp
-Tables may be defined with the following attributes:
-.Bl -tag -width persist
-.It Ar persist
-The
-.Ar persist
-flag forces the kernel to keep the table even when no rules refer to it.
-If the flag is not set, the kernel will automatically remove the table
-when the last rule referring to it is flushed.
-.It Ar const
-The
-.Ar const
-flag prevents the user from altering the contents of the table once it
-has been created.
-Without that flag,
-.Xr pfctl 8
-can be used to add or remove addresses from the table at any time, even
-when running with
-.Xr securelevel 7
-= 2.
-.It Ar counters
-The
-.Ar counters
-flag enables per-address packet and byte counters which can be displayed with
-.Xr pfctl 8 .
-.El
-.Pp
-For example,
-.Bd -literal -offset indent
-table \*(Ltprivate\*(Gt const { 10/8, 172.16/12, 192.168/16 }
-table \*(Ltbadhosts\*(Gt persist
-block on fxp0 from { \*(Ltprivate\*(Gt, \*(Ltbadhosts\*(Gt } to any
-.Ed
-.Pp
-creates a table called private, to hold RFC 1918 private network
-blocks, and a table called badhosts, which is initially empty.
-A filter rule is set up to block all traffic coming from addresses listed in
-either table.
-The private table cannot have its contents changed and the badhosts table
-will exist even when no active filter rules reference it.
-Addresses may later be added to the badhosts table, so that traffic from
-these hosts can be blocked by using
-.Bd -literal -offset indent
-# pfctl -t badhosts -Tadd 204.92.77.111
-.Ed
-.Pp
-A table can also be initialized with an address list specified in one or more
-external files, using the following syntax:
-.Bd -literal -offset indent
-table \*(Ltspam\*(Gt persist file \&"/etc/spammers\&" file \&"/etc/openrelays\&"
-block on fxp0 from \*(Ltspam\*(Gt to any
-.Ed
-.Pp
-The files
-.Pa /etc/spammers
-and
-.Pa /etc/openrelays
-list IP addresses, one per line.
-Any lines beginning with a # are treated as comments and ignored.
-In addition to being specified by IP address, hosts may also be
-specified by their hostname.
-When the resolver is called to add a hostname to a table,
-.Em all
-resulting IPv4 and IPv6 addresses are placed into the table.
-IP addresses can also be entered in a table by specifying a valid interface
-name, a valid interface group or the
-.Em self
-keyword, in which case all addresses assigned to the interface(s) will be
-added to the table.
-.Sh OPTIONS
-.Xr pf 4
-may be tuned for various situations using the
-.Ar set
-command.
-.Bl -tag -width xxxx
-.It Ar set timeout
-.Pp
-.Bl -tag -width "src.track" -compact
-.It Ar interval
-Interval between purging expired states and fragments.
-.It Ar frag
-Seconds before an unassembled fragment is expired.
-.It Ar src.track
-Length of time to retain a source tracking entry after the last state
-expires.
-.El
-.Pp
-When a packet matches a stateful connection, the seconds to live for the
-connection will be updated to that of the
-.Ar proto.modifier
-which corresponds to the connection state.
-Each packet which matches this state will reset the TTL.
-Tuning these values may improve the performance of the
-firewall at the risk of dropping valid idle connections.
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar tcp.first
-The state after the first packet.
-.It Ar tcp.opening
-The state before the destination host ever sends a packet.
-.It Ar tcp.established
-The fully established state.
-.It Ar tcp.closing
-The state after the first FIN has been sent.
-.It Ar tcp.finwait
-The state after both FINs have been exchanged and the connection is closed.
-Some hosts (notably web servers on Solaris) send TCP packets even after closing
-the connection.
-Increasing
-.Ar tcp.finwait
-(and possibly
-.Ar tcp.closing )
-can prevent blocking of such packets.
-.It Ar tcp.closed
-The state after one endpoint sends an RST.
-.El
-.Pp
-ICMP and UDP are handled in a fashion similar to TCP, but with a much more
-limited set of states:
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar udp.first
-The state after the first packet.
-.It Ar udp.single
-The state if the source host sends more than one packet but the destination
-host has never sent one back.
-.It Ar udp.multiple
-The state if both hosts have sent packets.
-.It Ar icmp.first
-The state after the first packet.
-.It Ar icmp.error
-The state after an ICMP error came back in response to an ICMP packet.
-.El
-.Pp
-Other protocols are handled similarly to UDP:
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar other.first
-.It Ar other.single
-.It Ar other.multiple
-.El
-.Pp
-Timeout values can be reduced adaptively as the number of state table
-entries grows.
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar adaptive.start
-When the number of state entries exceeds this value, adaptive scaling
-begins.
-All timeout values are scaled linearly with factor
-(adaptive.end - number of states) / (adaptive.end - adaptive.start).
-.It Ar adaptive.end
-When reaching this number of state entries, all timeout values become
-zero, effectively purging all state entries immediately.
-This value is used to define the scale factor, it should not actually
-be reached (set a lower state limit, see below).
-.El
-.Pp
-Adaptive timeouts are enabled by default, with an adaptive.start value
-equal to 60% of the state limit, and an adaptive.end value equal to
-120% of the state limit.
-They can be disabled by setting both adaptive.start and adaptive.end to 0.
-.Pp
-The adaptive timeout values can be defined both globally and for each rule.
-When used on a per-rule basis, the values relate to the number of
-states created by the rule, otherwise to the total number of
-states.
-.Pp
-For example:
-.Bd -literal -offset indent
-set timeout tcp.first 120
-set timeout tcp.established 86400
-set timeout { adaptive.start 6000, adaptive.end 12000 }
-set limit states 10000
-.Ed
-.Pp
-With 9000 state table entries, the timeout values are scaled to 50%
-(tcp.first 60, tcp.established 43200).
-.Pp
-.It Ar set loginterface
-Enable collection of packet and byte count statistics for the given
-interface or interface group.
-These statistics can be viewed using
-.Bd -literal -offset indent
-# pfctl -s info
-.Ed
-.Pp
-In this example
-.Xr pf 4
-collects statistics on the interface named dc0:
-.Bd -literal -offset indent
-set loginterface dc0
-.Ed
-.Pp
-One can disable the loginterface using:
-.Bd -literal -offset indent
-set loginterface none
-.Ed
-.Pp
-.It Ar set limit
-Sets hard limits on the memory pools used by the packet filter.
-See
-.Xr zone 9
-for an explanation of memory pools.
-.Pp
-For example,
-.Bd -literal -offset indent
-set limit states 20000
-.Ed
-.Pp
-sets the maximum number of entries in the memory pool used by state table
-entries (generated by
-.Ar pass
-rules which do not specify
-.Ar no state )
-to 20000.
-Using
-.Bd -literal -offset indent
-set limit frags 20000
-.Ed
-.Pp
-sets the maximum number of entries in the memory pool used for fragment
-reassembly (generated by
-.Ar scrub
-rules) to 20000.
-Using
-.Bd -literal -offset indent
-set limit src-nodes 2000
-.Ed
-.Pp
-sets the maximum number of entries in the memory pool used for tracking
-source IP addresses (generated by the
-.Ar sticky-address
-and
-.Ar src.track
-options) to 2000.
-Using
-.Bd -literal -offset indent
-set limit tables 1000
-set limit table-entries 100000
-.Ed
-.Pp
-sets limits on the memory pools used by tables.
-The first limits the number of tables that can exist to 1000.
-The second limits the overall number of addresses that can be stored
-in tables to 100000.
-.Pp
-Various limits can be combined on a single line:
-.Bd -literal -offset indent
-set limit { states 20000, frags 20000, src-nodes 2000 }
-.Ed
-.Pp
-.It Ar set ruleset-optimization
-.Bl -tag -width xxxxxxxx -compact
-.It Ar none
-Disable the ruleset optimizer.
-.It Ar basic
-Enable basic ruleset optimization.
-This is the default behaviour.
-Basic ruleset optimization does four things to improve the
-performance of ruleset evaluations:
-.Pp
-.Bl -enum -compact
-.It
-remove duplicate rules
-.It
-remove rules that are a subset of another rule
-.It
-combine multiple rules into a table when advantageous
-.It
-re-order the rules to improve evaluation performance
-.El
-.Pp
-.It Ar profile
-Uses the currently loaded ruleset as a feedback profile to tailor the
-ordering of quick rules to actual network traffic.
-.El
-.Pp
-It is important to note that the ruleset optimizer will modify the ruleset
-to improve performance.
-A side effect of the ruleset modification is that per-rule accounting
-statistics will have different meanings than before.
-If per-rule accounting is important for billing purposes or whatnot,
-either the ruleset optimizer should not be used or a label field should
-be added to all of the accounting rules to act as optimization barriers.
-.Pp
-Optimization can also be set as a command-line argument to
-.Xr pfctl 8 ,
-overriding the settings in
-.Nm .
-.It Ar set optimization
-Optimize state timeouts for one of the following network environments:
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar normal
-A normal network environment.
-Suitable for almost all networks.
-.It Ar high-latency
-A high-latency environment (such as a satellite connection).
-.It Ar satellite
-Alias for
-.Ar high-latency .
-.It Ar aggressive
-Aggressively expire connections.
-This can greatly reduce the memory usage of the firewall at the cost of
-dropping idle connections early.
-.It Ar conservative
-Extremely conservative settings.
-Avoid dropping legitimate connections at the
-expense of greater memory utilization (possibly much greater on a busy
-network) and slightly increased processor utilization.
-.El
-.Pp
-For example:
-.Bd -literal -offset indent
-set optimization aggressive
-.Ed
-.Pp
-.It Ar set block-policy
-The
-.Ar block-policy
-option sets the default behaviour for the packet
-.Ar block
-action:
-.Pp
-.Bl -tag -width xxxxxxxx -compact
-.It Ar drop
-Packet is silently dropped.
-.It Ar return
-A TCP RST is returned for blocked TCP packets,
-an ICMP UNREACHABLE is returned for blocked UDP packets,
-and all other packets are silently dropped.
-.El
-.Pp
-For example:
-.Bd -literal -offset indent
-set block-policy return
-.Ed
-.It Ar set state-policy
-The
-.Ar state-policy
-option sets the default behaviour for states:
-.Pp
-.Bl -tag -width group-bound -compact
-.It Ar if-bound
-States are bound to interface.
-.It Ar floating
-States can match packets on any interfaces (the default).
-.El
-.Pp
-For example:
-.Bd -literal -offset indent
-set state-policy if-bound
-.Ed
-.It Ar set state-defaults
-The
-.Ar state-defaults
-option sets the state options for states created from rules
-without an explicit
-.Ar keep state .
-For example:
-.Bd -literal -offset indent
-set state-defaults pflow, no-sync
-.Ed
-.It Ar set hostid
-The 32-bit
-.Ar hostid
-identifies this firewall's state table entries to other firewalls
-in a
-.Xr pfsync 4
-failover cluster.
-By default the hostid is set to a pseudo-random value, however it may be
-desirable to manually configure it, for example to more easily identify the
-source of state table entries.
-.Bd -literal -offset indent
-set hostid 1
-.Ed
-.Pp
-The hostid may be specified in either decimal or hexadecimal.
-.It Ar set require-order
-By default
-.Xr pfctl 8
-enforces an ordering of the statement types in the ruleset to:
-.Em options ,
-.Em normalization ,
-.Em queueing ,
-.Em translation ,
-.Em filtering .
-Setting this option to
-.Ar no
-disables this enforcement.
-There may be non-trivial and non-obvious implications to an out of
-order ruleset.
-Consider carefully before disabling the order enforcement.
-.It Ar set fingerprints
-Load fingerprints of known operating systems from the given filename.
-By default fingerprints of known operating systems are automatically
-loaded from
-.Xr pf.os 5
-in
-.Pa /etc
-but can be overridden via this option.
-Setting this option may leave a small period of time where the fingerprints
-referenced by the currently active ruleset are inconsistent until the new
-ruleset finishes loading.
-.Pp
-For example:
-.Pp
-.Dl set fingerprints \&"/etc/pf.os.devel\&"
-.Pp
-.It Ar set skip on Aq Ar ifspec
-List interfaces for which packets should not be filtered.
-Packets passing in or out on such interfaces are passed as if pf was
-disabled, i.e. pf does not process them in any way.
-This can be useful on loopback and other virtual interfaces, when
-packet filtering is not desired and can have unexpected effects.
-For example:
-.Pp
-.Dl set skip on lo0
-.Pp
-.It Ar set debug
-Set the debug
-.Ar level
-to one of the following:
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Ar none
-Don't generate debug messages.
-.It Ar urgent
-Generate debug messages only for serious errors.
-.It Ar misc
-Generate debug messages for various errors.
-.It Ar loud
-Generate debug messages for common conditions.
-.El
-.El
-.Sh TRAFFIC NORMALIZATION
-Traffic normalization is used to sanitize packet content in such
-a way that there are no ambiguities in packet interpretation on
-the receiving side.
-The normalizer does IP fragment reassembly to prevent attacks
-that confuse intrusion detection systems by sending overlapping
-IP fragments.
-Packet normalization is invoked with the
-.Ar scrub
-directive.
-.Pp
-.Ar scrub
-has the following options:
-.Bl -tag -width xxxx
-.It Ar no-df
-Clears the
-.Ar dont-fragment
-bit from a matching IP packet.
-Some operating systems are known to generate fragmented packets with the
-.Ar dont-fragment
-bit set.
-This is particularly true with NFS.
-.Ar Scrub
-will drop such fragmented
-.Ar dont-fragment
-packets unless
-.Ar no-df
-is specified.
-.Pp
-Unfortunately some operating systems also generate their
-.Ar dont-fragment
-packets with a zero IP identification field.
-Clearing the
-.Ar dont-fragment
-bit on packets with a zero IP ID may cause deleterious results if an
-upstream router later fragments the packet.
-Using the
-.Ar random-id
-modifier (see below) is recommended in combination with the
-.Ar no-df
-modifier to ensure unique IP identifiers.
-.It Ar min-ttl Aq Ar number
-Enforces a minimum TTL for matching IP packets.
-.It Ar max-mss Aq Ar number
-Enforces a maximum MSS for matching TCP packets.
-.It Xo Ar set-tos Aq Ar string
-.No \*(Ba Aq Ar number
-.Xc
-Enforces a
-.Em TOS
-for matching IP packets.
-.Em TOS
-may be
-given as one of
-.Ar lowdelay ,
-.Ar throughput ,
-.Ar reliability ,
-or as either hex or decimal.
-.It Ar random-id
-Replaces the IP identification field with random values to compensate
-for predictable values generated by many hosts.
-This option only applies to packets that are not fragmented
-after the optional fragment reassembly.
-.It Ar fragment reassemble
-Using
-.Ar scrub
-rules, fragments can be reassembled by normalization.
-In this case, fragments are buffered until they form a complete
-packet, and only the completed packet is passed on to the filter.
-The advantage is that filter rules have to deal only with complete
-packets, and can ignore fragments.
-The drawback of caching fragments is the additional memory cost.
-But the full reassembly method is the only method that currently works
-with NAT.
-This is the default behavior of a
-.Ar scrub
-rule if no fragmentation modifier is supplied.
-.It Ar fragment crop
-The default fragment reassembly method is expensive, hence the option
-to crop is provided.
-In this case,
-.Xr pf 4
-will track the fragments and cache a small range descriptor.
-Duplicate fragments are dropped and overlaps are cropped.
-Thus data will only occur once on the wire with ambiguities resolving to
-the first occurrence.
-Unlike the
-.Ar fragment reassemble
-modifier, fragments are not buffered, they are passed as soon as they
-are received.
-The
-.Ar fragment crop
-reassembly mechanism does not yet work with NAT.
-.Pp
-.It Ar fragment drop-ovl
-This option is similar to the
-.Ar fragment crop
-modifier except that all overlapping or duplicate fragments will be
-dropped, and all further corresponding fragments will be
-dropped as well.
-.It Ar reassemble tcp
-Statefully normalizes TCP connections.
-.Ar scrub reassemble tcp
-rules may not have the direction (in/out) specified.
-.Ar reassemble tcp
-performs the following normalizations:
-.Pp
-.Bl -tag -width timeout -compact
-.It ttl
-Neither side of the connection is allowed to reduce their IP TTL.
-An attacker may send a packet such that it reaches the firewall, affects
-the firewall state, and expires before reaching the destination host.
-.Ar reassemble tcp
-will raise the TTL of all packets back up to the highest value seen on
-the connection.
-.It timestamp modulation
-Modern TCP stacks will send a timestamp on every TCP packet and echo
-the other endpoint's timestamp back to them.
-Many operating systems will merely start the timestamp at zero when
-first booted, and increment it several times a second.
-The uptime of the host can be deduced by reading the timestamp and multiplying
-by a constant.
-Also observing several different timestamps can be used to count hosts
-behind a NAT device.
-And spoofing TCP packets into a connection requires knowing or guessing
-valid timestamps.
-Timestamps merely need to be monotonically increasing and not derived off a
-guessable base time.
-.Ar reassemble tcp
-will cause
-.Ar scrub
-to modulate the TCP timestamps with a random number.
-.It extended PAWS checks
-There is a problem with TCP on long fat pipes, in that a packet might get
-delayed for longer than it takes the connection to wrap its 32-bit sequence
-space.
-In such an occurrence, the old packet would be indistinguishable from a
-new packet and would be accepted as such.
-The solution to this is called PAWS: Protection Against Wrapped Sequence
-numbers.
-It protects against it by making sure the timestamp on each packet does
-not go backwards.
-.Ar reassemble tcp
-also makes sure the timestamp on the packet does not go forward more
-than the RFC allows.
-By doing this,
-.Xr pf 4
-artificially extends the security of TCP sequence numbers by 10 to 18
-bits when the host uses appropriately randomized timestamps, since a
-blind attacker would have to guess the timestamp as well.
-.El
-.El
-.Pp
-For example,
-.Bd -literal -offset indent
-scrub in on $ext_if all fragment reassemble
-.Ed
-.Pp
-The
-.Ar no
-option prefixed to a scrub rule causes matching packets to remain unscrubbed,
-much in the same way as
-.Ar drop quick
-works in the packet filter (see below).
-This mechanism should be used when it is necessary to exclude specific packets
-from broader scrub rules.
-.Sh QUEUEING
-The ALTQ system is currently not available in the GENERIC kernel nor as
-loadable modules.
-In order to use the herein after called queueing options one has to use a
-custom built kernel.
-Please refer to
-.Xr altq 4
-to learn about the related kernel options.
-.Pp
-Packets can be assigned to queues for the purpose of bandwidth
-control.
-At least two declarations are required to configure queues, and later
-any packet filtering rule can reference the defined queues by name.
-During the filtering component of
-.Nm pf.conf ,
-the last referenced
-.Ar queue
-name is where any packets from
-.Ar pass
-rules will be queued, while for
-.Ar block
-rules it specifies where any resulting ICMP or TCP RST
-packets should be queued.
-The
-.Ar scheduler
-defines the algorithm used to decide which packets get delayed, dropped, or
-sent out immediately.
-There are three
-.Ar schedulers
-currently supported.
-.Bl -tag -width xxxx
-.It Ar cbq
-Class Based Queueing.
-.Ar Queues
-attached to an interface build a tree, thus each
-.Ar queue
-can have further child
-.Ar queues .
-Each queue can have a
-.Ar priority
-and a
-.Ar bandwidth
-assigned.
-.Ar Priority
-mainly controls the time packets take to get sent out, while
-.Ar bandwidth
-has primarily effects on throughput.
-.Ar cbq
-achieves both partitioning and sharing of link bandwidth
-by hierarchically structured classes.
-Each class has its own
-.Ar queue
-and is assigned its share of
-.Ar bandwidth .
-A child class can borrow bandwidth from its parent class
-as long as excess bandwidth is available
-(see the option
-.Ar borrow ,
-below).
-.It Ar priq
-Priority Queueing.
-.Ar Queues
-are flat attached to the interface, thus,
-.Ar queues
-cannot have further child
-.Ar queues .
-Each
-.Ar queue
-has a unique
-.Ar priority
-assigned, ranging from 0 to 15.
-Packets in the
-.Ar queue
-with the highest
-.Ar priority
-are processed first.
-.It Ar hfsc
-Hierarchical Fair Service Curve.
-.Ar Queues
-attached to an interface build a tree, thus each
-.Ar queue
-can have further child
-.Ar queues .
-Each queue can have a
-.Ar priority
-and a
-.Ar bandwidth
-assigned.
-.Ar Priority
-mainly controls the time packets take to get sent out, while
-.Ar bandwidth
-primarily affects throughput.
-.Ar hfsc
-supports both link-sharing and guaranteed real-time services.
-It employs a service curve based QoS model,
-and its unique feature is an ability to decouple
-.Ar delay
-and
-.Ar bandwidth
-allocation.
-.El
-.Pp
-The interfaces on which queueing should be activated are declared using
-the
-.Ar altq on
-declaration.
-.Ar altq on
-has the following keywords:
-.Bl -tag -width xxxx
-.It Aq Ar interface
-Queueing is enabled on the named interface.
-.It Aq Ar scheduler
-Specifies which queueing scheduler to use.
-Currently supported values
-are
-.Ar cbq
-for Class Based Queueing,
-.Ar priq
-for Priority Queueing and
-.Ar hfsc
-for the Hierarchical Fair Service Curve scheduler.
-.It Ar bandwidth Aq Ar bw
-The maximum bitrate for all queues on an
-interface may be specified using the
-.Ar bandwidth
-keyword.
-The value can be specified as an absolute value or as a
-percentage of the interface bandwidth.
-When using an absolute value, the suffixes
-.Ar b ,
-.Ar Kb ,
-.Ar Mb ,
-and
-.Ar Gb
-are used to represent bits, kilobits, megabits, and
-gigabits per second, respectively.
-The value must not exceed the interface bandwidth.
-If
-.Ar bandwidth
-is not specified, the interface bandwidth is used
-(but take note that some interfaces do not know their bandwidth,
-or can adapt their bandwidth rates).
-.It Ar qlimit Aq Ar limit
-The maximum number of packets held in the queue.
-The default is 50.
-.It Ar tbrsize Aq Ar size
-Adjusts the size, in bytes, of the token bucket regulator.
-If not specified, heuristics based on the
-interface bandwidth are used to determine the size.
-.It Ar queue Aq Ar list
-Defines a list of subqueues to create on an interface.
-.El
-.Pp
-In the following example, the interface dc0
-should queue up to 5Mbps in four second-level queues using
-Class Based Queueing.
-Those four queues will be shown in a later example.
-.Bd -literal -offset indent
-altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh }
-.Ed
-.Pp
-Once interfaces are activated for queueing using the
-.Ar altq
-directive, a sequence of
-.Ar queue
-directives may be defined.
-The name associated with a
-.Ar queue
-must match a queue defined in the
-.Ar altq
-directive (e.g. mail), or, except for the
-.Ar priq
-.Ar scheduler ,
-in a parent
-.Ar queue
-declaration.
-The following keywords can be used:
-.Bl -tag -width xxxx
-.It Ar on Aq Ar interface
-Specifies the interface the queue operates on.
-If not given, it operates on all matching interfaces.
-.It Ar bandwidth Aq Ar bw
-Specifies the maximum bitrate to be processed by the queue.
-This value must not exceed the value of the parent
-.Ar queue
-and can be specified as an absolute value or a percentage of the parent
-queue's bandwidth.
-If not specified, defaults to 100% of the parent queue's bandwidth.
-The
-.Ar priq
-scheduler does not support bandwidth specification.
-.It Ar priority Aq Ar level
-Between queues a priority level can be set.
-For
-.Ar cbq
-and
-.Ar hfsc ,
-the range is 0 to 7 and for
-.Ar priq ,
-the range is 0 to 15.
-The default for all is 1.
-.Ar Priq
-queues with a higher priority are always served first.
-.Ar Cbq
-and
-.Ar Hfsc
-queues with a higher priority are preferred in the case of overload.
-.It Ar qlimit Aq Ar limit
-The maximum number of packets held in the queue.
-The default is 50.
-.El
-.Pp
-The
-.Ar scheduler
-can get additional parameters with
-.Xo Aq Ar scheduler
-.Pf ( Aq Ar parameters ) .
-.Xc
-Parameters are as follows:
-.Bl -tag -width Fl
-.It Ar default
-Packets not matched by another queue are assigned to this one.
-Exactly one default queue is required.
-.It Ar red
-Enable RED (Random Early Detection) on this queue.
-RED drops packets with a probability proportional to the average
-queue length.
-.It Ar rio
-Enables RIO on this queue.
-RIO is RED with IN/OUT, thus running
-RED two times more than RIO would achieve the same effect.
-RIO is currently not supported in the GENERIC kernel.
-.It Ar ecn
-Enables ECN (Explicit Congestion Notification) on this queue.
-ECN implies RED.
-.El
-.Pp
-The
-.Ar cbq
-.Ar scheduler
-supports an additional option:
-.Bl -tag -width Fl
-.It Ar borrow
-The queue can borrow bandwidth from the parent.
-.El
-.Pp
-The
-.Ar hfsc
-.Ar scheduler
-supports some additional options:
-.Bl -tag -width Fl
-.It Ar realtime Aq Ar sc
-The minimum required bandwidth for the queue.
-.It Ar upperlimit Aq Ar sc
-The maximum allowed bandwidth for the queue.
-.It Ar linkshare Aq Ar sc
-The bandwidth share of a backlogged queue.
-.El
-.Pp
-.Aq Ar sc
-is an acronym for
-.Ar service curve .
-.Pp
-The format for service curve specifications is
-.Ar ( m1 , d , m2 ) .
-.Ar m2
-controls the bandwidth assigned to the queue.
-.Ar m1
-and
-.Ar d
-are optional and can be used to control the initial bandwidth assignment.
-For the first
-.Ar d
-milliseconds the queue gets the bandwidth given as
-.Ar m1 ,
-afterwards the value given in
-.Ar m2 .
-.Pp
-Furthermore, with
-.Ar cbq
-and
-.Ar hfsc ,
-child queues can be specified as in an
-.Ar altq
-declaration, thus building a tree of queues using a part of
-their parent's bandwidth.
-.Pp
-Packets can be assigned to queues based on filter rules by using the
-.Ar queue
-keyword.
-Normally only one
-.Ar queue
-is specified; when a second one is specified it will instead be used for
-packets which have a
-.Em TOS
-of
-.Em lowdelay
-and for TCP ACKs with no data payload.
-.Pp
-To continue the previous example, the examples below would specify the
-four referenced
-queues, plus a few child queues.
-Interactive
-.Xr ssh 1
-sessions get priority over bulk transfers like
-.Xr scp 1
-and
-.Xr sftp 1 .
-The queues may then be referenced by filtering rules (see
-.Sx PACKET FILTERING
-below).
-.Bd -literal
-queue std bandwidth 10% cbq(default)
-queue http bandwidth 60% priority 2 cbq(borrow red) \e
- { employees, developers }
-queue developers bandwidth 75% cbq(borrow)
-queue employees bandwidth 15%
-queue mail bandwidth 10% priority 0 cbq(borrow ecn)
-queue ssh bandwidth 20% cbq(borrow) { ssh_interactive, ssh_bulk }
-queue ssh_interactive bandwidth 50% priority 7 cbq(borrow)
-queue ssh_bulk bandwidth 50% priority 0 cbq(borrow)
-
-block return out on dc0 inet all queue std
-pass out on dc0 inet proto tcp from $developerhosts to any port 80 \e
- queue developers
-pass out on dc0 inet proto tcp from $employeehosts to any port 80 \e
- queue employees
-pass out on dc0 inet proto tcp from any to any port 22 \e
- queue(ssh_bulk, ssh_interactive)
-pass out on dc0 inet proto tcp from any to any port 25 \e
- queue mail
-.Ed
-.Sh TRANSLATION
-Translation rules modify either the source or destination address of the
-packets associated with a stateful connection.
-A stateful connection is automatically created to track packets matching
-such a rule as long as they are not blocked by the filtering section of
-.Nm pf.conf .
-The translation engine modifies the specified address and/or port in the
-packet, recalculates IP, TCP and UDP checksums as necessary, and passes it to
-the packet filter for evaluation.
-.Pp
-Since translation occurs before filtering the filter
-engine will see packets as they look after any
-addresses and ports have been translated.
-Filter rules will therefore have to filter based on the translated
-address and port number.
-Packets that match a translation rule are only automatically passed if
-the
-.Ar pass
-modifier is given, otherwise they are
-still subject to
-.Ar block
-and
-.Ar pass
-rules.
-.Pp
-The state entry created permits
-.Xr pf 4
-to keep track of the original address for traffic associated with that state
-and correctly direct return traffic for that connection.
-.Pp
-Various types of translation are possible with pf:
-.Bl -tag -width xxxx
-.It Ar binat
-A
-.Ar binat
-rule specifies a bidirectional mapping between an external IP netblock
-and an internal IP netblock.
-.It Ar nat
-A
-.Ar nat
-rule specifies that IP addresses are to be changed as the packet
-traverses the given interface.
-This technique allows one or more IP addresses
-on the translating host to support network traffic for a larger range of
-machines on an "inside" network.
-Although in theory any IP address can be used on the inside, it is strongly
-recommended that one of the address ranges defined by RFC 1918 be used.
-These netblocks are:
-.Bd -literal
-10.0.0.0 - 10.255.255.255 (all of net 10, i.e., 10/8)
-172.16.0.0 - 172.31.255.255 (i.e., 172.16/12)
-192.168.0.0 - 192.168.255.255 (i.e., 192.168/16)
-.Ed
-.It Pa rdr
-The packet is redirected to another destination and possibly a
-different port.
-.Ar rdr
-rules can optionally specify port ranges instead of single ports.
-rdr ... port 2000:2999 -\*(Gt ... port 4000
-redirects ports 2000 to 2999 (inclusive) to port 4000.
-rdr ... port 2000:2999 -\*(Gt ... port 4000:*
-redirects port 2000 to 4000, 2001 to 4001, ..., 2999 to 4999.
-.El
-.Pp
-In addition to modifying the address, some translation rules may modify
-source or destination ports for
-.Xr tcp 4
-or
-.Xr udp 4
-connections; implicitly in the case of
-.Ar nat
-rules and explicitly in the case of
-.Ar rdr
-rules.
-Port numbers are never translated with a
-.Ar binat
-rule.
-.Pp
-Evaluation order of the translation rules is dependent on the type
-of the translation rules and of the direction of a packet.
-.Ar binat
-rules are always evaluated first.
-Then either the
-.Ar rdr
-rules are evaluated on an inbound packet or the
-.Ar nat
-rules on an outbound packet.
-Rules of the same type are evaluated in the same order in which they
-appear in the ruleset.
-The first matching rule decides what action is taken.
-.Pp
-The
-.Ar no
-option prefixed to a translation rule causes packets to remain untranslated,
-much in the same way as
-.Ar drop quick
-works in the packet filter (see below).
-If no rule matches the packet it is passed to the filter engine unmodified.
-.Pp
-Translation rules apply only to packets that pass through
-the specified interface, and if no interface is specified,
-translation is applied to packets on all interfaces.
-For instance, redirecting port 80 on an external interface to an internal
-web server will only work for connections originating from the outside.
-Connections to the address of the external interface from local hosts will
-not be redirected, since such packets do not actually pass through the
-external interface.
-Redirections cannot reflect packets back through the interface they arrive
-on, they can only be redirected to hosts connected to different interfaces
-or to the firewall itself.
-.Pp
-Note that redirecting external incoming connections to the loopback
-address, as in
-.Bd -literal -offset indent
-rdr on ne3 inet proto tcp to port smtp -\*(Gt 127.0.0.1 port spamd
-.Ed
-.Pp
-will effectively allow an external host to connect to daemons
-bound solely to the loopback address, circumventing the traditional
-blocking of such connections on a real interface.
-Unless this effect is desired, any of the local non-loopback addresses
-should be used as redirection target instead, which allows external
-connections only to daemons bound to this address or not bound to
-any address.
-.Pp
-See
-.Sx TRANSLATION EXAMPLES
-below.
-.Sh PACKET FILTERING
-.Xr pf 4
-has the ability to
-.Ar block
-and
-.Ar pass
-packets based on attributes of their layer 3 (see
-.Xr ip 4
-and
-.Xr ip6 4 )
-and layer 4 (see
-.Xr icmp 4 ,
-.Xr icmp6 4 ,
-.Xr tcp 4 ,
-.Xr udp 4 )
-headers.
-In addition, packets may also be
-assigned to queues for the purpose of bandwidth control.
-.Pp
-For each packet processed by the packet filter, the filter rules are
-evaluated in sequential order, from first to last.
-The last matching rule decides what action is taken.
-If no rule matches the packet, the default action is to pass
-the packet.
-.Pp
-The following actions can be used in the filter:
-.Bl -tag -width xxxx
-.It Ar block
-The packet is blocked.
-There are a number of ways in which a
-.Ar block
-rule can behave when blocking a packet.
-The default behaviour is to
-.Ar drop
-packets silently, however this can be overridden or made
-explicit either globally, by setting the
-.Ar block-policy
-option, or on a per-rule basis with one of the following options:
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar drop
-The packet is silently dropped.
-.It Ar return-rst
-This applies only to
-.Xr tcp 4
-packets, and issues a TCP RST which closes the
-connection.
-.It Ar return-icmp
-.It Ar return-icmp6
-This causes ICMP messages to be returned for packets which match the rule.
-By default this is an ICMP UNREACHABLE message, however this
-can be overridden by specifying a message as a code or number.
-.It Ar return
-This causes a TCP RST to be returned for
-.Xr tcp 4
-packets and an ICMP UNREACHABLE for UDP and other packets.
-.El
-.Pp
-Options returning ICMP packets currently have no effect if
-.Xr pf 4
-operates on a
-.Xr if_bridge 4 ,
-as the code to support this feature has not yet been implemented.
-.Pp
-The simplest mechanism to block everything by default and only pass
-packets that match explicit rules is specify a first filter rule of:
-.Bd -literal -offset indent
-block all
-.Ed
-.It Ar pass
-The packet is passed;
-state is created unless the
-.Ar no state
-option is specified.
-.El
-.Pp
-By default
-.Xr pf 4
-filters packets statefully; the first time a packet matches a
-.Ar pass
-rule, a state entry is created; for subsequent packets the filter checks
-whether the packet matches any state.
-If it does, the packet is passed without evaluation of any rules.
-After the connection is closed or times out, the state entry is automatically
-removed.
-.Pp
-This has several advantages.
-For TCP connections, comparing a packet to a state involves checking
-its sequence numbers, as well as TCP timestamps if a
-.Ar scrub reassemble tcp
-rule applies to the connection.
-If these values are outside the narrow windows of expected
-values, the packet is dropped.
-This prevents spoofing attacks, such as when an attacker sends packets with
-a fake source address/port but does not know the connection's sequence
-numbers.
-Similarly,
-.Xr pf 4
-knows how to match ICMP replies to states.
-For example,
-.Bd -literal -offset indent
-pass out inet proto icmp all icmp-type echoreq
-.Ed
-.Pp
-allows echo requests (such as those created by
-.Xr ping 8 )
-out statefully, and matches incoming echo replies correctly to states.
-.Pp
-Also, looking up states is usually faster than evaluating rules.
-If there are 50 rules, all of them are evaluated sequentially in O(n).
-Even with 50000 states, only 16 comparisons are needed to match a
-state, since states are stored in a binary search tree that allows
-searches in O(log2 n).
-.Pp
-Furthermore, correct handling of ICMP error messages is critical to
-many protocols, particularly TCP.
-.Xr pf 4
-matches ICMP error messages to the correct connection, checks them against
-connection parameters, and passes them if appropriate.
-For example if an ICMP source quench message referring to a stateful TCP
-connection arrives, it will be matched to the state and get passed.
-.Pp
-Finally, state tracking is required for
-.Ar nat , binat No and Ar rdr
-rules, in order to track address and port translations and reverse the
-translation on returning packets.
-.Pp
-.Xr pf 4
-will also create state for other protocols which are effectively stateless by
-nature.
-UDP packets are matched to states using only host addresses and ports,
-and other protocols are matched to states using only the host addresses.
-.Pp
-If stateless filtering of individual packets is desired,
-the
-.Ar no state
-keyword can be used to specify that state will not be created
-if this is the last matching rule.
-A number of parameters can also be set to affect how
-.Xr pf 4
-handles state tracking.
-See
-.Sx STATEFUL TRACKING OPTIONS
-below for further details.
-.Sh PARAMETERS
-The rule parameters specify the packets to which a rule applies.
-A packet always comes in on, or goes out through, one interface.
-Most parameters are optional.
-If a parameter is specified, the rule only applies to packets with
-matching attributes.
-Certain parameters can be expressed as lists, in which case
-.Xr pfctl 8
-generates all needed rule combinations.
-.Bl -tag -width xxxx
-.It Ar in No or Ar out
-This rule applies to incoming or outgoing packets.
-If neither
-.Ar in
-nor
-.Ar out
-are specified, the rule will match packets in both directions.
-.It Ar log
-In addition to the action specified, a log message is generated.
-Only the packet that establishes the state is logged,
-unless the
-.Ar no state
-option is specified.
-The logged packets are sent to a
-.Xr pflog 4
-interface, by default
-.Ar pflog0 .
-This interface is monitored by the
-.Xr pflogd 8
-logging daemon, which dumps the logged packets to the file
-.Pa /var/log/pflog
-in
-.Xr pcap 3
-binary format.
-.It Ar log (all)
-Used to force logging of all packets for a connection.
-This is not necessary when
-.Ar no state
-is explicitly specified.
-As with
-.Ar log ,
-packets are logged to
-.Xr pflog 4 .
-.It Ar log (user)
-Logs the
-.Ux
-user ID of the user that owns the socket and the PID of the process that
-has the socket open where the packet is sourced from or destined to
-(depending on which socket is local).
-This is in addition to the normal information logged.
-.Pp
-Only the first packet
-logged via
-.Ar log (all, user)
-will have the user credentials logged when using stateful matching.
-.It Ar log (to Aq Ar interface )
-Send logs to the specified
-.Xr pflog 4
-interface instead of
-.Ar pflog0 .
-.It Ar quick
-If a packet matches a rule which has the
-.Ar quick
-option set, this rule
-is considered the last matching rule, and evaluation of subsequent rules
-is skipped.
-.It Ar on Aq Ar interface
-This rule applies only to packets coming in on, or going out through, this
-particular interface or interface group.
-For more information on interface groups,
-see the
-.Ic group
-keyword in
-.Xr ifconfig 8 .
-.It Aq Ar af
-This rule applies only to packets of this address family.
-Supported values are
-.Ar inet
-and
-.Ar inet6 .
-.It Ar proto Aq Ar protocol
-This rule applies only to packets of this protocol.
-Common protocols are
-.Xr icmp 4 ,
-.Xr icmp6 4 ,
-.Xr tcp 4 ,
-and
-.Xr udp 4 .
-For a list of all the protocol name to number mappings used by
-.Xr pfctl 8 ,
-see the file
-.Em /etc/protocols .
-.It Xo
-.Ar from Aq Ar source
-.Ar port Aq Ar source
-.Ar os Aq Ar source
-.Ar to Aq Ar dest
-.Ar port Aq Ar dest
-.Xc
-This rule applies only to packets with the specified source and destination
-addresses and ports.
-.Pp
-Addresses can be specified in CIDR notation (matching netblocks), as
-symbolic host names, interface names or interface group names, or as any
-of the following keywords:
-.Pp
-.Bl -tag -width xxxxxxxxxxxxxx -compact
-.It Ar any
-Any address.
-.It Ar no-route
-Any address which is not currently routable.
-.It Ar urpf-failed
-Any source address that fails a unicast reverse path forwarding (URPF)
-check, i.e. packets coming in on an interface other than that which holds
-the route back to the packet's source address.
-.It Aq Ar table
-Any address that matches the given table.
-.El
-.Pp
-Ranges of addresses are specified by using the
-.Sq -
-operator.
-For instance:
-.Dq 10.1.1.10 - 10.1.1.12
-means all addresses from 10.1.1.10 to 10.1.1.12,
-hence addresses 10.1.1.10, 10.1.1.11, and 10.1.1.12.
-.Pp
-Interface names and interface group names can have modifiers appended:
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Ar :network
-Translates to the network(s) attached to the interface.
-.It Ar :broadcast
-Translates to the interface's broadcast address(es).
-.It Ar :peer
-Translates to the point-to-point interface's peer address(es).
-.It Ar :0
-Do not include interface aliases.
-.El
-.Pp
-Host names may also have the
-.Ar :0
-option appended to restrict the name resolution to the first of each
-v4 and v6 address found.
-.Pp
-Host name resolution and interface to address translation are done at
-ruleset load-time.
-When the address of an interface (or host name) changes (under DHCP or PPP,
-for instance), the ruleset must be reloaded for the change to be reflected
-in the kernel.
-Surrounding the interface name (and optional modifiers) in parentheses
-changes this behaviour.
-When the interface name is surrounded by parentheses, the rule is
-automatically updated whenever the interface changes its address.
-The ruleset does not need to be reloaded.
-This is especially useful with
-.Ar nat .
-.Pp
-Ports can be specified either by number or by name.
-For example, port 80 can be specified as
-.Em www .
-For a list of all port name to number mappings used by
-.Xr pfctl 8 ,
-see the file
-.Pa /etc/services .
-.Pp
-Ports and ranges of ports are specified by using these operators:
-.Bd -literal -offset indent
-= (equal)
-!= (unequal)
-\*(Lt (less than)
-\*(Le (less than or equal)
-\*(Gt (greater than)
-\*(Ge (greater than or equal)
-: (range including boundaries)
-\*(Gt\*(Lt (range excluding boundaries)
-\*(Lt\*(Gt (except range)
-.Ed
-.Pp
-.Sq \*(Gt\*(Lt ,
-.Sq \*(Lt\*(Gt
-and
-.Sq \&:
-are binary operators (they take two arguments).
-For instance:
-.Bl -tag -width Fl
-.It Ar port 2000:2004
-means
-.Sq all ports \*(Ge 2000 and \*(Le 2004 ,
-hence ports 2000, 2001, 2002, 2003 and 2004.
-.It Ar port 2000 \*(Gt\*(Lt 2004
-means
-.Sq all ports \*(Gt 2000 and \*(Lt 2004 ,
-hence ports 2001, 2002 and 2003.
-.It Ar port 2000 \*(Lt\*(Gt 2004
-means
-.Sq all ports \*(Lt 2000 or \*(Gt 2004 ,
-hence ports 1-1999 and 2005-65535.
-.El
-.Pp
-The operating system of the source host can be specified in the case of TCP
-rules with the
-.Ar OS
-modifier.
-See the
-.Sx OPERATING SYSTEM FINGERPRINTING
-section for more information.
-.Pp
-The host, port and OS specifications are optional, as in the following examples:
-.Bd -literal -offset indent
-pass in all
-pass in from any to any
-pass in proto tcp from any port \*(Le 1024 to any
-pass in proto tcp from any to any port 25
-pass in proto tcp from 10.0.0.0/8 port \*(Gt 1024 \e
- to ! 10.1.2.3 port != ssh
-pass in proto tcp from any os "OpenBSD"
-.Ed
-.It Ar all
-This is equivalent to "from any to any".
-.It Ar group Aq Ar group
-Similar to
-.Ar user ,
-this rule only applies to packets of sockets owned by the specified group.
-.It Ar user Aq Ar user
-This rule only applies to packets of sockets owned by the specified user.
-For outgoing connections initiated from the firewall, this is the user
-that opened the connection.
-For incoming connections to the firewall itself, this is the user that
-listens on the destination port.
-For forwarded connections, where the firewall is not a connection endpoint,
-the user and group are
-.Em unknown .
-.Pp
-All packets, both outgoing and incoming, of one connection are associated
-with the same user and group.
-Only TCP and UDP packets can be associated with users; for other protocols
-these parameters are ignored.
-.Pp
-User and group refer to the effective (as opposed to the real) IDs, in
-case the socket is created by a setuid/setgid process.
-User and group IDs are stored when a socket is created;
-when a process creates a listening socket as root (for instance, by
-binding to a privileged port) and subsequently changes to another
-user ID (to drop privileges), the credentials will remain root.
-.Pp
-User and group IDs can be specified as either numbers or names.
-The syntax is similar to the one for ports.
-The value
-.Em unknown
-matches packets of forwarded connections.
-.Em unknown
-can only be used with the operators
-.Cm =
-and
-.Cm != .
-Other constructs like
-.Cm user \*(Ge unknown
-are invalid.
-Forwarded packets with unknown user and group ID match only rules
-that explicitly compare against
-.Em unknown
-with the operators
-.Cm =
-or
-.Cm != .
-For instance
-.Cm user \*(Ge 0
-does not match forwarded packets.
-The following example allows only selected users to open outgoing
-connections:
-.Bd -literal -offset indent
-block out proto { tcp, udp } all
-pass out proto { tcp, udp } all user { \*(Lt 1000, dhartmei }
-.Ed
-.It Xo Ar flags Aq Ar a
-.Pf / Ns Aq Ar b
-.No \*(Ba / Ns Aq Ar b
-.No \*(Ba any
-.Xc
-This rule only applies to TCP packets that have the flags
-.Aq Ar a
-set out of set
-.Aq Ar b .
-Flags not specified in
-.Aq Ar b
-are ignored.
-For stateful connections, the default is
-.Ar flags S/SA .
-To indicate that flags should not be checked at all, specify
-.Ar flags any .
-The flags are: (F)IN, (S)YN, (R)ST, (P)USH, (A)CK, (U)RG, (E)CE, and C(W)R.
-.Bl -tag -width Fl
-.It Ar flags S/S
-Flag SYN is set.
-The other flags are ignored.
-.It Ar flags S/SA
-This is the default setting for stateful connections.
-Out of SYN and ACK, exactly SYN may be set.
-SYN, SYN+PSH and SYN+RST match, but SYN+ACK, ACK and ACK+RST do not.
-This is more restrictive than the previous example.
-.It Ar flags /SFRA
-If the first set is not specified, it defaults to none.
-All of SYN, FIN, RST and ACK must be unset.
-.El
-.Pp
-Because
-.Ar flags S/SA
-is applied by default (unless
-.Ar no state
-is specified), only the initial SYN packet of a TCP handshake will create
-a state for a TCP connection.
-It is possible to be less restrictive, and allow state creation from
-intermediate
-.Pq non-SYN
-packets, by specifying
-.Ar flags any .
-This will cause
-.Xr pf 4
-to synchronize to existing connections, for instance
-if one flushes the state table.
-However, states created from such intermediate packets may be missing
-connection details such as the TCP window scaling factor.
-States which modify the packet flow, such as those affected by
-.Ar nat , binat No or Ar rdr
-rules,
-.Ar modulate No or Ar synproxy state
-options, or scrubbed with
-.Ar reassemble tcp
-will also not be recoverable from intermediate packets.
-Such connections will stall and time out.
-.It Xo Ar icmp-type Aq Ar type
-.Ar code Aq Ar code
-.Xc
-.It Xo Ar icmp6-type Aq Ar type
-.Ar code Aq Ar code
-.Xc
-This rule only applies to ICMP or ICMPv6 packets with the specified type
-and code.
-Text names for ICMP types and codes are listed in
-.Xr icmp 4
-and
-.Xr icmp6 4 .
-This parameter is only valid for rules that cover protocols ICMP or
-ICMP6.
-The protocol and the ICMP type indicator
-.Po
-.Ar icmp-type
-or
-.Ar icmp6-type
-.Pc
-must match.
-.It Xo Ar tos Aq Ar string
-.No \*(Ba Aq Ar number
-.Xc
-This rule applies to packets with the specified
-.Em TOS
-bits set.
-.Em TOS
-may be
-given as one of
-.Ar lowdelay ,
-.Ar throughput ,
-.Ar reliability ,
-or as either hex or decimal.
-.Pp
-For example, the following rules are identical:
-.Bd -literal -offset indent
-pass all tos lowdelay
-pass all tos 0x10
-pass all tos 16
-.Ed
-.It Ar allow-opts
-By default, IPv4 packets with IP options or IPv6 packets with routing
-extension headers are blocked.
-When
-.Ar allow-opts
-is specified for a
-.Ar pass
-rule, packets that pass the filter based on that rule (last matching)
-do so even if they contain IP options or routing extension headers.
-For packets that match state, the rule that initially created the
-state is used.
-The implicit
-.Ar pass
-rule that is used when a packet does not match any rules does not
-allow IP options.
-.It Ar label Aq Ar string
-Adds a label (name) to the rule, which can be used to identify the rule.
-For instance,
-pfctl -s labels
-shows per-rule statistics for rules that have labels.
-.Pp
-The following macros can be used in labels:
-.Pp
-.Bl -tag -width $srcaddr -compact -offset indent
-.It Ar $if
-The interface.
-.It Ar $srcaddr
-The source IP address.
-.It Ar $dstaddr
-The destination IP address.
-.It Ar $srcport
-The source port specification.
-.It Ar $dstport
-The destination port specification.
-.It Ar $proto
-The protocol name.
-.It Ar $nr
-The rule number.
-.El
-.Pp
-For example:
-.Bd -literal -offset indent
-ips = \&"{ 1.2.3.4, 1.2.3.5 }\&"
-pass in proto tcp from any to $ips \e
- port \*(Gt 1023 label \&"$dstaddr:$dstport\&"
-.Ed
-.Pp
-expands to
-.Bd -literal -offset indent
-pass in inet proto tcp from any to 1.2.3.4 \e
- port \*(Gt 1023 label \&"1.2.3.4:\*(Gt1023\&"
-pass in inet proto tcp from any to 1.2.3.5 \e
- port \*(Gt 1023 label \&"1.2.3.5:\*(Gt1023\&"
-.Ed
-.Pp
-The macro expansion for the
-.Ar label
-directive occurs only at configuration file parse time, not during runtime.
-.It Xo Ar queue Aq Ar queue
-.No \*(Ba ( Aq Ar queue ,
-.Aq Ar queue )
-.Xc
-Packets matching this rule will be assigned to the specified queue.
-If two queues are given, packets which have a
-.Em TOS
-of
-.Em lowdelay
-and TCP ACKs with no data payload will be assigned to the second one.
-See
-.Sx QUEUEING
-for setup details.
-.Pp
-For example:
-.Bd -literal -offset indent
-pass in proto tcp to port 25 queue mail
-pass in proto tcp to port 22 queue(ssh_bulk, ssh_prio)
-.Ed
-.It Ar tag Aq Ar string
-Packets matching this rule will be tagged with the
-specified string.
-The tag acts as an internal marker that can be used to
-identify these packets later on.
-This can be used, for example, to provide trust between
-interfaces and to determine if packets have been
-processed by translation rules.
-Tags are
-.Qq sticky ,
-meaning that the packet will be tagged even if the rule
-is not the last matching rule.
-Further matching rules can replace the tag with a
-new one but will not remove a previously applied tag.
-A packet is only ever assigned one tag at a time.
-Packet tagging can be done during
-.Ar nat ,
-.Ar rdr ,
-or
-.Ar binat
-rules in addition to filter rules.
-Tags take the same macros as labels (see above).
-.It Ar tagged Aq Ar string
-Used with filter, translation or scrub rules
-to specify that packets must already
-be tagged with the given tag in order to match the rule.
-Inverse tag matching can also be done
-by specifying the
-.Cm !\&
-operator before the
-.Ar tagged
-keyword.
-.It Ar rtable Aq Ar number
-Used to select an alternate routing table for the routing lookup.
-Only effective before the route lookup happened, i.e. when filtering inbound.
-.It Xo Ar divert-to Aq Ar host
-.Ar port Aq Ar port
-.Xc
-Used to redirect packets to a local socket bound to
-.Ar host
-and
-.Ar port .
-The packets will not be modified, so
-.Xr getsockname 2
-on the socket will return the original destination address of the packet.
-.It Ar divert-reply
-Used to receive replies for sockets that are bound to addresses
-which are not local to the machine.
-See
-.Xr setsockopt 2
-for information on how to bind these sockets.
-.It Ar probability Aq Ar number
-A probability attribute can be attached to a rule, with a value set between
-0 and 1, bounds not included.
-In that case, the rule will be honoured using the given probability value
-only.
-For example, the following rule will drop 20% of incoming ICMP packets:
-.Bd -literal -offset indent
-block in proto icmp probability 20%
-.Ed
-.El
-.Sh ROUTING
-If a packet matches a rule with a route option set, the packet filter will
-route the packet according to the type of route option.
-When such a rule creates state, the route option is also applied to all
-packets matching the same connection.
-.Bl -tag -width xxxx
-.It Ar fastroute
-The
-.Ar fastroute
-option does a normal route lookup to find the next hop for the packet.
-.It Ar route-to
-The
-.Ar route-to
-option routes the packet to the specified interface with an optional address
-for the next hop.
-When a
-.Ar route-to
-rule creates state, only packets that pass in the same direction as the
-filter rule specifies will be routed in this way.
-Packets passing in the opposite direction (replies) are not affected
-and are routed normally.
-.It Ar reply-to
-The
-.Ar reply-to
-option is similar to
-.Ar route-to ,
-but routes packets that pass in the opposite direction (replies) to the
-specified interface.
-Opposite direction is only defined in the context of a state entry, and
-.Ar reply-to
-is useful only in rules that create state.
-It can be used on systems with multiple external connections to
-route all outgoing packets of a connection through the interface
-the incoming connection arrived through (symmetric routing enforcement).
-.It Ar dup-to
-The
-.Ar dup-to
-option creates a duplicate of the packet and routes it like
-.Ar route-to .
-The original packet gets routed as it normally would.
-.El
-.Sh POOL OPTIONS
-For
-.Ar nat
-and
-.Ar rdr
-rules, (as well as for the
-.Ar route-to ,
-.Ar reply-to
-and
-.Ar dup-to
-rule options) for which there is a single redirection address which has a
-subnet mask smaller than 32 for IPv4 or 128 for IPv6 (more than one IP
-address), a variety of different methods for assigning this address can be
-used:
-.Bl -tag -width xxxx
-.It Ar bitmask
-The
-.Ar bitmask
-option applies the network portion of the redirection address to the address
-to be modified (source with
-.Ar nat ,
-destination with
-.Ar rdr ) .
-.It Ar random
-The
-.Ar random
-option selects an address at random within the defined block of addresses.
-.It Ar source-hash
-The
-.Ar source-hash
-option uses a hash of the source address to determine the redirection address,
-ensuring that the redirection address is always the same for a given source.
-An optional key can be specified after this keyword either in hex or as a
-string; by default
-.Xr pfctl 8
-randomly generates a key for source-hash every time the
-ruleset is reloaded.
-.It Ar round-robin
-The
-.Ar round-robin
-option loops through the redirection address(es).
-.Pp
-When more than one redirection address is specified,
-.Ar round-robin
-is the only permitted pool type.
-.It Ar static-port
-With
-.Ar nat
-rules, the
-.Ar static-port
-option prevents
-.Xr pf 4
-from modifying the source port on TCP and UDP packets.
-.El
-.Pp
-Additionally, the
-.Ar sticky-address
-option can be specified to help ensure that multiple connections from the
-same source are mapped to the same redirection address.
-This option can be used with the
-.Ar random
-and
-.Ar round-robin
-pool options.
-Note that by default these associations are destroyed as soon as there are
-no longer states which refer to them; in order to make the mappings last
-beyond the lifetime of the states, increase the global options with
-.Ar set timeout src.track .
-See
-.Sx STATEFUL TRACKING OPTIONS
-for more ways to control the source tracking.
-.Sh STATE MODULATION
-Much of the security derived from TCP is attributable to how well the
-initial sequence numbers (ISNs) are chosen.
-Some popular stack implementations choose
-.Em very
-poor ISNs and thus are normally susceptible to ISN prediction exploits.
-By applying a
-.Ar modulate state
-rule to a TCP connection,
-.Xr pf 4
-will create a high quality random sequence number for each connection
-endpoint.
-.Pp
-The
-.Ar modulate state
-directive implicitly keeps state on the rule and is
-only applicable to TCP connections.
-.Pp
-For instance:
-.Bd -literal -offset indent
-block all
-pass out proto tcp from any to any modulate state
-pass in proto tcp from any to any port 25 flags S/SFRA modulate state
-.Ed
-.Pp
-Note that modulated connections will not recover when the state table
-is lost (firewall reboot, flushing the state table, etc...).
-.Xr pf 4
-will not be able to infer a connection again after the state table flushes
-the connection's modulator.
-When the state is lost, the connection may be left dangling until the
-respective endpoints time out the connection.
-It is possible on a fast local network for the endpoints to start an ACK
-storm while trying to resynchronize after the loss of the modulator.
-The default
-.Ar flags
-settings (or a more strict equivalent) should be used on
-.Ar modulate state
-rules to prevent ACK storms.
-.Pp
-Note that alternative methods are available
-to prevent loss of the state table
-and allow for firewall failover.
-See
-.Xr carp 4
-and
-.Xr pfsync 4
-for further information.
-.Sh SYN PROXY
-By default,
-.Xr pf 4
-passes packets that are part of a
-.Xr tcp 4
-handshake between the endpoints.
-The
-.Ar synproxy state
-option can be used to cause
-.Xr pf 4
-itself to complete the handshake with the active endpoint, perform a handshake
-with the passive endpoint, and then forward packets between the endpoints.
-.Pp
-No packets are sent to the passive endpoint before the active endpoint has
-completed the handshake, hence so-called SYN floods with spoofed source
-addresses will not reach the passive endpoint, as the sender can't complete the
-handshake.
-.Pp
-The proxy is transparent to both endpoints, they each see a single
-connection from/to the other endpoint.
-.Xr pf 4
-chooses random initial sequence numbers for both handshakes.
-Once the handshakes are completed, the sequence number modulators
-(see previous section) are used to translate further packets of the
-connection.
-.Ar synproxy state
-includes
-.Ar modulate state .
-.Pp
-Rules with
-.Ar synproxy
-will not work if
-.Xr pf 4
-operates on a
-.Xr bridge 4 .
-.Pp
-Example:
-.Bd -literal -offset indent
-pass in proto tcp from any to any port www synproxy state
-.Ed
-.Sh STATEFUL TRACKING OPTIONS
-A number of options related to stateful tracking can be applied on a
-per-rule basis.
-.Ar keep state ,
-.Ar modulate state
-and
-.Ar synproxy state
-support these options, and
-.Ar keep state
-must be specified explicitly to apply options to a rule.
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar max Aq Ar number
-Limits the number of concurrent states the rule may create.
-When this limit is reached, further packets that would create
-state will not match this rule until existing states time out.
-.It Ar no-sync
-Prevent state changes for states created by this rule from appearing on the
-.Xr pfsync 4
-interface.
-.It Xo Aq Ar timeout
-.Aq Ar seconds
-.Xc
-Changes the timeout values used for states created by this rule.
-For a list of all valid timeout names, see
-.Sx OPTIONS
-above.
-.It Ar sloppy
-Uses a sloppy TCP connection tracker that does not check sequence
-numbers at all, which makes insertion and ICMP teardown attacks way
-easier.
-This is intended to be used in situations where one does not see all
-packets of a connection, e.g. in asymmetric routing situations.
-Cannot be used with modulate or synproxy state.
-.It Ar pflow
-States created by this rule are exported on the
-.Xr pflow 4
-interface.
-.El
-.Pp
-Multiple options can be specified, separated by commas:
-.Bd -literal -offset indent
-pass in proto tcp from any to any \e
- port www keep state \e
- (max 100, source-track rule, max-src-nodes 75, \e
- max-src-states 3, tcp.established 60, tcp.closing 5)
-.Ed
-.Pp
-When the
-.Ar source-track
-keyword is specified, the number of states per source IP is tracked.
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar source-track rule
-The maximum number of states created by this rule is limited by the rule's
-.Ar max-src-nodes
-and
-.Ar max-src-states
-options.
-Only state entries created by this particular rule count toward the rule's
-limits.
-.It Ar source-track global
-The number of states created by all rules that use this option is limited.
-Each rule can specify different
-.Ar max-src-nodes
-and
-.Ar max-src-states
-options, however state entries created by any participating rule count towards
-each individual rule's limits.
-.El
-.Pp
-The following limits can be set:
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar max-src-nodes Aq Ar number
-Limits the maximum number of source addresses which can simultaneously
-have state table entries.
-.It Ar max-src-states Aq Ar number
-Limits the maximum number of simultaneous state entries that a single
-source address can create with this rule.
-.El
-.Pp
-For stateful TCP connections, limits on established connections (connections
-which have completed the TCP 3-way handshake) can also be enforced
-per source IP.
-.Pp
-.Bl -tag -width xxxx -compact
-.It Ar max-src-conn Aq Ar number
-Limits the maximum number of simultaneous TCP connections which have
-completed the 3-way handshake that a single host can make.
-.It Xo Ar max-src-conn-rate Aq Ar number
-.No / Aq Ar seconds
-.Xc
-Limit the rate of new connections over a time interval.
-The connection rate is an approximation calculated as a moving average.
-.El
-.Pp
-Because the 3-way handshake ensures that the source address is not being
-spoofed, more aggressive action can be taken based on these limits.
-With the
-.Ar overload Aq Ar table
-state option, source IP addresses which hit either of the limits on
-established connections will be added to the named table.
-This table can be used in the ruleset to block further activity from
-the offending host, redirect it to a tarpit process, or restrict its
-bandwidth.
-.Pp
-The optional
-.Ar flush
-keyword kills all states created by the matching rule which originate
-from the host which exceeds these limits.
-The
-.Ar global
-modifier to the flush command kills all states originating from the
-offending host, regardless of which rule created the state.
-.Pp
-For example, the following rules will protect the webserver against
-hosts making more than 100 connections in 10 seconds.
-Any host which connects faster than this rate will have its address added
-to the
-.Aq bad_hosts
-table and have all states originating from it flushed.
-Any new packets arriving from this host will be dropped unconditionally
-by the block rule.
-.Bd -literal -offset indent
-block quick from \*(Ltbad_hosts\*(Gt
-pass in on $ext_if proto tcp to $webserver port www keep state \e
- (max-src-conn-rate 100/10, overload \*(Ltbad_hosts\*(Gt flush global)
-.Ed
-.Sh OPERATING SYSTEM FINGERPRINTING
-Passive OS Fingerprinting is a mechanism to inspect nuances of a TCP
-connection's initial SYN packet and guess at the host's operating system.
-Unfortunately these nuances are easily spoofed by an attacker so the
-fingerprint is not useful in making security decisions.
-But the fingerprint is typically accurate enough to make policy decisions
-upon.
-.Pp
-The fingerprints may be specified by operating system class, by
-version, or by subtype/patchlevel.
-The class of an operating system is typically the vendor or genre
-and would be
-.Ox
-for the
-.Xr pf 4
-firewall itself.
-The version of the oldest available
-.Ox
-release on the main FTP site
-would be 2.6 and the fingerprint would be written
-.Pp
-.Dl \&"OpenBSD 2.6\&"
-.Pp
-The subtype of an operating system is typically used to describe the
-patchlevel if that patch led to changes in the TCP stack behavior.
-In the case of
-.Ox ,
-the only subtype is for a fingerprint that was
-normalized by the
-.Ar no-df
-scrub option and would be specified as
-.Pp
-.Dl \&"OpenBSD 3.3 no-df\&"
-.Pp
-Fingerprints for most popular operating systems are provided by
-.Xr pf.os 5 .
-Once
-.Xr pf 4
-is running, a complete list of known operating system fingerprints may
-be listed by running:
-.Pp
-.Dl # pfctl -so
-.Pp
-Filter rules can enforce policy at any level of operating system specification
-assuming a fingerprint is present.
-Policy could limit traffic to approved operating systems or even ban traffic
-from hosts that aren't at the latest service pack.
-.Pp
-The
-.Ar unknown
-class can also be used as the fingerprint which will match packets for
-which no operating system fingerprint is known.
-.Pp
-Examples:
-.Bd -literal -offset indent
-pass out proto tcp from any os OpenBSD
-block out proto tcp from any os Doors
-block out proto tcp from any os "Doors PT"
-block out proto tcp from any os "Doors PT SP3"
-block out from any os "unknown"
-pass on lo0 proto tcp from any os "OpenBSD 3.3 lo0"
-.Ed
-.Pp
-Operating system fingerprinting is limited only to the TCP SYN packet.
-This means that it will not work on other protocols and will not match
-a currently established connection.
-.Pp
-Caveat: operating system fingerprints are occasionally wrong.
-There are three problems: an attacker can trivially craft his packets to
-appear as any operating system he chooses;
-an operating system patch could change the stack behavior and no fingerprints
-will match it until the database is updated;
-and multiple operating systems may have the same fingerprint.
-.Sh BLOCKING SPOOFED TRAFFIC
-"Spoofing" is the faking of IP addresses, typically for malicious
-purposes.
-The
-.Ar antispoof
-directive expands to a set of filter rules which will block all
-traffic with a source IP from the network(s) directly connected
-to the specified interface(s) from entering the system through
-any other interface.
-.Pp
-For example, the line
-.Bd -literal -offset indent
-antispoof for lo0
-.Ed
-.Pp
-expands to
-.Bd -literal -offset indent
-block drop in on ! lo0 inet from 127.0.0.1/8 to any
-block drop in on ! lo0 inet6 from ::1 to any
-.Ed
-.Pp
-For non-loopback interfaces, there are additional rules to block incoming
-packets with a source IP address identical to the interface's IP(s).
-For example, assuming the interface wi0 had an IP address of 10.0.0.1 and a
-netmask of 255.255.255.0,
-the line
-.Bd -literal -offset indent
-antispoof for wi0 inet
-.Ed
-.Pp
-expands to
-.Bd -literal -offset indent
-block drop in on ! wi0 inet from 10.0.0.0/24 to any
-block drop in inet from 10.0.0.1 to any
-.Ed
-.Pp
-Caveat: Rules created by the
-.Ar antispoof
-directive interfere with packets sent over loopback interfaces
-to local addresses.
-One should pass these explicitly.
-.Sh FRAGMENT HANDLING
-The size of IP datagrams (packets) can be significantly larger than the
-maximum transmission unit (MTU) of the network.
-In cases when it is necessary or more efficient to send such large packets,
-the large packet will be fragmented into many smaller packets that will each
-fit onto the wire.
-Unfortunately for a firewalling device, only the first logical fragment will
-contain the necessary header information for the subprotocol that allows
-.Xr pf 4
-to filter on things such as TCP ports or to perform NAT.
-.Pp
-Besides the use of
-.Ar scrub
-rules as described in
-.Sx TRAFFIC NORMALIZATION
-above, there are three options for handling fragments in the packet filter.
-.Pp
-One alternative is to filter individual fragments with filter rules.
-If no
-.Ar scrub
-rule applies to a fragment, it is passed to the filter.
-Filter rules with matching IP header parameters decide whether the
-fragment is passed or blocked, in the same way as complete packets
-are filtered.
-Without reassembly, fragments can only be filtered based on IP header
-fields (source/destination address, protocol), since subprotocol header
-fields are not available (TCP/UDP port numbers, ICMP code/type).
-The
-.Ar fragment
-option can be used to restrict filter rules to apply only to
-fragments, but not complete packets.
-Filter rules without the
-.Ar fragment
-option still apply to fragments, if they only specify IP header fields.
-For instance, the rule
-.Bd -literal -offset indent
-pass in proto tcp from any to any port 80
-.Ed
-.Pp
-never applies to a fragment, even if the fragment is part of a TCP
-packet with destination port 80, because without reassembly this information
-is not available for each fragment.
-This also means that fragments cannot create new or match existing
-state table entries, which makes stateful filtering and address
-translation (NAT, redirection) for fragments impossible.
-.Pp
-It's also possible to reassemble only certain fragments by specifying
-source or destination addresses or protocols as parameters in
-.Ar scrub
-rules.
-.Pp
-In most cases, the benefits of reassembly outweigh the additional
-memory cost, and it's recommended to use
-.Ar scrub
-rules to reassemble
-all fragments via the
-.Ar fragment reassemble
-modifier.
-.Pp
-The memory allocated for fragment caching can be limited using
-.Xr pfctl 8 .
-Once this limit is reached, fragments that would have to be cached
-are dropped until other entries time out.
-The timeout value can also be adjusted.
-.Pp
-Currently, only IPv4 fragments are supported and IPv6 fragments
-are blocked unconditionally.
-.Sh ANCHORS
-Besides the main ruleset,
-.Xr pfctl 8
-can load rulesets into
-.Ar anchor
-attachment points.
-An
-.Ar anchor
-is a container that can hold rules, address tables, and other anchors.
-.Pp
-An
-.Ar anchor
-has a name which specifies the path where
-.Xr pfctl 8
-can be used to access the anchor to perform operations on it, such as
-attaching child anchors to it or loading rules into it.
-Anchors may be nested, with components separated by
-.Sq /
-characters, similar to how file system hierarchies are laid out.
-The main ruleset is actually the default anchor, so filter and
-translation rules, for example, may also be contained in any anchor.
-.Pp
-An anchor can reference another
-.Ar anchor
-attachment point
-using the following kinds
-of rules:
-.Bl -tag -width xxxx
-.It Ar nat-anchor Aq Ar name
-Evaluates the
-.Ar nat
-rules in the specified
-.Ar anchor .
-.It Ar rdr-anchor Aq Ar name
-Evaluates the
-.Ar rdr
-rules in the specified
-.Ar anchor .
-.It Ar binat-anchor Aq Ar name
-Evaluates the
-.Ar binat
-rules in the specified
-.Ar anchor .
-.It Ar anchor Aq Ar name
-Evaluates the filter rules in the specified
-.Ar anchor .
-.It Xo Ar load anchor
-.Aq Ar name
-.Ar from Aq Ar file
-.Xc
-Loads the rules from the specified file into the
-anchor
-.Ar name .
-.El
-.Pp
-When evaluation of the main ruleset reaches an
-.Ar anchor
-rule,
-.Xr pf 4
-will proceed to evaluate all rules specified in that anchor.
-.Pp
-Matching filter and translation rules marked with the
-.Ar quick
-option are final and abort the evaluation of the rules in other
-anchors and the main ruleset.
-If the
-.Ar anchor
-itself is marked with the
-.Ar quick
-option,
-ruleset evaluation will terminate when the anchor is exited if the packet is
-matched by any rule within the anchor.
-.Pp
-.Ar anchor
-rules are evaluated relative to the anchor in which they are contained.
-For example, all
-.Ar anchor
-rules specified in the main ruleset will reference anchor
-attachment points underneath the main ruleset, and
-.Ar anchor
-rules specified in a file loaded from a
-.Ar load anchor
-rule will be attached under that anchor point.
-.Pp
-Rules may be contained in
-.Ar anchor
-attachment points which do not contain any rules when the main ruleset
-is loaded, and later such anchors can be manipulated through
-.Xr pfctl 8
-without reloading the main ruleset or other anchors.
-For example,
-.Bd -literal -offset indent
-ext_if = \&"kue0\&"
-block on $ext_if all
-anchor spam
-pass out on $ext_if all
-pass in on $ext_if proto tcp from any \e
- to $ext_if port smtp
-.Ed
-.Pp
-blocks all packets on the external interface by default, then evaluates
-all rules in the
-.Ar anchor
-named "spam", and finally passes all outgoing connections and
-incoming connections to port 25.
-.Bd -literal -offset indent
-# echo \&"block in quick from 1.2.3.4 to any\&" \&| \e
- pfctl -a spam -f -
-.Ed
-.Pp
-This loads a single rule into the
-.Ar anchor ,
-which blocks all packets from a specific address.
-.Pp
-The anchor can also be populated by adding a
-.Ar load anchor
-rule after the
-.Ar anchor
-rule:
-.Bd -literal -offset indent
-anchor spam
-load anchor spam from "/etc/pf-spam.conf"
-.Ed
-.Pp
-When
-.Xr pfctl 8
-loads
-.Nm pf.conf ,
-it will also load all the rules from the file
-.Pa /etc/pf-spam.conf
-into the anchor.
-.Pp
-Optionally,
-.Ar anchor
-rules can specify packet filtering parameters using the same syntax as
-filter rules.
-When parameters are used, the
-.Ar anchor
-rule is only evaluated for matching packets.
-This allows conditional evaluation of anchors, like:
-.Bd -literal -offset indent
-block on $ext_if all
-anchor spam proto tcp from any to any port smtp
-pass out on $ext_if all
-pass in on $ext_if proto tcp from any to $ext_if port smtp
-.Ed
-.Pp
-The rules inside
-.Ar anchor
-spam are only evaluated for
-.Ar tcp
-packets with destination port 25.
-Hence,
-.Bd -literal -offset indent
-# echo \&"block in quick from 1.2.3.4 to any" \&| \e
- pfctl -a spam -f -
-.Ed
-.Pp
-will only block connections from 1.2.3.4 to port 25.
-.Pp
-Anchors may end with the asterisk
-.Pq Sq *
-character, which signifies that all anchors attached at that point
-should be evaluated in the alphabetical ordering of their anchor name.
-For example,
-.Bd -literal -offset indent
-anchor "spam/*"
-.Ed
-.Pp
-will evaluate each rule in each anchor attached to the
-.Li spam
-anchor.
-Note that it will only evaluate anchors that are directly attached to the
-.Li spam
-anchor, and will not descend to evaluate anchors recursively.
-.Pp
-Since anchors are evaluated relative to the anchor in which they are
-contained, there is a mechanism for accessing the parent and ancestor
-anchors of a given anchor.
-Similar to file system path name resolution, if the sequence
-.Dq ..
-appears as an anchor path component, the parent anchor of the current
-anchor in the path evaluation at that point will become the new current
-anchor.
-As an example, consider the following:
-.Bd -literal -offset indent
-# echo ' anchor "spam/allowed" ' | pfctl -f -
-# echo -e ' anchor "../banned" \en pass' | \e
- pfctl -a spam/allowed -f -
-.Ed
-.Pp
-Evaluation of the main ruleset will lead into the
-.Li spam/allowed
-anchor, which will evaluate the rules in the
-.Li spam/banned
-anchor, if any, before finally evaluating the
-.Ar pass
-rule.
-.Pp
-Filter rule
-.Ar anchors
-can also be loaded inline in the ruleset within a brace ('{' '}') delimited
-block.
-Brace delimited blocks may contain rules or other brace-delimited blocks.
-When anchors are loaded this way the anchor name becomes optional.
-.Bd -literal -offset indent
-anchor "external" on egress {
- block
- anchor out {
- pass proto tcp from any to port { 25, 80, 443 }
- }
- pass in proto tcp to any port 22
-}
-.Ed
-.Pp
-Since the parser specification for anchor names is a string, any
-reference to an anchor name containing
-.Sq /
-characters will require double quote
-.Pq Sq \&"
-characters around the anchor name.
-.Sh TRANSLATION EXAMPLES
-This example maps incoming requests on port 80 to port 8080, on
-which a daemon is running (because, for example, it is not run as root,
-and therefore lacks permission to bind to port 80).
-.Bd -literal
-# use a macro for the interface name, so it can be changed easily
-ext_if = \&"ne3\&"
-
-# map daemon on 8080 to appear to be on 80
-rdr on $ext_if proto tcp from any to any port 80 -\*(Gt 127.0.0.1 port 8080
-.Ed
-.Pp
-If the
-.Ar pass
-modifier is given, packets matching the translation rule are passed without
-inspecting the filter rules:
-.Bd -literal
-rdr pass on $ext_if proto tcp from any to any port 80 -\*(Gt 127.0.0.1 \e
- port 8080
-.Ed
-.Pp
-In the example below, vlan12 is configured as 192.168.168.1;
-the machine translates all packets coming from 192.168.168.0/24 to 204.92.77.111
-when they are going out any interface except vlan12.
-This has the net effect of making traffic from the 192.168.168.0/24
-network appear as though it is the Internet routable address
-204.92.77.111 to nodes behind any interface on the router except
-for the nodes on vlan12.
-(Thus, 192.168.168.1 can talk to the 192.168.168.0/24 nodes.)
-.Bd -literal
-nat on ! vlan12 from 192.168.168.0/24 to any -\*(Gt 204.92.77.111
-.Ed
-.Pp
-In the example below, the machine sits between a fake internal 144.19.74.*
-network, and a routable external IP of 204.92.77.100.
-The
-.Ar no nat
-rule excludes protocol AH from being translated.
-.Bd -literal
-# NO NAT
-no nat on $ext_if proto ah from 144.19.74.0/24 to any
-nat on $ext_if from 144.19.74.0/24 to any -\*(Gt 204.92.77.100
-.Ed
-.Pp
-In the example below, packets bound for one specific server, as well as those
-generated by the sysadmins are not proxied; all other connections are.
-.Bd -literal
-# NO RDR
-no rdr on $int_if proto { tcp, udp } from any to $server port 80
-no rdr on $int_if proto { tcp, udp } from $sysadmins to any port 80
-rdr on $int_if proto { tcp, udp } from any to any port 80 -\*(Gt 127.0.0.1 \e
- port 80
-.Ed
-.Pp
-This longer example uses both a NAT and a redirection.
-The external interface has the address 157.161.48.183.
-On localhost, we are running
-.Xr ftp-proxy 8 ,
-waiting for FTP sessions to be redirected to it.
-The three mandatory anchors for
-.Xr ftp-proxy 8
-are omitted from this example; see the
-.Xr ftp-proxy 8
-manpage.
-.Bd -literal
-# NAT
-# Translate outgoing packets' source addresses (any protocol).
-# In this case, any address but the gateway's external address is mapped.
-nat on $ext_if inet from ! ($ext_if) to any -\*(Gt ($ext_if)
-
-# NAT PROXYING
-# Map outgoing packets' source port to an assigned proxy port instead of
-# an arbitrary port.
-# In this case, proxy outgoing isakmp with port 500 on the gateway.
-nat on $ext_if inet proto udp from any port = isakmp to any -\*(Gt ($ext_if) \e
- port 500
-
-# BINAT
-# Translate outgoing packets' source address (any protocol).
-# Translate incoming packets' destination address to an internal machine
-# (bidirectional).
-binat on $ext_if from 10.1.2.150 to any -\*(Gt $ext_if
-
-# RDR
-# Translate incoming packets' destination addresses.
-# As an example, redirect a TCP and UDP port to an internal machine.
-rdr on $ext_if inet proto tcp from any to ($ext_if) port 8080 \e
- -\*(Gt 10.1.2.151 port 22
-rdr on $ext_if inet proto udp from any to ($ext_if) port 8080 \e
- -\*(Gt 10.1.2.151 port 53
-
-# RDR
-# Translate outgoing ftp control connections to send them to localhost
-# for proxying with ftp-proxy(8) running on port 8021.
-rdr on $int_if proto tcp from any to any port 21 -\*(Gt 127.0.0.1 port 8021
-.Ed
-.Pp
-In this example, a NAT gateway is set up to translate internal addresses
-using a pool of public addresses (192.0.2.16/28) and to redirect
-incoming web server connections to a group of web servers on the internal
-network.
-.Bd -literal
-# NAT LOAD BALANCE
-# Translate outgoing packets' source addresses using an address pool.
-# A given source address is always translated to the same pool address by
-# using the source-hash keyword.
-nat on $ext_if inet from any to any -\*(Gt 192.0.2.16/28 source-hash
-
-# RDR ROUND ROBIN
-# Translate incoming web server connections to a group of web servers on
-# the internal network.
-rdr on $ext_if proto tcp from any to any port 80 \e
- -\*(Gt { 10.1.2.155, 10.1.2.160, 10.1.2.161 } round-robin
-.Ed
-.Sh FILTER EXAMPLES
-.Bd -literal
-# The external interface is kue0
-# (157.161.48.183, the only routable address)
-# and the private network is 10.0.0.0/8, for which we are doing NAT.
-
-# use a macro for the interface name, so it can be changed easily
-ext_if = \&"kue0\&"
-
-# normalize all incoming traffic
-scrub in on $ext_if all fragment reassemble
-
-# block and log everything by default
-block return log on $ext_if all
-
-# block anything coming from source we have no back routes for
-block in from no-route to any
-
-# block packets whose ingress interface does not match the one in
-# the route back to their source address
-block in from urpf-failed to any
-
-# block and log outgoing packets that do not have our address as source,
-# they are either spoofed or something is misconfigured (NAT disabled,
-# for instance), we want to be nice and do not send out garbage.
-block out log quick on $ext_if from ! 157.161.48.183 to any
-
-# silently drop broadcasts (cable modem noise)
-block in quick on $ext_if from any to 255.255.255.255
-
-# block and log incoming packets from reserved address space and invalid
-# addresses, they are either spoofed or misconfigured, we cannot reply to
-# them anyway (hence, no return-rst).
-block in log quick on $ext_if from { 10.0.0.0/8, 172.16.0.0/12, \e
- 192.168.0.0/16, 255.255.255.255/32 } to any
-
-# ICMP
-
-# pass out/in certain ICMP queries and keep state (ping)
-# state matching is done on host addresses and ICMP id (not type/code),
-# so replies (like 0/0 for 8/0) will match queries
-# ICMP error messages (which always refer to a TCP/UDP packet) are
-# handled by the TCP/UDP states
-pass on $ext_if inet proto icmp all icmp-type 8 code 0
-
-# UDP
-
-# pass out all UDP connections and keep state
-pass out on $ext_if proto udp all
-
-# pass in certain UDP connections and keep state (DNS)
-pass in on $ext_if proto udp from any to any port domain
-
-# TCP
-
-# pass out all TCP connections and modulate state
-pass out on $ext_if proto tcp all modulate state
-
-# pass in certain TCP connections and keep state (SSH, SMTP, DNS, IDENT)
-pass in on $ext_if proto tcp from any to any port { ssh, smtp, domain, \e
- auth }
-
-# Do not allow Windows 9x SMTP connections since they are typically
-# a viral worm. Alternately we could limit these OSes to 1 connection each.
-block in on $ext_if proto tcp from any os {"Windows 95", "Windows 98"} \e
- to any port smtp
-
-# IPv6
-# pass in/out all IPv6 traffic: note that we have to enable this in two
-# different ways, on both our physical interface and our tunnel
-pass quick on gif0 inet6
-pass quick on $ext_if proto ipv6
-
-# Packet Tagging
-
-# three interfaces: $int_if, $ext_if, and $wifi_if (wireless). NAT is
-# being done on $ext_if for all outgoing packets. tag packets in on
-# $int_if and pass those tagged packets out on $ext_if. all other
-# outgoing packets (i.e., packets from the wireless network) are only
-# permitted to access port 80.
-
-pass in on $int_if from any to any tag INTNET
-pass in on $wifi_if from any to any
-
-block out on $ext_if from any to any
-pass out quick on $ext_if tagged INTNET
-pass out on $ext_if proto tcp from any to any port 80
-
-# tag incoming packets as they are redirected to spamd(8). use the tag
-# to pass those packets through the packet filter.
-
-rdr on $ext_if inet proto tcp from \*(Ltspammers\*(Gt to port smtp \e
- tag SPAMD -\*(Gt 127.0.0.1 port spamd
-
-block in on $ext_if
-pass in on $ext_if inet proto tcp tagged SPAMD
-.Ed
-.Sh GRAMMAR
-Syntax for
-.Nm
-in BNF:
-.Bd -literal
-line = ( option | pf-rule | nat-rule | binat-rule | rdr-rule |
- antispoof-rule | altq-rule | queue-rule | trans-anchors |
- anchor-rule | anchor-close | load-anchor | table-rule |
- include )
-
-option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] |
- [ "ruleset-optimization" [ "none" | "basic" | "profile" ]] |
- [ "optimization" [ "default" | "normal" |
- "high-latency" | "satellite" |
- "aggressive" | "conservative" ] ]
- [ "limit" ( limit-item | "{" limit-list "}" ) ] |
- [ "loginterface" ( interface-name | "none" ) ] |
- [ "block-policy" ( "drop" | "return" ) ] |
- [ "state-policy" ( "if-bound" | "floating" ) ]
- [ "state-defaults" state-opts ]
- [ "require-order" ( "yes" | "no" ) ]
- [ "fingerprints" filename ] |
- [ "skip on" ifspec ] |
- [ "debug" ( "none" | "urgent" | "misc" | "loud" ) ] )
-
-pf-rule = action [ ( "in" | "out" ) ]
- [ "log" [ "(" logopts ")"] ] [ "quick" ]
- [ "on" ifspec ] [ "fastroute" | route ] [ af ] [ protospec ]
- hosts [ filteropt-list ]
-
-logopts = logopt [ "," logopts ]
-logopt = "all" | "user" | "to" interface-name
-
-filteropt-list = filteropt-list filteropt | filteropt
-filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos |
- ( "no" | "keep" | "modulate" | "synproxy" ) "state"
- [ "(" state-opts ")" ] |
- "fragment" | "no-df" | "min-ttl" number | "set-tos" tos |
- "max-mss" number | "random-id" | "reassemble tcp" |
- fragmentation | "allow-opts" |
- "label" string | "tag" string | [ ! ] "tagged" string |
- "queue" ( string | "(" string [ [ "," ] string ] ")" ) |
- "rtable" number | "probability" number"%"
-
-nat-rule = [ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
- [ "on" ifspec ] [ af ]
- [ protospec ] hosts [ "tag" string ] [ "tagged" string ]
- [ "-\*(Gt" ( redirhost | "{" redirhost-list "}" )
- [ portspec ] [ pooltype ] [ "static-port" ] ]
-
-binat-rule = [ "no" ] "binat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
- [ "on" interface-name ] [ af ]
- [ "proto" ( proto-name | proto-number ) ]
- "from" address [ "/" mask-bits ] "to" ipspec
- [ "tag" string ] [ "tagged" string ]
- [ "-\*(Gt" address [ "/" mask-bits ] ]
-
-rdr-rule = [ "no" ] "rdr" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
- [ "on" ifspec ] [ af ]
- [ protospec ] hosts [ "tag" string ] [ "tagged" string ]
- [ "-\*(Gt" ( redirhost | "{" redirhost-list "}" )
- [ portspec ] [ pooltype ] ]
-
-antispoof-rule = "antispoof" [ "log" ] [ "quick" ]
- "for" ifspec [ af ] [ "label" string ]
-
-table-rule = "table" "\*(Lt" string "\*(Gt" [ tableopts-list ]
-tableopts-list = tableopts-list tableopts | tableopts
-tableopts = "persist" | "const" | "counters" | "file" string |
- "{" [ tableaddr-list ] "}"
-tableaddr-list = tableaddr-list [ "," ] tableaddr-spec | tableaddr-spec
-tableaddr-spec = [ "!" ] tableaddr [ "/" mask-bits ]
-tableaddr = hostname | ifspec | "self" |
- ipv4-dotted-quad | ipv6-coloned-hex
-
-altq-rule = "altq on" interface-name queueopts-list
- "queue" subqueue
-queue-rule = "queue" string [ "on" interface-name ] queueopts-list
- subqueue
-
-anchor-rule = "anchor" [ string ] [ ( "in" | "out" ) ] [ "on" ifspec ]
- [ af ] [ protospec ] [ hosts ] [ filteropt-list ] [ "{" ]
-
-anchor-close = "}"
-
-trans-anchors = ( "nat-anchor" | "rdr-anchor" | "binat-anchor" ) string
- [ "on" ifspec ] [ af ] [ "proto" ] [ protospec ] [ hosts ]
-
-load-anchor = "load anchor" string "from" filename
-
-queueopts-list = queueopts-list queueopts | queueopts
-queueopts = [ "bandwidth" bandwidth-spec ] |
- [ "qlimit" number ] | [ "tbrsize" number ] |
- [ "priority" number ] | [ schedulers ]
-schedulers = ( cbq-def | priq-def | hfsc-def )
-bandwidth-spec = "number" ( "b" | "Kb" | "Mb" | "Gb" | "%" )
-
-action = "pass" | "block" [ return ] | [ "no" ] "scrub"
-return = "drop" | "return" | "return-rst" [ "( ttl" number ")" ] |
- "return-icmp" [ "(" icmpcode [ [ "," ] icmp6code ] ")" ] |
- "return-icmp6" [ "(" icmp6code ")" ]
-icmpcode = ( icmp-code-name | icmp-code-number )
-icmp6code = ( icmp6-code-name | icmp6-code-number )
-
-ifspec = ( [ "!" ] ( interface-name | interface-group ) ) |
- "{" interface-list "}"
-interface-list = [ "!" ] ( interface-name | interface-group )
- [ [ "," ] interface-list ]
-route = ( "route-to" | "reply-to" | "dup-to" )
- ( routehost | "{" routehost-list "}" )
- [ pooltype ]
-af = "inet" | "inet6"
-
-protospec = "proto" ( proto-name | proto-number |
- "{" proto-list "}" )
-proto-list = ( proto-name | proto-number ) [ [ "," ] proto-list ]
-
-hosts = "all" |
- "from" ( "any" | "no-route" | "urpf-failed" | "self" | host |
- "{" host-list "}" ) [ port ] [ os ]
- "to" ( "any" | "no-route" | "self" | host |
- "{" host-list "}" ) [ port ]
-
-ipspec = "any" | host | "{" host-list "}"
-host = [ "!" ] ( address [ "/" mask-bits ] | "\*(Lt" string "\*(Gt" )
-redirhost = address [ "/" mask-bits ]
-routehost = "(" interface-name [ address [ "/" mask-bits ] ] ")"
-address = ( interface-name | interface-group |
- "(" ( interface-name | interface-group ) ")" |
- hostname | ipv4-dotted-quad | ipv6-coloned-hex )
-host-list = host [ [ "," ] host-list ]
-redirhost-list = redirhost [ [ "," ] redirhost-list ]
-routehost-list = routehost [ [ "," ] routehost-list ]
-
-port = "port" ( unary-op | binary-op | "{" op-list "}" )
-portspec = "port" ( number | name ) [ ":" ( "*" | number | name ) ]
-os = "os" ( os-name | "{" os-list "}" )
-user = "user" ( unary-op | binary-op | "{" op-list "}" )
-group = "group" ( unary-op | binary-op | "{" op-list "}" )
-
-unary-op = [ "=" | "!=" | "\*(Lt" | "\*(Le" | "\*(Gt" | "\*(Ge" ]
- ( name | number )
-binary-op = number ( "\*(Lt\*(Gt" | "\*(Gt\*(Lt" | ":" ) number
-op-list = ( unary-op | binary-op ) [ [ "," ] op-list ]
-
-os-name = operating-system-name
-os-list = os-name [ [ "," ] os-list ]
-
-flags = "flags" ( [ flag-set ] "/" flag-set | "any" )
-flag-set = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] [ "E" ]
- [ "W" ]
-
-icmp-type = "icmp-type" ( icmp-type-code | "{" icmp-list "}" )
-icmp6-type = "icmp6-type" ( icmp-type-code | "{" icmp-list "}" )
-icmp-type-code = ( icmp-type-name | icmp-type-number )
- [ "code" ( icmp-code-name | icmp-code-number ) ]
-icmp-list = icmp-type-code [ [ "," ] icmp-list ]
-
-tos = ( "lowdelay" | "throughput" | "reliability" |
- [ "0x" ] number )
-
-state-opts = state-opt [ [ "," ] state-opts ]
-state-opt = ( "max" number | "no-sync" | timeout | "sloppy" | "pflow" |
- "source-track" [ ( "rule" | "global" ) ] |
- "max-src-nodes" number | "max-src-states" number |
- "max-src-conn" number |
- "max-src-conn-rate" number "/" number |
- "overload" "\*(Lt" string "\*(Gt" [ "flush" ] |
- "if-bound" | "floating" )
-
-fragmentation = [ "fragment reassemble" | "fragment crop" |
- "fragment drop-ovl" ]
-
-timeout-list = timeout [ [ "," ] timeout-list ]
-timeout = ( "tcp.first" | "tcp.opening" | "tcp.established" |
- "tcp.closing" | "tcp.finwait" | "tcp.closed" |
- "udp.first" | "udp.single" | "udp.multiple" |
- "icmp.first" | "icmp.error" |
- "other.first" | "other.single" | "other.multiple" |
- "frag" | "interval" | "src.track" |
- "adaptive.start" | "adaptive.end" ) number
-
-limit-list = limit-item [ [ "," ] limit-list ]
-limit-item = ( "states" | "frags" | "src-nodes" ) number
-
-pooltype = ( "bitmask" | "random" |
- "source-hash" [ ( hex-key | string-key ) ] |
- "round-robin" ) [ sticky-address ]
-
-subqueue = string | "{" queue-list "}"
-queue-list = string [ [ "," ] string ]
-cbq-def = "cbq" [ "(" cbq-opt [ [ "," ] cbq-opt ] ")" ]
-priq-def = "priq" [ "(" priq-opt [ [ "," ] priq-opt ] ")" ]
-hfsc-def = "hfsc" [ "(" hfsc-opt [ [ "," ] hfsc-opt ] ")" ]
-cbq-opt = ( "default" | "borrow" | "red" | "ecn" | "rio" )
-priq-opt = ( "default" | "red" | "ecn" | "rio" )
-hfsc-opt = ( "default" | "red" | "ecn" | "rio" |
- linkshare-sc | realtime-sc | upperlimit-sc )
-linkshare-sc = "linkshare" sc-spec
-realtime-sc = "realtime" sc-spec
-upperlimit-sc = "upperlimit" sc-spec
-sc-spec = ( bandwidth-spec |
- "(" bandwidth-spec number bandwidth-spec ")" )
-include = "include" filename
-.Ed
-.Sh FILES
-.Bl -tag -width "/etc/protocols" -compact
-.It Pa /etc/hosts
-Host name database.
-.It Pa /etc/pf.conf
-Default location of the ruleset file.
-.It Pa /etc/pf.os
-Default location of OS fingerprints.
-.It Pa /etc/protocols
-Protocol name database.
-.It Pa /etc/services
-Service name database.
-.El
-.Sh SEE ALSO
-.Xr altq 4 ,
-.Xr carp 4 ,
-.Xr icmp 4 ,
-.Xr icmp6 4 ,
-.Xr ip 4 ,
-.Xr ip6 4 ,
-.Xr pf 4 ,
-.Xr pflow 4 ,
-.Xr pfsync 4 ,
-.Xr tcp 4 ,
-.Xr udp 4 ,
-.Xr hosts 5 ,
-.Xr pf.os 5 ,
-.Xr protocols 5 ,
-.Xr services 5 ,
-.Xr ftp-proxy 8 ,
-.Xr pfctl 8 ,
-.Xr pflogd 8 ,
-.Sh HISTORY
-The
-.Nm
-file format first appeared in
-.Ox 3.0 .
diff --git a/contrib/pf/man/pf.os.5 b/contrib/pf/man/pf.os.5
deleted file mode 100644
index 5930525..0000000
--- a/contrib/pf/man/pf.os.5
+++ /dev/null
@@ -1,223 +0,0 @@
-.\" $OpenBSD: pf.os.5,v 1.8 2007/05/31 19:19:58 jmc Exp $
-.\"
-.\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd May 31 2007
-.Dt PF.OS 5
-.Os
-.Sh NAME
-.Nm pf.os
-.Nd format of the operating system fingerprints file
-.Sh DESCRIPTION
-The
-.Xr pf 4
-firewall and the
-.Xr tcpdump 1
-program can both fingerprint the operating system of hosts that
-originate an IPv4 TCP connection.
-The file consists of newline-separated records, one per fingerprint,
-containing nine colon
-.Pq Ql \&:
-separated fields.
-These fields are as follows:
-.Pp
-.Bl -tag -width Description -offset indent -compact
-.It window
-The TCP window size.
-.It TTL
-The IP time to live.
-.It df
-The presence of the IPv4 don't fragment bit.
-.It packet size
-The size of the initial TCP packet.
-.It TCP options
-An ordered list of the TCP options.
-.It class
-The class of operating system.
-.It version
-The version of the operating system.
-.It subtype
-The subtype of patchlevel of the operating system.
-.It description
-The overall textual description of the operating system, version and subtype.
-.El
-.Pp
-The
-.Ar window
-field corresponds to the th->th_win field in the TCP header and is the
-source host's advertised TCP window size.
-It may be between zero and 65,535 inclusive.
-The window size may be given as a multiple of a constant by prepending
-the size with a percent sign
-.Sq %
-and the value will be used as a modulus.
-Three special values may be used for the window size:
-.Pp
-.Bl -tag -width xxx -offset indent -compact
-.It *
-An asterisk will wildcard the value so any window size will match.
-.It S
-Allow any window size which is a multiple of the maximum segment size (MSS).
-.It T
-Allow any window size which is a multiple of the maximum transmission unit
-(MTU).
-.El
-.Pp
-The
-.Ar ttl
-value is the initial time to live in the IP header.
-The fingerprint code will account for the volatility of the packet's TTL
-as it traverses a network.
-.Pp
-The
-.Ar df
-bit corresponds to the Don't Fragment bit in an IPv4 header.
-It tells intermediate routers not to fragment the packet and is used for
-path MTU discovery.
-It may be either a zero or a one.
-.Pp
-The
-.Ar packet size
-is the literal size of the full IP packet and is a function of all of
-the IP and TCP options.
-.Pp
-The
-.Ar TCP options
-field is an ordered list of the individual TCP options that appear in the
-SYN packet.
-Each option is described by a single character separated by a comma and
-certain ones may include a value.
-The options are:
-.Pp
-.Bl -tag -width Description -offset indent -compact
-.It Mnnn
-maximum segment size (MSS) option.
-The value is the maximum packet size of the network link which may
-include the
-.Sq %
-modulus or match all MSSes with the
-.Sq *
-value.
-.It N
-the NOP option (NO Operation).
-.It T[0]
-the timestamp option.
-Certain operating systems always start with a zero timestamp in which
-case a zero value is added to the option; otherwise no value is appended.
-.It S
-the Selective ACKnowledgement OK (SACKOK) option.
-.It Wnnn
-window scaling option.
-The value is the size of the window scaling which may include the
-.Sq %
-modulus or match all window scalings with the
-.Sq *
-value.
-.El
-.Pp
-No TCP options in the fingerprint may be given with a single dot
-.Sq \&. .
-.Pp
-An example of OpenBSD's TCP options are:
-.Pp
-.Dl M*,N,N,S,N,W0,N,N,T
-.Pp
-The first option
-.Ar M*
-is the MSS option and will match all values.
-The second and third options
-.Ar N
-will match two NOPs.
-The fourth option
-.Ar S
-will match the SACKOK option.
-The fifth
-.Ar N
-will match another NOP.
-The sixth
-.Ar W0
-will match a window scaling option with a zero scaling size.
-The seventh and eighth
-.Ar N
-options will match two NOPs.
-And the ninth and final option
-.Ar T
-will match the timestamp option with any time value.
-.Pp
-The TCP options in a fingerprint will only match packets with the
-exact same TCP options in the same order.
-.Pp
-The
-.Ar class
-field is the class, genre or vendor of the operating system.
-.Pp
-The
-.Ar version
-is the version of the operating system.
-It is used to distinguish between different fingerprints of operating
-systems of the same class but different versions.
-.Pp
-The
-.Ar subtype
-is the subtype or patch level of the operating system version.
-It is used to distinguish between different fingerprints of operating
-systems of the same class and same version but slightly different
-patches or tweaking.
-.Pp
-The
-.Ar description
-is a general description of the operating system, its version,
-patchlevel and any further useful details.
-.Sh EXAMPLES
-The fingerprint of a plain
-.Ox 3.3
-host is:
-.Bd -literal
- 16384:64:1:64:M*,N,N,S,N,W0,N,N,T:OpenBSD:3.3::OpenBSD 3.3
-.Ed
-.Pp
-The fingerprint of an
-.Ox 3.3
-host behind a PF scrubbing firewall with a no-df rule would be:
-.Bd -literal
- 16384:64:0:64:M*,N,N,S,N,W0,N,N,T:OpenBSD:3.3:!df:OpenBSD 3.3 scrub no-df
-.Ed
-.Pp
-An absolutely braindead embedded operating system fingerprint could be:
-.Bd -literal
- 65535:255:0:40:.:DUMMY:1.1:p3:Dummy embedded OS v1.1p3
-.Ed
-.Pp
-The
-.Xr tcpdump 1
-output of
-.Bd -literal
- # tcpdump -s128 -c1 -nv 'tcp[13] == 2'
- 03:13:48.118526 10.0.0.1.3377 > 10.0.0.2.80: S [tcp sum ok] \e
- 534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \e
- (ttl 64, id 11315, len 44)
-.Ed
-.Pp
-almost translates into the following fingerprint
-.Bd -literal
- 57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0
-.Ed
-.Sh SEE ALSO
-.Xr pf 4 ,
-.Xr pf.conf 5 ,
-.Xr pfctl 8 ,
-.Xr tcpdump 1
diff --git a/contrib/pf/man/pflog.4 b/contrib/pf/man/pflog.4
deleted file mode 100644
index c1039a3..0000000
--- a/contrib/pf/man/pflog.4
+++ /dev/null
@@ -1,107 +0,0 @@
-.\" $OpenBSD: pflog.4,v 1.10 2007/05/31 19:19:51 jmc Exp $
-.\"
-.\" Copyright (c) 2001 Tobias Weingartner
-.\" 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd May 31 2007
-.Dt PFLOG 4
-.Os
-.Sh NAME
-.Nm pflog
-.Nd packet filter logging interface
-.Sh SYNOPSIS
-.Cd "device pflog"
-.Sh DESCRIPTION
-The
-.Nm pflog
-interface is a device which makes visible all packets logged by
-the packet filter,
-.Xr pf 4 .
-Logged packets can easily be monitored in real
-time by invoking
-.Xr tcpdump 1
-on the
-.Nm
-interface, or stored to disk using
-.Xr pflogd 8 .
-.Pp
-The pflog0 interface is created automatically at boot if both
-.Xr pf 4
-and
-.Xr pflogd 8
-are enabled;
-further instances can be created using
-.Xr ifconfig 8 .
-.Pp
-Each packet retrieved on this interface has a header associated
-with it of length
-.Dv PFLOG_HDRLEN .
-This header documents the address family, interface name, rule
-number, reason, action, and direction of the packet that was logged.
-This structure, defined in
-.Aq Pa net/if_pflog.h
-looks like
-.Bd -literal -offset indent
-struct pfloghdr {
- u_int8_t length;
- sa_family_t af;
- u_int8_t action;
- u_int8_t reason;
- char ifname[IFNAMSIZ];
- char ruleset[PF_RULESET_NAME_SIZE];
- u_int32_t rulenr;
- u_int32_t subrulenr;
- uid_t uid;
- pid_t pid;
- uid_t rule_uid;
- pid_t rule_pid;
- u_int8_t dir;
- u_int8_t pad[3];
-};
-.Ed
-.Sh EXAMPLES
-Create a
-.Nm
-interface
-and monitor all packets logged on it:
-.Bd -literal -offset indent
-# ifconfig pflog1 up
-# tcpdump -n -e -ttt -i pflog1
-.Ed
-.Sh SEE ALSO
-.Xr inet 4 ,
-.Xr inet6 4 ,
-.Xr netintro 4 ,
-.Xr pf 4 ,
-.Xr ifconfig 8 ,
-.Xr pflogd 8 ,
-.Xr tcpdump 1
-.Sh HISTORY
-The
-.Nm
-device first appeared in
-.Ox 3.0 .
-.\" .Sh BUGS
-.\" Anything here?
diff --git a/contrib/pf/man/pfsync.4 b/contrib/pf/man/pfsync.4
deleted file mode 100644
index b00bf9d..0000000
--- a/contrib/pf/man/pfsync.4
+++ /dev/null
@@ -1,229 +0,0 @@
-.\" $OpenBSD: pfsync.4,v 1.28 2009/02/17 10:05:18 dlg Exp $
-.\"
-.\" Copyright (c) 2002 Michael Shalayeff
-.\" Copyright (c) 2003-2004 Ryan McBride
-.\" 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 MIND,
-.\" 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$
-.\"
-.Dd December 20 2011
-.Dt PFSYNC 4
-.Os
-.Sh NAME
-.Nm pfsync
-.Nd packet filter state table sychronisation interface
-.Sh SYNOPSIS
-.Cd "device pfsync"
-.Sh DESCRIPTION
-The
-.Nm
-interface is a pseudo-device which exposes certain changes to the state
-table used by
-.Xr pf 4 .
-State changes can be viewed by invoking
-.Xr tcpdump 1
-on the
-.Nm
-interface.
-If configured with a physical synchronisation interface,
-.Nm
-will also send state changes out on that interface,
-and insert state changes received on that interface from other systems
-into the state table.
-.Pp
-By default, all local changes to the state table are exposed via
-.Nm .
-State changes from packets received by
-.Nm
-over the network are not rebroadcast.
-Updates to states created by a rule marked with the
-.Ar no-sync
-keyword are ignored by the
-.Nm
-interface (see
-.Xr pf.conf 5
-for details).
-.Pp
-The
-.Nm
-interface will attempt to collapse multiple state updates into a single
-packet where possible.
-The maximum number of times a single state can be updated before a
-.Nm
-packet will be sent out is controlled by the
-.Ar maxupd
-parameter to ifconfig
-(see
-.Xr ifconfig 8
-and the example below for more details).
-The sending out of a
-.Nm
-packet will be delayed by a maximum of one second.
-.Sh NETWORK SYNCHRONISATION
-States can be synchronised between two or more firewalls using this
-interface, by specifying a synchronisation interface using
-.Xr ifconfig 8 .
-For example, the following command sets fxp0 as the synchronisation
-interface:
-.Bd -literal -offset indent
-# ifconfig pfsync0 syncdev fxp0
-.Ed
-.Pp
-By default, state change messages are sent out on the synchronisation
-interface using IP multicast packets to the 244.0.0.240 group address.
-An alternative destination address for
-.Nm
-packets can be specified using the
-.Ic syncpeer
-keyword.
-This can be used in combination with
-.Xr ipsec 4
-to protect the synchronisation traffic.
-In such a configuration, the syncdev should be set to the
-.Xr enc 4
-interface, as this is where the traffic arrives when it is decapsulated,
-e.g.:
-.Bd -literal -offset indent
-# ifconfig pfsync0 syncpeer 10.0.0.2 syncdev enc0
-.Ed
-.Pp
-It is important that the pfsync traffic be well secured
-as there is no authentication on the protocol and it would
-be trivial to spoof packets which create states, bypassing the pf ruleset.
-Either run the pfsync protocol on a trusted network \- ideally a network
-dedicated to pfsync messages such as a crossover cable between two firewalls,
-or specify a peer address and protect the traffic with
-.Xr ipsec 4 .
-.Pp
-.Nm
-has the following
-.Xr sysctl 8
-tunables:
-.Bl -tag -width ".Va net.pfsync"
-.It Va net.pfsync.carp_demotion_factor
-Value added to
-.Va net.inet.carp.demotion
-while
-.Nm
-tries to perform its bulk update.
-See
-.Xr carp 4
-for more information.
-Default value is 240.
-.El
-.Sh EXAMPLES
-.Nm
-and
-.Xr carp 4
-can be used together to provide automatic failover of a pair of firewalls
-configured in parallel.
-One firewall will handle all traffic until it dies, is shut down, or is
-manually demoted, at which point the second firewall will take over
-automatically.
-.Pp
-Both firewalls in this example have three
-.Xr sis 4
-interfaces.
-sis0 is the external interface, on the 10.0.0.0/24 subnet; sis1 is the
-internal interface, on the 192.168.0.0/24 subnet; and sis2 is the
-.Nm
-interface, using the 192.168.254.0/24 subnet.
-A crossover cable connects the two firewalls via their sis2 interfaces.
-On all three interfaces, firewall A uses the .254 address, while firewall B
-uses .253.
-The interfaces are configured as follows (firewall A unless otherwise
-indicated):
-.Pp
-Interfaces configuration in
-.Pa /etc/rc.conf :
-.Bd -literal -offset indent
-network_interfaces="lo0 sis0 sis1 sis2"
-ifconfig_sis0="10.0.0.254/24"
-ifconfig_sis0_alias0="inet 10.0.0.1/24 vhid 1 pass foo"
-ifconfig_sis1="192.168.0.254/24"
-ifconfig_sis1_alias0="inet 192.168.0.1/24 vhid 2 pass bar"
-ifconfig_sis2="192.168.254.254/24"
-pfsync_enable="YES"
-pfsync_syncdev="sis2"
-.Ed
-.Pp
-.Xr pf 4
-must also be configured to allow
-.Nm
-and
-.Xr carp 4
-traffic through.
-The following should be added to the top of
-.Pa /etc/pf.conf :
-.Bd -literal -offset indent
-pass quick on { sis2 } proto pfsync keep state (no-sync)
-pass on { sis0 sis1 } proto carp keep state (no-sync)
-.Ed
-.Pp
-It is preferable that one firewall handle the forwarding of all the traffic,
-therefore the
-.Ar advskew
-on the backup firewall's
-.Xr carp 4
-vhids should be set to something higher than
-the primary's.
-For example, if firewall B is the backup, its
-carp1 configuration would look like this:
-would look like this:
-.Bd -literal -offset indent
-ifconfig_sis1_alias0="inet 192.168.0.1/24 vhid 2 pass bar advskew 100"
-.Ed
-.Pp
-The following must also be added to
-.Pa /etc/sysctl.conf :
-.Bd -literal -offset indent
-net.inet.carp.preempt=1
-.Ed
-.Sh SEE ALSO
-.Xr bpf 4 ,
-.Xr carp 4 ,
-.Xr enc 4 ,
-.Xr inet 4 ,
-.Xr inet6 4 ,
-.Xr ipsec 4 ,
-.Xr netintro 4 ,
-.Xr pf 4 ,
-.Xr pf.conf 5 ,
-.Xr protocols 5 ,
-.Xr rc.conf 5 ,
-.Xr ifconfig 8 ,
-.Xr tcpdump 1
-.Sh HISTORY
-The
-.Nm
-device first appeared in
-.Ox 3.3 .
-It was first imported to
-.Fx 5.3 .
-.Pp
-The
-.Nm
-protocol and kernel implementation were significantly modified in
-.Fx 9.0 .
-The newer protocol is not compatible with older one and will not interoperate
-with it.
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y
deleted file mode 100644
index 99c26c0..0000000
--- a/contrib/pf/pfctl/parse.y
+++ /dev/null
@@ -1,6038 +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.
- */
-%{
-#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;
-
-TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
-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);
-
-TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
-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, };
-
-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;
-};
-
-struct node_queue {
- 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;
-};
-
-struct filter_opts {
- 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;
-
-struct antispoof_opts {
- char *label;
- u_int rtableid;
-} antispoof_opts;
-
-struct scrub_opts {
- 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;
-
-struct queue_opts {
- 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;
-
-struct table_opts {
- int flags;
- int init_addr;
- struct node_tinithead init_nodes;
-} table_opts;
-
-struct pool_opts {
- int marker;
-#define POM_TYPE 0x01
-#define POM_STICKYADDRESS 0x02
- u_int8_t opts;
- int type;
- int staticport;
- struct pf_poolhashkey *key;
-
-} pool_opts;
-
-
-struct node_hfsc_opts hfsc_opts;
-struct node_state_opt *keep_state_defaults = NULL;
-
-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);
-
-TAILQ_HEAD(loadanchorshead, loadanchors)
- 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
-%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_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 = $$;
- }
- ;
-
-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 = $$;
- }
- | 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},
- { "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
-
-char *parsebuf;
-int parseindex;
-char pushback_buffer[MAXPUSHBACK];
-int pushback_index = 0;
-
-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
-}
diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c
deleted file mode 100644
index d6637b4..0000000
--- a/contrib/pf/pfctl/pf_print_state.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/* $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.
- *
- */
-
-#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;
- 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->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/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8
deleted file mode 100644
index b178a07..0000000
--- a/contrib/pf/pfctl/pfctl.8
+++ /dev/null
@@ -1,687 +0,0 @@
-.\" $OpenBSD: pfctl.8,v 1.138 2008/06/10 20:55:02 mcbride Exp $
-.\"
-.\" Copyright (c) 2001 Kjell Wooding. 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.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission.
-.\"
-.\" 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd June 21, 2011
-.Dt PFCTL 8
-.Os
-.Sh NAME
-.Nm pfctl
-.Nd control the packet filter (PF) device
-.Sh SYNOPSIS
-.Nm pfctl
-.Bk -words
-.Op Fl AdeghmNnOPqRrvz
-.Op Fl a Ar anchor
-.Oo Fl D Ar macro Ns =
-.Ar value Oc
-.Op Fl F Ar modifier
-.Op Fl f Ar file
-.Op Fl i Ar interface
-.Op Fl K Ar host | network
-.Xo
-.Oo Fl k
-.Ar host | network | label | id
-.Oc Xc
-.Op Fl o Ar level
-.Op Fl p Ar device
-.Op Fl s Ar modifier
-.Xo
-.Oo Fl t Ar table
-.Fl T Ar command
-.Op Ar address ... Oc
-.Xc
-.Op Fl x Ar level
-.Ek
-.Sh DESCRIPTION
-The
-.Nm
-utility communicates with the packet filter device using the
-ioctl interface described in
-.Xr pf 4 .
-It allows ruleset and parameter configuration and retrieval of status
-information from the packet filter.
-.Pp
-Packet filtering restricts the types of packets that pass through
-network interfaces entering or leaving the host based on filter
-rules as described in
-.Xr pf.conf 5 .
-The packet filter can also replace addresses and ports of packets.
-Replacing source addresses and ports of outgoing packets is called
-NAT (Network Address Translation) and is used to connect an internal
-network (usually reserved address space) to an external one (the
-Internet) by making all connections to external hosts appear to
-come from the gateway.
-Replacing destination addresses and ports of incoming packets
-is used to redirect connections to different hosts and/or ports.
-A combination of both translations, bidirectional NAT, is also
-supported.
-Translation rules are described in
-.Xr pf.conf 5 .
-.Pp
-When the variable
-.Va pf
-is set to
-.Dv YES
-in
-.Xr rc.conf 5 ,
-the rule file specified with the variable
-.Va pf_rules
-is loaded automatically by the
-.Xr rc 8
-scripts and the packet filter is enabled.
-.Pp
-The packet filter does not itself forward packets between interfaces.
-Forwarding can be enabled by setting the
-.Xr sysctl 8
-variables
-.Em net.inet.ip.forwarding
-and/or
-.Em net.inet6.ip6.forwarding
-to 1.
-Set them permanently in
-.Xr sysctl.conf 5 .
-.Pp
-The
-.Nm
-utility provides several commands.
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl A
-Load only the queue rules present in the rule file.
-Other rules and options are ignored.
-.It Fl a Ar anchor
-Apply flags
-.Fl f ,
-.Fl F ,
-and
-.Fl s
-only to the rules in the specified
-.Ar anchor .
-In addition to the main ruleset,
-.Nm
-can load and manipulate additional rulesets by name,
-called anchors.
-The main ruleset is the default anchor.
-.Pp
-Anchors are referenced by name and may be nested,
-with the various components of the anchor path separated by
-.Sq /
-characters, similar to how file system hierarchies are laid out.
-The last component of the anchor path is where ruleset operations are
-performed.
-.Pp
-Evaluation of
-.Ar anchor
-rules from the main ruleset is described in
-.Xr pf.conf 5 .
-.Pp
-For example, the following will show all filter rules (see the
-.Fl s
-flag below) inside the anchor
-.Dq authpf/smith(1234) ,
-which would have been created for user
-.Dq smith
-by
-.Xr authpf 8 ,
-PID 1234:
-.Bd -literal -offset indent
-# pfctl -a "authpf/smith(1234)" -s rules
-.Ed
-.Pp
-Private tables can also be put inside anchors, either by having table
-statements in the
-.Xr pf.conf 5
-file that is loaded in the anchor, or by using regular table commands, as in:
-.Bd -literal -offset indent
-# pfctl -a foo/bar -t mytable -T add 1.2.3.4 5.6.7.8
-.Ed
-.Pp
-When a rule referring to a table is loaded in an anchor, the rule will use the
-private table if one is defined, and then fall back to the table defined in the
-main ruleset, if there is one.
-This is similar to C rules for variable scope.
-It is possible to create distinct tables with the same name in the global
-ruleset and in an anchor, but this is often bad design and a warning will be
-issued in that case.
-.Pp
-By default, recursive inline printing of anchors applies only to unnamed
-anchors specified inline in the ruleset.
-If the anchor name is terminated with a
-.Sq *
-character, the
-.Fl s
-flag will recursively print all anchors in a brace delimited block.
-For example the following will print the
-.Dq authpf
-ruleset recursively:
-.Bd -literal -offset indent
-# pfctl -a 'authpf/*' -sr
-.Ed
-.Pp
-To print the main ruleset recursively, specify only
-.Sq *
-as the anchor name:
-.Bd -literal -offset indent
-# pfctl -a '*' -sr
-.Ed
-.It Fl D Ar macro Ns = Ns Ar value
-Define
-.Ar macro
-to be set to
-.Ar value
-on the command line.
-Overrides the definition of
-.Ar macro
-in the ruleset.
-.It Fl d
-Disable the packet filter.
-.It Fl e
-Enable the packet filter.
-.It Fl F Ar modifier
-Flush the filter parameters specified by
-.Ar modifier
-(may be abbreviated):
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Fl F Cm nat
-Flush the NAT rules.
-.It Fl F Cm queue
-Flush the queue rules.
-.It Fl F Cm rules
-Flush the filter rules.
-.It Fl F Cm states
-Flush the state table (NAT and filter).
-.It Fl F Cm Sources
-Flush the source tracking table.
-.It Fl F Cm info
-Flush the filter information (statistics that are not bound to rules).
-.It Fl F Cm Tables
-Flush the tables.
-.It Fl F Cm osfp
-Flush the passive operating system fingerprints.
-.It Fl F Cm all
-Flush all of the above.
-.El
-.It Fl f Ar file
-Load the rules contained in
-.Ar file .
-This
-.Ar file
-may contain macros, tables, options, and normalization, queueing,
-translation, and filtering rules.
-With the exception of macros and tables, the statements must appear in that
-order.
-.It Fl g
-Include output helpful for debugging.
-.It Fl h
-Help.
-.It Fl i Ar interface
-Restrict the operation to the given
-.Ar interface .
-.It Fl K Ar host | network
-Kill all of the source tracking entries originating from the specified
-.Ar host
-or
-.Ar network .
-A second
-.Fl K Ar host
-or
-.Fl K Ar network
-option may be specified, which will kill all the source tracking
-entries from the first host/network to the second.
-.It Xo
-.Fl k
-.Ar host | network | label | id
-.Xc
-Kill all of the state entries matching the specified
-.Ar host ,
-.Ar network ,
-.Ar label ,
-or
-.Ar id .
-.Pp
-For example, to kill all of the state entries originating from
-.Dq host :
-.Pp
-.Dl # pfctl -k host
-.Pp
-A second
-.Fl k Ar host
-or
-.Fl k Ar network
-option may be specified, which will kill all the state entries
-from the first host/network to the second.
-To kill all of the state entries from
-.Dq host1
-to
-.Dq host2 :
-.Pp
-.Dl # pfctl -k host1 -k host2
-.Pp
-To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16:
-.Pp
-.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16
-.Pp
-A network prefix length of 0 can be used as a wildcard.
-To kill all states with the target
-.Dq host2 :
-.Pp
-.Dl # pfctl -k 0.0.0.0/0 -k host2
-.Pp
-It is also possible to kill states by rule label or state ID.
-In this mode the first
-.Fl k
-argument is used to specify the type
-of the second argument.
-The following command would kill all states that have been created
-from rules carrying the label
-.Dq foobar :
-.Pp
-.Dl # pfctl -k label -k foobar
-.Pp
-To kill one specific state by its unique state ID
-(as shown by pfctl -s state -vv),
-use the
-.Ar id
-modifier and as a second argument the state ID and optional creator ID.
-To kill a state with ID 4823e84500000003 use:
-.Pp
-.Dl # pfctl -k id -k 4823e84500000003
-.Pp
-To kill a state with ID 4823e84500000018 created from a backup
-firewall with hostid 00000002 use:
-.Pp
-.Dl # pfctl -k id -k 4823e84500000018/2
-.Pp
-.It Fl m
-Merge in explicitly given options without resetting those
-which are omitted.
-Allows single options to be modified without disturbing the others:
-.Bd -literal -offset indent
-# echo "set loginterface fxp0" | pfctl -mf -
-.Ed
-.It Fl N
-Load only the NAT rules present in the rule file.
-Other rules and options are ignored.
-.It Fl n
-Do not actually load rules, just parse them.
-.It Fl O
-Load only the options present in the rule file.
-Other rules and options are ignored.
-.It Fl o Ar level
-Control the ruleset optimizer, overriding any rule file settings.
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Fl o Cm none
-Disable the ruleset optimizer.
-.It Fl o Cm basic
-Enable basic ruleset optimizations.
-This is the default behaviour.
-.It Fl o Cm profile
-Enable basic ruleset optimizations with profiling.
-.El
-For further information on the ruleset optimizer, see
-.Xr pf.conf 5 .
-.It Fl P
-Do not perform service name lookup for port specific rules,
-instead display the ports numerically.
-.It Fl p Ar device
-Use the device file
-.Ar device
-instead of the default
-.Pa /dev/pf .
-.It Fl q
-Only print errors and warnings.
-.It Fl R
-Load only the filter rules present in the rule file.
-Other rules and options are ignored.
-.It Fl r
-Perform reverse DNS lookups on states when displaying them.
-.It Fl s Ar modifier
-Show the filter parameters specified by
-.Ar modifier
-(may be abbreviated):
-.Pp
-.Bl -tag -width xxxxxxxxxxxxx -compact
-.It Fl s Cm nat
-Show the currently loaded NAT rules.
-.It Fl s Cm queue
-Show the currently loaded queue rules.
-When used together with
-.Fl v ,
-per-queue statistics are also shown.
-When used together with
-.Fl v v ,
-.Nm
-will loop and show updated queue statistics every five seconds, including
-measured bandwidth and packets per second.
-.It Fl s Cm rules
-Show the currently loaded filter rules.
-When used together with
-.Fl v ,
-the per-rule statistics (number of evaluations,
-packets and bytes) are also shown.
-Note that the
-.Dq skip step
-optimization done automatically by the kernel
-will skip evaluation of rules where possible.
-Packets passed statefully are counted in the rule that created the state
-(even though the rule isn't evaluated more than once for the entire
-connection).
-.It Fl s Cm Anchors
-Show the currently loaded anchors directly attached to the main ruleset.
-If
-.Fl a Ar anchor
-is specified as well, the anchors loaded directly below the given
-.Ar anchor
-are shown instead.
-If
-.Fl v
-is specified, all anchors attached under the target anchor will be
-displayed recursively.
-.It Fl s Cm states
-Show the contents of the state table.
-.It Fl s Cm Sources
-Show the contents of the source tracking table.
-.It Fl s Cm info
-Show filter information (statistics and counters).
-When used together with
-.Fl v ,
-source tracking statistics are also shown.
-.It Fl s Cm labels
-Show per-rule statistics (label, evaluations, packets total, bytes total,
-packets in, bytes in, packets out, bytes out, state creations) of
-filter rules with labels, useful for accounting.
-.It Fl s Cm timeouts
-Show the current global timeouts.
-.It Fl s Cm memory
-Show the current pool memory hard limits.
-.It Fl s Cm Tables
-Show the list of tables.
-.It Fl s Cm osfp
-Show the list of operating system fingerprints.
-.It Fl s Cm Interfaces
-Show the list of interfaces and interface drivers available to PF.
-When used together with
-.Fl v ,
-it additionally lists which interfaces have skip rules activated.
-When used together with
-.Fl vv ,
-interface statistics are also shown.
-.Fl i
-can be used to select an interface or a group of interfaces.
-.It Fl s Cm all
-Show all of the above, except for the lists of interfaces and operating
-system fingerprints.
-.El
-.It Fl T Ar command Op Ar address ...
-Specify the
-.Ar command
-(may be abbreviated) to apply to the table.
-Commands include:
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Fl T Cm kill
-Kill a table.
-.It Fl T Cm flush
-Flush all addresses of a table.
-.It Fl T Cm add
-Add one or more addresses in a table.
-Automatically create a nonexisting table.
-.It Fl T Cm delete
-Delete one or more addresses from a table.
-.It Fl T Cm expire Ar number
-Delete addresses which had their statistics cleared more than
-.Ar number
-seconds ago.
-For entries which have never had their statistics cleared,
-.Ar number
-refers to the time they were added to the table.
-.It Fl T Cm replace
-Replace the addresses of the table.
-Automatically create a nonexisting table.
-.It Fl T Cm show
-Show the content (addresses) of a table.
-.It Fl T Cm test
-Test if the given addresses match a table.
-.It Fl T Cm zero
-Clear all the statistics of a table.
-.It Fl T Cm load
-Load only the table definitions from
-.Xr pf.conf 5 .
-This is used in conjunction with the
-.Fl f
-flag, as in:
-.Bd -literal -offset indent
-# pfctl -Tl -f pf.conf
-.Ed
-.El
-.Pp
-For the
-.Cm add ,
-.Cm delete ,
-.Cm replace ,
-and
-.Cm test
-commands, the list of addresses can be specified either directly on the command
-line and/or in an unformatted text file, using the
-.Fl f
-flag.
-Comments starting with a
-.Sq #
-are allowed in the text file.
-With these commands, the
-.Fl v
-flag can also be used once or twice, in which case
-.Nm
-will print the
-detailed result of the operation for each individual address, prefixed by
-one of the following letters:
-.Pp
-.Bl -tag -width XXX -compact
-.It A
-The address/network has been added.
-.It C
-The address/network has been changed (negated).
-.It D
-The address/network has been deleted.
-.It M
-The address matches
-.Po
-.Cm test
-operation only
-.Pc .
-.It X
-The address/network is duplicated and therefore ignored.
-.It Y
-The address/network cannot be added/deleted due to conflicting
-.Sq \&!
-attributes.
-.It Z
-The address/network has been cleared (statistics).
-.El
-.Pp
-Each table can maintain a set of counters that can be retrieved using the
-.Fl v
-flag of
-.Nm .
-For example, the following commands define a wide open firewall which will keep
-track of packets going to or coming from the
-.Ox
-FTP server.
-The following commands configure the firewall and send 10 pings to the FTP
-server:
-.Bd -literal -offset indent
-# printf "table <test> counters { ftp.openbsd.org }\en \e
- pass out to <test>\en" | pfctl -f-
-# ping -qc10 ftp.openbsd.org
-.Ed
-.Pp
-We can now use the table
-.Cm show
-command to output, for each address and packet direction, the number of packets
-and bytes that are being passed or blocked by rules referencing the table.
-The time at which the current accounting started is also shown with the
-.Dq Cleared
-line.
-.Bd -literal -offset indent
-# pfctl -t test -vTshow
- 129.128.5.191
- Cleared: Thu Feb 13 18:55:18 2003
- In/Block: [ Packets: 0 Bytes: 0 ]
- In/Pass: [ Packets: 10 Bytes: 840 ]
- Out/Block: [ Packets: 0 Bytes: 0 ]
- Out/Pass: [ Packets: 10 Bytes: 840 ]
-.Ed
-.Pp
-Similarly, it is possible to view global information about the tables
-by using the
-.Fl v
-modifier twice and the
-.Fl s
-.Cm Tables
-command.
-This will display the number of addresses on each table,
-the number of rules which reference the table, and the global
-packet statistics for the whole table:
-.Bd -literal -offset indent
-# pfctl -vvsTables
---a-r-C test
- Addresses: 1
- Cleared: Thu Feb 13 18:55:18 2003
- References: [ Anchors: 0 Rules: 1 ]
- Evaluations: [ NoMatch: 3496 Match: 1 ]
- In/Block: [ Packets: 0 Bytes: 0 ]
- In/Pass: [ Packets: 10 Bytes: 840 ]
- In/XPass: [ Packets: 0 Bytes: 0 ]
- Out/Block: [ Packets: 0 Bytes: 0 ]
- Out/Pass: [ Packets: 10 Bytes: 840 ]
- Out/XPass: [ Packets: 0 Bytes: 0 ]
-.Ed
-.Pp
-As we can see here, only one packet \- the initial ping request \- matched the
-table, but all packets passing as the result of the state are correctly
-accounted for.
-Reloading the table(s) or ruleset will not affect packet accounting in any way.
-The two
-.Dq XPass
-counters are incremented instead of the
-.Dq Pass
-counters when a
-.Dq stateful
-packet is passed but doesn't match the table anymore.
-This will happen in our example if someone flushes the table while the
-.Xr ping 8
-command is running.
-.Pp
-When used with a single
-.Fl v ,
-.Nm
-will only display the first line containing the table flags and name.
-The flags are defined as follows:
-.Pp
-.Bl -tag -width XXX -compact
-.It c
-For constant tables, which cannot be altered outside
-.Xr pf.conf 5 .
-.It p
-For persistent tables, which don't get automatically killed when no rules
-refer to them.
-.It a
-For tables which are part of the
-.Em active
-tableset.
-Tables without this flag do not really exist, cannot contain addresses, and are
-only listed if the
-.Fl g
-flag is given.
-.It i
-For tables which are part of the
-.Em inactive
-tableset.
-This flag can only be witnessed briefly during the loading of
-.Xr pf.conf 5 .
-.It r
-For tables which are referenced (used) by rules.
-.It h
-This flag is set when a table in the main ruleset is hidden by one or more
-tables of the same name from anchors attached below it.
-.It C
-This flag is set when per-address counters are enabled on the table.
-.El
-.It Fl t Ar table
-Specify the name of the table.
-.It Fl v
-Produce more verbose output.
-A second use of
-.Fl v
-will produce even more verbose output including ruleset warnings.
-See the previous section for its effect on table commands.
-.It Fl x Ar level
-Set the debug
-.Ar level
-(may be abbreviated) to one of the following:
-.Pp
-.Bl -tag -width xxxxxxxxxxxx -compact
-.It Fl x Cm none
-Don't generate debug messages.
-.It Fl x Cm urgent
-Generate debug messages only for serious errors.
-.It Fl x Cm misc
-Generate debug messages for various errors.
-.It Fl x Cm loud
-Generate debug messages for common conditions.
-.El
-.It Fl z
-Clear per-rule statistics.
-.El
-.Sh FILES
-.Bl -tag -width "/etc/pf.conf" -compact
-.It Pa /etc/pf.conf
-Packet filter rules file.
-.It Pa /etc/pf.os
-Passive operating system fingerprint database.
-.El
-.Sh SEE ALSO
-.Xr pf 4 ,
-.Xr pf.conf 5 ,
-.Xr pf.os 5 ,
-.Xr rc.conf 5 ,
-.Xr services 5 ,
-.Xr sysctl.conf 5 ,
-.Xr authpf 8 ,
-.Xr ftp-proxy 8 ,
-.Xr rc 8 ,
-.Xr sysctl 8
-.Sh HISTORY
-The
-.Nm
-program and the
-.Xr pf 4
-filter mechanism first appeared in
-.Ox 3.0 .
diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c
deleted file mode 100644
index 90a2bb5..0000000
--- a/contrib/pf/pfctl/pfctl.c
+++ /dev/null
@@ -1,2391 +0,0 @@
-/* $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.
- *
- */
-
-#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 *);
-int pfctl_load_hostid(struct pfctl *, unsigned int);
-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);
-const char *pfctl_lookup_option(char *, const char **);
-
-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];
-int loadopt;
-int altqsupport;
-
-int dev = -1;
-int first_title = 1;
-int labels = 0;
-
-#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 },
- { "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 }
-};
-
-static const char *clearopt_list[] = {
- "nat", "queue", "rules", "Sources",
- "states", "info", "Tables", "osfp", "all", NULL
-};
-
-static const char *showopt_list[] = {
- "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
- "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
- "all", NULL
-};
-
-static const char *tblcmdopt_list[] = {
- "kill", "flush", "add", "delete", "load", "replace", "show",
- "test", "zero", "expire", NULL
-};
-
-static const char *debugopt_list[] = {
- "none", "urgent", "misc", "loud", NULL
-};
-
-static const char *optiopt_list[] = {
- "none", "basic", "profile", NULL
-};
-
-void
-usage(void)
-{
- extern char *__progname;
-
- 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;
- static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
- 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)
-{
-
- 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_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
-
- 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 *
-pfctl_lookup_option(char *cmd, const char **list)
-{
- if (cmd != NULL && *cmd)
- for (; *list; list++)
- if (!strncmp(cmd, *list, strlen(cmd)))
- return (*list);
- return (NULL);
-}
-
-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;
-
- 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);
-}
diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h
deleted file mode 100644
index 2c69bc2..0000000
--- a/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/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c
deleted file mode 100644
index 40e11d5..0000000
--- a/contrib/pf/pfctl/pfctl_altq.c
+++ /dev/null
@@ -1,1258 +0,0 @@
-/* $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.
- */
-
-#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))
-
-TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs);
-LIST_HEAD(gen_sc, segment) rtsc, lssc;
-
-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
-
-char *
-rate2str(double rate)
-{
- char *buf;
- static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
- static int idx = 0;
- int i;
- static const char unit[] = " KMG";
-
- buf = r2sbuf[idx++];
- if (idx == R2S_BUFS)
- idx = 0;
-
- 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(")");
-}
diff --git a/contrib/pf/pfctl/pfctl_optimize.c b/contrib/pf/pfctl/pfctl_optimize.c
deleted file mode 100644
index 9511720..0000000
--- a/contrib/pf/pfctl/pfctl_optimize.c
+++ /dev/null
@@ -1,1655 +0,0 @@
-/* $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.
- */
-
-#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?!? */
-struct pf_rule_field {
- 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),
-};
-
-
-
-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 *);
-
-
-int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, struct pf_rule *);
-const char *skip_comparitors_names[PF_SKIP_COUNT];
-#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 } \
-}
-
-struct pfr_buffer table_buffer;
-int table_identifier;
-
-
-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 */
- static int tablenum = 0;
- 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",
- PF_OPT_TABLE_PREFIX, tablenum++);
- 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)
-{
- static int tablenum;
- 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,
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
- snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
- PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
- 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;
- }
- }
- tablenum++;
-
-
- 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);
-}
-
diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c
deleted file mode 100644
index df78981..0000000
--- a/contrib/pf/pfctl/pfctl_osfp.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/* $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.
- */
-
-#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;
-};
-struct name_list classes = LIST_HEAD_INITIALIZER(&classes);
-int class_count;
-int fingerprint_count;
-
-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)
-{
- static char buf[1024];
- 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);
-}
diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c
deleted file mode 100644
index f248995..0000000
--- a/contrib/pf/pfctl/pfctl_parser.c
+++ /dev/null
@@ -1,1746 +0,0 @@
-/* $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.
- *
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/param.h>
-#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);
-
-const char *tcpflags = "FSRPAUEW";
-
-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");
-}
-
-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;
-
-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;
- }
- 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 */
-
-struct node_host *iftab;
-
-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);
-}
diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h
deleted file mode 100644
index 4560d66..0000000
--- a/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/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c
deleted file mode 100644
index 95371e4..0000000
--- a/contrib/pf/pfctl/pfctl_qstats.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/* $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.
- */
-
-#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;
-};
-
-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;
- static u_int32_t last_ticket;
-
- 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++;
-}
diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c
deleted file mode 100644
index 38f16c4..0000000
--- a/contrib/pf/pfctl/pfctl_radix.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/* $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.
- *
- */
-
-#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 */
-
-size_t buf_esize[PFRB_MAX] = { 0,
- 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);
-}
-
-int
-pfr_next_token(char buf[BUF_SIZE], FILE *fp)
-{
- static char next_ch = ' ';
- 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);
- }
-}
diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c
deleted file mode 100644
index f3a1efd..0000000
--- a/contrib/pf/pfctl/pfctl_table.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/* $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.
- *
- */
-
-#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)
-{
- extern char *__progname;
- 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: %-18d\n", p->pfik_rulerefs);
- 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]);
- }
-}
OpenPOWER on IntegriCloud