npf_handler.c revision 1.2 1 /* $NetBSD: npf_handler.c,v 1.2 2010/09/16 04:53:27 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This material is based upon work partially supported by The
8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * NPF packet handler.
34 */
35
36 #ifdef _KERNEL
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.2 2010/09/16 04:53:27 rmind Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #endif
43
44 #include <sys/mbuf.h>
45 #include <sys/mutex.h>
46 #include <net/if.h>
47 #include <net/pfil.h>
48 #include <sys/socketvar.h>
49
50 #include "npf_impl.h"
51
52 /*
53 * If npf_ph_if != NULL, pfil hooks are registers. If NULL, not registered.
54 * Used to check the state. Locked by: softnet_lock + KERNEL_LOCK (XXX).
55 */
56 static struct pfil_head * npf_ph_if = NULL;
57 static struct pfil_head * npf_ph_inet = NULL;
58
59 static bool default_pass = true;
60
61 int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int);
62
63 /*
64 * npf_ifhook: hook handling interface changes.
65 */
66 static int
67 npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
68 {
69
70 return 0;
71 }
72
73 /*
74 * npf_packet_handler: main packet handling routine for layer 3.
75 *
76 * Note: packet flow and inspection logic is in strict order.
77 */
78 int
79 npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
80 {
81 nbuf_t *nbuf = *mp;
82 npf_cache_t npc;
83 npf_session_t *se;
84 npf_rule_t *rl;
85 bool keepstate;
86 int retfl, error;
87
88 /*
89 * Initialise packet information cache.
90 * Note: it is enough to clear the info bits.
91 */
92 npc.npc_info = 0;
93 error = 0;
94 retfl = 0;
95
96 /* Inspect the list of sessions. */
97 se = npf_session_inspect(&npc, nbuf, ifp, di);
98
99 /* If "passing" session found - skip the ruleset inspection. */
100 if (se && npf_session_pass(se)) {
101 goto pass;
102 }
103
104 /* Inspect the ruleset using this packet. */
105 rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, NPF_LAYER_3);
106 if (rl == NULL) {
107 if (default_pass) {
108 goto pass;
109 }
110 error = ENETUNREACH;
111 goto out;
112 }
113
114 /* Apply the rule. */
115 error = npf_rule_apply(&npc, rl, &keepstate, &retfl);
116 if (error) {
117 goto out;
118 }
119
120 /* Establish a "pass" session, if required. */
121 if (keepstate && !se) {
122 se = npf_session_establish(&npc, NULL, di);
123 if (se == NULL) {
124 error = ENOMEM;
125 goto out;
126 }
127 npf_session_setpass(se);
128 }
129 pass:
130 KASSERT(error == 0);
131 /*
132 * Perform NAT.
133 */
134 error = npf_do_nat(&npc, se, nbuf, ifp, di);
135 out:
136 /* Release reference on session. */
137 if (se != NULL) {
138 npf_session_release(se);
139 }
140
141 /*
142 * If error is set - drop the packet.
143 * Normally, ENETUNREACH is used for "block".
144 */
145 if (error) {
146 /*
147 * Depending on flags and protocol, return TCP reset (RST)
148 * or ICMP destination unreachable
149 */
150 if (retfl) {
151 npf_return_block(&npc, nbuf, retfl);
152 }
153 m_freem(*mp);
154 *mp = NULL;
155 }
156 return error;
157 }
158
159 /*
160 * npf_register_pfil: register pfil(9) hooks.
161 */
162 int
163 npf_register_pfil(void)
164 {
165 int error;
166
167 mutex_enter(softnet_lock);
168 KERNEL_LOCK(1, NULL);
169
170 /* Check if pfil hooks are not already registered. */
171 if (npf_ph_if) {
172 error = EEXIST;
173 goto fail;
174 }
175
176 /* Capture point of any activity in interfaces and IP layer. */
177 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
178 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
179 if (npf_ph_if == NULL || npf_ph_inet == NULL) {
180 npf_ph_if = NULL;
181 error = ENOENT;
182 goto fail;
183 }
184
185 /* Interface re-config or attach/detach hook. */
186 error = pfil_add_hook(npf_ifhook, NULL,
187 PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
188 KASSERT(error == 0);
189
190 /* Packet IN/OUT handler on all interfaces and IP layer. */
191 error = pfil_add_hook(npf_packet_handler, NULL,
192 PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
193 KASSERT(error == 0);
194
195 fail:
196 KERNEL_UNLOCK_ONE(NULL);
197 mutex_exit(softnet_lock);
198
199 return error;
200 }
201
202 /*
203 * npf_unregister: unregister pfil(9) hooks.
204 */
205 void
206 npf_unregister_pfil(void)
207 {
208
209 mutex_enter(softnet_lock);
210 KERNEL_LOCK(1, NULL);
211
212 if (npf_ph_if) {
213 (void)pfil_remove_hook(npf_packet_handler, NULL,
214 PFIL_ALL, npf_ph_inet);
215 (void)pfil_remove_hook(npf_ifhook, NULL,
216 PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
217
218 npf_ph_if = NULL;
219 }
220
221 KERNEL_UNLOCK_ONE(NULL);
222 mutex_exit(softnet_lock);
223 }
224