1
|
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
|
2
|
index 591db6b..01bc089 100644
|
3
|
--- a/sbin/pfctl/parse.y
|
4
|
+++ b/sbin/pfctl/parse.y
|
5
|
@@ -162,6 +162,7 @@ struct node_icmp {
|
6
|
enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
|
7
|
PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
|
8
|
PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
|
9
|
+ PF_STATE_OPT_MAX_PACKETS,
|
10
|
PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
|
11
|
PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
|
12
|
|
13
|
@@ -173,6 +174,7 @@ struct node_state_opt {
|
14
|
u_int32_t max_states;
|
15
|
u_int32_t max_src_states;
|
16
|
u_int32_t max_src_conn;
|
17
|
+ u_int32_t max_packets;
|
18
|
struct {
|
19
|
u_int32_t limit;
|
20
|
u_int32_t seconds;
|
21
|
@@ -472,7 +474,7 @@ int parseport(char *, struct range *r, int);
|
22
|
%token LOAD RULESET_OPTIMIZATION
|
23
|
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
|
24
|
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
|
25
|
-%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
|
26
|
+%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS MAXPCKT
|
27
|
%token IEEE8021QPCP IEEE8021QSETPCP
|
28
|
%token DIVERTTO DIVERTREPLY
|
29
|
%token <v.string> STRING
|
30
|
@@ -2132,6 +2134,14 @@ pfrule : action dir logquick interface route af proto fromto
|
31
|
}
|
32
|
r.rule_flag |= PFRULE_NOSYNC;
|
33
|
break;
|
34
|
+ case PF_STATE_OPT_MAX_PACKETS:
|
35
|
+ if (o->data.max_packets == 0) {
|
36
|
+ yyerror("max_packets must be"
|
37
|
+ "greater than 0");
|
38
|
+ YYERROR;
|
39
|
+ }
|
40
|
+ r.spare2 = o->data.max_packets;
|
41
|
+ break;
|
42
|
case PF_STATE_OPT_SRCTRACK:
|
43
|
if (srctrack) {
|
44
|
yyerror("state option "
|
45
|
@@ -5667,6 +5677,7 @@ lookup(char *s)
|
46
|
{ "match", MATCH},
|
47
|
{ "max", MAXIMUM},
|
48
|
{ "max-mss", MAXMSS},
|
49
|
+ { "max-packets", MAXPCKT},
|
50
|
{ "max-src-conn", MAXSRCCONN},
|
51
|
{ "max-src-conn-rate", MAXSRCCONNRATE},
|
52
|
{ "max-src-nodes", MAXSRCNODES},
|
53
|
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
|
54
|
index 2612b11..735db95 100644
|
55
|
--- a/sbin/pfctl/pfctl_parser.c
|
56
|
+++ b/sbin/pfctl/pfctl_parser.c
|
57
|
@@ -969,6 +969,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
|
58
|
printf("max-src-conn %u", r->max_src_conn);
|
59
|
opts = 0;
|
60
|
}
|
61
|
+ if (r->spare2) {
|
62
|
+ if (!opts)
|
63
|
+ printf(", ");
|
64
|
+ printf("max-packets %u", r->spare2);
|
65
|
+ opts = 0;
|
66
|
+ }
|
67
|
if (r->max_src_conn_rate.limit) {
|
68
|
if (!opts)
|
69
|
printf(", ");
|
70
|
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
|
71
|
index 8ecb0d5..d8f6bbe 100644
|
72
|
--- a/sys/net/pfvar.h
|
73
|
+++ b/sys/net/pfvar.h
|
74
|
@@ -761,7 +761,13 @@ struct pf_state {
|
75
|
u_int64_t id;
|
76
|
u_int32_t creatorid;
|
77
|
u_int8_t direction;
|
78
|
- u_int8_t pad[3];
|
79
|
+ u_int8_t pad[2];
|
80
|
+ u_int8_t local_flags;
|
81
|
+#define PFSTATE_DIVERT_ALTQ 0x10
|
82
|
+#define PFSTATE_DIVERT_DNCOOKIE 0x20
|
83
|
+#define PFSTATE_DIVERT_ACTION 0x40
|
84
|
+#define PFSTATE_DIVERT_TAG 0x80
|
85
|
+#define PFSTATE_DIVERT_MASK 0xFF00
|
86
|
|
87
|
u_int refs;
|
88
|
TAILQ_ENTRY(pf_state) sync_list;
|
89
|
@@ -788,6 +794,7 @@ struct pf_state {
|
90
|
u_int32_t pdnpipe;
|
91
|
u_int32_t dnpipe;
|
92
|
u_int16_t tag;
|
93
|
+ u_int16_t divert_cookie;
|
94
|
u_int8_t log;
|
95
|
u_int8_t state_flags;
|
96
|
#define PFSTATE_ALLOWOPTS 0x01
|
97
|
@@ -800,7 +807,7 @@ struct pf_state {
|
98
|
|
99
|
/* XXX */
|
100
|
u_int8_t sync_updates;
|
101
|
- u_int8_t _tail[3];
|
102
|
+ u_int8_t _tail;
|
103
|
};
|
104
|
|
105
|
/*
|
106
|
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
|
107
|
index e698035..b74d60d 100644
|
108
|
--- a/sys/netinet/ip_divert.c
|
109
|
+++ b/sys/netinet/ip_divert.c
|
110
|
@@ -267,8 +267,7 @@ divert_packet(struct mbuf *m, int incoming)
|
111
|
* this iface name will come along for the ride.
|
112
|
* (see div_output for the other half of this.)
|
113
|
*/
|
114
|
- strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
|
115
|
- sizeof(divsrc.sin_zero));
|
116
|
+ *((u_short *)divsrc.sin_zero) = m->m_pkthdr.rcvif->if_index;
|
117
|
}
|
118
|
|
119
|
/* Put packet on socket queue, if any */
|
120
|
@@ -342,7 +341,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
121
|
|
122
|
/* Loopback avoidance and state recovery */
|
123
|
if (sin) {
|
124
|
- int i;
|
125
|
+ u_short idx;
|
126
|
|
127
|
/* set the starting point. We provide a non-zero slot,
|
128
|
* but a non_matching chain_id to skip that info and use
|
129
|
@@ -350,7 +349,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
130
|
*/
|
131
|
dt->slot = 1; /* dummy, chain_id is invalid */
|
132
|
dt->chain_id = 0;
|
133
|
- dt->rulenum = sin->sin_port+1; /* host format ? */
|
134
|
+ dt->rulenum = sin->sin_port; /* host format ? */
|
135
|
dt->rule_id = 0;
|
136
|
/*
|
137
|
* Find receive interface with the given name, stuffed
|
138
|
@@ -358,10 +357,9 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
139
|
* The name is user supplied data so don't trust its size
|
140
|
* or that it is zero terminated.
|
141
|
*/
|
142
|
- for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++)
|
143
|
- ;
|
144
|
- if ( i > 0 && i < sizeof(sin->sin_zero))
|
145
|
- m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
|
146
|
+ idx = *((u_short *)sin->sin_zero);
|
147
|
+ if ( idx > 0 )
|
148
|
+ m->m_pkthdr.rcvif = ifnet_byindex(idx);
|
149
|
}
|
150
|
|
151
|
/* Reinject packet into the system as incoming or outgoing */
|
152
|
@@ -832,5 +830,4 @@ static moduledata_t ipdivertmod = {
|
153
|
};
|
154
|
|
155
|
DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
|
156
|
-MODULE_DEPEND(ipdivert, ipfw, 2, 2, 2);
|
157
|
MODULE_VERSION(ipdivert, 1);
|
158
|
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
|
159
|
index cb38fcb..4303676 100644
|
160
|
--- a/sys/netpfil/pf/pf.c
|
161
|
+++ b/sys/netpfil/pf/pf.c
|
162
|
@@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$");
|
163
|
#include <netpfil/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */
|
164
|
#include <netinet/ip_fw.h>
|
165
|
#include <netinet/ip_dummynet.h>
|
166
|
+#include <netinet/ip_divert.h>
|
167
|
|
168
|
#ifdef INET6
|
169
|
#include <netinet/ip6.h>
|
170
|
@@ -316,6 +317,14 @@ VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
|
171
|
|
172
|
#define PACKET_LOOPED(mtag) ((mtag)->flags & PF_PACKET_LOOPED)
|
173
|
|
174
|
+#define PF_DIVERT_MAXPACKETS_REACHED() \
|
175
|
+do { \
|
176
|
+ if (r->spare2 && \
|
177
|
+ s->packets[dir == PF_OUT] > r->spare2) \
|
178
|
+ /* fake that divert already happened */ \
|
179
|
+ pd.pf_mtag->flags |= PF_PACKET_LOOPED; \
|
180
|
+} while(0)
|
181
|
+
|
182
|
#define STATE_LOOKUP(i, k, d, s, pd) \
|
183
|
do { \
|
184
|
(s) = pf_find_state((i), (k), (d)); \
|
185
|
@@ -6069,6 +6078,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
186
|
struct pf_pdesc pd;
|
187
|
int off = 0, dirndx, pqid = 0;
|
188
|
int loopedfrom = 0;
|
189
|
+ u_int16_t divertcookie = 0;
|
190
|
+ u_int8_t divflags = 0;
|
191
|
struct ip_fw_args dnflow;
|
192
|
|
193
|
M_ASSERTPKTHDR(m);
|
194
|
@@ -6101,12 +6112,10 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
195
|
pd.pf_mtag->flags |= PF_PACKET_LOOPED;
|
196
|
if (rr->info & IPFW_IS_DUMMYNET)
|
197
|
loopedfrom = 1;
|
198
|
- if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) {
|
199
|
- if (pd.pf_mtag == NULL &&
|
200
|
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
|
201
|
- action = PF_DROP;
|
202
|
- goto done;
|
203
|
- }
|
204
|
+ if (rr->info & IPFW_IS_DIVERT) {
|
205
|
+ divertcookie = rr->rulenum;
|
206
|
+ divflags = (u_int8_t)(divertcookie >> 8);
|
207
|
+ divertcookie &= ~PFSTATE_DIVERT_MASK;
|
208
|
}
|
209
|
if (pd.pf_mtag && pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) {
|
210
|
m->m_flags |= M_FASTFWD_OURS;
|
211
|
@@ -6273,6 +6282,17 @@ done:
|
212
|
("pf: dropping packet with ip options\n"));
|
213
|
}
|
214
|
|
215
|
+ if (s) {
|
216
|
+ PF_DIVERT_MAXPACKETS_REACHED();
|
217
|
+
|
218
|
+ if (divflags) {
|
219
|
+ s->divert_cookie = divertcookie;
|
220
|
+ s->local_flags |= divflags;
|
221
|
+ } else {
|
222
|
+ divertcookie = s->divert_cookie;
|
223
|
+ divflags = s->local_flags;
|
224
|
+ }
|
225
|
+ }
|
226
|
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
|
227
|
action = PF_DROP;
|
228
|
REASON_SET(&reason, PFRES_MEMORY);
|
229
|
@@ -6300,7 +6320,33 @@ done:
|
230
|
}
|
231
|
#endif /* ALTQ */
|
232
|
|
233
|
- if (s && (s->dnpipe || s->pdnpipe)) {
|
234
|
+ if (divflags & PFSTATE_DIVERT_TAG)
|
235
|
+ pd.pf_mtag->tag = divertcookie;
|
236
|
+ else if (divflags & PFSTATE_DIVERT_ALTQ)
|
237
|
+ pd.pf_mtag->qid = divertcookie;
|
238
|
+ else if (divflags & PFSTATE_DIVERT_ACTION) {
|
239
|
+ struct pf_rule *dlr;
|
240
|
+ action = PF_DROP;
|
241
|
+ if (s)
|
242
|
+ pf_unlink_state(s, PF_ENTER_LOCKED);
|
243
|
+ REASON_SET(&reason, PFRES_DIVERT);
|
244
|
+ log = 1;
|
245
|
+ DPFPRINTF(PF_DEBUG_MISC,
|
246
|
+ ("pf: changing action to with overload from divert.\n"));
|
247
|
+ dlr = r;
|
248
|
+ PFLOG_PACKET(kif, m, AF_INET, dir, reason, dlr, a,
|
249
|
+ ruleset, &pd, (s == NULL));
|
250
|
+ m_freem(*m0);
|
251
|
+ *m0 = NULL;
|
252
|
+ /* NOTE: Fake this to avoid divert giving errors to the application. */
|
253
|
+ return (PF_PASS);
|
254
|
+ }
|
255
|
+
|
256
|
+ if (divflags & PFSTATE_DIVERT_DNCOOKIE) {
|
257
|
+ pd.act.dnpipe = divertcookie;
|
258
|
+ pd.act.pdnpipe = divertcookie;
|
259
|
+ pd.act.flags |= PFRULE_DN_IS_PIPE;
|
260
|
+ } else if (s && (s->dnpipe || s->pdnpipe)) {
|
261
|
pd.act.dnpipe = s->dnpipe;
|
262
|
pd.act.pdnpipe = s->pdnpipe;
|
263
|
pd.act.flags = s->state_flags;
|
264
|
@@ -6355,10 +6401,51 @@ done:
|
265
|
PF_STATE_UNLOCK(s);
|
266
|
return (action);
|
267
|
}
|
268
|
- } else
|
269
|
- pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
|
270
|
+ }
|
271
|
continueprocessing:
|
272
|
|
273
|
+ if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
|
274
|
+ !PACKET_LOOPED(&pd)) {
|
275
|
+ if (!r->spare2 ||
|
276
|
+ (s && s->packets[dir == PF_OUT] <= r->spare2)) {
|
277
|
+ ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
|
278
|
+ sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
|
279
|
+ if (ipfwtag != NULL) {
|
280
|
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
|
281
|
+ ntohs(r->divert.port);
|
282
|
+ ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
|
283
|
+
|
284
|
+ if (s)
|
285
|
+ PF_STATE_UNLOCK(s);
|
286
|
+
|
287
|
+ m_tag_prepend(m, ipfwtag);
|
288
|
+ if (m->m_flags & M_FASTFWD_OURS) {
|
289
|
+ if (pd.pf_mtag == NULL &&
|
290
|
+ ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
|
291
|
+ action = PF_DROP;
|
292
|
+ REASON_SET(&reason, PFRES_MEMORY);
|
293
|
+ log = 1;
|
294
|
+ DPFPRINTF(PF_DEBUG_MISC,
|
295
|
+ ("pf: failed to allocate tag\n"));
|
296
|
+ }
|
297
|
+ pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
|
298
|
+ m->m_flags &= ~M_FASTFWD_OURS;
|
299
|
+ }
|
300
|
+ ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
|
301
|
+ *m0 = NULL;
|
302
|
+
|
303
|
+ return (action);
|
304
|
+ } else {
|
305
|
+ /* XXX: ipfw has the same behaviour! */
|
306
|
+ action = PF_DROP;
|
307
|
+ REASON_SET(&reason, PFRES_MEMORY);
|
308
|
+ log = 1;
|
309
|
+ DPFPRINTF(PF_DEBUG_MISC,
|
310
|
+ ("pf: failed to allocate divert tag\n"));
|
311
|
+ }
|
312
|
+ }
|
313
|
+ }
|
314
|
+
|
315
|
/*
|
316
|
* connections redirected to loopback should not match sockets
|
317
|
* bound specifically to loopback due to security implications,
|
318
|
@@ -6368,49 +6455,14 @@ continueprocessing:
|
319
|
pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
|
320
|
(s->nat_rule.ptr->action == PF_RDR ||
|
321
|
s->nat_rule.ptr->action == PF_BINAT) &&
|
322
|
- (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
|
323
|
+ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
|
324
|
m->m_flags |= M_SKIP_FIREWALL;
|
325
|
-
|
326
|
- if (action == PF_PASS && r->divert.port && ip_divert_ptr != NULL &&
|
327
|
- !PACKET_LOOPED(&pd)) {
|
328
|
-
|
329
|
- ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
|
330
|
- sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
|
331
|
- if (ipfwtag != NULL) {
|
332
|
- ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
|
333
|
- ntohs(r->divert.port);
|
334
|
- ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
|
335
|
-
|
336
|
- if (s)
|
337
|
- PF_STATE_UNLOCK(s);
|
338
|
-
|
339
|
- m_tag_prepend(m, ipfwtag);
|
340
|
- if (m->m_flags & M_FASTFWD_OURS) {
|
341
|
- if (pd.pf_mtag == NULL &&
|
342
|
- ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
|
343
|
- action = PF_DROP;
|
344
|
- REASON_SET(&reason, PFRES_MEMORY);
|
345
|
- log = 1;
|
346
|
- DPFPRINTF(PF_DEBUG_MISC,
|
347
|
- ("pf: failed to allocate tag\n"));
|
348
|
- }
|
349
|
- pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT;
|
350
|
- m->m_flags &= ~M_FASTFWD_OURS;
|
351
|
- }
|
352
|
- ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT);
|
353
|
- *m0 = NULL;
|
354
|
-
|
355
|
- return (action);
|
356
|
- } else {
|
357
|
- /* XXX: ipfw has the same behaviour! */
|
358
|
- action = PF_DROP;
|
359
|
- REASON_SET(&reason, PFRES_MEMORY);
|
360
|
- log = 1;
|
361
|
- DPFPRINTF(PF_DEBUG_MISC,
|
362
|
- ("pf: failed to allocate divert tag\n"));
|
363
|
- }
|
364
|
+ if (PACKET_LOOPED(pd.pf_mtag) && !loopedfrom)
|
365
|
+ m->m_flags |= M_FASTFWD_OURS;
|
366
|
}
|
367
|
|
368
|
+ pd.pf_mtag->flags &= ~PF_PACKET_LOOPED;
|
369
|
+
|
370
|
if (log) {
|
371
|
struct pf_rule *lr;
|
372
|
|
373
|
@@ -6532,7 +6584,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
|
374
|
|
375
|
PF_RULES_RLOCK();
|
376
|
|
377
|
- if (ip_dn_io_ptr != NULL &&
|
378
|
+ if (((ip_dn_io_ptr != NULL) || (ip_divert_ptr != NULL)) &&
|
379
|
((dn_tag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
|
380
|
struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(dn_tag+1);
|
381
|
pd.pf_mtag->flags |= PF_PACKET_LOOPED;
|
382
|
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
|
383
|
index f25adde..0a768ba 100644
|
384
|
--- a/sys/netpfil/pf/pf.h
|
385
|
+++ b/sys/netpfil/pf/pf.h
|
386
|
@@ -126,7 +126,8 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
|
387
|
#define PFRES_MAXSTATES 12 /* State limit */
|
388
|
#define PFRES_SRCLIMIT 13 /* Source node/conn limit */
|
389
|
#define PFRES_SYNPROXY 14 /* SYN proxy */
|
390
|
-#define PFRES_MAX 15 /* total+1 */
|
391
|
+#define PFRES_DIVERT 15 /* Divert override */
|
392
|
+#define PFRES_MAX 16 /* total+1 */
|
393
|
|
394
|
#define PFRES_NAMES { \
|
395
|
"match", \
|
396
|
@@ -144,6 +145,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
|
397
|
"state-limit", \
|
398
|
"src-limit", \
|
399
|
"synproxy", \
|
400
|
+ "divert", \
|
401
|
NULL \
|
402
|
}
|
403
|
|