xref: /netbsd-src/sys/net/npf/npf_handler.c (revision 179b12252ecaf3553d9c2b7458ce62b6a2203d0c)
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