FreeBSD kernel netgraph code
ng_ipfw.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright 2005, Gleb Smirnoff <glebius@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31#include "opt_inet.h"
32#include "opt_inet6.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/lock.h>
38#include <sys/mbuf.h>
39#include <sys/malloc.h>
40#include <sys/ctype.h>
41#include <sys/errno.h>
42#include <sys/rwlock.h>
43#include <sys/socket.h>
44#include <sys/syslog.h>
45
46#include <net/if.h>
47#include <net/if_var.h>
48
49#include <netinet/in.h>
50#include <netinet/in_systm.h>
51#include <netinet/in_var.h>
52#include <netinet/ip_var.h>
53#include <netinet/ip_fw.h>
54#include <netinet/ip.h>
55#include <netinet/ip6.h>
56#include <netinet6/ip6_var.h>
57
58#include <netpfil/ipfw/ip_fw_private.h>
59
60#include <netgraph/ng_message.h>
61#include <netgraph/ng_parse.h>
62#include <netgraph/ng_ipfw.h>
63#include <netgraph/netgraph.h>
64
65static int ng_ipfw_mod_event(module_t mod, int event, void *data);
73
74static hook_p ng_ipfw_findhook1(node_p, u_int16_t );
75static int ng_ipfw_input(struct mbuf **, struct ip_fw_args *, bool);
76
77/* We have only one node */
79
80/* Netgraph node type descriptor */
81static struct ng_type ng_ipfw_typestruct = {
83 .name = NG_IPFW_NODE_TYPE,
84 .mod_event = ng_ipfw_mod_event,
85 .constructor = ng_ipfw_constructor,
86 .shutdown = ng_ipfw_shutdown,
87 .newhook = ng_ipfw_newhook,
88 .connect = ng_ipfw_connect,
89 .findhook = ng_ipfw_findhook,
90 .rcvdata = ng_ipfw_rcvdata,
91 .disconnect = ng_ipfw_disconnect,
92};
94MODULE_DEPEND(ng_ipfw, ipfw, 3, 3, 3);
95
96/* Information we store for each hook */
99 u_int16_t rulenum;
100};
102
103static int
104ng_ipfw_mod_event(module_t mod, int event, void *data)
105{
106 int error = 0;
107
108 switch (event) {
109 case MOD_LOAD:
110
111 if (ng_ipfw_input_p != NULL) {
112 error = EEXIST;
113 break;
114 }
115
116 /* Setup node without any private data */
118 != 0) {
119 log(LOG_ERR, "%s: can't create ng_ipfw node", __func__);
120 break;
121 }
122
123 /* Try to name node */
124 if (ng_name_node(fw_node, "ipfw") != 0)
125 log(LOG_WARNING, "%s: failed to name node \"ipfw\"",
126 __func__);
127
128 /* Register hook */
129 ng_ipfw_input_p = ng_ipfw_input;
130 break;
131
132 case MOD_UNLOAD:
133 /*
134 * This won't happen if a node exists.
135 * ng_ipfw_input_p is already cleared.
136 */
137 break;
138
139 default:
140 error = EOPNOTSUPP;
141 break;
142 }
143
144 return (error);
145}
146
147static int
149{
150 return (EINVAL); /* Only one node */
151}
152
153static int
155{
156 hpriv_p hpriv;
157 u_int16_t rulenum;
158 const char *cp;
159 char *endptr;
160
161 /* Protect from leading zero */
162 if (name[0] == '0' && name[1] != '\0')
163 return (EINVAL);
164
165 /* Check that name contains only digits */
166 for (cp = name; *cp != '\0'; cp++)
167 if (!isdigit(*cp))
168 return (EINVAL);
169
170 /* Convert it to integer */
171 rulenum = (u_int16_t)strtol(name, &endptr, 10);
172 if (*endptr != '\0')
173 return (EINVAL);
174
175 /* Allocate memory for this hook's private data */
176 hpriv = malloc(sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO);
177 if (hpriv== NULL)
178 return (ENOMEM);
179
180 hpriv->hook = hook;
181 hpriv->rulenum = rulenum;
182
184
185 return(0);
186}
187
188/*
189 * Set hooks into queueing mode, to avoid recursion between
190 * netgraph layer and ip_{input,output}.
191 */
192static int
194{
196 return (0);
197}
198
199/* Look up hook by name */
200static hook_p
201ng_ipfw_findhook(node_p node, const char *name)
202{
203 u_int16_t n; /* numeric representation of hook */
204 char *endptr;
205
206 n = (u_int16_t)strtol(name, &endptr, 10);
207 if (*endptr != '\0')
208 return NULL;
209 return ng_ipfw_findhook1(node, n);
210}
211
212/* Look up hook by rule number */
213static hook_p
215{
216 hook_p hook;
217 hpriv_p hpriv;
218
219 LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
220 hpriv = NG_HOOK_PRIVATE(hook);
221 if (NG_HOOK_IS_VALID(hook) && (hpriv->rulenum == rulenum))
222 return (hook);
223 }
224
225 return (NULL);
226}
227
228static int
230{
231 struct m_tag *tag;
232 struct ipfw_rule_ref *r;
233 struct mbuf *m;
234 struct ip *ip;
235
236 NGI_GET_M(item, m);
237 NG_FREE_ITEM(item);
238
239 tag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
240 if (tag == NULL) {
241 NG_FREE_M(m);
242 return (EINVAL); /* XXX: find smth better */
243 }
244
245 if (m->m_len < sizeof(struct ip) &&
246 (m = m_pullup(m, sizeof(struct ip))) == NULL)
247 return (ENOBUFS);
248
249 ip = mtod(m, struct ip *);
250
251 r = (struct ipfw_rule_ref *)(tag + 1);
252 if (r->info & IPFW_INFO_IN) {
253 switch (ip->ip_v) {
254#ifdef INET
255 case IPVERSION:
256 ip_input(m);
257 return (0);
258#endif
259#ifdef INET6
260 case IPV6_VERSION >> 4:
261 ip6_input(m);
262 return (0);
263#endif
264 }
265 } else {
266 switch (ip->ip_v) {
267#ifdef INET
268 case IPVERSION:
269 return (ip_output(m, NULL, NULL, IP_FORWARDING,
270 NULL, NULL));
271#endif
272#ifdef INET6
273 case IPV6_VERSION >> 4:
274 return (ip6_output(m, NULL, NULL, 0, NULL,
275 NULL, NULL));
276#endif
277 }
278 }
279
280 /* unknown IP protocol version */
281 NG_FREE_M(m);
282 return (EPROTONOSUPPORT);
283}
284
285static int
286ng_ipfw_input(struct mbuf **m0, struct ip_fw_args *fwa, bool tee)
287{
288 struct mbuf *m;
289 hook_p hook;
290 int error = 0;
291
292 /*
293 * Node must be loaded and corresponding hook must be present.
294 */
295 if (fw_node == NULL ||
296 (hook = ng_ipfw_findhook1(fw_node, fwa->rule.info)) == NULL)
297 return (ESRCH); /* no hook associated with this rule */
298
299 /*
300 * We have two modes: in normal mode we add a tag to packet, which is
301 * important to return packet back to IP stack. In tee mode we make
302 * a copy of a packet and forward it into netgraph without a tag.
303 */
304 if (tee == false) {
305 struct m_tag *tag;
306 struct ipfw_rule_ref *r;
307 m = *m0;
308 *m0 = NULL; /* it belongs now to netgraph */
309
310 tag = m_tag_alloc(MTAG_IPFW_RULE, 0, sizeof(*r),
311 M_NOWAIT|M_ZERO);
312 if (tag == NULL) {
313 m_freem(m);
314 return (ENOMEM);
315 }
316 r = (struct ipfw_rule_ref *)(tag + 1);
317 *r = fwa->rule;
318 r->info &= IPFW_ONEPASS; /* keep this info */
319 r->info |= (fwa->flags & IPFW_ARGS_IN) ?
320 IPFW_INFO_IN : IPFW_INFO_OUT;
321 m_tag_prepend(m, tag);
322
323 } else
324 if ((m = m_dup(*m0, M_NOWAIT)) == NULL)
325 return (ENOMEM); /* which is ignored */
326
327 if (m->m_len < sizeof(struct ip) &&
328 (m = m_pullup(m, sizeof(struct ip))) == NULL)
329 return (EINVAL);
330
331 NG_SEND_DATA_ONLY(error, hook, m);
332
333 return (error);
334}
335
336static int
338{
339
340 /*
341 * After our single node has been removed,
342 * the only thing that can be done is
343 * 'kldunload ng_ipfw.ko'
344 */
345 ng_ipfw_input_p = NULL;
346 NG_NODE_UNREF(node);
347 return (0);
348}
349
350static int
352{
353 const hpriv_p hpriv = NG_HOOK_PRIVATE(hook);
354
355 free(hpriv, M_NETGRAPH);
356 NG_HOOK_SET_PRIVATE(hook, NULL);
357
358 return (0);
359}
struct netflow_v5_record r[NETFLOW_V5_MAX_RECORDS]
Definition: netflow.h:1
int ng_connect_t(hook_p hook)
Definition: netgraph.h:104
#define NG_FREE_M(m)
Definition: netgraph.h:946
hook_p ng_findhook_t(node_p node, const char *name)
Definition: netgraph.h:103
int ng_disconnect_t(hook_p hook)
Definition: netgraph.h:107
#define NG_NODE_UNREF(node)
Definition: netgraph.h:607
#define NG_HOOK_SET_PRIVATE(hook, val)
Definition: netgraph.h:333
#define NG_SEND_DATA_ONLY(error, hook, m)
Definition: netgraph.h:932
#define NG_HOOK_FORCE_QUEUE(hook)
Definition: netgraph.h:342
int ng_rcvdata_t(hook_p hook, item_p item)
Definition: netgraph.h:106
int ng_shutdown_t(node_p node)
Definition: netgraph.h:101
#define NG_FREE_ITEM(item)
Definition: netgraph.h:847
int ng_make_node_common(struct ng_type *typep, node_p *nodep)
Definition: ng_base.c:642
int ng_name_node(node_p node, const char *name)
Definition: ng_base.c:852
int ng_constructor_t(node_p node)
Definition: netgraph.h:99
#define NGI_GET_M(i, m)
Definition: netgraph.h:852
#define NG_HOOK_IS_VALID(hook)
Definition: netgraph.h:338
#define NG_ABI_VERSION
Definition: netgraph.h:77
int ng_newhook_t(node_p node, hook_p hook, const char *name)
Definition: netgraph.h:102
#define NG_HOOK_PRIVATE(hook)
Definition: netgraph.h:336
NETGRAPH_INIT(ipfw, &ng_ipfw_typestruct)
static ng_connect_t ng_ipfw_connect
Definition: ng_ipfw.c:69
static ng_shutdown_t ng_ipfw_shutdown
Definition: ng_ipfw.c:67
static ng_newhook_t ng_ipfw_newhook
Definition: ng_ipfw.c:68
static struct ng_type ng_ipfw_typestruct
Definition: ng_ipfw.c:81
static ng_disconnect_t ng_ipfw_disconnect
Definition: ng_ipfw.c:72
static int ng_ipfw_mod_event(module_t mod, int event, void *data)
Definition: ng_ipfw.c:104
static ng_rcvdata_t ng_ipfw_rcvdata
Definition: ng_ipfw.c:71
static ng_constructor_t ng_ipfw_constructor
Definition: ng_ipfw.c:66
static int ng_ipfw_input(struct mbuf **, struct ip_fw_args *, bool)
Definition: ng_ipfw.c:286
static hook_p ng_ipfw_findhook1(node_p, u_int16_t)
Definition: ng_ipfw.c:214
MODULE_DEPEND(ng_ipfw, ipfw, 3, 3, 3)
struct ng_ipfw_hook_priv * hpriv_p
Definition: ng_ipfw.c:101
static node_p fw_node
Definition: ng_ipfw.c:78
static ng_findhook_t ng_ipfw_findhook
Definition: ng_ipfw.c:70
#define NG_IPFW_NODE_TYPE
Definition: ng_ipfw.h:33
char *const name
Definition: ng_ppp.c:261
uint8_t data[]
Definition: ng_ubt_var.h:2
uint8_t event
Definition: ng_ubt_var.h:0
u_int16_t rulenum
Definition: ng_ipfw.c:99
u_int32_t version
Definition: netgraph.h:1077