2 * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * The main interface to build ipfw+dummynet as a linux module.
30 * (and possibly as a windows module as well, though that part
31 * is not complete yet).
33 * The control interface uses the sockopt mechanism
34 * on a socket(AF_INET, SOCK_RAW, IPPROTO_RAW).
36 * The data interface uses the netfilter interface, at the moment
37 * hooked to the PRE_ROUTING and POST_ROUTING hooks.
38 * Unfortunately the netfilter interface is a moving target,
39 * so we need a set of macros to adapt to the various cases.
41 * In the netfilter hook we just mark packet as 'QUEUE' and then
42 * let the queue handler to do the whole work (filtering and
43 * possibly emulation).
44 * As we receive packets, we wrap them with an mbuf descriptor
45 * so the existing ipfw+dummynet code runs unmodified.
48 #include <sys/cdefs.h>
49 #include <sys/mbuf.h> /* sizeof struct mbuf */
52 #include <linux/module.h>
53 #include <linux/kernel.h>
54 #include <linux/netfilter.h>
55 #include <linux/netfilter_ipv4.h> /* NF_IP_PRI_FILTER */
57 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
58 #include <net/netfilter/nf_queue.h> /* nf_queue */
61 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
65 #endif /* !__linux__ */
67 #include <netinet/in.h> /* in_addr */
68 #include <netinet/ip_fw.h> /* ip_fw_ctl_t, ip_fw_chk_t */
69 #include <netinet/ip_dummynet.h> /* ip_dn_ctl_t, ip_dn_io_t */
70 #include <net/pfil.h> /* PFIL_IN, PFIL_OUT */
73 * Here we allocate some global variables used in the firewall.
75 ip_dn_ctl_t *ip_dn_ctl_ptr;
76 ip_fw_ctl_t *ip_fw_ctl_ptr;
78 ip_dn_io_t *ip_dn_io_ptr;
79 ip_fw_chk_t *ip_fw_chk_ptr;
81 void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
84 * Glue code to implement the registration of children with the parent.
85 * Each child should call my_mod_register() when linking, so that
86 * module_init() and module_exit() can call init_children() and
87 * fini_children() to provide the necessary initialization.
89 #include <sys/module.h>
91 struct moduledata *mod;
96 static unsigned int mod_idx;
97 static struct mod_args mods[10]; /* hard limit to 10 modules */
100 * my_mod_register should be called automatically as the init
101 * functions in the submodules. Unfortunately this compiler/linker
102 * trick is not supported yet so we call it manually.
105 my_mod_register(struct moduledata *mod, const char *name, int order)
107 struct mod_args m = { mod, name, order };
109 printf("%s %s called\n", __FUNCTION__, name);
110 if (mod_idx < sizeof(mods) / sizeof(mods[0]))
120 /* Call the functions registered at init time. */
121 printf("%s mod_idx value %d\n", __FUNCTION__, mod_idx);
122 for (i = 0; i < mod_idx; i++) {
123 printf("+++ start module %d %s %s at %p order 0x%x\n",
124 i, mods[i].name, mods[i].mod->name,
125 mods[i].mod, mods[i].order);
126 mods[i].mod->evhand(NULL, MOD_LOAD, mods[i].mod->priv);
135 /* Call the functions registered at init time. */
136 for (i = mod_idx - 1; i >= 0; i--) {
137 printf("+++ end module %d %s %s at %p order 0x%x\n",
138 i, mods[i].name, mods[i].mod->name,
139 mods[i].mod, mods[i].order);
140 mods[i].mod->evhand(NULL, MOD_UNLOAD, mods[i].mod->priv);
143 /* end of module bindinghelper functions */
147 * ipfw_ctl_h() is a wrapper for linux to FreeBSD sockopt call convention.
148 * then call the ipfw handler in order to manage requests.
149 * In turn this is called by the linux set/get handlers.
152 ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user)
157 memset(s, 0, sizeof(s));
160 s->sopt_valsize = len;
163 /* sopt_td is not used but it is referenced */
164 memset(&t, 0, sizeof(t));
167 printf("%s called with cmd %d len %d\n", __FUNCTION__, cmd, len);
169 if (cmd < IP_DUMMYNET_CONFIGURE && ip_fw_ctl_ptr)
170 ret = ip_fw_ctl_ptr(s);
171 else if (cmd >= IP_DUMMYNET_CONFIGURE && ip_dn_ctl_ptr)
172 ret = ip_dn_ctl_ptr(s);
174 return -ret; /* errors are < 0 on linux */
180 netisr_dispatch(int __unused num, struct mbuf *m)
185 ip_output(struct mbuf *m, struct mbuf __unused *opt,
186 struct route __unused *ro, int __unused flags,
187 struct ip_moptions __unused *imo, struct inpcb __unused *inp)
189 netisr_dispatch(0, m);
193 #else /* this is the linux glue */
195 * setsockopt hook has no return value other than the error code.
198 do_ipfw_set_ctl(struct sock __unused *sk, int cmd,
199 void __user *user, unsigned int len)
201 struct sockopt s; /* pass arguments */
203 return ipfw_ctl_h(&s, cmd, SOPT_SET, len, user);
207 * getsockopt can can return a block of data in response.
210 do_ipfw_get_ctl(struct sock __unused *sk,
211 int cmd, void __user *user, int *len)
213 struct sockopt s; /* pass arguments */
214 int ret = ipfw_ctl_h(&s, cmd, SOPT_GET, *len, user);
216 *len = s.sopt_valsize; /* return lenght back to the caller */
221 * declare our [get|set]sockopt hooks
223 static struct nf_sockopt_ops ipfw_sockopts = {
225 .set_optmin = _IPFW_SOCKOPT_BASE,
226 .set_optmax = _IPFW_SOCKOPT_END,
227 .set = do_ipfw_set_ctl,
228 .get_optmin = _IPFW_SOCKOPT_BASE,
229 .get_optmax = _IPFW_SOCKOPT_END,
230 .get = do_ipfw_get_ctl,
231 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
232 .owner = THIS_MODULE,
237 * declare hook to grab packets from the netfilter interface.
238 * The NF_* names change in different versions of linux, in some
239 * cases they are #defines, in others they are enum, so we
242 #ifndef NF_IP_PRE_ROUTING
243 #define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
245 #ifndef NF_IP_POST_ROUTING
246 #define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
250 * The main netfilter hook.
251 * To make life simple, we queue everything and then do all the
252 * decision in the queue handler.
254 * XXX note that in 2.4 the skbuf is passed as sk_buff**
257 call_ipfw(unsigned int __unused hooknum,
258 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) // in 2.6.22 we have **
259 struct sk_buff __unused **skb,
261 struct sk_buff __unused *skb,
263 const struct net_device __unused *in,
264 const struct net_device __unused *out,
265 int __unused (*okfn)(struct sk_buff *))
270 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
271 #define NF_STOP NF_ACCEPT
274 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
276 #define nf_queue_entry nf_info /* for simplicity */
277 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* unsure on the exact boundary */
278 /* on 2.4 we use nf_info */
279 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, void *data
280 #else /* 2.6.1.. 2.6.24 */
281 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data
284 #define DEFINE_SKB /* nothing, already an argument */
285 #define REINJECT(_inf, _verd) nf_reinject(skb, _inf, _verd)
287 #else /* 2.6.25 and above */
289 #define QH_ARGS struct nf_queue_entry *info, unsigned int queuenum
290 #define DEFINE_SKB struct sk_buff *skb = info->skb;
291 #define REINJECT(_inf, _verd) nf_reinject(_inf, _verd)
295 * used by dummynet when dropping packets
296 * XXX use dummynet_send()
299 reinject_drop(struct mbuf* m)
301 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) /* unsure on the exact boundary */
302 struct sk_buff *skb = (struct sk_buff *)m;
304 REINJECT(m->queue_entry, NF_DROP);
308 * The real call to the firewall. nf_queue_entry points to the skbuf,
309 * and eventually we need to return both through nf_reinject().
312 ipfw2_queue_handler(QH_ARGS)
314 DEFINE_SKB /* no semicolon here, goes in the macro */
315 int ret = 0; /* return value */
318 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
319 if (skb->nh.iph == NULL) {
320 printf("null dp, len %d reinject now\n", skb->len);
321 REINJECT(info, NF_ACCEPT);
325 m = malloc(sizeof(*m), 0, 0);
327 printf("malloc fail, len %d reinject now\n", skb->len);
328 REINJECT(info, NF_ACCEPT);
333 m->m_len = skb->len; /* len in this skbuf */
334 m->m_pkthdr.len = skb->len; /* total packet len */
335 m->m_pkthdr.rcvif = info->indev;
336 m->queue_entry = info;
337 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
338 m->m_data = skb->nh.iph;
340 m->m_data = skb_network_header(skb);
342 /* XXX add the interface */
343 if (info->hook == NF_IP_PRE_ROUTING) {
344 ret = ipfw_check_in(NULL, &m, info->indev, PFIL_IN, NULL);
346 ret = ipfw_check_out(NULL, &m, info->outdev, PFIL_OUT, NULL);
349 if (m != NULL) { /* Accept. reinject and free the mbuf */
350 REINJECT(info, NF_STOP);
352 } else if (ret == 0) {
353 /* dummynet has kept the packet, will reinject later. */
356 * Packet dropped by ipfw or dummynet, reinject as NF_DROP
357 * mbuf already released by ipfw itself
359 REINJECT(info, NF_DROP);
369 /* XXX should include prototypes for netisr_dispatch and ip_output */
371 * The reinjection routine after a packet comes out from dummynet.
372 * We must update the skb timestamp so ping reports the right time.
375 netisr_dispatch(int num, struct mbuf *m)
377 struct nf_queue_entry *info = m->queue_entry;
378 struct sk_buff *skb = m->m_skb; /* always used */
381 KASSERT((info != NULL), ("%s info null!\n", __FUNCTION__));
382 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) // XXX above 2.6.x ?
383 __net_timestamp(skb); /* update timestamp */
386 /* XXX to obey one-pass, possibly call the queue handler here */
387 REINJECT(info, ((num == -1)?NF_DROP:NF_STOP)); /* accept but no more firewall */
391 ip_output(struct mbuf *m, struct mbuf __unused *opt,
392 struct route __unused *ro, int __unused flags,
393 struct ip_moptions __unused *imo, struct inpcb __unused *inp)
395 netisr_dispatch(0, m);
401 * Now prepare to hook the various functions.
402 * Linux 2.4 has a different API so we need some adaptation
403 * for register and unregister hooks
405 * the unregister function changed arguments between 2.6.22 and 2.6.24
407 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
409 nf_register_hooks(struct nf_hook_ops *ops, int n)
412 for (i = 0; i < n; i++) {
413 ret = nf_register_hook(ops + i);
421 nf_unregister_hooks(struct nf_hook_ops *ops, int n)
424 for (i = 0; i < n; i++) {
425 nf_unregister_hook(ops + i);
428 #define REG_QH_ARG(fn) fn, NULL /* argument for nf_[un]register_queue_handler */
429 #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */
430 #define SET_MOD_OWNER
432 #else /* linux >= 2.6.0 */
434 struct nf_queue_handler ipfw2_queue_handler_desc = {
435 .outfn = ipfw2_queue_handler,
436 .name = "ipfw2 dummynet queue",
438 #define REG_QH_ARG(fn) &(fn ## _desc)
440 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
441 #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */
443 #define UNREG_QH_ARG(fn) , &(fn ## _desc)
444 #endif /* 2.6.0 < LINUX > 2.6.24 */
446 #define SET_MOD_OWNER .owner = THIS_MODULE,
448 #endif /* !LINUX < 2.6.0 */
450 static struct nf_hook_ops ipfw_ops[] __read_mostly = {
454 .hooknum = NF_IP_PRE_ROUTING,
455 .priority = NF_IP_PRI_FILTER,
461 .hooknum = NF_IP_POST_ROUTING,
462 .priority = NF_IP_PRI_FILTER,
466 #endif /* !__linux__ */
468 /* descriptors for the children */
469 extern moduledata_t *moddesc_ipfw;
470 extern moduledata_t *moddesc_dummynet;
473 * Module glue - init and exit function.
476 ipfw_module_init(void)
480 printf("%s called\n", __FUNCTION__);
482 my_mod_register(moddesc_ipfw, "ipfw", 1);
483 my_mod_register(moddesc_dummynet, "dummynet", 2);
489 #else /* linux hook */
490 /* sockopt register, in order to talk with user space */
491 ret = nf_register_sockopt(&ipfw_sockopts);
493 printf("error %d in nf_register_sockopt\n", ret);
497 /* queue handler registration, in order to get network
498 * packet under a private queue */
499 ret = nf_register_queue_handler(PF_INET, REG_QH_ARG(ipfw2_queue_handler) );
500 if (ret < 0) /* queue busy */
501 goto unregister_sockopt;
503 ret = nf_register_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
505 goto unregister_sockopt;
507 printf("%s loaded\n", __FUNCTION__);
511 /* handle errors on load */
513 nf_unregister_queue_handler(PF_INET UNREG_QH_ARG(ipfw2_queue_handler) );
514 nf_unregister_sockopt(&ipfw_sockopts);
518 printf("%s error\n", __FUNCTION__);
524 /* module shutdown */
526 ipfw_module_exit(void)
529 #else /* linux hook */
530 nf_unregister_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
531 /* maybe drain the queue before unregistering ? */
532 nf_unregister_queue_handler(PF_INET UNREG_QH_ARG(ipfw2_queue_handler) );
533 nf_unregister_sockopt(&ipfw_sockopts);
538 printf("%s unloaded\n", __FUNCTION__);
542 module_init(ipfw_module_init)
543 module_exit(ipfw_module_exit)
544 MODULE_LICENSE("GPL"); /* mandatory */