aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_htable.c45
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_htable.h2
-rw-r--r--sys/netpfil/ipfilter/netinet/ip_nat.c1
-rw-r--r--sys/netpfil/ipfw/ip_dn_glue.c858
-rw-r--r--sys/netpfil/ipfw/ip_dn_io.c6
-rw-r--r--sys/netpfil/ipfw/ip_dn_private.h10
-rw-r--r--sys/netpfil/ipfw/ip_dummynet.c100
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c9
-rw-r--r--sys/netpfil/ipfw/ip_fw_nat.c16
-rw-r--r--sys/netpfil/ipfw/pmod/tcpmod.c25
-rw-r--r--sys/netpfil/pf/if_pfsync.c3
-rw-r--r--sys/netpfil/pf/pf.c585
-rw-r--r--sys/netpfil/pf/pf_if.c2
-rw-r--r--sys/netpfil/pf/pf_ioctl.c17
-rw-r--r--sys/netpfil/pf/pf_lb.c122
-rw-r--r--sys/netpfil/pf/pf_nl.c132
-rw-r--r--sys/netpfil/pf/pf_nl.h4
-rw-r--r--sys/netpfil/pf/pf_table.c12
18 files changed, 740 insertions, 1209 deletions
diff --git a/sys/netpfil/ipfilter/netinet/ip_htable.c b/sys/netpfil/ipfilter/netinet/ip_htable.c
index 91b375f80db1..5f5c04732d69 100644
--- a/sys/netpfil/ipfilter/netinet/ip_htable.c
+++ b/sys/netpfil/ipfilter/netinet/ip_htable.c
@@ -96,6 +96,8 @@ typedef struct ipf_htable_softc_s {
u_long ipf_nhtnodes[LOOKUP_POOL_SZ];
iphtable_t *ipf_htables[LOOKUP_POOL_SZ];
iphtent_t *ipf_node_explist;
+ ipftuneable_t *ipf_htable_tune;
+ u_int ipf_htable_size_max;
} ipf_htable_softc_t;
ipf_lookup_t ipf_htable_backend = {
@@ -122,6 +124,18 @@ ipf_lookup_t ipf_htable_backend = {
};
+static ipftuneable_t ipf_htable_tuneables[] = {
+ { { (void *)offsetof(ipf_htable_softc_t, ipf_htable_size_max) },
+ "htable_size_max", 1, 0x7fffffff,
+ stsizeof(ipf_htable_softc_t, ipf_htable_size_max),
+ 0, NULL, NULL },
+ { { NULL },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
+};
+
+
/* ------------------------------------------------------------------------ */
/* Function: ipf_htable_soft_create */
/* Returns: void * - NULL = failure, else pointer to local context */
@@ -142,6 +156,18 @@ ipf_htable_soft_create(ipf_main_softc_t *softc)
bzero((char *)softh, sizeof(*softh));
+ softh->ipf_htable_tune = ipf_tune_array_copy(softh,
+ sizeof(ipf_htable_tuneables),
+ ipf_htable_tuneables);
+ if (softh->ipf_htable_tune == NULL) {
+ ipf_htable_soft_destroy(softc, softh);
+ return (NULL);
+ }
+ if (ipf_tune_array_link(softc, softh->ipf_htable_tune) == -1) {
+ ipf_htable_soft_destroy(softc, softh);
+ return (NULL);
+ }
+
return (softh);
}
@@ -160,6 +186,12 @@ ipf_htable_soft_destroy(ipf_main_softc_t *softc, void *arg)
{
ipf_htable_softc_t *softh = arg;
+ if (softh->ipf_htable_tune != NULL) {
+ ipf_tune_array_unlink(softc, softh->ipf_htable_tune);
+ KFREES(softh->ipf_htable_tune, sizeof(ipf_htable_tuneables));
+ softh->ipf_htable_tune = NULL;
+ }
+
KFREE(softh);
}
@@ -179,6 +211,8 @@ ipf_htable_soft_init(ipf_main_softc_t *softc, void *arg)
bzero((char *)softh, sizeof(*softh));
+ softh->ipf_htable_size_max = IPHTABLE_MAX_SIZE;
+
return (0);
}
@@ -230,6 +264,8 @@ ipf_htable_stats_get(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
return (EINVAL);
}
+ bzero(&stats, sizeof(stats));
+
stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
@@ -325,6 +361,15 @@ ipf_htable_create(ipf_main_softc_t *softc, void *arg, iplookupop_t *op)
iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
}
+ if ((iph->iph_size == 0) ||
+ (iph->iph_size > softh->ipf_htable_size_max)) {
+ IPFERROR(30027);
+ return (EINVAL);
+ }
+ if (iph->iph_size > ( SIZE_MAX / sizeof(*iph->iph_table))) {
+ IPFERROR(30028);
+ return (EINVAL);
+ }
KMALLOCS(iph->iph_table, iphtent_t **,
iph->iph_size * sizeof(*iph->iph_table));
if (iph->iph_table == NULL) {
diff --git a/sys/netpfil/ipfilter/netinet/ip_htable.h b/sys/netpfil/ipfilter/netinet/ip_htable.h
index 55c289e57ff6..3a8782ccd4b2 100644
--- a/sys/netpfil/ipfilter/netinet/ip_htable.h
+++ b/sys/netpfil/ipfilter/netinet/ip_htable.h
@@ -55,6 +55,8 @@ typedef struct iphtable_s {
char iph_name[FR_GROUPLEN]; /* hash table number */
} iphtable_t;
+#define IPHTABLE_MAX_SIZE 1024
+
/* iph_type */
#define IPHASH_LOOKUP 0
#define IPHASH_GROUPMAP 1
diff --git a/sys/netpfil/ipfilter/netinet/ip_nat.c b/sys/netpfil/ipfilter/netinet/ip_nat.c
index 972511f43bd5..53c180cdfbca 100644
--- a/sys/netpfil/ipfilter/netinet/ip_nat.c
+++ b/sys/netpfil/ipfilter/netinet/ip_nat.c
@@ -1771,6 +1771,7 @@ ipf_nat_getent(ipf_main_softc_t *softc, caddr_t data, int getlock)
IPFERROR(60029);
return (ENOMEM);
}
+ bzero(ipn, ipns.ipn_dsize);
if (getlock) {
READ_ENTER(&softc->ipf_nat);
diff --git a/sys/netpfil/ipfw/ip_dn_glue.c b/sys/netpfil/ipfw/ip_dn_glue.c
deleted file mode 100644
index 0412b730e4df..000000000000
--- a/sys/netpfil/ipfw/ip_dn_glue.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa
- * 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 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 AUTHOR 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.
- */
-
-/*
- *
- * Binary compatibility support for /sbin/ipfw RELENG_7 and RELENG_8
- */
-
-#include "opt_inet6.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/rwlock.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/time.h>
-#include <sys/taskqueue.h>
-#include <net/if.h> /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */
-#include <netinet/in.h>
-#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */
-#include <netinet/ip_fw.h>
-#include <netinet/ip_dummynet.h>
-
-#include <netpfil/ipfw/ip_fw_private.h>
-#include <netpfil/ipfw/dn_heap.h>
-#include <netpfil/ipfw/ip_dn_private.h>
-#ifdef NEW_AQM
-#include <netpfil/ipfw/dn_aqm.h>
-#endif
-#include <netpfil/ipfw/dn_sched.h>
-
-/* FREEBSD7.2 ip_dummynet.h r191715*/
-
-struct dn_heap_entry7 {
- int64_t key; /* sorting key. Topmost element is smallest one */
- void *object; /* object pointer */
-};
-
-struct dn_heap7 {
- int size;
- int elements;
- int offset; /* XXX if > 0 this is the offset of direct ptr to obj */
- struct dn_heap_entry7 *p; /* really an array of "size" entries */
-};
-
-/* Common to 7.2 and 8 */
-struct dn_flow_set {
- SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
-
- u_short fs_nr ; /* flow_set number */
- u_short flags_fs;
-#define DNOLD_HAVE_FLOW_MASK 0x0001
-#define DNOLD_IS_RED 0x0002
-#define DNOLD_IS_GENTLE_RED 0x0004
-#define DNOLD_QSIZE_IS_BYTES 0x0008 /* queue size is measured in bytes */
-#define DNOLD_NOERROR 0x0010 /* do not report ENOBUFS on drops */
-#define DNOLD_HAS_PROFILE 0x0020 /* the pipe has a delay profile. */
-#define DNOLD_IS_PIPE 0x4000
-#define DNOLD_IS_QUEUE 0x8000
-
- struct dn_pipe7 *pipe ; /* pointer to parent pipe */
- u_short parent_nr ; /* parent pipe#, 0 if local to a pipe */
-
- int weight ; /* WFQ queue weight */
- int qsize ; /* queue size in slots or bytes */
- int plr[4] ; /* pkt loss rate (2^31-1 means 100%) */
-
- struct ipfw_flow_id flow_mask ;
-
- /* hash table of queues onto this flow_set */
- int rq_size ; /* number of slots */
- int rq_elements ; /* active elements */
- struct dn_flow_queue7 **rq ; /* array of rq_size entries */
-
- u_int32_t last_expired ; /* do not expire too frequently */
- int backlogged ; /* #active queues for this flowset */
-
- /* RED parameters */
-#define SCALE_RED 16
-#define SCALE(x) ( (x) << SCALE_RED )
-#define SCALE_VAL(x) ( (x) >> SCALE_RED )
-#define SCALE_MUL(x,y) ( ( (x) * (y) ) >> SCALE_RED )
- int w_q ; /* queue weight (scaled) */
- int max_th ; /* maximum threshold for queue (scaled) */
- int min_th ; /* minimum threshold for queue (scaled) */
- int max_p ; /* maximum value for p_b (scaled) */
- u_int c_1 ; /* max_p/(max_th-min_th) (scaled) */
- u_int c_2 ; /* max_p*min_th/(max_th-min_th) (scaled) */
- u_int c_3 ; /* for GRED, (1-max_p)/max_th (scaled) */
- u_int c_4 ; /* for GRED, 1 - 2*max_p (scaled) */
- u_int * w_q_lookup ; /* lookup table for computing (1-w_q)^t */
- u_int lookup_depth ; /* depth of lookup table */
- int lookup_step ; /* granularity inside the lookup table */
- int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
- int avg_pkt_size ; /* medium packet size */
- int max_pkt_size ; /* max packet size */
-};
-SLIST_HEAD(dn_flow_set_head, dn_flow_set);
-
-#define DN_IS_PIPE 0x4000
-#define DN_IS_QUEUE 0x8000
-struct dn_flow_queue7 {
- struct dn_flow_queue7 *next ;
- struct ipfw_flow_id id ;
-
- struct mbuf *head, *tail ; /* queue of packets */
- u_int len ;
- u_int len_bytes ;
-
- u_long numbytes;
-
- u_int64_t tot_pkts ; /* statistics counters */
- u_int64_t tot_bytes ;
- u_int32_t drops ;
-
- int hash_slot ; /* debugging/diagnostic */
-
- /* RED parameters */
- int avg ; /* average queue length est. (scaled) */
- int count ; /* arrivals since last RED drop */
- int random ; /* random value (scaled) */
- u_int32_t q_time; /* start of queue idle time */
-
- /* WF2Q+ support */
- struct dn_flow_set *fs ; /* parent flow set */
- int heap_pos ; /* position (index) of struct in heap */
- int64_t sched_time ; /* current time when queue enters ready_heap */
-
- int64_t S,F ; /* start time, finish time */
-};
-
-struct dn_pipe7 { /* a pipe */
- SLIST_ENTRY(dn_pipe7) next; /* linked list in a hash slot */
-
- int pipe_nr ; /* number */
- uint32_t bandwidth; /* really, bytes/tick. */
- int delay ; /* really, ticks */
-
- struct mbuf *head, *tail ; /* packets in delay line */
-
- /* WF2Q+ */
- struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
- struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
- struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
-
- int64_t V ; /* virtual time */
- int sum; /* sum of weights of all active sessions */
-
- int numbytes;
-
- int64_t sched_time ; /* time pipe was scheduled in ready_heap */
-
- /*
- * When the tx clock come from an interface (if_name[0] != '\0'), its name
- * is stored below, whereas the ifp is filled when the rule is configured.
- */
- char if_name[IFNAMSIZ];
- struct ifnet *ifp ;
- int ready ; /* set if ifp != NULL and we got a signal from it */
-
- struct dn_flow_set fs ; /* used with fixed-rate flows */
-};
-SLIST_HEAD(dn_pipe_head7, dn_pipe7);
-
-/* FREEBSD8 ip_dummynet.h r196045 */
-struct dn_flow_queue8 {
- struct dn_flow_queue8 *next ;
- struct ipfw_flow_id id ;
-
- struct mbuf *head, *tail ; /* queue of packets */
- u_int len ;
- u_int len_bytes ;
-
- uint64_t numbytes ; /* credit for transmission (dynamic queues) */
- int64_t extra_bits; /* extra bits simulating unavailable channel */
-
- u_int64_t tot_pkts ; /* statistics counters */
- u_int64_t tot_bytes ;
- u_int32_t drops ;
-
- int hash_slot ; /* debugging/diagnostic */
-
- /* RED parameters */
- int avg ; /* average queue length est. (scaled) */
- int count ; /* arrivals since last RED drop */
- int random ; /* random value (scaled) */
- int64_t idle_time; /* start of queue idle time */
-
- /* WF2Q+ support */
- struct dn_flow_set *fs ; /* parent flow set */
- int heap_pos ; /* position (index) of struct in heap */
- int64_t sched_time ; /* current time when queue enters ready_heap */
-
- int64_t S,F ; /* start time, finish time */
-};
-
-struct dn_pipe8 { /* a pipe */
- SLIST_ENTRY(dn_pipe8) next; /* linked list in a hash slot */
-
- int pipe_nr ; /* number */
- uint32_t bandwidth; /* really, bytes/tick. */
- int delay ; /* really, ticks */
-
- struct mbuf *head, *tail ; /* packets in delay line */
-
- /* WF2Q+ */
- struct dn_heap7 scheduler_heap ; /* top extract - key Finish time*/
- struct dn_heap7 not_eligible_heap; /* top extract- key Start time */
- struct dn_heap7 idle_heap ; /* random extract - key Start=Finish time */
-
- int64_t V ; /* virtual time */
- int sum; /* sum of weights of all active sessions */
-
- /* Same as in dn_flow_queue, numbytes can become large */
- int64_t numbytes; /* bits I can transmit (more or less). */
- uint64_t burst; /* burst size, scaled: bits * hz */
-
- int64_t sched_time ; /* time pipe was scheduled in ready_heap */
- int64_t idle_time; /* start of pipe idle time */
-
- char if_name[IFNAMSIZ];
- struct ifnet *ifp ;
- int ready ; /* set if ifp != NULL and we got a signal from it */
-
- struct dn_flow_set fs ; /* used with fixed-rate flows */
-
- /* fields to simulate a delay profile */
-#define ED_MAX_NAME_LEN 32
- char name[ED_MAX_NAME_LEN];
- int loss_level;
- int samples_no;
- int *samples;
-};
-
-#define ED_MAX_SAMPLES_NO 1024
-struct dn_pipe_max8 {
- struct dn_pipe8 pipe;
- int samples[ED_MAX_SAMPLES_NO];
-};
-SLIST_HEAD(dn_pipe_head8, dn_pipe8);
-
-/*
- * Changes from 7.2 to 8:
- * dn_pipe:
- * numbytes from int to int64_t
- * add burst (int64_t)
- * add idle_time (int64_t)
- * add profile
- * add struct dn_pipe_max
- * add flag DN_HAS_PROFILE
- *
- * dn_flow_queue
- * numbytes from u_long to int64_t
- * add extra_bits (int64_t)
- * q_time from u_int32_t to int64_t and name idle_time
- *
- * dn_flow_set unchanged
- *
- */
-
-/* NOTE:XXX copied from dummynet.c */
-#define O_NEXT(p, len) ((void *)((char *)p + len))
-static void
-oid_fill(struct dn_id *oid, int len, int type, uintptr_t id)
-{
- oid->len = len;
- oid->type = type;
- oid->subtype = 0;
- oid->id = id;
-}
-/* make room in the buffer and move the pointer forward */
-static void *
-o_next(struct dn_id **o, int len, int type)
-{
- struct dn_id *ret = *o;
- oid_fill(ret, len, type, 0);
- *o = O_NEXT(*o, len);
- return ret;
-}
-
-static size_t pipesize7 = sizeof(struct dn_pipe7);
-static size_t pipesize8 = sizeof(struct dn_pipe8);
-static size_t pipesizemax8 = sizeof(struct dn_pipe_max8);
-
-/* Indicate 'ipfw' version
- * 1: from FreeBSD 7.2
- * 0: from FreeBSD 8
- * -1: unknown (for now is unused)
- *
- * It is update when a IP_DUMMYNET_DEL or IP_DUMMYNET_CONFIGURE request arrives
- * NOTE: if a IP_DUMMYNET_GET arrives and the 'ipfw' version is unknown,
- * it is suppose to be the FreeBSD 8 version.
- */
-static int is7 = 0;
-
-static int
-convertflags2new(int src)
-{
- int dst = 0;
-
- if (src & DNOLD_HAVE_FLOW_MASK)
- dst |= DN_HAVE_MASK;
- if (src & DNOLD_QSIZE_IS_BYTES)
- dst |= DN_QSIZE_BYTES;
- if (src & DNOLD_NOERROR)
- dst |= DN_NOERROR;
- if (src & DNOLD_IS_RED)
- dst |= DN_IS_RED;
- if (src & DNOLD_IS_GENTLE_RED)
- dst |= DN_IS_GENTLE_RED;
- if (src & DNOLD_HAS_PROFILE)
- dst |= DN_HAS_PROFILE;
-
- return dst;
-}
-
-static int
-convertflags2old(int src)
-{
- int dst = 0;
-
- if (src & DN_HAVE_MASK)
- dst |= DNOLD_HAVE_FLOW_MASK;
- if (src & DN_IS_RED)
- dst |= DNOLD_IS_RED;
- if (src & DN_IS_GENTLE_RED)
- dst |= DNOLD_IS_GENTLE_RED;
- if (src & DN_NOERROR)
- dst |= DNOLD_NOERROR;
- if (src & DN_HAS_PROFILE)
- dst |= DNOLD_HAS_PROFILE;
- if (src & DN_QSIZE_BYTES)
- dst |= DNOLD_QSIZE_IS_BYTES;
-
- return dst;
-}
-
-static int
-dn_compat_del(void *v)
-{
- struct dn_pipe7 *p = (struct dn_pipe7 *) v;
- struct dn_pipe8 *p8 = (struct dn_pipe8 *) v;
- struct {
- struct dn_id oid;
- uintptr_t a[1]; /* add more if we want a list */
- } cmd;
-
- /* XXX DN_API_VERSION ??? */
- oid_fill((void *)&cmd, sizeof(cmd), DN_CMD_DELETE, DN_API_VERSION);
-
- if (is7) {
- if (p->pipe_nr == 0 && p->fs.fs_nr == 0)
- return EINVAL;
- if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
- return EINVAL;
- } else {
- if (p8->pipe_nr == 0 && p8->fs.fs_nr == 0)
- return EINVAL;
- if (p8->pipe_nr != 0 && p8->fs.fs_nr != 0)
- return EINVAL;
- }
-
- if (p->pipe_nr != 0) { /* pipe x delete */
- cmd.a[0] = p->pipe_nr;
- cmd.oid.subtype = DN_LINK;
- } else { /* queue x delete */
- cmd.oid.subtype = DN_FS;
- cmd.a[0] = (is7) ? p->fs.fs_nr : p8->fs.fs_nr;
- }
-
- return do_config(&cmd, cmd.oid.len);
-}
-
-static int
-dn_compat_config_queue(struct dn_fs *fs, void* v)
-{
- struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
- struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
- struct dn_flow_set *f;
-
- if (is7)
- f = &p7->fs;
- else
- f = &p8->fs;
-
- fs->fs_nr = f->fs_nr;
- fs->sched_nr = f->parent_nr;
- fs->flow_mask = f->flow_mask;
- fs->buckets = f->rq_size;
- fs->qsize = f->qsize;
- fs->plr[0] = f->plr[0];
- fs->plr[1] = f->plr[1];
- fs->plr[2] = f->plr[2];
- fs->plr[3] = f->plr[3];
- fs->par[0] = f->weight;
- fs->flags = convertflags2new(f->flags_fs);
- if (fs->flags & DN_IS_GENTLE_RED || fs->flags & DN_IS_RED) {
- fs->w_q = f->w_q;
- fs->max_th = f->max_th;
- fs->min_th = f->min_th;
- fs->max_p = f->max_p;
- }
-
- return 0;
-}
-
-static int
-dn_compat_config_pipe(struct dn_sch *sch, struct dn_link *p,
- struct dn_fs *fs, void* v)
-{
- struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
- struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
- int i = p7->pipe_nr;
-
- sch->sched_nr = i;
- sch->oid.subtype = 0;
- p->link_nr = i;
- fs->fs_nr = i + 2*DN_MAX_ID;
- fs->sched_nr = i + DN_MAX_ID;
-
- /* Common to 7 and 8 */
- p->bandwidth = p7->bandwidth;
- p->delay = p7->delay;
- if (!is7) {
- /* FreeBSD 8 has burst */
- p->burst = p8->burst;
- }
-
- /* fill the fifo flowset */
- dn_compat_config_queue(fs, v);
- fs->fs_nr = i + 2*DN_MAX_ID;
- fs->sched_nr = i + DN_MAX_ID;
-
- /* Move scheduler related parameter from fs to sch */
- sch->buckets = fs->buckets; /*XXX*/
- fs->buckets = 0;
- if (fs->flags & DN_HAVE_MASK) {
- sch->flags |= DN_HAVE_MASK;
- fs->flags &= ~DN_HAVE_MASK;
- sch->sched_mask = fs->flow_mask;
- bzero(&fs->flow_mask, sizeof(struct ipfw_flow_id));
- }
-
- return 0;
-}
-
-static int
-dn_compat_config_profile(struct dn_profile *pf, struct dn_link *p,
- void *v)
-{
- struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
-
- p8->samples = &(((struct dn_pipe_max8 *)p8)->samples[0]);
-
- pf->link_nr = p->link_nr;
- pf->loss_level = p8->loss_level;
-// pf->bandwidth = p->bandwidth; //XXX bandwidth redundant?
- pf->samples_no = p8->samples_no;
- strncpy(pf->name, p8->name,sizeof(pf->name));
- bcopy(p8->samples, pf->samples, sizeof(pf->samples));
-
- return 0;
-}
-
-/*
- * If p->pipe_nr != 0 the command is 'pipe x config', so need to create
- * the three main struct, else only a flowset is created
- */
-static int
-dn_compat_configure(void *v)
-{
- struct dn_id *buf = NULL, *base;
- struct dn_sch *sch = NULL;
- struct dn_link *p = NULL;
- struct dn_fs *fs = NULL;
- struct dn_profile *pf = NULL;
- int lmax;
- int error;
-
- struct dn_pipe7 *p7 = (struct dn_pipe7 *)v;
- struct dn_pipe8 *p8 = (struct dn_pipe8 *)v;
-
- int i; /* number of object to configure */
-
- lmax = sizeof(struct dn_id); /* command header */
- lmax += sizeof(struct dn_sch) + sizeof(struct dn_link) +
- sizeof(struct dn_fs) + sizeof(struct dn_profile);
-
- base = buf = malloc(lmax, M_DUMMYNET, M_WAITOK|M_ZERO);
- o_next(&buf, sizeof(struct dn_id), DN_CMD_CONFIG);
- base->id = DN_API_VERSION;
-
- /* pipe_nr is the same in p7 and p8 */
- i = p7->pipe_nr;
- if (i != 0) { /* pipe config */
- sch = o_next(&buf, sizeof(*sch), DN_SCH);
- p = o_next(&buf, sizeof(*p), DN_LINK);
- fs = o_next(&buf, sizeof(*fs), DN_FS);
-
- error = dn_compat_config_pipe(sch, p, fs, v);
- if (error) {
- free(buf, M_DUMMYNET);
- return error;
- }
- if (!is7 && p8->samples_no > 0) {
- /* Add profiles*/
- pf = o_next(&buf, sizeof(*pf), DN_PROFILE);
- error = dn_compat_config_profile(pf, p, v);
- if (error) {
- free(buf, M_DUMMYNET);
- return error;
- }
- }
- } else { /* queue config */
- fs = o_next(&buf, sizeof(*fs), DN_FS);
- error = dn_compat_config_queue(fs, v);
- if (error) {
- free(buf, M_DUMMYNET);
- return error;
- }
- }
- error = do_config(base, (char *)buf - (char *)base);
-
- if (buf)
- free(buf, M_DUMMYNET);
- return error;
-}
-
-int
-dn_compat_calc_size(void)
-{
- int need = 0;
- /* XXX use FreeBSD 8 struct size */
- /* NOTE:
- * - half scheduler: schk_count/2
- * - all flowset: fsk_count
- * - all flowset queues: queue_count
- * - all pipe queue: si_count
- */
- need += V_dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2;
- need += V_dn_cfg.fsk_count * sizeof(struct dn_flow_set);
- need += V_dn_cfg.si_count * sizeof(struct dn_flow_queue8);
- need += V_dn_cfg.queue_count * sizeof(struct dn_flow_queue8);
-
- return need;
-}
-
-int
-dn_c_copy_q (void *_ni, void *arg)
-{
- struct copy_args *a = arg;
- struct dn_flow_queue7 *fq7 = (struct dn_flow_queue7 *)*a->start;
- struct dn_flow_queue8 *fq8 = (struct dn_flow_queue8 *)*a->start;
- struct dn_flow *ni = (struct dn_flow *)_ni;
- int size = 0;
-
- /* XXX hash slot not set */
- /* No difference between 7.2/8 */
- fq7->len = ni->length;
- fq7->len_bytes = ni->len_bytes;
- fq7->id = ni->fid;
-
- if (is7) {
- size = sizeof(struct dn_flow_queue7);
- fq7->tot_pkts = ni->tot_pkts;
- fq7->tot_bytes = ni->tot_bytes;
- fq7->drops = ni->drops;
- } else {
- size = sizeof(struct dn_flow_queue8);
- fq8->tot_pkts = ni->tot_pkts;
- fq8->tot_bytes = ni->tot_bytes;
- fq8->drops = ni->drops;
- }
-
- *a->start += size;
- return 0;
-}
-
-int
-dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq)
-{
- struct dn_link *l = &s->link;
- struct dn_fsk *f = s->fs;
-
- struct dn_pipe7 *pipe7 = (struct dn_pipe7 *)*a->start;
- struct dn_pipe8 *pipe8 = (struct dn_pipe8 *)*a->start;
- struct dn_flow_set *fs;
- int size = 0;
-
- if (is7) {
- fs = &pipe7->fs;
- size = sizeof(struct dn_pipe7);
- } else {
- fs = &pipe8->fs;
- size = sizeof(struct dn_pipe8);
- }
-
- /* These 4 field are the same in pipe7 and pipe8 */
- pipe7->next.sle_next = (struct dn_pipe7 *)DN_IS_PIPE;
- pipe7->bandwidth = l->bandwidth;
- pipe7->delay = l->delay * 1000 / hz;
- pipe7->pipe_nr = l->link_nr - DN_MAX_ID;
-
- if (!is7) {
- if (s->profile) {
- struct dn_profile *pf = s->profile;
- strncpy(pipe8->name, pf->name, sizeof(pf->name));
- pipe8->loss_level = pf->loss_level;
- pipe8->samples_no = pf->samples_no;
- }
- pipe8->burst = div64(l->burst , 8 * hz);
- }
-
- fs->flow_mask = s->sch.sched_mask;
- fs->rq_size = s->sch.buckets ? s->sch.buckets : 1;
-
- fs->parent_nr = l->link_nr - DN_MAX_ID;
- fs->qsize = f->fs.qsize;
- fs->plr[0] = f->fs.plr[0];
- fs->plr[1] = f->fs.plr[1];
- fs->plr[2] = f->fs.plr[2];
- fs->plr[3] = f->fs.plr[3];
- fs->w_q = f->fs.w_q;
- fs->max_th = f->max_th;
- fs->min_th = f->min_th;
- fs->max_p = f->fs.max_p;
- fs->rq_elements = nq;
-
- fs->flags_fs = convertflags2old(f->fs.flags);
-
- *a->start += size;
- return 0;
-}
-
-int
-dn_compat_copy_pipe(struct copy_args *a, void *_o)
-{
- int have = a->end - *a->start;
- int need = 0;
- int pipe_size = sizeof(struct dn_pipe8);
- int queue_size = sizeof(struct dn_flow_queue8);
- int n_queue = 0; /* number of queues */
-
- struct dn_schk *s = (struct dn_schk *)_o;
- /* calculate needed space:
- * - struct dn_pipe
- * - if there are instances, dn_queue * n_instances
- */
- n_queue = (s->sch.flags & DN_HAVE_MASK ? dn_ht_entries(s->siht) :
- (s->siht ? 1 : 0));
- need = pipe_size + queue_size * n_queue;
- if (have < need) {
- D("have %d < need %d", have, need);
- return 1;
- }
- /* copy pipe */
- dn_c_copy_pipe(s, a, n_queue);
-
- /* copy queues */
- if (s->sch.flags & DN_HAVE_MASK)
- dn_ht_scan(s->siht, dn_c_copy_q, a);
- else if (s->siht)
- dn_c_copy_q(s->siht, a);
- return 0;
-}
-
-int
-dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq)
-{
- struct dn_flow_set *fs = (struct dn_flow_set *)*a->start;
-
- fs->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
- fs->fs_nr = f->fs.fs_nr;
- fs->qsize = f->fs.qsize;
- fs->plr[0] = f->fs.plr[0];
- fs->plr[1] = f->fs.plr[1];
- fs->plr[2] = f->fs.plr[2];
- fs->plr[3] = f->fs.plr[3];
- fs->w_q = f->fs.w_q;
- fs->max_th = f->max_th;
- fs->min_th = f->min_th;
- fs->max_p = f->fs.max_p;
- fs->flow_mask = f->fs.flow_mask;
- fs->rq_elements = nq;
- fs->rq_size = (f->fs.buckets ? f->fs.buckets : 1);
- fs->parent_nr = f->fs.sched_nr;
- fs->weight = f->fs.par[0];
-
- fs->flags_fs = convertflags2old(f->fs.flags);
- *a->start += sizeof(struct dn_flow_set);
- return 0;
-}
-
-int
-dn_compat_copy_queue(struct copy_args *a, void *_o)
-{
- int have = a->end - *a->start;
- int need = 0;
- int fs_size = sizeof(struct dn_flow_set);
- int queue_size = sizeof(struct dn_flow_queue8);
-
- struct dn_fsk *fs = (struct dn_fsk *)_o;
- int n_queue = 0; /* number of queues */
-
- n_queue = (fs->fs.flags & DN_HAVE_MASK ? dn_ht_entries(fs->qht) :
- (fs->qht ? 1 : 0));
-
- need = fs_size + queue_size * n_queue;
- if (have < need) {
- D("have < need");
- return 1;
- }
-
- /* copy flowset */
- dn_c_copy_fs(fs, a, n_queue);
-
- /* copy queues */
- if (fs->fs.flags & DN_HAVE_MASK)
- dn_ht_scan(fs->qht, dn_c_copy_q, a);
- else if (fs->qht)
- dn_c_copy_q(fs->qht, a);
-
- return 0;
-}
-
-int
-copy_data_helper_compat(void *_o, void *_arg)
-{
- struct copy_args *a = _arg;
-
- if (a->type == DN_COMPAT_PIPE) {
- struct dn_schk *s = _o;
- if (s->sch.oid.subtype != 1 || s->sch.sched_nr <= DN_MAX_ID) {
- return 0; /* not old type */
- }
- /* copy pipe parameters, and if instance exists, copy
- * other parameters and eventually queues.
- */
- if(dn_compat_copy_pipe(a, _o))
- return DNHT_SCAN_END;
- } else if (a->type == DN_COMPAT_QUEUE) {
- struct dn_fsk *fs = _o;
- if (fs->fs.fs_nr >= DN_MAX_ID)
- return 0;
- if (dn_compat_copy_queue(a, _o))
- return DNHT_SCAN_END;
- }
- return 0;
-}
-
-/* Main function to manage old requests */
-int
-ip_dummynet_compat(struct sockopt *sopt)
-{
- int error=0;
- void *v = NULL;
- struct dn_id oid;
-
- /* Length of data, used to found ipfw version... */
- int len = sopt->sopt_valsize;
-
- /* len can be 0 if command was dummynet_flush */
- if (len == pipesize7) {
- D("setting compatibility with FreeBSD 7.2");
- is7 = 1;
- }
- else if (len == pipesize8 || len == pipesizemax8) {
- D("setting compatibility with FreeBSD 8");
- is7 = 0;
- }
-
- switch (sopt->sopt_name) {
- default:
- printf("dummynet: -- unknown option %d", sopt->sopt_name);
- error = EINVAL;
- break;
-
- case IP_DUMMYNET_FLUSH:
- oid_fill(&oid, sizeof(oid), DN_CMD_FLUSH, DN_API_VERSION);
- do_config(&oid, oid.len);
- break;
-
- case IP_DUMMYNET_DEL:
- v = malloc(len, M_TEMP, M_WAITOK);
- error = sooptcopyin(sopt, v, len, len);
- if (error)
- break;
- error = dn_compat_del(v);
- free(v, M_TEMP);
- break;
-
- case IP_DUMMYNET_CONFIGURE:
- v = malloc(len, M_TEMP, M_NOWAIT);
- if (v == NULL) {
- error = ENOMEM;
- break;
- }
- error = sooptcopyin(sopt, v, len, len);
- if (error)
- break;
- error = dn_compat_configure(v);
- free(v, M_TEMP);
- break;
-
- case IP_DUMMYNET_GET: {
- void *buf;
- int ret;
- int original_size = sopt->sopt_valsize;
- int size;
-
- ret = dummynet_get(sopt, &buf);
- if (ret)
- return 0;//XXX ?
- size = sopt->sopt_valsize;
- sopt->sopt_valsize = original_size;
- D("size=%d, buf=%p", size, buf);
- ret = sooptcopyout(sopt, buf, size);
- if (ret)
- printf(" %s ERROR sooptcopyout\n", __FUNCTION__);
- if (buf)
- free(buf, M_DUMMYNET);
- }
- }
-
- return error;
-}
diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c
index 03116cb0641c..3a8de2b2bfee 100644
--- a/sys/netpfil/ipfw/ip_dn_io.c
+++ b/sys/netpfil/ipfw/ip_dn_io.c
@@ -43,6 +43,7 @@
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
+#include <sys/sdt.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/sysctl.h>
@@ -70,6 +71,9 @@
#endif
#include <netpfil/ipfw/dn_sched.h>
+SDT_PROVIDER_DEFINE(dummynet);
+SDT_PROBE_DEFINE2(dummynet, , , drop, "struct mbuf *", "struct dn_queue *");
+
/*
* We keep a private variable for the simulation time, but we could
* probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
@@ -545,6 +549,7 @@ dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
drop:
V_dn_cfg.io_pkt_drop++;
+ SDT_PROBE2(dummynet, , , drop, m, q);
q->ni.drops++;
ni->drops++;
FREE_PKT(m);
@@ -1001,6 +1006,7 @@ done:
dropit:
V_dn_cfg.io_pkt_drop++;
+ SDT_PROBE2(dummynet, , , drop, m, q);
DN_BH_WUNLOCK();
if (m)
FREE_PKT(m);
diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h
index 756a997b6ec3..9a43b86791e0 100644
--- a/sys/netpfil/ipfw/ip_dn_private.h
+++ b/sys/netpfil/ipfw/ip_dn_private.h
@@ -437,15 +437,7 @@ struct copy_args {
};
struct sockopt;
-int ip_dummynet_compat(struct sockopt *sopt);
-int dummynet_get(struct sockopt *sopt, void **compat);
-int dn_c_copy_q (void *_ni, void *arg);
-int dn_c_copy_pipe(struct dn_schk *s, struct copy_args *a, int nq);
-int dn_c_copy_fs(struct dn_fsk *f, struct copy_args *a, int nq);
-int dn_compat_copy_queue(struct copy_args *a, void *_o);
-int dn_compat_copy_pipe(struct copy_args *a, void *_o);
-int copy_data_helper_compat(void *_o, void *_arg);
-int dn_compat_calc_size(void);
+int dummynet_get(struct sockopt *sopt);
int do_config(void *p, size_t l);
/* function to drain idle object */
diff --git a/sys/netpfil/ipfw/ip_dummynet.c b/sys/netpfil/ipfw/ip_dummynet.c
index b3f52322425f..61442c617753 100644
--- a/sys/netpfil/ipfw/ip_dummynet.c
+++ b/sys/netpfil/ipfw/ip_dummynet.c
@@ -1150,7 +1150,7 @@ copy_data_helper(void *_o, void *_arg)
return 0; /* not a pipe */
/* see if the object is within one of our ranges */
- for (;r < lim; r += 2) {
+ for (; r < lim; r += 2) {
if (n < r[0] || n > r[1])
continue;
/* Found a valid entry, copy and we are done */
@@ -1183,7 +1183,7 @@ copy_data_helper(void *_o, void *_arg)
if (n >= DN_MAX_ID)
return 0;
/* see if the object is within one of our ranges */
- for (;r < lim; r += 2) {
+ for (; r < lim; r += 2) {
if (n < r[0] || n > r[1])
continue;
if (copy_flowset(a, fs, 0))
@@ -2198,9 +2198,6 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
case DN_FS: /* queue show */
x = DN_C_FS | DN_C_QUEUE;
break;
- case DN_GET_COMPAT: /* compatibility mode */
- need = dn_compat_calc_size();
- break;
}
a->flags = x;
if (x & DN_C_SCH) {
@@ -2226,11 +2223,9 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
}
/*
- * If compat != NULL dummynet_get is called in compatibility mode.
- * *compat will be the pointer to the buffer to pass to ipfw
*/
int
-dummynet_get(struct sockopt *sopt, void **compat)
+dummynet_get(struct sockopt *sopt)
{
int have, i, need, error;
char *start = NULL, *buf;
@@ -2248,37 +2243,28 @@ dummynet_get(struct sockopt *sopt, void **compat)
cmd = &r.o;
- if (!compat) {
- /* copy at least an oid, and possibly a full object */
- error = sooptcopyin(sopt, cmd, sizeof(r), sizeof(*cmd));
- sopt->sopt_valsize = sopt_valsize;
- if (error)
- goto done;
- l = cmd->len;
+ /* copy at least an oid, and possibly a full object */
+ error = sooptcopyin(sopt, cmd, sizeof(r), sizeof(*cmd));
+ sopt->sopt_valsize = sopt_valsize;
+ if (error)
+ goto done;
+ l = cmd->len;
#ifdef EMULATE_SYSCTL
- /* sysctl emulation. */
- if (cmd->type == DN_SYSCTL_GET)
- return kesysctl_emu_get(sopt);
+ /* sysctl emulation. */
+ if (cmd->type == DN_SYSCTL_GET)
+ return kesysctl_emu_get(sopt);
#endif
- if (l > sizeof(r)) {
- /* request larger than default, allocate buffer */
- cmd = malloc(l, M_DUMMYNET, M_NOWAIT);
- if (cmd == NULL) {
- error = ENOMEM;
- goto done;
- }
- error = sooptcopyin(sopt, cmd, l, l);
- sopt->sopt_valsize = sopt_valsize;
- if (error)
- goto done;
+ if (l > sizeof(r)) {
+ /* request larger than default, allocate buffer */
+ cmd = malloc(l, M_DUMMYNET, M_NOWAIT);
+ if (cmd == NULL) {
+ error = ENOMEM;
+ goto done;
}
- } else { /* compatibility */
- error = 0;
- cmd->type = DN_CMD_GET;
- cmd->len = sizeof(struct dn_id);
- cmd->subtype = DN_GET_COMPAT;
- // cmd->id = sopt_valsize;
- D("compatibility mode");
+ error = sooptcopyin(sopt, cmd, l, l);
+ sopt->sopt_valsize = sopt_valsize;
+ if (error)
+ goto done;
}
#ifdef NEW_AQM
@@ -2337,12 +2323,7 @@ dummynet_get(struct sockopt *sopt, void **compat)
}
if (start == NULL) {
- if (compat) {
- *compat = NULL;
- error = 1; // XXX
- } else {
- error = sooptcopyout(sopt, cmd, sizeof(*cmd));
- }
+ error = sooptcopyout(sopt, cmd, sizeof(*cmd));
goto done;
}
ND("have %d:%d sched %d, %d:%d links %d, %d:%d flowsets %d, "
@@ -2355,35 +2336,20 @@ dummynet_get(struct sockopt *sopt, void **compat)
sopt->sopt_valsize = sopt_valsize;
a.type = cmd->subtype;
- if (compat == NULL) {
- memcpy(start, cmd, sizeof(*cmd));
- ((struct dn_id*)(start))->len = sizeof(struct dn_id);
- buf = start + sizeof(*cmd);
- } else
- buf = start;
+ memcpy(start, cmd, sizeof(*cmd));
+ ((struct dn_id*)(start))->len = sizeof(struct dn_id);
+ buf = start + sizeof(*cmd);
a.start = &buf;
a.end = start + have;
/* start copying other objects */
- if (compat) {
- a.type = DN_COMPAT_PIPE;
- dn_ht_scan(V_dn_cfg.schedhash, copy_data_helper_compat, &a);
- a.type = DN_COMPAT_QUEUE;
- dn_ht_scan(V_dn_cfg.fshash, copy_data_helper_compat, &a);
- } else if (a.type == DN_FS) {
+ if (a.type == DN_FS) {
dn_ht_scan(V_dn_cfg.fshash, copy_data_helper, &a);
} else {
dn_ht_scan(V_dn_cfg.schedhash, copy_data_helper, &a);
}
DN_BH_WUNLOCK();
- if (compat) {
- *compat = start;
- sopt->sopt_valsize = buf - start;
- /* free() is done by ip_dummynet_compat() */
- start = NULL; //XXX hack
- } else {
- error = sooptcopyout(sopt, start, buf - start);
- }
+ error = sooptcopyout(sopt, start, buf - start);
done:
if (cmd != &r.o)
free(cmd, M_DUMMYNET);
@@ -2519,17 +2485,9 @@ ip_dn_ctl(struct sockopt *sopt)
error = EINVAL;
break;
- case IP_DUMMYNET_FLUSH:
- case IP_DUMMYNET_CONFIGURE:
- case IP_DUMMYNET_DEL: /* remove a pipe or queue */
- case IP_DUMMYNET_GET:
- D("dummynet: compat option %d", sopt->sopt_name);
- error = ip_dummynet_compat(sopt);
- break;
-
case IP_DUMMYNET3:
if (sopt->sopt_dir == SOPT_GET) {
- error = dummynet_get(sopt, NULL);
+ error = dummynet_get(sopt);
break;
}
l = sopt->sopt_valsize;
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index b59d8d08bf80..d15d7760d7f1 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -3578,11 +3578,9 @@ sysctl_ipfw_tables_sets(SYSCTL_HANDLER_ARGS)
/*
* Stuff that must be initialised only on boot or module load
*/
-static int
-ipfw_init(void)
+static void
+ipfw_init(void *dummy __unused)
{
- int error = 0;
-
/*
* Only print out this stuff the first time around,
* when called from the sysinit code.
@@ -3627,14 +3625,13 @@ ipfw_init(void)
ipfw_init_sopt_handler();
ipfw_init_obj_rewriter();
ipfw_iface_init();
- return (error);
}
/*
* Called for the removal of the last instance only on module unload.
*/
static void
-ipfw_destroy(void)
+ipfw_destroy(void *dummy __unused)
{
ipfw_iface_destroy();
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
index 1e2ff1bca290..8bd27f6885ab 100644
--- a/sys/netpfil/ipfw/ip_fw_nat.c
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
@@ -999,9 +999,11 @@ ipfw_nat_del(struct sockopt *sopt)
{
struct cfg_nat *ptr;
struct ip_fw_chain *chain = &V_layer3_chain;
- int i;
+ int error, i;
- sooptcopyin(sopt, &i, sizeof i, sizeof i);
+ error = sooptcopyin(sopt, &i, sizeof i, sizeof i);
+ if (error != 0)
+ return (error);
/* XXX validate i */
IPFW_UH_WLOCK(chain);
ptr = lookup_nat(&chain->nat, i);
@@ -1104,7 +1106,7 @@ ipfw_nat_get_log(struct sockopt *sopt)
{
uint8_t *data;
struct cfg_nat *ptr;
- int i, size;
+ int error, i, size;
struct ip_fw_chain *chain;
IPFW_RLOCK_TRACKER;
@@ -1134,9 +1136,9 @@ ipfw_nat_get_log(struct sockopt *sopt)
i += LIBALIAS_BUF_SIZE;
}
IPFW_RUNLOCK(chain);
- sooptcopyout(sopt, data, size);
+ error = sooptcopyout(sopt, data, size);
free(data, M_IPFW);
- return(0);
+ return (error);
}
static int
@@ -1166,7 +1168,7 @@ vnet_ipfw_nat_uninit(const void *arg __unused)
}
static void
-ipfw_nat_init(void)
+ipfw_nat_init(void *dummy __unused)
{
/* init ipfw hooks */
@@ -1183,7 +1185,7 @@ ipfw_nat_init(void)
}
static void
-ipfw_nat_destroy(void)
+ipfw_nat_destroy(void *dummy __unused)
{
EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
diff --git a/sys/netpfil/ipfw/pmod/tcpmod.c b/sys/netpfil/ipfw/pmod/tcpmod.c
index 0338dc792c64..50074ee98cca 100644
--- a/sys/netpfil/ipfw/pmod/tcpmod.c
+++ b/sys/netpfil/ipfw/pmod/tcpmod.c
@@ -57,7 +57,8 @@ VNET_DEFINE_STATIC(uint32_t, tcpmod_setmss_eid) = 0;
#define V_tcpmod_setmss_eid VNET(tcpmod_setmss_eid)
static int
-tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
+tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss,
+ int *done)
{
struct mbuf *m;
u_char *cp;
@@ -72,8 +73,10 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
* TCP header with options.
*/
*mp = m = m_pullup(m, m->m_pkthdr.len);
- if (m == NULL)
+ if (m == NULL) {
+ *done = 1;
return (ret);
+ }
}
/* Parse TCP options. */
for (tlen -= sizeof(struct tcphdr), cp = (u_char *)(tcp + 1);
@@ -114,7 +117,7 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
#ifdef INET6
static int
-tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)
+tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss, int *done)
{
struct ip6_hdr *ip6;
struct ip6_hbh *hbh;
@@ -142,13 +145,13 @@ tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)
/* We must have TCP options and enough data in a packet. */
if (hlen <= sizeof(struct tcphdr) || hlen > plen)
return (IP_FW_DENY);
- return (tcpmod_setmss(mp, tcp, hlen, mss));
+ return (tcpmod_setmss(mp, tcp, hlen, mss, done));
}
#endif /* INET6 */
#ifdef INET
static int
-tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)
+tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss, int *done)
{
struct tcphdr *tcp;
struct ip *ip;
@@ -162,7 +165,7 @@ tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)
/* We must have TCP options and enough data in a packet. */
if (hlen <= sizeof(struct tcphdr) || hlen > plen)
return (IP_FW_DENY);
- return (tcpmod_setmss(mp, tcp, hlen, mss));
+ return (tcpmod_setmss(mp, tcp, hlen, mss, done));
}
#endif /* INET */
@@ -206,19 +209,23 @@ ipfw_tcpmod(struct ip_fw_chain *chain, struct ip_fw_args *args,
switch (args->f_id.addr_type) {
#ifdef INET
case 4:
- ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1));
+ ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1),
+ done);
break;
#endif
#ifdef INET6
case 6:
- ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1));
+ ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1),
+ done);
break;
#endif
}
/*
* We return zero in both @ret and @done on success, and ipfw_chk()
* will update rule counters. Otherwise a packet will not be matched
- * by rule.
+ * by rule. We passed @done around above in case we hit a fatal error
+ * somewhere, we'll return non-zero but signal that rule processing
+ * cannot succeed.
*/
return (ret);
}
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 66bc99df2afa..de69ecbb0985 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -546,6 +546,9 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
PF_RULES_RASSERT();
+ if (strnlen(sp->pfs_1301.ifname, IFNAMSIZ) == IFNAMSIZ)
+ return (EINVAL);
+
if (sp->pfs_1301.creatorid == 0) {
if (V_pf_status.debug >= PF_DEBUG_MISC)
printf("%s: invalid creator id: %08x\n", __func__,
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index ec6960180413..a39f5fe58cd6 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -344,10 +344,12 @@ static int pf_test_eth_rule(int, struct pfi_kkif *,
struct mbuf **);
static int pf_test_rule(struct pf_krule **, struct pf_kstate **,
struct pf_pdesc *, struct pf_krule **,
- struct pf_kruleset **, u_short *, struct inpcb *);
+ struct pf_kruleset **, u_short *, struct inpcb *,
+ struct pf_krule_slist *);
static int pf_create_state(struct pf_krule *,
struct pf_test_ctx *,
- struct pf_kstate **, u_int16_t, u_int16_t);
+ struct pf_kstate **, u_int16_t, u_int16_t,
+ struct pf_krule_slist *match_rules);
static int pf_state_key_addr_setup(struct pf_pdesc *,
struct pf_state_key_cmp *, int);
static int pf_tcp_track_full(struct pf_kstate *,
@@ -393,7 +395,7 @@ static bool pf_src_connlimit(struct pf_kstate *);
static int pf_match_rcvif(struct mbuf *, struct pf_krule *);
static void pf_counters_inc(int, struct pf_pdesc *,
struct pf_kstate *, struct pf_krule *,
- struct pf_krule *);
+ struct pf_krule *, struct pf_krule_slist *);
static void pf_log_matches(struct pf_pdesc *, struct pf_krule *,
struct pf_krule *, struct pf_kruleset *,
struct pf_krule_slist *);
@@ -489,26 +491,30 @@ BOUND_IFACE(struct pf_kstate *st, struct pf_pdesc *pd)
counter_u64_add(s->anchor->states_cur, 1); \
counter_u64_add(s->anchor->states_tot, 1); \
} \
- if (s->nat_rule != NULL) { \
- counter_u64_add(s->nat_rule->states_cur, 1);\
- counter_u64_add(s->nat_rule->states_tot, 1);\
+ if (s->nat_rule != NULL && s->nat_rule != s->rule) { \
+ counter_u64_add(s->nat_rule->states_cur, 1); \
+ counter_u64_add(s->nat_rule->states_tot, 1); \
} \
SLIST_FOREACH(mrm, &s->match_rules, entry) { \
- counter_u64_add(mrm->r->states_cur, 1); \
- counter_u64_add(mrm->r->states_tot, 1); \
+ if (s->nat_rule != mrm->r) { \
+ counter_u64_add(mrm->r->states_cur, 1); \
+ counter_u64_add(mrm->r->states_tot, 1); \
+ } \
} \
} while (0)
#define STATE_DEC_COUNTERS(s) \
do { \
struct pf_krule_item *mrm; \
- if (s->nat_rule != NULL) \
- counter_u64_add(s->nat_rule->states_cur, -1);\
- if (s->anchor != NULL) \
- counter_u64_add(s->anchor->states_cur, -1); \
counter_u64_add(s->rule->states_cur, -1); \
+ if (s->anchor != NULL) \
+ counter_u64_add(s->anchor->states_cur, -1); \
+ if (s->nat_rule != NULL && s->nat_rule != s->rule) \
+ counter_u64_add(s->nat_rule->states_cur, -1); \
SLIST_FOREACH(mrm, &s->match_rules, entry) \
- counter_u64_add(mrm->r->states_cur, -1); \
+ if (s->nat_rule != mrm->r) { \
+ counter_u64_add(mrm->r->states_cur, -1);\
+ } \
} while (0)
MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures");
@@ -1001,7 +1007,7 @@ pf_src_node_exists(struct pf_ksrc_node **sn, struct pf_srchash *sh)
return (false);
}
-static void
+void
pf_free_src_node(struct pf_ksrc_node *sn)
{
@@ -2869,20 +2875,24 @@ pf_alloc_state(int flags)
return (uma_zalloc(V_pf_state_z, flags | M_ZERO));
}
+static __inline void
+pf_free_match_rules(struct pf_krule_slist *match_rules) {
+ struct pf_krule_item *ri;
+
+ while ((ri = SLIST_FIRST(match_rules))) {
+ SLIST_REMOVE_HEAD(match_rules, entry);
+ free(ri, M_PF_RULE_ITEM);
+ }
+}
+
void
pf_free_state(struct pf_kstate *cur)
{
- struct pf_krule_item *ri;
-
KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur));
KASSERT(cur->timeout == PFTM_UNLINKED, ("%s: timeout %u", __func__,
cur->timeout));
- while ((ri = SLIST_FIRST(&cur->match_rules))) {
- SLIST_REMOVE_HEAD(&cur->match_rules, entry);
- free(ri, M_PF_RULE_ITEM);
- }
-
+ pf_free_match_rules(&(cur->match_rules));
pf_normalize_tcp_cleanup(cur);
uma_zfree(V_pf_state_z, cur);
pf_counter_u64_add(&V_pf_status.fcounters[FCNT_STATE_REMOVALS], 1);
@@ -3354,7 +3364,7 @@ pf_change_ap(struct pf_pdesc *pd, struct pf_addr *a, u_int16_t *p,
u_int16_t po;
uint8_t u = pd->virtual_proto == IPPROTO_UDP;
- MPASS(pd->pcksum);
+ MPASS(pd->pcksum != NULL);
if (pd->af == AF_INET) {
MPASS(pd->ip_sum);
}
@@ -4740,7 +4750,8 @@ pf_tag_packet(struct pf_pdesc *pd, int tag)
} while (0)
enum pf_test_status
-pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_krule *r)
+pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_krule *r,
+ struct pf_krule_slist *match_rules)
{
enum pf_test_status rv;
@@ -4758,7 +4769,7 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_krule *r)
struct pf_kanchor *child;
rv = PF_TEST_OK;
RB_FOREACH(child, pf_kanchor_node, &r->anchor->children) {
- rv = pf_match_rule(ctx, &child->ruleset);
+ rv = pf_match_rule(ctx, &child->ruleset, match_rules);
if ((rv == PF_TEST_QUICK) || (rv == PF_TEST_FAIL)) {
/*
* we either hit a rule with quick action
@@ -4769,7 +4780,7 @@ pf_step_into_anchor(struct pf_test_ctx *ctx, struct pf_krule *r)
}
}
} else {
- rv = pf_match_rule(ctx, &r->anchor->ruleset);
+ rv = pf_match_rule(ctx, &r->anchor->ruleset, match_rules);
/*
* Unless errors occured, stop iff any rule matched
* within quick anchors.
@@ -5618,9 +5629,10 @@ pf_rule_apply_nat(struct pf_test_ctx *ctx, struct pf_krule *r)
}
enum pf_test_status
-pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset)
+pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset,
+ struct pf_krule_slist *match_rules)
{
- struct pf_krule_item *ri;
+ struct pf_krule_item *ri, *rt;
struct pf_krule *r;
struct pf_krule *save_a;
struct pf_kruleset *save_aruleset;
@@ -5777,11 +5789,14 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset)
return (PF_TEST_FAIL);
}
ri->r = r;
- SLIST_INSERT_HEAD(&ctx->rules, ri, entry);
- pf_counter_u64_critical_enter();
- pf_counter_u64_add_protected(&r->packets[pd->dir == PF_OUT], 1);
- pf_counter_u64_add_protected(&r->bytes[pd->dir == PF_OUT], pd->tot_len);
- pf_counter_u64_critical_exit();
+
+ if (SLIST_EMPTY(match_rules)) {
+ SLIST_INSERT_HEAD(match_rules, ri, entry);
+ } else {
+ SLIST_INSERT_AFTER(rt, ri, entry);
+ }
+ rt = ri;
+
pf_rule_to_actions(r, &pd->act);
if (r->log)
PFLOG_PACKET(r->action, PFRES_MATCH, r,
@@ -5805,7 +5820,7 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset)
ctx->arsm = ctx->aruleset;
}
if (pd->act.log & PF_LOG_MATCHES)
- pf_log_matches(pd, r, ctx->a, ruleset, &ctx->rules);
+ pf_log_matches(pd, r, ctx->a, ruleset, match_rules);
if (r->quick) {
ctx->test_status = PF_TEST_QUICK;
break;
@@ -5822,7 +5837,7 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset)
* Note: we don't need to restore if we are not going
* to continue with ruleset evaluation.
*/
- if (pf_step_into_anchor(ctx, r) != PF_TEST_OK) {
+ if (pf_step_into_anchor(ctx, r, match_rules) != PF_TEST_OK) {
break;
}
ctx->a = save_a;
@@ -5838,11 +5853,11 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset)
static int
pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
struct pf_pdesc *pd, struct pf_krule **am,
- struct pf_kruleset **rsm, u_short *reason, struct inpcb *inp)
+ struct pf_kruleset **rsm, u_short *reason, struct inpcb *inp,
+ struct pf_krule_slist *match_rules)
{
struct pf_krule *r = NULL;
struct pf_kruleset *ruleset = NULL;
- struct pf_krule_item *ri;
struct pf_test_ctx ctx;
u_short transerror;
int action = PF_PASS;
@@ -5859,7 +5874,6 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
ctx.rsm = rsm;
ctx.th = &pd->hdr.tcp;
ctx.reason = *reason;
- SLIST_INIT(&ctx.rules);
pf_addrcpy(&pd->nsaddr, pd->src, pd->af);
pf_addrcpy(&pd->ndaddr, pd->dst, pd->af);
@@ -5951,44 +5965,50 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
ctx.nat_pool = &(ctx.nr->rdr);
}
- ruleset = &pf_main_ruleset;
- rv = pf_match_rule(&ctx, ruleset);
- if (rv == PF_TEST_FAIL) {
- /*
- * Reason has been set in pf_match_rule() already.
- */
- goto cleanup;
- }
-
- r = *ctx.rm; /* matching rule */
- ctx.a = *ctx.am; /* rule that defines an anchor containing 'r' */
- ruleset = *ctx.rsm; /* ruleset of the anchor defined by the rule 'a' */
- ctx.aruleset = ctx.arsm; /* ruleset of the 'a' rule itself */
+ *ctx.rm = &V_pf_default_rule;
+ if (ctx.nr && ctx.nr->natpass) {
+ r = ctx.nr;
+ ruleset = *ctx.rsm;
+ } else {
+ ruleset = &pf_main_ruleset;
+ rv = pf_match_rule(&ctx, ruleset, match_rules);
+ if (rv == PF_TEST_FAIL) {
+ /*
+ * Reason has been set in pf_match_rule() already.
+ */
+ goto cleanup;
+ }
- REASON_SET(&ctx.reason, PFRES_MATCH);
+ r = *ctx.rm; /* matching rule */
+ ctx.a = *ctx.am; /* rule that defines an anchor containing 'r' */
+ ruleset = *ctx.rsm; /* ruleset of the anchor defined by the rule 'a' */
+ ctx.aruleset = ctx.arsm; /* ruleset of the 'a' rule itself */
- /* apply actions for last matching pass/block rule */
- pf_rule_to_actions(r, &pd->act);
- transerror = pf_rule_apply_nat(&ctx, r);
- switch (transerror) {
- case PFRES_MATCH:
- /* Translation action found in rule and applied successfully */
- case PFRES_MAX:
- /* No translation action found in rule */
- break;
- default:
- /* Translation action found in rule but failed to apply */
- REASON_SET(&ctx.reason, transerror);
- goto cleanup;
+ /* apply actions for last matching pass/block rule */
+ pf_rule_to_actions(r, &pd->act);
+ transerror = pf_rule_apply_nat(&ctx, r);
+ switch (transerror) {
+ case PFRES_MATCH:
+ /* Translation action found in rule and applied successfully */
+ case PFRES_MAX:
+ /* No translation action found in rule */
+ break;
+ default:
+ /* Translation action found in rule but failed to apply */
+ REASON_SET(&ctx.reason, transerror);
+ goto cleanup;
+ }
}
+ REASON_SET(&ctx.reason, PFRES_MATCH);
+
if (r->log) {
if (ctx.rewrite)
m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any);
PFLOG_PACKET(r->action, ctx.reason, r, ctx.a, ruleset, pd, 1, NULL);
}
if (pd->act.log & PF_LOG_MATCHES)
- pf_log_matches(pd, r, ctx.a, ruleset, &ctx.rules);
+ pf_log_matches(pd, r, ctx.a, ruleset, match_rules);
if (pd->virtual_proto != PF_VPROTO_FRAGMENT &&
(r->action == PF_DROP) &&
((r->rule_flag & PFRULE_RETURNRST) ||
@@ -6033,7 +6053,8 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
(pd->flags & PFDESC_TCP_NORM)))) {
bool nat64;
- action = pf_create_state(r, &ctx, sm, bproto_sum, bip_sum);
+ action = pf_create_state(r, &ctx, sm, bproto_sum, bip_sum,
+ match_rules);
ctx.sk = ctx.nk = NULL;
if (action != PF_PASS) {
pf_udp_mapping_release(ctx.udp_mapping);
@@ -6079,11 +6100,6 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
action = PF_AFRT;
}
} else {
- while ((ri = SLIST_FIRST(&ctx.rules))) {
- SLIST_REMOVE_HEAD(&ctx.rules, entry);
- free(ri, M_PF_RULE_ITEM);
- }
-
uma_zfree(V_pf_state_key_z, ctx.sk);
uma_zfree(V_pf_state_key_z, ctx.nk);
ctx.sk = ctx.nk = NULL;
@@ -6111,11 +6127,6 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
return (action);
cleanup:
- while ((ri = SLIST_FIRST(&ctx.rules))) {
- SLIST_REMOVE_HEAD(&ctx.rules, entry);
- free(ri, M_PF_RULE_ITEM);
- }
-
uma_zfree(V_pf_state_key_z, ctx.sk);
uma_zfree(V_pf_state_key_z, ctx.nk);
pf_udp_mapping_release(ctx.udp_mapping);
@@ -6126,7 +6137,8 @@ cleanup:
static int
pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
- struct pf_kstate **sm, u_int16_t bproto_sum, u_int16_t bip_sum)
+ struct pf_kstate **sm, u_int16_t bproto_sum, u_int16_t bip_sum,
+ struct pf_krule_slist *match_rules)
{
struct pf_pdesc *pd = ctx->pd;
struct pf_kstate *s = NULL;
@@ -6140,7 +6152,6 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
struct tcphdr *th = &pd->hdr.tcp;
u_int16_t mss = V_tcp_mssdflt;
u_short sn_reason;
- struct pf_krule_item *ri;
/* check maximums */
if (r->max_states &&
@@ -6192,7 +6203,7 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
s->rule = r;
s->nat_rule = ctx->nr;
s->anchor = ctx->a;
- memcpy(&s->match_rules, &ctx->rules, sizeof(s->match_rules));
+ s->match_rules = *match_rules;
memcpy(&s->act, &pd->act, sizeof(struct pf_rule_actions));
if (pd->act.allow_opts)
@@ -6356,11 +6367,6 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
return (PF_PASS);
csfailed:
- while ((ri = SLIST_FIRST(&ctx->rules))) {
- SLIST_REMOVE_HEAD(&ctx->rules, entry);
- free(ri, M_PF_RULE_ITEM);
- }
-
uma_zfree(V_pf_state_key_z, ctx->sk);
uma_zfree(V_pf_state_key_z, ctx->nk);
@@ -7518,6 +7524,7 @@ static void
pf_sctp_multihome_delayed(struct pf_pdesc *pd, struct pfi_kkif *kif,
struct pf_kstate *s, int action)
{
+ struct pf_krule_slist match_rules;
struct pf_sctp_multihome_job *j, *tmp;
struct pf_sctp_source *i;
int ret;
@@ -7565,8 +7572,14 @@ again:
if (s->rule->rule_flag & PFRULE_ALLOW_RELATED) {
j->pd.related_rule = s->rule;
}
+ SLIST_INIT(&match_rules);
ret = pf_test_rule(&r, &sm,
- &j->pd, &ra, &rs, &reason, NULL);
+ &j->pd, &ra, &rs, &reason, NULL, &match_rules);
+ /*
+ * Nothing to do about match rules, the processed
+ * packet has already increased the counters.
+ */
+ pf_free_match_rules(&match_rules);
PF_RULES_RUNLOCK();
SDT_PROBE4(pf, sctp, multihome, test, kif, r, j->pd.m, ret);
if (ret != PF_DROP && sm != NULL) {
@@ -7627,6 +7640,7 @@ again:
nj->pd.m = j->pd.m;
nj->op = j->op;
+ MPASS(nj->pd.pcksum);
TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, nj, next);
}
PF_SCTP_ENDPOINTS_UNLOCK();
@@ -7746,6 +7760,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
job->pd.m = pd->m;
job->op = op;
+ MPASS(job->pd.pcksum);
TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next);
break;
}
@@ -7779,6 +7794,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
job->pd.m = pd->m;
job->op = op;
+ MPASS(job->pd.pcksum);
TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next);
break;
}
@@ -9221,28 +9237,41 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
}
}
- if (r->rt == PF_DUPTO)
+ if (r->rt == PF_DUPTO || (pd->af != pd->naf && s->direction == PF_IN))
skip_test = true;
- if (pd->dir == PF_IN && !skip_test) {
- if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
- &pd->act) != PF_PASS) {
- action = PF_DROP;
- SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
- goto bad;
- } else if (m0 == NULL) {
- action = PF_DROP;
- SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
- goto done;
- }
- if (m0->m_len < sizeof(struct ip)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- "%s: m0->m_len < sizeof(struct ip)", __func__);
- SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
- action = PF_DROP;
- goto bad;
+ if (pd->dir == PF_IN) {
+ if (skip_test) {
+ struct pfi_kkif *out_kif = (struct pfi_kkif *)ifp->if_pf_kif;
+ MPASS(s != NULL);
+ pf_counter_u64_critical_enter();
+ pf_counter_u64_add_protected(
+ &out_kif->pfik_bytes[pd->naf == AF_INET6][1]
+ [action != PF_PASS && action != PF_AFRT], pd->tot_len);
+ pf_counter_u64_add_protected(
+ &out_kif->pfik_packets[pd->naf == AF_INET6][1]
+ [action != PF_PASS && action != PF_AFRT], 1);
+ pf_counter_u64_critical_exit();
+ } else {
+ if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
+ &pd->act) != PF_PASS) {
+ action = PF_DROP;
+ SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+ goto bad;
+ } else if (m0 == NULL) {
+ action = PF_DROP;
+ SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+ goto done;
+ }
+ if (m0->m_len < sizeof(struct ip)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ "%s: m0->m_len < sizeof(struct ip)", __func__);
+ SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+ action = PF_DROP;
+ goto bad;
+ }
+ ip = mtod(m0, struct ip *);
}
- ip = mtod(m0, struct ip *);
}
if (ifp->if_flags & IFF_LOOPBACK)
@@ -9538,29 +9567,42 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp,
}
}
- if (r->rt == PF_DUPTO)
+ if (r->rt == PF_DUPTO || (pd->af != pd->naf && s->direction == PF_IN))
skip_test = true;
- if (pd->dir == PF_IN && !skip_test) {
- if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
- ifp, &m0, inp, &pd->act) != PF_PASS) {
- action = PF_DROP;
- SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
- goto bad;
- } else if (m0 == NULL) {
- action = PF_DROP;
- SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
- goto done;
- }
- if (m0->m_len < sizeof(struct ip6_hdr)) {
- DPFPRINTF(PF_DEBUG_URGENT,
- "%s: m0->m_len < sizeof(struct ip6_hdr)",
- __func__);
- action = PF_DROP;
- SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
- goto bad;
+ if (pd->dir == PF_IN) {
+ if (skip_test) {
+ struct pfi_kkif *out_kif = (struct pfi_kkif *)ifp->if_pf_kif;
+ MPASS(s != NULL);
+ pf_counter_u64_critical_enter();
+ pf_counter_u64_add_protected(
+ &out_kif->pfik_bytes[pd->naf == AF_INET6][1]
+ [action != PF_PASS && action != PF_AFRT], pd->tot_len);
+ pf_counter_u64_add_protected(
+ &out_kif->pfik_packets[pd->naf == AF_INET6][1]
+ [action != PF_PASS && action != PF_AFRT], 1);
+ pf_counter_u64_critical_exit();
+ } else {
+ if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
+ ifp, &m0, inp, &pd->act) != PF_PASS) {
+ action = PF_DROP;
+ SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+ goto bad;
+ } else if (m0 == NULL) {
+ action = PF_DROP;
+ SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+ goto done;
+ }
+ if (m0->m_len < sizeof(struct ip6_hdr)) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ "%s: m0->m_len < sizeof(struct ip6_hdr)",
+ __func__);
+ action = PF_DROP;
+ SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+ goto bad;
+ }
+ ip6 = mtod(m0, struct ip6_hdr *);
}
- ip6 = mtod(m0, struct ip6_hdr *);
}
if (ifp->if_flags & IFF_LOOPBACK)
@@ -10410,28 +10452,28 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
__func__);
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
h = mtod(pd->m, struct ip *);
if (pd->m->m_pkthdr.len < ntohs(h->ip_len)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
if (pf_normalize_ip(reason, pd) != PF_PASS) {
/* We do IP header normalization and packet reassembly here */
*m0 = pd->m;
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
*m0 = pd->m;
h = mtod(pd->m, struct ip *);
if (pf_walk_header(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
pd->src = (struct pf_addr *)&h->ip_src;
@@ -10461,7 +10503,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
", pullup failed", __func__);
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
h = mtod(pd->m, struct ip6_hdr *);
@@ -10469,7 +10511,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
sizeof(struct ip6_hdr) + ntohs(h->ip6_plen)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
/*
@@ -10478,12 +10520,12 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
*/
if (htons(h->ip6_plen) == 0) {
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
if (pf_walk_header6(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
h = mtod(pd->m, struct ip6_hdr *);
@@ -10505,13 +10547,13 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
PF_PASS) {
*m0 = pd->m;
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
*m0 = pd->m;
if (pd->m == NULL) {
/* packet sits in reassembly queue, no error */
*action = PF_PASS;
- return (-1);
+ return (PF_DROP);
}
/* Update pointers into the packet. */
@@ -10523,7 +10565,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
if (pf_walk_header6(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
- return (-1);
+ return (PF_DROP);
}
if (m_tag_find(pd->m, PACKET_TAG_PF_REASSEMBLED, NULL) != NULL) {
@@ -10553,7 +10595,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->hdrlen = sizeof(*th);
pd->p_len = pd->tot_len - pd->off - (th->th_off << 2);
@@ -10569,7 +10611,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->hdrlen = sizeof(*uh);
if (uh->uh_dport == 0 ||
@@ -10577,7 +10619,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
ntohs(uh->uh_ulen) < sizeof(struct udphdr)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->sport = &uh->uh_sport;
pd->dport = &uh->uh_dport;
@@ -10589,7 +10631,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->hdrlen = sizeof(pd->hdr.sctp);
pd->p_len = pd->tot_len - pd->off;
@@ -10599,19 +10641,23 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
- }
- if (pf_scan_sctp(pd) != PF_PASS) {
- *action = PF_DROP;
- REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
+
/*
* Placeholder. The SCTP checksum is 32-bits, but
* pf_test_state() expects to update a 16-bit checksum.
* Provide a dummy value which we'll subsequently ignore.
+ * Do this before pf_scan_sctp() so any jobs we enqueue
+ * have a pcksum set.
*/
pd->pcksum = &pd->sctp_dummy_sum;
+
+ if (pf_scan_sctp(pd) != PF_PASS) {
+ *action = PF_DROP;
+ REASON_SET(reason, PFRES_SHORT);
+ return (PF_DROP);
+ }
break;
}
case IPPROTO_ICMP: {
@@ -10619,7 +10665,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->pcksum = &pd->hdr.icmp.icmp_cksum;
pd->hdrlen = ICMP_MINLEN;
@@ -10633,7 +10679,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
/* ICMP headers we look further into to match state */
switch (pd->hdr.icmp6.icmp6_type) {
@@ -10659,7 +10705,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
reason, af)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
- return (-1);
+ return (PF_DROP);
}
pd->hdrlen = icmp_hlen;
pd->pcksum = &pd->hdr.icmp6.icmp6_cksum;
@@ -10682,111 +10728,173 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
MPASS(pd->pcksum != NULL);
- return (0);
+ return (PF_PASS);
+}
+
+static __inline void
+pf_rule_counters_inc(struct pf_pdesc *pd, struct pf_krule *r, int dir_out,
+ int op_pass, sa_family_t af, struct pf_addr *src_host,
+ struct pf_addr *dst_host)
+{
+ pf_counter_u64_add_protected(&(r->packets[dir_out]), 1);
+ pf_counter_u64_add_protected(&(r->bytes[dir_out]), pd->tot_len);
+ pf_update_timestamp(r);
+
+ if (r->src.addr.type == PF_ADDR_TABLE)
+ pfr_update_stats(r->src.addr.p.tbl, src_host, af,
+ pd->tot_len, dir_out, op_pass, r->src.neg);
+ if (r->dst.addr.type == PF_ADDR_TABLE)
+ pfr_update_stats(r->dst.addr.p.tbl, dst_host, af,
+ pd->tot_len, dir_out, op_pass, r->dst.neg);
}
static void
-pf_counters_inc(int action, struct pf_pdesc *pd,
- struct pf_kstate *s, struct pf_krule *r, struct pf_krule *a)
+pf_counters_inc(int action, struct pf_pdesc *pd, struct pf_kstate *s,
+ struct pf_krule *r, struct pf_krule *a, struct pf_krule_slist *match_rules)
{
- struct pf_krule *tr;
- int dir = pd->dir;
- int dirndx;
+ struct pf_krule_slist *mr = match_rules;
+ struct pf_krule_item *ri;
+ struct pf_krule *nr = NULL;
+ struct pf_addr *src_host = pd->src;
+ struct pf_addr *dst_host = pd->dst;
+ struct pf_state_key *key;
+ int dir_out = (pd->dir == PF_OUT);
+ int op_r_pass = (r->action == PF_PASS);
+ int op_pass = (action == PF_PASS || action == PF_AFRT);
+ int s_dir_in, s_dir_out, s_dir_rev;
+ sa_family_t af = pd->af;
pf_counter_u64_critical_enter();
+
+ /*
+ * Set AF for interface counters, it will be later overwritten for
+ * rule and state counters with value from proper state key.
+ */
+ if (action == PF_AFRT) {
+ MPASS(s != NULL);
+ if (s->direction == PF_OUT && dir_out)
+ af = pd->naf;
+ }
+
pf_counter_u64_add_protected(
- &pd->kif->pfik_bytes[pd->af == AF_INET6][dir == PF_OUT][action != PF_PASS],
+ &pd->kif->pfik_bytes[af == AF_INET6][dir_out][!op_pass],
pd->tot_len);
pf_counter_u64_add_protected(
- &pd->kif->pfik_packets[pd->af == AF_INET6][dir == PF_OUT][action != PF_PASS],
+ &pd->kif->pfik_packets[af == AF_INET6][dir_out][!op_pass],
1);
- if (action == PF_PASS || action == PF_AFRT || r->action == PF_DROP) {
- dirndx = (dir == PF_OUT);
- pf_counter_u64_add_protected(&r->packets[dirndx], 1);
- pf_counter_u64_add_protected(&r->bytes[dirndx], pd->tot_len);
- pf_update_timestamp(r);
+ /* If the rule has failed to apply, don't increase its counters */
+ if (!(op_pass || r->action == PF_DROP)) {
+ pf_counter_u64_critical_exit();
+ return;
+ }
+
+ if (s != NULL) {
+ PF_STATE_LOCK_ASSERT(s);
+ mr = &(s->match_rules);
- if (a != NULL) {
- pf_counter_u64_add_protected(&a->packets[dirndx], 1);
- pf_counter_u64_add_protected(&a->bytes[dirndx], pd->tot_len);
+ /*
+ * For af-to on the inbound direction we can determine
+ * the direction of passing packet only by checking direction
+ * of AF translation. The af-to in "in" direction covers both
+ * the inbound and the outbound side of state tracking,
+ * so pd->dir is always PF_IN. We set dir_out and s_dir_rev
+ * in a way to count packets as if the state was outbound,
+ * because pfctl -ss shows the state with "->", as if it was
+ * oubound.
+ */
+ if (action == PF_AFRT && s->direction == PF_IN) {
+ dir_out = (pd->naf == s->rule->naf);
+ s_dir_in = 1;
+ s_dir_out = 0;
+ s_dir_rev = (pd->naf == s->rule->af);
+ } else {
+ dir_out = (pd->dir == PF_OUT);
+ s_dir_in = (s->direction == PF_IN);
+ s_dir_out = (s->direction == PF_OUT);
+ s_dir_rev = (pd->dir != s->direction);
}
- if (s != NULL) {
- struct pf_krule_item *ri;
- if (s->nat_rule != NULL) {
- pf_counter_u64_add_protected(&s->nat_rule->packets[dirndx],
+ /* pd->tot_len is a problematic with af-to rules. Sure, we can
+ * agree that it's the post-af-to packet length that was
+ * forwarded through a state, but what about tables which match
+ * on pre-af-to addresses? We don't have access the the original
+ * packet length anymore.
+ */
+ s->packets[s_dir_rev]++;
+ s->bytes[s_dir_rev] += pd->tot_len;
+
+ /*
+ * Source nodes are accessed unlocked here. But since we are
+ * operating with stateful tracking and the state is locked,
+ * those SNs could not have been freed.
+ */
+ for (pf_sn_types_t sn_type=0; sn_type<PF_SN_MAX; sn_type++) {
+ if (s->sns[sn_type] != NULL) {
+ counter_u64_add(
+ s->sns[sn_type]->packets[dir_out],
1);
- pf_counter_u64_add_protected(&s->nat_rule->bytes[dirndx],
+ counter_u64_add(
+ s->sns[sn_type]->bytes[dir_out],
pd->tot_len);
}
- /*
- * Source nodes are accessed unlocked here.
- * But since we are operating with stateful tracking
- * and the state is locked, those SNs could not have
- * been freed.
- */
- for (pf_sn_types_t sn_type=0; sn_type<PF_SN_MAX; sn_type++) {
- if (s->sns[sn_type] != NULL) {
- counter_u64_add(
- s->sns[sn_type]->packets[dirndx],
- 1);
- counter_u64_add(
- s->sns[sn_type]->bytes[dirndx],
- pd->tot_len);
- }
- }
- dirndx = (dir == s->direction) ? 0 : 1;
- s->packets[dirndx]++;
- s->bytes[dirndx] += pd->tot_len;
-
- SLIST_FOREACH(ri, &s->match_rules, entry) {
- pf_counter_u64_add_protected(&ri->r->packets[dirndx], 1);
- pf_counter_u64_add_protected(&ri->r->bytes[dirndx], pd->tot_len);
+ }
- if (ri->r->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(ri->r->src.addr.p.tbl,
- (s == NULL) ? pd->src :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_OUT)],
- pd->af, pd->tot_len, dir == PF_OUT,
- r->action == PF_PASS, ri->r->src.neg);
- if (ri->r->dst.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(ri->r->dst.addr.p.tbl,
- (s == NULL) ? pd->dst :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_IN)],
- pd->af, pd->tot_len, dir == PF_OUT,
- r->action == PF_PASS, ri->r->dst.neg);
+ /* Start with pre-NAT addresses */
+ key = s->key[(s->direction == PF_OUT)];
+ src_host = &(key->addr[s_dir_out]);
+ dst_host = &(key->addr[s_dir_in]);
+ af = key->af;
+ if (s->nat_rule) {
+ /* Old-style NAT rules */
+ if (s->nat_rule->action == PF_NAT ||
+ s->nat_rule->action == PF_RDR ||
+ s->nat_rule->action == PF_BINAT) {
+ nr = s->nat_rule;
+ pf_rule_counters_inc(pd, s->nat_rule, dir_out,
+ op_r_pass, af, src_host, dst_host);
+ /* Use post-NAT addresses from now on */
+ key = s->key[s_dir_in];
+ src_host = &(key->addr[s_dir_out]);
+ dst_host = &(key->addr[s_dir_in]);
+ af = key->af;
}
}
+ }
- tr = r;
- if (s != NULL && s->nat_rule != NULL &&
- r == &V_pf_default_rule)
- tr = s->nat_rule;
-
- if (tr->src.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(tr->src.addr.p.tbl,
- (s == NULL) ? pd->src :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_OUT)],
- pd->af, pd->tot_len, dir == PF_OUT,
- r->action == PF_PASS, tr->src.neg);
- if (tr->dst.addr.type == PF_ADDR_TABLE)
- pfr_update_stats(tr->dst.addr.p.tbl,
- (s == NULL) ? pd->dst :
- &s->key[(s->direction == PF_IN)]->
- addr[(s->direction == PF_IN)],
- pd->af, pd->tot_len, dir == PF_OUT,
- r->action == PF_PASS, tr->dst.neg);
+ SLIST_FOREACH(ri, mr, entry) {
+ pf_rule_counters_inc(pd, ri->r, dir_out, op_r_pass, af,
+ src_host, dst_host);
+ if (s && s->nat_rule == ri->r) {
+ /* Use post-NAT addresses after a match NAT rule */
+ key = s->key[s_dir_in];
+ src_host = &(key->addr[s_dir_out]);
+ dst_host = &(key->addr[s_dir_in]);
+ af = key->af;
+ }
}
+
+ if (s == NULL) {
+ pf_free_match_rules(mr);
+ }
+
+ if (a != NULL) {
+ pf_rule_counters_inc(pd, a, dir_out, op_r_pass, af,
+ src_host, dst_host);
+ }
+
+ if (r != nr) {
+ pf_rule_counters_inc(pd, r, dir_out, op_r_pass, af,
+ src_host, dst_host);
+ }
+
pf_counter_u64_critical_exit();
}
+
static void
pf_log_matches(struct pf_pdesc *pd, struct pf_krule *rm,
struct pf_krule *am, struct pf_kruleset *ruleset,
- struct pf_krule_slist *matchrules)
+ struct pf_krule_slist *match_rules)
{
struct pf_krule_item *ri;
@@ -10794,7 +10902,7 @@ pf_log_matches(struct pf_pdesc *pd, struct pf_krule *rm,
if (rm->log & PF_LOG_MATCHES)
return;
- SLIST_FOREACH(ri, matchrules, entry)
+ SLIST_FOREACH(ri, match_rules, entry)
if (ri->r->log & PF_LOG_MATCHES)
PFLOG_PACKET(rm->action, PFRES_MATCH, rm, am,
ruleset, pd, 1, ri->r);
@@ -10811,6 +10919,8 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
struct pf_krule *a = NULL, *r = &V_pf_default_rule;
struct pf_kstate *s = NULL;
struct pf_kruleset *ruleset = NULL;
+ struct pf_krule_item *ri;
+ struct pf_krule_slist match_rules;
struct pf_pdesc pd;
int use_2nd_queue = 0;
uint16_t tag;
@@ -10847,6 +10957,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
}
pf_init_pdesc(&pd, *m0);
+ SLIST_INIT(&match_rules);
if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) {
pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
@@ -10879,7 +10990,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
PF_RULES_RLOCK();
if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason,
- kif, default_actions) == -1) {
+ kif, default_actions) != PF_PASS) {
if (action != PF_PASS)
pd.act.log |= PF_LOG_FORCE;
goto done;
@@ -10943,7 +11054,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
action = PF_DROP;
else
action = pf_test_rule(&r, &s, &pd, &a,
- &ruleset, &reason, inp);
+ &ruleset, &reason, inp, &match_rules);
if (action != PF_PASS)
REASON_SET(&reason, PFRES_FRAG);
break;
@@ -11001,7 +11112,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
break;
} else {
action = pf_test_rule(&r, &s, &pd,
- &a, &ruleset, &reason, inp);
+ &a, &ruleset, &reason, inp, &match_rules);
}
}
break;
@@ -11022,7 +11133,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
a = s->anchor;
} else if (s == NULL) {
action = pf_test_rule(&r, &s,
- &pd, &a, &ruleset, &reason, inp);
+ &pd, &a, &ruleset, &reason, inp, &match_rules);
}
break;
@@ -11050,7 +11161,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
a = s->anchor;
} else if (s == NULL)
action = pf_test_rule(&r, &s, &pd,
- &a, &ruleset, &reason, inp);
+ &a, &ruleset, &reason, inp, &match_rules);
break;
}
@@ -11059,8 +11170,11 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
done:
PF_RULES_RUNLOCK();
- if (pd.m == NULL)
+ /* if packet sits in reassembly queue, return without error */
+ if (pd.m == NULL) {
+ pf_free_match_rules(&match_rules);
goto eat_pkt;
+ }
if (s)
memcpy(&pd.act, &s->act, sizeof(s->act));
@@ -11157,6 +11271,8 @@ done:
(dir == PF_IN) ? PF_DIVERT_MTAG_DIR_IN :
PF_DIVERT_MTAG_DIR_OUT;
+ pf_counters_inc(action, &pd, s, r, a, &match_rules);
+
if (s)
PF_STATE_UNLOCK(s);
@@ -11198,7 +11314,6 @@ done:
if (pd.act.log) {
struct pf_krule *lr;
- struct pf_krule_item *ri;
if (s != NULL && s->nat_rule != NULL &&
s->nat_rule->log & PF_LOG_ALL)
@@ -11217,7 +11332,7 @@ done:
}
}
- pf_counters_inc(action, &pd, s, r, a);
+ pf_counters_inc(action, &pd, s, r, a, &match_rules);
switch (action) {
case PF_SYNPROXY_DROP:
diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c
index f3be036ef745..6f41d453a7d1 100644
--- a/sys/netpfil/pf/pf_if.c
+++ b/sys/netpfil/pf/pf_if.c
@@ -702,7 +702,7 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kkif *kif, uint8_t net,
}
if ((e = pfr_set_addrs(&kt->pfrkt_t, V_pfi_buffer, V_pfi_buffer_cnt, &size2,
- NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK)))
+ NULL, NULL, NULL, PFR_FLAG_START | PFR_FLAG_DONE, PFR_TFLAG_ALLMASK)))
printf("%s: cannot set %d new addresses into table %s: %d\n",
__func__, V_pfi_buffer_cnt, kt->pfrkt_name, e);
}
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index d58af6e5ec4d..5ec67021068b 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -259,7 +259,7 @@ static void dehook_pf_eth(void);
static void dehook_pf(void);
static int shutdown_pf(void);
static int pf_load(void);
-static void pf_unload(void);
+static void pf_unload(void *);
static struct cdevsw pf_cdevsw = {
.d_ioctl = pfioctl,
@@ -4792,6 +4792,17 @@ DIOCCHANGEADDR_error:
error = ENODEV;
goto fail;
}
+ if (strnlen(io->pfrio_table.pfrt_anchor, MAXPATHLEN)
+ == MAXPATHLEN) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (strnlen(io->pfrio_table.pfrt_name, PF_TABLE_NAME_SIZE)
+ == PF_TABLE_NAME_SIZE) {
+ error = EINVAL;
+ goto fail;
+ }
+
PF_RULES_WLOCK();
error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
io->pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -5131,7 +5142,7 @@ DIOCCHANGEADDR_error:
error = pfr_set_addrs(&io->pfrio_table, pfras,
io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
&io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
- PFR_FLAG_USERIOCTL, 0);
+ PFR_FLAG_START | PFR_FLAG_DONE | PFR_FLAG_USERIOCTL, 0);
PF_RULES_WUNLOCK();
if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
error = copyout(pfras, io->pfrio_buffer, totlen);
@@ -7082,7 +7093,7 @@ pf_unload_vnet(void)
}
static void
-pf_unload(void)
+pf_unload(void *dummy __unused)
{
sx_xlock(&pf_end_lock);
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index b8b5157c9b15..7aeb8266ca8c 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -73,7 +73,7 @@ VNET_DEFINE_STATIC(int, pf_rdr_srcport_rewrite_tries) = 16;
static uint64_t pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
-struct pf_krule *pf_match_translation(int, struct pf_test_ctx *);
+static struct pf_krule *pf_match_translation(int, struct pf_test_ctx *);
static enum pf_test_status pf_step_into_translation_anchor(int, struct pf_test_ctx *,
struct pf_krule *);
static int pf_get_sport(struct pf_pdesc *, struct pf_krule *,
@@ -216,6 +216,7 @@ pf_match_translation_rule(int rs_num, struct pf_test_ctx *ctx, struct pf_krulese
*/
ctx->arsm = ctx->aruleset;
}
+ break;
} else {
ctx->a = r; /* remember anchor */
ctx->aruleset = ruleset; /* and its ruleset */
@@ -273,7 +274,7 @@ pf_step_into_translation_anchor(int rs_num, struct pf_test_ctx *ctx, struct pf_k
return (rv);
}
-struct pf_krule *
+static struct pf_krule *
pf_match_translation(int rs_num, struct pf_test_ctx *ctx)
{
enum pf_test_status rv;
@@ -534,6 +535,63 @@ pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
return (1);
}
+static __inline u_short
+pf_check_src_node_valid(struct pf_ksrc_node *sn, struct pf_kpool *rpool)
+{
+ struct pf_addr *raddr, *rmask;
+ struct pf_addr *caddr; /* cached redirection address */
+ struct pf_kpooladdr *pa;
+ sa_family_t raf;
+ sa_family_t caf; /* cached redirection AF */
+ u_short valid = 0;
+
+ KASSERT(sn != NULL, ("sn is NULL"));
+ KASSERT(rpool != NULL, ("rpool is NULL"));
+
+ /* check if the cached entry is still valid */
+
+ if (sn->type == PF_SN_LIMIT) {
+ /* Always valid as it does not store redirection address */
+ return (1);
+ }
+
+ mtx_lock(&rpool->mtx);
+ caddr = &(sn->raddr);
+ caf = sn->raf;
+
+ TAILQ_FOREACH(pa, &rpool->list, entries) {
+ if (PF_AZERO(caddr, caf)) {
+ valid = 1;
+ goto done;
+ } else if (pa->addr.type == PF_ADDR_DYNIFTL) {
+ if (pfr_kentry_byaddr(pa->addr.p.dyn->pfid_kt, caddr, caf, 0)) {
+ valid = 1;
+ goto done;
+ }
+ } else if (pa->addr.type == PF_ADDR_TABLE) {
+ if (pfr_kentry_byaddr(pa->addr.p.tbl, caddr, caf, 0)) {
+ valid = 1;
+ goto done;
+ }
+ } else if (pa->addr.type != PF_ADDR_NOROUTE) {
+ /* PF_ADDR_URPFFAILED, PF_ADDR_RANGE, PF_ADDR_ADDRMASK */
+ raddr = &(pa->addr.v.a.addr);
+ rmask = &(pa->addr.v.a.mask);
+ raf = pa->af;
+ if (raf == caf && pf_match_addr(0, raddr, rmask, caddr, caf)) {
+ valid = 1;
+ goto done;
+ }
+ }
+ /* else PF_ADDR_NOROUTE */
+ }
+
+done:
+ mtx_unlock(&rpool->mtx);
+
+ return (valid);
+}
+
u_short
pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
struct pf_addr *naddr, struct pfi_kkif **nkif, sa_family_t *naf,
@@ -873,6 +931,45 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
if (sn != NULL) {
PF_SRC_NODE_LOCK_ASSERT(sn);
+ /*
+ * Check if source node's redirection address still exists
+ * in pool from which the SN was created. If not, delete it.
+ * Similar to pf_kill_srcnodes(). Unlink the source node
+ * from tree, unlink it from states, then free it. Do not
+ * overlap source node and state locks to avoid LOR.
+ */
+ if (!pf_check_src_node_valid(sn, rpool)) {
+ pf_unlink_src_node(sn);
+ PF_SRC_NODE_UNLOCK(sn);
+ if (V_pf_status.debug >= PF_DEBUG_NOISY) {
+ printf("%s: stale src tracking (%d) ",
+ __func__, sn_type);
+ pf_print_host(saddr, 0, saf);
+ printf(" to ");
+ pf_print_host(&(sn->raddr), 0, sn->raf);
+ if (nkif)
+ printf("@%s", sn->rkif->pfik_name);
+ printf("\n");
+ }
+
+ for (int i = 0; i <= V_pf_hashmask; i++) {
+ struct pf_idhash *ih = &V_pf_idhash[i];
+ struct pf_kstate *st;
+
+ PF_HASHROW_LOCK(ih);
+ LIST_FOREACH(st, &ih->states, entry) {
+ if (st->sns[sn->type] == sn) {
+ st->sns[sn->type] = NULL;
+ }
+ }
+ PF_HASHROW_UNLOCK(ih);
+ }
+ pf_free_src_node(sn);
+ counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1);
+ sn = NULL;
+ goto map_addr;
+ }
+
(*naf) = sn->raf;
/* If the supplied address is the same as the current one we've
@@ -901,9 +998,10 @@ pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
goto done;
}
+map_addr:
/*
- * Source node has not been found. Find a new address and store it
- * in variables given by the caller.
+ * Source node has not been found or is invalid. Find a new address
+ * and store it in variables given by the caller.
*/
if ((reason = pf_map_addr(saf, r, saddr, naddr, nkif, naf, init_addr,
rpool)) != 0) {
@@ -973,6 +1071,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
{
struct pf_pdesc *pd = ctx->pd;
struct pf_addr *naddr;
+ int idx;
uint16_t *nportp;
uint16_t low, high;
u_short reason;
@@ -987,8 +1086,19 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
return (PFRES_MEMORY);
}
- naddr = &ctx->nk->addr[1];
- nportp = &ctx->nk->port[1];
+ switch (nat_action) {
+ case PF_NAT:
+ idx = pd->sidx;
+ break;
+ case PF_BINAT:
+ idx = 1;
+ break;
+ case PF_RDR:
+ idx = pd->didx;
+ break;
+ }
+ naddr = &ctx->nk->addr[idx];
+ nportp = &ctx->nk->port[idx];
switch (nat_action) {
case PF_NAT:
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 082b9b565153..993981a9c0de 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -2100,6 +2100,7 @@ struct nl_parsed_table_addrs {
size_t addr_count;
int nadd;
int ndel;
+ int nchange;
};
#define _OUT(_field) offsetof(struct pfr_addr, _field)
static const struct nlattr_parser nla_p_pfr_addr[] = {
@@ -2209,6 +2210,123 @@ pf_handle_table_del_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (error);
}
+static int
+pf_handle_table_set_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct nl_parsed_table_addrs attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ PF_RULES_WLOCK();
+ error = pfr_set_addrs(&attrs.table, &attrs.addrs[0],
+ attrs.addr_count, NULL, &attrs.nadd, &attrs.ndel, &attrs.nchange,
+ attrs.flags | PFR_FLAG_USERIOCTL, 0);
+ PF_RULES_WUNLOCK();
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_TABLE_DEL_ADDR;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd);
+ nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel);
+ nlattr_add_u32(nw, PF_TA_NBR_CHANGED, attrs.nchange);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
+static int
+nlattr_add_pfr_addr(struct nl_writer *nw, int attr, const struct pfr_addr *a)
+{
+ int off = nlattr_add_nested(nw, attr);
+ if (off == 0)
+ return (false);
+
+ nlattr_add_u32(nw, PFR_A_AF, a->pfra_af);
+ nlattr_add_u8(nw, PFR_A_NET, a->pfra_net);
+ nlattr_add_bool(nw, PFR_A_NOT, a->pfra_not);
+ nlattr_add_in6_addr(nw, PFR_A_ADDR, &a->pfra_u._pfra_ip6addr);
+
+ nlattr_set_len(nw, off);
+
+ return (true);
+}
+
+static int
+pf_handle_table_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_table attrs = { 0 };
+ struct pfr_addr *pfras;
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int size = 0;
+ int error;
+
+ PF_RULES_RLOCK_TRACKER;
+
+ error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ PF_RULES_RLOCK();
+ /* Get required size. */
+ error = pfr_get_addrs(&attrs.pfrio_table, NULL,
+ &size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
+ if (error != 0) {
+ PF_RULES_RUNLOCK();
+ return (error);
+ }
+ pfras = mallocarray(size, sizeof(struct pfr_addr), M_PF,
+ M_NOWAIT | M_ZERO);
+ if (pfras == NULL) {
+ PF_RULES_RUNLOCK();
+ return (ENOMEM);
+ }
+ /* Now get the addresses. */
+ error = pfr_get_addrs(&attrs.pfrio_table, pfras,
+ &size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
+ PF_RULES_RUNLOCK();
+ if (error != 0)
+ goto out;
+
+ for (int i = 0; i < size; i++) {
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
+ nlmsg_abort(nw);
+ error = ENOMEM;
+ goto out;
+ }
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_TABLE_GET_ADDR;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ if (i == 0)
+ nlattr_add_u32(nw, PF_TA_ADDR_COUNT, size);
+
+ nlattr_add_pfr_addr(nw, PF_TA_ADDR, &pfras[i]);
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ error = ENOMEM;
+ goto out;
+ }
+ }
+
+out:
+ free(pfras, M_PF);
+ return (error);
+}
+
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
@@ -2460,6 +2578,20 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
+ {
+ .cmd_num = PFNL_CMD_TABLE_SET_ADDR,
+ .cmd_name = "TABLE_SET_ADDRS",
+ .cmd_cb = pf_handle_table_set_addrs,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_TABLE_GET_ADDR,
+ .cmd_name = "TABLE_GET_ADDRS",
+ .cmd_cb = pf_handle_table_get_addrs,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
};
void
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index c46c8f2b2592..e1eb3e628df5 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -69,6 +69,8 @@ enum {
PFNL_CMD_CLR_ADDRS = 31,
PFNL_CMD_TABLE_ADD_ADDR = 32,
PFNL_CMD_TABLE_DEL_ADDR = 33,
+ PFNL_CMD_TABLE_SET_ADDR = 34,
+ PFNL_CMD_TABLE_GET_ADDR = 35,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -483,6 +485,8 @@ enum pf_table_addrs_t {
PF_TA_FLAGS = 3, /* u32 */
PF_TA_NBR_ADDED = 4, /* u32 */
PF_TA_NBR_DELETED = 5, /* u32 */
+ PF_TA_NBR_CHANGED = 6, /* u32 */
+ PF_TA_ADDR_COUNT = 7, /* u32 */
};
#ifdef _KERNEL
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c
index 73ec18fa7646..0e2b9fe1cac8 100644
--- a/sys/netpfil/pf/pf_table.c
+++ b/sys/netpfil/pf/pf_table.c
@@ -399,7 +399,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
PF_RULES_WASSERT();
- ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
+ ACCEPT_FLAGS(flags, PFR_FLAG_START | PFR_FLAG_DONE |
+ PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &
PFR_FLAG_USERIOCTL))
return (EINVAL);
@@ -411,7 +412,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
tmpkt = pfr_create_ktable(&V_pfr_nulltable, 0, 0);
if (tmpkt == NULL)
return (ENOMEM);
- pfr_mark_addrs(kt);
+ if (flags & PFR_FLAG_START)
+ pfr_mark_addrs(kt);
SLIST_INIT(&addq);
SLIST_INIT(&delq);
SLIST_INIT(&changeq);
@@ -444,6 +446,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
}
p = pfr_create_kentry(&ad,
(kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0);
+ p->pfrke_mark = PFR_FB_ADDED;
if (p == NULL)
senderr(ENOMEM);
if (pfr_route_kentry(tmpkt, p)) {
@@ -459,7 +462,8 @@ _skip:
if (flags & PFR_FLAG_FEEDBACK)
bcopy(&ad, addr + i, sizeof(ad));
}
- pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
+ if (flags & PFR_FLAG_DONE)
+ pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
if (*size2 < size+xdel) {
*size2 = size+xdel;
@@ -2071,7 +2075,7 @@ pfr_lookup_table(struct pfr_table *tbl)
(struct pfr_ktable *)tbl));
}
-static struct pfr_kentry *
+struct pfr_kentry *
pfr_kentry_byaddr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
int exact)
{