summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-08-17 13:53:13 -0300
committerRenato Botelho <renato@netgate.com>2015-08-17 13:53:13 -0300
commit14cc93f3403d906f596ddc18d531bb13f053fa76 (patch)
treeb10a13ccfcf21df206a5471e9b3a8b11ec927232
parentfa9181508d9f4170f8a35bdfbe349210c30dbceb (diff)
downloadFreeBSD-src-14cc93f3403d906f596ddc18d531bb13f053fa76.zip
FreeBSD-src-14cc93f3403d906f596ddc18d531bb13f053fa76.tar.gz
Importing pfSense patch divert.RELENG_10.diff
-rw-r--r--sbin/pfctl/parse.y22
-rw-r--r--sbin/pfctl/pfctl_parser.c8
-rw-r--r--sys/net/pfvar.h11
-rw-r--r--sys/netinet/ip_divert.c15
-rw-r--r--sys/netpfil/pf/pf.c153
-rw-r--r--sys/netpfil/pf/pf.h4
6 files changed, 148 insertions, 65 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 75e7e99..a32bbb1 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -162,6 +162,7 @@ struct node_icmp {
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_MAX_PACKETS,
PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
@@ -173,6 +174,7 @@ struct node_state_opt {
u_int32_t max_states;
u_int32_t max_src_states;
u_int32_t max_src_conn;
+ u_int32_t max_packets;
struct {
u_int32_t limit;
u_int32_t seconds;
@@ -472,7 +474,7 @@ int parseport(char *, struct range *r, int);
%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 TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS MAXPCKT
%token IEEE8021QPCP IEEE8021QSETPCP
%token DIVERTTO DIVERTREPLY
%token <v.string> STRING
@@ -2132,6 +2134,14 @@ pfrule : action dir logquick interface route af proto fromto
}
r.rule_flag |= PFRULE_NOSYNC;
break;
+ case PF_STATE_OPT_MAX_PACKETS:
+ if (o->data.max_packets == 0) {
+ yyerror("max_packets must be"
+ "greater than 0");
+ YYERROR;
+ }
+ r.spare2 = o->data.max_packets;
+ break;
case PF_STATE_OPT_SRCTRACK:
if (srctrack) {
yyerror("state option "
@@ -3839,6 +3849,15 @@ state_opt_item : MAXIMUM NUMBER {
$$->next = NULL;
$$->tail = $$;
}
+ | MAXPCKT NUMBER {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_PACKETS;
+ $$->data.max_packets = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| MAXSRCCONN NUMBER {
if ($2 < 0 || $2 > UINT_MAX) {
yyerror("only positive values permitted");
@@ -5667,6 +5686,7 @@ lookup(char *s)
{ "match", MATCH},
{ "max", MAXIMUM},
{ "max-mss", MAXMSS},
+ { "max-packets", MAXPCKT},
{ "max-src-conn", MAXSRCCONN},
{ "max-src-conn-rate", MAXSRCCONNRATE},
{ "max-src-nodes", MAXSRCNODES},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index ab20398..b4fe20a 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -922,7 +922,7 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
printf(" probability %s%%", buf);
}
opts = 0;
- if (r->max_states || r->max_src_nodes || r->max_src_states)
+ if (r->max_states || r->max_src_nodes || r->max_src_states || r->spare2)
opts = 1;
if (r->rule_flag & PFRULE_NOSYNC)
opts = 1;
@@ -969,6 +969,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
printf("max-src-conn %u", r->max_src_conn);
opts = 0;
}
+ if (r->spare2) {
+ if (!opts)
+ printf(", ");
+ printf("max-packets %u", r->spare2);
+ opts = 0;
+ }
if (r->max_src_conn_rate.limit) {
if (!opts)
printf(", ");
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 01efaa0..3be7615 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -761,7 +761,13 @@ struct pf_state {
u_int64_t id;
u_int32_t creatorid;
u_int8_t direction;
- u_int8_t pad[3];
+ u_int8_t pad[2];
+ u_int8_t local_flags;
+#define PFSTATE_DIVERT_ALTQ 0x10
+#define PFSTATE_DIVERT_DNCOOKIE 0x20
+#define PFSTATE_DIVERT_ACTION 0x40
+#define PFSTATE_DIVERT_TAG 0x80
+#define PFSTATE_DIVERT_MASK 0xFF00
u_int refs;
TAILQ_ENTRY(pf_state) sync_list;
@@ -788,6 +794,7 @@ struct pf_state {
u_int32_t pdnpipe;
u_int32_t dnpipe;
u_int16_t tag;
+ u_int16_t divert_cookie;
u_int8_t log;
u_int8_t state_flags;
#define PFSTATE_ALLOWOPTS 0x01
@@ -800,7 +807,7 @@ struct pf_state {
/* XXX */
u_int8_t sync_updates;
- u_int8_t _tail[3];
+ u_int8_t _tail;
};
/*
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index e698035..b74d60d 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -267,8 +267,7 @@ divert_packet(struct mbuf *m, int incoming)
* this iface name will come along for the ride.
* (see div_output for the other half of this.)
*/
- strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
- sizeof(divsrc.sin_zero));
+ *((u_short *)divsrc.sin_zero) = m->m_pkthdr.rcvif->if_index;
}
/* Put packet on socket queue, if any */
@@ -342,7 +341,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
/* Loopback avoidance and state recovery */
if (sin) {
- int i;
+ u_short idx;
/* set the starting point. We provide a non-zero slot,
* but a non_matching chain_id to skip that info and use
@@ -350,7 +349,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
*/
dt->slot = 1; /* dummy, chain_id is invalid */
dt->chain_id = 0;
- dt->rulenum = sin->sin_port+1; /* host format ? */
+ dt->rulenum = sin->sin_port; /* host format ? */
dt->rule_id = 0;
/*
* Find receive interface with the given name, stuffed
@@ -358,10 +357,9 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
* The name is user supplied data so don't trust its size
* or that it is zero terminated.
*/
- for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++)
- ;
- if ( i > 0 && i < sizeof(sin->sin_zero))
- m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
+ idx = *((u_short *)sin->sin_zero);
+ if ( idx > 0 )
+ m->m_pkthdr.rcvif = ifnet_byindex(idx);
}
/* Reinject packet into the system as incoming or outgoing */
@@ -832,5 +830,4 @@ static moduledata_t ipdivertmod = {
};
DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
-MODULE_DEPEND(ipdivert, ipfw, 2, 2, 2);
MODULE_VERSION(ipdivert, 1);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 76cfebc..0fcb0d7 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$");
#include <netpfil/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
+#include <netinet/ip_divert.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -313,6 +314,14 @@ VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
#define PACKET_LOOPED(mtag) ((mtag)->flags & PF_PACKET_LOOPED)
+#define PF_DIVERT_MAXPACKETS_REACHED() \
+do { \
+ if (r->spare2 && \
+ s->packets[dir == PF_OUT] > r->spare2) \
+ /* fake that divert already happened */ \
+ pd.pf_mtag->flags |= PF_PACKET_LOOPED; \
+} while(0)
+
#define STATE_LOOKUP(i, k, d, s, pd) \
do { \
(s) = pf_find_state((i), (k), (d)); \
@@ -6128,6 +6137,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
struct pf_pdesc pd;
int off = 0, dirndx, pqid = 0;
int loopedfrom = 0;
+ u_int16_t divertcookie = 0;
+ u_int8_t divflags = 0;
struct ip_fw_args dnflow;
M_ASSERTPKTHDR(m);
@@ -6160,12 +6171,10 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
pd.pf_mtag->flags |= PF_PACKET_LOOPED;
if (rr->info & IPFW_IS_DUMMYNET)
loopedfrom = 1;
- if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- goto done;
- }
+ if (rr->info & IPFW_IS_DIVERT) {
+ divertcookie = rr->rulenum;
+ divflags = (u_int8_t)(divertcookie >> 8);
+ divertcookie &= ~PFSTATE_DIVERT_MASK;
}
if (pd.pf_mtag && pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) {
m->m_flags |= M_FASTFWD_OURS;
@@ -6332,6 +6341,17 @@ done:
("pf: dropping packet with ip options\n"));
}
+ if (s) {
+ PF_DIVERT_MAXPACKETS_REACHED();
+
+ if (divflags) {
+ s->divert_cookie = divertcookie;
+ s->local_flags |= divflags;
+ } else {
+ divertcookie = s->divert_cookie;
+ divflags = s->local_flags;
+ }
+ }
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
@@ -6359,7 +6379,33 @@ done:
}
#endif /* ALTQ */
- if (s && (s->dnpipe || s->pdnpipe)) {
+ if (divflags & PFSTATE_DIVERT_TAG)
+ pd.pf_mtag->tag = divertcookie;
+ else if (divflags & PFSTATE_DIVERT_ALTQ)
+ pd.pf_mtag->qid = divertcookie;
+ else if (divflags & PFSTATE_DIVERT_ACTION) {
+ struct pf_rule *dlr;
+ action = PF_DROP;
+ if (s)
+ pf_unlink_state(s, PF_ENTER_LOCKED);
+ REASON_SET(&reason, PFRES_DIVERT);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: changing action to with overload from divert.\n"));
+ dlr = r;
+ PFLOG_PACKET(kif, m, AF_INET, dir, reason, dlr, a,
+ ruleset, &pd, (s == NULL));
+ m_freem(*m0);
+ *m0 = NULL;
+ /* NOTE: Fake this to avoid divert giving errors to the application. */
+ return (PF_PASS);
+ }
+
+ if (divflags & PFSTATE_DIVERT_DNCOOKIE) {
+ pd.act.dnpipe = divertcookie;
+ pd.act.pdnpipe = divertcookie;
+ pd.act.flags |= PFRULE_DN_IS_PIPE;
+ } else if (s && (s->dnpipe || s->pdnpipe)) {
pd.act.dnpipe = s->dnpipe;
pd.act.pdnpipe = s->pdnpipe;
pd.act.flags = s->state_flags;
@@ -6414,10 +6460,51 @@ done:
PF_STATE_UNLOCK(s);
return (action);
}
- } else
- pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
+ }
continueprocessing:
+ if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
+ !PACKET_LOOPED(&pd)) {
+ if (!r->spare2 ||
+ (s && s->packets[dir == PF_OUT] <= r->spare2)) {
+ ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
+ sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
+ if (ipfwtag != NULL) {
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
+ ntohs(r->divert.port);
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
+
+ if (s)
+ PF_STATE_UNLOCK(s);
+
+ m_tag_prepend(m, ipfwtag);
+ if (m->m_flags & M_FASTFWD_OURS) {
+ if (pd.pf_mtag == NULL &&
+ ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate tag\n"));
+ }
+ pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
+ m->m_flags &= ~M_FASTFWD_OURS;
+ }
+ ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
+ *m0 = NULL;
+
+ return (action);
+ } else {
+ /* XXX: ipfw has the same behaviour! */
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_MEMORY);
+ log = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: failed to allocate divert tag\n"));
+ }
+ }
+ }
+
/*
* connections redirected to loopback should not match sockets
* bound specifically to loopback due to security implications,
@@ -6427,51 +6514,15 @@ continueprocessing:
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
(s->nat_rule.ptr->action == PF_RDR ||
s->nat_rule.ptr->action == PF_BINAT) &&
- (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
m->m_flags |= M_SKIP_FIREWALL;
- if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
- !PACKET_LOOPED(&pd)) {
-
- ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
- sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
- if (ipfwtag != NULL) {
- ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
- ntohs(r->divert.port);
- ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
-
- if (s)
- PF_STATE_UNLOCK(s);
-
- m_tag_prepend(m, ipfwtag);
- if (m->m_flags & M_FASTFWD_OURS) {
- if (pd.pf_mtag == NULL &&
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate tag\n"));
- } else {
- pd.pf_mtag->flags |=
- PF_FASTFWD_OURS_PRESENT;
- m->m_flags &= ~M_FASTFWD_OURS;
- }
- }
- ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
- *m0 = NULL;
-
- return (action);
- } else {
- /* XXX: ipfw has the same behaviour! */
- action = PF_DROP;
- REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate divert tag\n"));
- }
+ if (PACKET_LOOPED(pd.pf_mtag) && !loopedfrom)
+ m->m_flags |= M_FASTFWD_OURS;
}
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
+
if (log) {
struct pf_rule *lr;
@@ -6605,7 +6656,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
PF_RULES_RLOCK();
- if (ip_dn_io_ptr != NULL &&
+ if (((ip_dn_io_ptr != NULL) || (ip_divert_ptr != NULL)) &&
((dn_tag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(dn_tag+1);
pd.pf_mtag->flags |= PF_PACKET_LOOPED;
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index e588eb1..5351786 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -126,7 +126,8 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PFRES_MAXSTATES 12 /* State limit */
#define PFRES_SRCLIMIT 13 /* Source node/conn limit */
#define PFRES_SYNPROXY 14 /* SYN proxy */
-#define PFRES_MAX 15 /* total+1 */
+#define PFRES_DIVERT 15 /* Divert override */
+#define PFRES_MAX 16 /* total+1 */
#define PFRES_NAMES { \
"match", \
@@ -144,6 +145,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
"state-limit", \
"src-limit", \
"synproxy", \
+ "divert", \
NULL \
}
OpenPOWER on IntegriCloud