npf_handler.c revision 1.1 1 /* $NetBSD: npf_handler.c,v 1.1 2010/08/22 18:56:22 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.1 2010/08/22 18:56:22 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 int npf_packet_handler(void *, struct mbuf **, struct ifnet *, int);
60
61 /*
62 * npf_ifhook: hook handling interface changes.
63 */
64 static int
65 npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
66 {
67
68 return 0;
69 }
70
71 /*
72 * npf_packet_handler: main packet handling routine.
73 *
74 * Note: packet flow and inspection logic is in strict order.
75 */
76 int
77 npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
78 {
79 const int layer = (const int)(long)arg;
80 nbuf_t *nbuf = *mp;
81 npf_cache_t npc;
82 npf_session_t *se;
83 npf_rule_t *rl;
84 int error;
85
86 /*
87 * Initialise packet information cache.
88 * Note: it is enough to clear the info bits.
89 */
90 npc.npc_info = 0;
91
92 /* Inspect the list of sessions. */
93 se = npf_session_inspect(&npc, nbuf, ifp, di, layer);
94
95 /* Inbound NAT. */
96 if ((di & PFIL_IN) && (error = npf_natin(&npc, se, nbuf, layer)) != 0) {
97 goto out;
98 }
99
100 /* If session found - we pass this packet. */
101 if (se && npf_session_pass(se)) {
102 error = 0;
103 } else {
104 /* Inspect ruleset using this packet. */
105 rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, layer);
106 if (rl != NULL) {
107 bool keepstate;
108 /* Apply the rule. */
109 error = npf_rule_apply(&npc, rl, &keepstate);
110 if (error) {
111 goto out;
112 }
113 /* Establish a session, if required. */
114 if (keepstate) {
115 se = npf_session_establish(&npc, NULL, di);
116 }
117 }
118 /* No rules or "default" rule - pass. */
119 }
120
121 /* Outbound NAT. */
122 if (di & PFIL_OUT) {
123 error = npf_natout(&npc, se, nbuf, ifp, layer);
124 }
125 out:
126 /* Release reference on session. */
127 if (se != NULL) {
128 npf_session_release(se);
129 }
130
131 /*
132 * If error is set - drop the packet.
133 * Normally, ENETUNREACH is used to "block".
134 */
135 if (error) {
136 m_freem(*mp);
137 *mp = NULL;
138 }
139 return error;
140 }
141
142 /*
143 * npf_register_pfil: register pfil(9) hooks.
144 */
145 int
146 npf_register_pfil(void)
147 {
148 int error;
149
150 mutex_enter(softnet_lock);
151 KERNEL_LOCK(1, NULL);
152
153 /* Check if pfil hooks are not already registered. */
154 if (npf_ph_if) {
155 error = EEXIST;
156 goto fail;
157 }
158
159 /* Capture point of any activity in interfaces and IP layer. */
160 npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
161 npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
162 if (npf_ph_if == NULL || npf_ph_inet == NULL) {
163 npf_ph_if = NULL;
164 error = ENOENT;
165 goto fail;
166 }
167
168 /* Interface re-config or attach/detach hook. */
169 error = pfil_add_hook(npf_ifhook, NULL,
170 PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
171 KASSERT(error == 0);
172
173 /* Packet IN/OUT handler on all interfaces and IP layer. */
174 error = pfil_add_hook(npf_packet_handler, (void *)NPF_LAYER_3,
175 PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
176 KASSERT(error == 0);
177
178 fail:
179 KERNEL_UNLOCK_ONE(NULL);
180 mutex_exit(softnet_lock);
181
182 return error;
183 }
184
185 /*
186 * npf_unregister: unregister pfil(9) hooks.
187 */
188 void
189 npf_unregister_pfil(void)
190 {
191
192 mutex_enter(softnet_lock);
193 KERNEL_LOCK(1, NULL);
194
195 if (npf_ph_if) {
196 (void)pfil_remove_hook(npf_packet_handler, (void *)NPF_LAYER_3,
197 PFIL_ALL, npf_ph_inet);
198 (void)pfil_remove_hook(npf_ifhook, NULL,
199 PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
200
201 npf_ph_if = NULL;
202 }
203
204 KERNEL_UNLOCK_ONE(NULL);
205 mutex_exit(softnet_lock);
206 }
207