Projet

Général

Profil

Télécharger (12,6 ko) Statistiques
| Branche: | Révision:

univnautes-tools / patches / stable / 10 / divert.RELENG_10.diff @ 4ab3b90b

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
 
(14-14/67)