Deleted Added
full compact
ip_fw_pfil.c (201124) ip_fw_pfil.c (201527)
1/*-
2 * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_pfil.c 201124 2009-12-28 12:29:13Z luigi $");
28__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_pfil.c 201527 2010-01-04 19:01:22Z luigi $");
29
30#if !defined(KLD_MODULE)
31#include "opt_ipfw.h"
32#include "opt_ipdn.h"
33#include "opt_inet.h"
34#ifndef INET
35#error IPFIREWALL requires INET.
36#endif /* INET */

--- 17 unchanged lines hidden (view full) ---

54#include <net/vnet.h>
55
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_fw.h>
61#include <netinet/ipfw/ip_fw_private.h>
29
30#if !defined(KLD_MODULE)
31#include "opt_ipfw.h"
32#include "opt_ipdn.h"
33#include "opt_inet.h"
34#ifndef INET
35#error IPFIREWALL requires INET.
36#endif /* INET */

--- 17 unchanged lines hidden (view full) ---

54#include <net/vnet.h>
55
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
59#include <netinet/ip_var.h>
60#include <netinet/ip_fw.h>
61#include <netinet/ipfw/ip_fw_private.h>
62#include <netinet/ip_divert.h>
63#include <netinet/ip_dummynet.h>
64#include <netgraph/ng_ipfw.h>
65
66#include <machine/in_cksum.h>
67
68static VNET_DEFINE(int, fw_enable) = 1;
69#define V_fw_enable VNET(fw_enable)
70
71#ifdef INET6
72static VNET_DEFINE(int, fw6_enable) = 1;
73#define V_fw6_enable VNET(fw6_enable)
74#endif
75
76int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
77
78/* Divert hooks. */
62#include <netinet/ip_dummynet.h>
63#include <netgraph/ng_ipfw.h>
64
65#include <machine/in_cksum.h>
66
67static VNET_DEFINE(int, fw_enable) = 1;
68#define V_fw_enable VNET(fw_enable)
69
70#ifdef INET6
71static VNET_DEFINE(int, fw6_enable) = 1;
72#define V_fw6_enable VNET(fw6_enable)
73#endif
74
75int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
76
77/* Divert hooks. */
79ip_divert_packet_t *ip_divert_ptr = NULL;
78void (*ip_divert_ptr)(struct mbuf *m, int incoming);
80
81/* ng_ipfw hooks. */
82ng_ipfw_input_t *ng_ipfw_input_p = NULL;
83
84/* Forward declarations. */
79
80/* ng_ipfw hooks. */
81ng_ipfw_input_t *ng_ipfw_input_p = NULL;
82
83/* Forward declarations. */
85static void ipfw_divert(struct mbuf **, int, int);
84static int ipfw_divert(struct mbuf **, int, struct ipfw_rule_ref *, int);
86
87#ifdef SYSCTL_NODE
88SYSCTL_DECL(_net_inet_ip_fw);
89SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable,
90 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0,
91 ipfw_chg_hook, "I", "Enable ipfw");
92#ifdef INET6
93SYSCTL_DECL(_net_inet6_ip6_fw);

--- 8 unchanged lines hidden (view full) ---

102 * dummynet, divert, netgraph or other modules.
103 * The packet may be consumed.
104 */
105static int
106ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
107 struct inpcb *inp)
108{
109 struct ip_fw_args args;
85
86#ifdef SYSCTL_NODE
87SYSCTL_DECL(_net_inet_ip_fw);
88SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable,
89 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0,
90 ipfw_chg_hook, "I", "Enable ipfw");
91#ifdef INET6
92SYSCTL_DECL(_net_inet6_ip6_fw);

--- 8 unchanged lines hidden (view full) ---

101 * dummynet, divert, netgraph or other modules.
102 * The packet may be consumed.
103 */
104static int
105ipfw_check_hook(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
106 struct inpcb *inp)
107{
108 struct ip_fw_args args;
110 struct ng_ipfw_tag *ng_tag;
111 struct m_tag *dn_tag;
109 struct m_tag *tag;
112 int ipfw;
113 int ret;
110 int ipfw;
111 int ret;
114#ifdef IPFIREWALL_FORWARD
115 struct m_tag *fwd_tag;
116#endif
117
112
113 /* all the processing now uses ip_len in net format */
114 SET_NET_IPLEN(mtod(*m0, struct ip *));
115
118 /* convert dir to IPFW values */
119 dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
120 bzero(&args, sizeof(args));
121
116 /* convert dir to IPFW values */
117 dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT;
118 bzero(&args, sizeof(args));
119
122 ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
123 NULL);
124 if (ng_tag != NULL) {
125 KASSERT(ng_tag->dir == dir,
126 ("ng_ipfw tag with wrong direction"));
127 args.slot = ng_tag->slot;
128 args.rulenum = ng_tag->rulenum;
129 args.rule_id = ng_tag->rule_id;
130 args.chain_id = ng_tag->chain_id;
131 m_tag_delete(*m0, (struct m_tag *)ng_tag);
132 }
133
134again:
120again:
135 dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
136 if (dn_tag != NULL) {
137 struct dn_pkt_tag *dt;
138
139 dt = (struct dn_pkt_tag *)(dn_tag+1);
140 args.slot = dt->slot;
141 args.rulenum = dt->rulenum;
142 args.rule_id = dt->rule_id;
143 args.chain_id = dt->chain_id;
144 m_tag_delete(*m0, dn_tag);
121 /*
122 * extract and remove the tag if present. If we are left
123 * with onepass, optimize the outgoing path.
124 */
125 tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL);
126 if (tag != NULL) {
127 args.rule = *((struct ipfw_rule_ref *)(tag+1));
128 m_tag_delete(*m0, tag);
129 if (args.rule.info & IPFW_ONEPASS) {
130 SET_HOST_IPLEN(mtod(*m0, struct ip *));
131 return 0;
132 }
145 }
146
147 args.m = *m0;
148 args.oif = dir == DIR_OUT ? ifp : NULL;
149 args.inp = inp;
150
133 }
134
135 args.m = *m0;
136 args.oif = dir == DIR_OUT ? ifp : NULL;
137 args.inp = inp;
138
151 if (V_fw_one_pass == 0 || args.slot == 0) {
152 ipfw = ipfw_chk(&args);
153 *m0 = args.m;
154 } else
155 ipfw = IP_FW_PASS;
139 ipfw = ipfw_chk(&args);
140 *m0 = args.m;
156
157 KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
158 __func__));
159
160 /* breaking out of the switch means drop */
161 ret = 0; /* default return value for pass */
162 switch (ipfw) {
163 case IP_FW_PASS:
164 /* next_hop may be set by ipfw_chk */
165 if (args.next_hop == NULL)
166 break; /* pass */
167#ifndef IPFIREWALL_FORWARD
168 ret = EACCES;
169#else
141
142 KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
143 __func__));
144
145 /* breaking out of the switch means drop */
146 ret = 0; /* default return value for pass */
147 switch (ipfw) {
148 case IP_FW_PASS:
149 /* next_hop may be set by ipfw_chk */
150 if (args.next_hop == NULL)
151 break; /* pass */
152#ifndef IPFIREWALL_FORWARD
153 ret = EACCES;
154#else
155 {
156 struct m_tag *fwd_tag;
157
170 /* Incoming packets should not be tagged so we do not
171 * m_tag_find. Outgoing packets may be tagged, so we
172 * reuse the tag if present.
173 */
174 fwd_tag = (dir == DIR_IN) ? NULL :
175 m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
176 if (fwd_tag != NULL) {
177 m_tag_unlink(*m0, fwd_tag);

--- 5 unchanged lines hidden (view full) ---

183 break; /* i.e. drop */
184 }
185 }
186 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
187 m_tag_prepend(*m0, fwd_tag);
188
189 if (in_localip(args.next_hop->sin_addr))
190 (*m0)->m_flags |= M_FASTFWD_OURS;
158 /* Incoming packets should not be tagged so we do not
159 * m_tag_find. Outgoing packets may be tagged, so we
160 * reuse the tag if present.
161 */
162 fwd_tag = (dir == DIR_IN) ? NULL :
163 m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
164 if (fwd_tag != NULL) {
165 m_tag_unlink(*m0, fwd_tag);

--- 5 unchanged lines hidden (view full) ---

171 break; /* i.e. drop */
172 }
173 }
174 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
175 m_tag_prepend(*m0, fwd_tag);
176
177 if (in_localip(args.next_hop->sin_addr))
178 (*m0)->m_flags |= M_FASTFWD_OURS;
179 }
191#endif
192 break;
193
194 case IP_FW_DENY:
195 ret = EACCES;
196 break; /* i.e. drop */
197
198 case IP_FW_DUMMYNET:

--- 18 unchanged lines hidden (view full) ---

217 break;
218
219 case IP_FW_TEE:
220 case IP_FW_DIVERT:
221 if (ip_divert_ptr == NULL) {
222 ret = EACCES;
223 break; /* i.e. drop */
224 }
180#endif
181 break;
182
183 case IP_FW_DENY:
184 ret = EACCES;
185 break; /* i.e. drop */
186
187 case IP_FW_DUMMYNET:

--- 18 unchanged lines hidden (view full) ---

206 break;
207
208 case IP_FW_TEE:
209 case IP_FW_DIVERT:
210 if (ip_divert_ptr == NULL) {
211 ret = EACCES;
212 break; /* i.e. drop */
213 }
225 ipfw_divert(m0, dir, (ipfw == IP_FW_TEE) ? 1 : 0);
226 if (*m0) {
227 /* continue processing for this one. We set
228 * args.slot=0, but the divert tag is processed
229 * in ipfw_chk to jump to the right place.
230 */
231 args.slot = 0;
232 goto again; /* continue with packet */
233 }
214 ret = ipfw_divert(m0, dir, &args.rule,
215 (ipfw == IP_FW_TEE) ? 1 : 0);
216 /* continue processing for the original packet (tee). */
217 if (*m0)
218 goto again;
234 break;
235
236 case IP_FW_NGTEE:
237 case IP_FW_NETGRAPH:
238 if (!NG_IPFW_LOADED) {
239 ret = EACCES;
240 break; /* i.e. drop */
241 }

--- 8 unchanged lines hidden (view full) ---

250 goto again; /* continue with packet */
251
252 default:
253 KASSERT(0, ("%s: unknown retval", __func__));
254 }
255
256 if (ret != 0) {
257 if (*m0)
219 break;
220
221 case IP_FW_NGTEE:
222 case IP_FW_NETGRAPH:
223 if (!NG_IPFW_LOADED) {
224 ret = EACCES;
225 break; /* i.e. drop */
226 }

--- 8 unchanged lines hidden (view full) ---

235 goto again; /* continue with packet */
236
237 default:
238 KASSERT(0, ("%s: unknown retval", __func__));
239 }
240
241 if (ret != 0) {
242 if (*m0)
258 m_freem(*m0);
243 FREE_PKT(*m0);
259 *m0 = NULL;
260 }
244 *m0 = NULL;
245 }
246 if (*m0)
247 SET_HOST_IPLEN(mtod(*m0, struct ip *));
261 return ret;
262}
263
248 return ret;
249}
250
264static void
265ipfw_divert(struct mbuf **m0, int incoming, int tee)
251/* do the divert, return 1 on error 0 on success */
252static int
253ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule,
254 int tee)
266{
267 /*
268 * ipfw_chk() has already tagged the packet with the divert tag.
269 * If tee is set, copy packet and return original.
270 * If not tee, consume packet and send it to divert socket.
271 */
272 struct mbuf *clone;
273 struct ip *ip;
255{
256 /*
257 * ipfw_chk() has already tagged the packet with the divert tag.
258 * If tee is set, copy packet and return original.
259 * If not tee, consume packet and send it to divert socket.
260 */
261 struct mbuf *clone;
262 struct ip *ip;
263 struct m_tag *tag;
274
275 /* Cloning needed for tee? */
276 if (tee == 0) {
277 clone = *m0; /* use the original mbuf */
278 *m0 = NULL;
279 } else {
280 clone = m_dup(*m0, M_DONTWAIT);
281 /* If we cannot duplicate the mbuf, we sacrifice the divert
282 * chain and continue with the tee-ed packet.
283 */
284 if (clone == NULL)
264
265 /* Cloning needed for tee? */
266 if (tee == 0) {
267 clone = *m0; /* use the original mbuf */
268 *m0 = NULL;
269 } else {
270 clone = m_dup(*m0, M_DONTWAIT);
271 /* If we cannot duplicate the mbuf, we sacrifice the divert
272 * chain and continue with the tee-ed packet.
273 */
274 if (clone == NULL)
285 return;
275 return 1;
286 }
287
288 /*
289 * Divert listeners can normally handle non-fragmented packets,
290 * but we can only reass in the non-tee case.
291 * This means that listeners on a tee rule may get fragments,
292 * and have to live with that.
293 * Note that we now have the 'reass' ipfw option so if we care
294 * we can do it before a 'tee'.
295 */
296 ip = mtod(clone, struct ip *);
276 }
277
278 /*
279 * Divert listeners can normally handle non-fragmented packets,
280 * but we can only reass in the non-tee case.
281 * This means that listeners on a tee rule may get fragments,
282 * and have to live with that.
283 * Note that we now have the 'reass' ipfw option so if we care
284 * we can do it before a 'tee'.
285 */
286 ip = mtod(clone, struct ip *);
297 if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
287 if (!tee && ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
298 int hlen;
299 struct mbuf *reass;
300
288 int hlen;
289 struct mbuf *reass;
290
291 SET_HOST_IPLEN(ip); /* ip_reass wants host order */
301 reass = ip_reass(clone); /* Reassemble packet. */
302 if (reass == NULL)
292 reass = ip_reass(clone); /* Reassemble packet. */
293 if (reass == NULL)
303 return;
294 return 0; /* not an error */
304 /* if reass = NULL then it was consumed by ip_reass */
305 /*
306 * IP header checksum fixup after reassembly and leave header
307 * in network byte order.
308 */
309 ip = mtod(reass, struct ip *);
310 hlen = ip->ip_hl << 2;
311 SET_NET_IPLEN(ip);
312 ip->ip_sum = 0;
313 if (hlen == sizeof(struct ip))
314 ip->ip_sum = in_cksum_hdr(ip);
315 else
316 ip->ip_sum = in_cksum(reass, hlen);
317 clone = reass;
295 /* if reass = NULL then it was consumed by ip_reass */
296 /*
297 * IP header checksum fixup after reassembly and leave header
298 * in network byte order.
299 */
300 ip = mtod(reass, struct ip *);
301 hlen = ip->ip_hl << 2;
302 SET_NET_IPLEN(ip);
303 ip->ip_sum = 0;
304 if (hlen == sizeof(struct ip))
305 ip->ip_sum = in_cksum_hdr(ip);
306 else
307 ip->ip_sum = in_cksum(reass, hlen);
308 clone = reass;
318 } else {
319 /* Convert header to network byte order. */
320 SET_NET_IPLEN(ip);
321 }
309 }
310 /* attach a tag to the packet with the reinject info */
311 tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
312 sizeof(struct ipfw_rule_ref), M_NOWAIT);
313 if (tag == NULL) {
314 FREE_PKT(clone);
315 return 1;
316 }
317 *((struct ipfw_rule_ref *)(tag+1)) = *rule;
318 m_tag_prepend(clone, tag);
322
323 /* Do the dirty job... */
324 ip_divert_ptr(clone, incoming);
319
320 /* Do the dirty job... */
321 ip_divert_ptr(clone, incoming);
322 return 0;
325}
326
327/*
328 * attach or detach hooks for a given protocol family
329 */
330static int
331ipfw_hook(int onoff, int pf)
332{
323}
324
325/*
326 * attach or detach hooks for a given protocol family
327 */
328static int
329ipfw_hook(int onoff, int pf)
330{
333 const int arg = PFIL_IN | PFIL_OUT | PFIL_WAITOK;
334 struct pfil_head *pfh;
335
336 pfh = pfil_head_get(PFIL_TYPE_AF, pf);
337 if (pfh == NULL)
338 return ENOENT;
339
331 struct pfil_head *pfh;
332
333 pfh = pfil_head_get(PFIL_TYPE_AF, pf);
334 if (pfh == NULL)
335 return ENOENT;
336
340 if (onoff)
341 (void)pfil_add_hook(ipfw_check_hook, NULL, arg, pfh);
342 else
343 (void)pfil_remove_hook(ipfw_check_hook, NULL, arg, pfh);
337 (void) (onoff ? pfil_add_hook : pfil_remove_hook)
338 (ipfw_check_hook, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
344
345 return 0;
346}
347
348int
349ipfw_attach_hooks(int arg)
350{
351 int error = 0;

--- 64 unchanged lines hidden ---
339
340 return 0;
341}
342
343int
344ipfw_attach_hooks(int arg)
345{
346 int error = 0;

--- 64 unchanged lines hidden ---