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 */
50 #include <sys/param.h> /* NGROUPS */
53 #include <linux/module.h>
54 #include <linux/kernel.h>
55 #include <linux/netfilter.h>
56 #include <linux/netfilter_ipv4.h> /* NF_IP_PRI_FILTER */
58 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
59 #include <net/netfilter/nf_queue.h> /* nf_queue */
62 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
66 #endif /* !__linux__ */
68 #include <netinet/in.h> /* in_addr */
69 #include <netinet/ip_fw.h> /* ip_fw_ctl_t, ip_fw_chk_t */
70 #include <netinet/ip_dummynet.h> /* ip_dn_ctl_t, ip_dn_io_t */
71 #include <net/pfil.h> /* PFIL_IN, PFIL_OUT */
72 #include <net/inet_hashtables.h> /* inet_lookup */
73 #include <net/route.h> /* inet_iif */
76 * Here we allocate some global variables used in the firewall.
78 ip_dn_ctl_t *ip_dn_ctl_ptr;
79 ip_fw_ctl_t *ip_fw_ctl_ptr;
81 ip_dn_io_t *ip_dn_io_ptr;
82 ip_fw_chk_t *ip_fw_chk_ptr;
84 void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
87 * Glue code to implement the registration of children with the parent.
88 * Each child should call my_mod_register() when linking, so that
89 * module_init() and module_exit() can call init_children() and
90 * fini_children() to provide the necessary initialization.
92 #include <sys/module.h>
94 struct moduledata *mod;
99 static unsigned int mod_idx;
100 static struct mod_args mods[10]; /* hard limit to 10 modules */
103 * Data structure to cache our ucred related
104 * information. This structure only gets used if
105 * the user specified UID/GID based constraints in
109 gid_t fw_groups[NGROUPS];
116 * my_mod_register should be called automatically as the init
117 * functions in the submodules. Unfortunately this compiler/linker
118 * trick is not supported yet so we call it manually.
121 my_mod_register(struct moduledata *mod, const char *name, int order)
123 struct mod_args m = { mod, name, order };
125 printf("%s %s called\n", __FUNCTION__, name);
126 if (mod_idx < sizeof(mods) / sizeof(mods[0]))
136 /* Call the functions registered at init time. */
137 printf("%s mod_idx value %d\n", __FUNCTION__, mod_idx);
138 for (i = 0; i < mod_idx; i++) {
139 printf("+++ start module %d %s %s at %p order 0x%x\n",
140 i, mods[i].name, mods[i].mod->name,
141 mods[i].mod, mods[i].order);
142 mods[i].mod->evhand(NULL, MOD_LOAD, mods[i].mod->priv);
151 /* Call the functions registered at init time. */
152 for (i = mod_idx - 1; i >= 0; i--) {
153 printf("+++ end module %d %s %s at %p order 0x%x\n",
154 i, mods[i].name, mods[i].mod->name,
155 mods[i].mod, mods[i].order);
156 mods[i].mod->evhand(NULL, MOD_UNLOAD, mods[i].mod->priv);
159 /*--- end of module bindinghelper functions ---*/
163 * ipfw_ctl_h() is a wrapper for linux to FreeBSD sockopt call convention.
164 * then call the ipfw handler in order to manage requests.
165 * In turn this is called by the linux set/get handlers.
168 ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user)
173 memset(s, 0, sizeof(s));
176 s->sopt_valsize = len;
179 /* sopt_td is not used but it is referenced */
180 memset(&t, 0, sizeof(t));
183 // printf("%s called with cmd %d len %d\n", __FUNCTION__, cmd, len);
185 if (cmd < IP_DUMMYNET_CONFIGURE && ip_fw_ctl_ptr)
186 ret = ip_fw_ctl_ptr(s);
187 else if (cmd >= IP_DUMMYNET_CONFIGURE && ip_dn_ctl_ptr)
188 ret = ip_dn_ctl_ptr(s);
190 return -ret; /* errors are < 0 on linux */
196 netisr_dispatch(int __unused num, struct mbuf *m)
201 ip_output(struct mbuf *m, struct mbuf __unused *opt,
202 struct route __unused *ro, int __unused flags,
203 struct ip_moptions __unused *imo, struct inpcb __unused *inp)
205 netisr_dispatch(0, m);
209 #else /* this is the linux glue */
211 * setsockopt hook has no return value other than the error code.
214 do_ipfw_set_ctl(struct sock __unused *sk, int cmd,
215 void __user *user, unsigned int len)
217 struct sockopt s; /* pass arguments */
219 return ipfw_ctl_h(&s, cmd, SOPT_SET, len, user);
223 * getsockopt can can return a block of data in response.
226 do_ipfw_get_ctl(struct sock __unused *sk,
227 int cmd, void __user *user, int *len)
229 struct sockopt s; /* pass arguments */
230 int ret = ipfw_ctl_h(&s, cmd, SOPT_GET, *len, user);
232 *len = s.sopt_valsize; /* return lenght back to the caller */
237 * declare our [get|set]sockopt hooks
239 static struct nf_sockopt_ops ipfw_sockopts = {
241 .set_optmin = _IPFW_SOCKOPT_BASE,
242 .set_optmax = _IPFW_SOCKOPT_END,
243 .set = do_ipfw_set_ctl,
244 .get_optmin = _IPFW_SOCKOPT_BASE,
245 .get_optmax = _IPFW_SOCKOPT_END,
246 .get = do_ipfw_get_ctl,
247 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
248 .owner = THIS_MODULE,
253 * We need a number of macros to adapt to the various APIs in
254 * different linux versions. Among them:
256 * - the hook names change between macros (NF_IP*) and enum NF_INET_*
258 * - the second argument to the netfilter hook is
259 * struct sk_buff ** in kernels <= 2.6.22
260 * struct sk_buff * in kernels > 2.6.22
262 * - NF_STOP is not defined before 2.6 so we remap it to NF_ACCEPT
264 * - the packet descriptor passed to the queue handler is
265 * struct nf_info in kernels <= 2.6.24
266 * struct nf_queue_entry in kernels <= 2.6.24
268 * - the arguments to the queue handler also change;
272 * declare hook to grab packets from the netfilter interface.
273 * The NF_* names change in different versions of linux, in some
274 * cases they are #defines, in others they are enum, so we
277 #ifndef NF_IP_PRE_ROUTING
278 #define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
280 #ifndef NF_IP_POST_ROUTING
281 #define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
285 * ipfw hooks the POST_ROUTING and the PRE_ROUTING chain.
286 * PlanetLab tags the xid in the LOCAL_INPUT and in the
287 * POST_ROUTING chain, so if we want to intercept the
288 * traffic by using the id we need to hook the LOCAL_INPUT
289 * chain instead of the PRE_ROUTING.
291 #ifdef IPFW_PLANETLAB
292 #define IPFW_HOOK_IN NF_IP_LOCAL_IN
294 #define IPFW_HOOK_IN NF_IP_PRE_ROUTING
298 * The main netfilter hook.
299 * To make life simple, we queue everything and then do all the
300 * decision in the queue handler.
302 * XXX note that in 2.4 and up to 2.6.22 the skbuf is passed as sk_buff**
303 * so we have an #ifdef to set the proper argument type.
306 call_ipfw(unsigned int __unused hooknum,
307 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) // in 2.6.22 we have **
308 struct sk_buff __unused **skb,
310 struct sk_buff __unused *skb,
312 const struct net_device __unused *in,
313 const struct net_device __unused *out,
314 int __unused (*okfn)(struct sk_buff *))
319 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
320 #define NF_STOP NF_ACCEPT
323 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
326 * nf_queue_entry is a recent addition, in previous versions
327 * of the code the struct is called nf_info.
329 #define nf_queue_entry nf_info /* for simplicity */
331 /* also, 2.4 and perhaps something else have different arguments */
332 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* unsure on the exact boundary */
333 /* on 2.4 we use nf_info */
334 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, void *data
335 #else /* 2.6.1.. 2.6.24 */
336 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data
339 #define DEFINE_SKB /* nothing, already an argument */
340 #define REINJECT(_inf, _verd) nf_reinject(skb, _inf, _verd)
342 #else /* 2.6.25 and above */
344 #define QH_ARGS struct nf_queue_entry *info, unsigned int queuenum
345 #define DEFINE_SKB struct sk_buff *skb = info->skb;
346 #define REINJECT(_inf, _verd) nf_reinject(_inf, _verd)
350 * used by dummynet when dropping packets
351 * XXX use dummynet_send()
354 reinject_drop(struct mbuf* m)
356 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) /* unsure on the exact boundary */
357 struct sk_buff *skb = (struct sk_buff *)m;
359 REINJECT(m->queue_entry, NF_DROP);
363 * The real call to the firewall. nf_queue_entry points to the skbuf,
364 * and eventually we need to return both through nf_reinject().
367 ipfw2_queue_handler(QH_ARGS)
369 DEFINE_SKB /* no semicolon here, goes in the macro */
370 int ret = 0; /* return value */
373 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
374 if (skb->nh.iph == NULL) {
375 printf("null dp, len %d reinject now\n", skb->len);
376 REINJECT(info, NF_ACCEPT);
380 m = malloc(sizeof(*m), 0, 0);
382 printf("malloc fail, len %d reinject now\n", skb->len);
383 REINJECT(info, NF_ACCEPT);
388 m->m_len = skb->len; /* len in this skbuf */
389 m->m_pkthdr.len = skb->len; /* total packet len */
390 m->m_pkthdr.rcvif = info->indev;
391 m->queue_entry = info;
392 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
393 m->m_data = skb->nh.iph;
395 m->m_data = skb_network_header(skb);
398 /* XXX add the interface */
399 if (info->hook == IPFW_HOOK_IN) {
400 ret = ipfw_check_in(NULL, &m, info->indev, PFIL_IN, NULL);
402 ret = ipfw_check_out(NULL, &m, info->outdev, PFIL_OUT, NULL);
405 if (m != NULL) { /* Accept. reinject and free the mbuf */
406 REINJECT(info, NF_STOP);
408 } else if (ret == 0) {
409 /* dummynet has kept the packet, will reinject later. */
412 * Packet dropped by ipfw or dummynet, reinject as NF_DROP
413 * mbuf already released by ipfw itself
415 REINJECT(info, NF_DROP);
425 /* XXX should include prototypes for netisr_dispatch and ip_output */
427 * The reinjection routine after a packet comes out from dummynet.
428 * We must update the skb timestamp so ping reports the right time.
431 netisr_dispatch(int num, struct mbuf *m)
433 struct nf_queue_entry *info = m->queue_entry;
434 struct sk_buff *skb = m->m_skb; /* always used */
438 KASSERT((info != NULL), ("%s info null!\n", __FUNCTION__));
439 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) // XXX above 2.6.x ?
440 __net_timestamp(skb); /* update timestamp */
443 /* XXX to obey one-pass, possibly call the queue handler here */
444 REINJECT(info, ((num == -1)?NF_DROP:NF_STOP)); /* accept but no more firewall */
448 ip_output(struct mbuf *m, struct mbuf __unused *opt,
449 struct route __unused *ro, int __unused flags,
450 struct ip_moptions __unused *imo, struct inpcb __unused *inp)
452 netisr_dispatch(0, m);
457 * socket lookup function for linux.
458 * This code is used to associate uid, gid, jail/xid to packets,
459 * and store the info in a cache *ugp where they can be accessed quickly.
460 * The function returns 1 if the info is found, -1 otherwise.
462 * We do this only on selected protocols: TCP, ...
464 * Note- for locally generated, outgoing packets we don't need to
465 * do a lookup because the sk_buff already points to the socket where
468 extern struct inet_hashinfo tcp_hashinfo;
470 linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
471 const __be32 daddr, const __be16 dport,
472 struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp)
475 int ret = -1; /* default return value */
476 int uid = -1; /* user id */
477 int st = -1; /* state */
479 if (proto != IPPROTO_TCP)
482 if ((dir ? (void *)skb->dst : (void *)skb->dev) == NULL) {
483 panic(" -- this should not happen\n");
488 * inet_lookup above 2.6.24 has an additional 'net' parameter
489 * so we use a macro to conditionally supply it.
490 * Also we need to switch dst and src depending on the direction.
492 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
494 #else /* 2.6.25 and above */
495 #define _OPT_NET_ARG dev_net(skb->dev),
499 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
500 daddr, dport, saddr, sport, // matches outgoing for server sockets
502 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
503 saddr, sport, daddr, dport, // matches incoming for server sockets
507 /* no match, nothing to be done */
512 * On a match, sk is returned with a refcount.
513 * In tcp some states reference a valid struct sock
514 * which is what we want, otherwise the struct sock
515 * referenced can be invalid, as in the case of the
516 * TCP_TIME_WAIT state, when it references a
517 * struct inet_timewait_sock which does not point to credentials.
518 * To be safe we exclude TCP_CLOSE and TCP_LAST_ACK states too.
520 * Once again we need conditional code because the UID and GID
521 * location changes between the two kernels.
523 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
524 /* use the current's real uid/gid */
525 #define _CURR_UID f_uid
526 #define _CURR_GID f_gid
527 #else /* 2.6.29 and above */
528 /* use the current's file access real uid/gid */
529 #define _CURR_UID f_cred->fsuid
530 #define _CURR_GID f_cred->fsgid
533 if (st != TCP_TIME_WAIT && st != TCP_CLOSE && st != TCP_LAST_ACK &&
534 sk->sk_socket && sk->sk_socket->file) {
535 ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
543 //printf("%s dir %d sb>dst %p sb>dev %p ret %d id %d st%d\n", __FUNCTION__, dir, skb->dst, skb->dev, ret, uid, st);
548 * Now prepare to hook the various functions.
549 * Linux 2.4 has a different API so we need some adaptation
550 * for register and unregister hooks
552 * the unregister function changed arguments between 2.6.22 and 2.6.24
554 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
556 nf_register_hooks(struct nf_hook_ops *ops, int n)
559 for (i = 0; i < n; i++) {
560 ret = nf_register_hook(ops + i);
568 nf_unregister_hooks(struct nf_hook_ops *ops, int n)
571 for (i = 0; i < n; i++) {
572 nf_unregister_hook(ops + i);
575 #define REG_QH_ARG(fn) fn, NULL /* argument for nf_[un]register_queue_handler */
576 #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */
577 #define SET_MOD_OWNER
579 #else /* linux >= 2.6.0 */
581 struct nf_queue_handler ipfw2_queue_handler_desc = {
582 .outfn = ipfw2_queue_handler,
583 .name = "ipfw2 dummynet queue",
585 #define REG_QH_ARG(fn) &(fn ## _desc)
587 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
588 #define UNREG_QH_ARG(fn) //fn /* argument for nf_[un]register_queue_handler */
590 #define UNREG_QH_ARG(fn) , &(fn ## _desc)
591 #endif /* 2.6.0 < LINUX > 2.6.24 */
593 #define SET_MOD_OWNER .owner = THIS_MODULE,
595 #endif /* !LINUX < 2.6.0 */
597 static struct nf_hook_ops ipfw_ops[] __read_mostly = {
601 .hooknum = IPFW_HOOK_IN,
602 .priority = NF_IP_PRI_FILTER,
608 .hooknum = NF_IP_POST_ROUTING,
609 .priority = NF_IP_PRI_FILTER,
613 #endif /* !__linux__ */
615 /* descriptors for the children */
616 extern moduledata_t *moddesc_ipfw;
617 extern moduledata_t *moddesc_dummynet;
620 * Module glue - init and exit function.
623 ipfw_module_init(void)
627 printf("%s in-hook %d svn id %s\n", __FUNCTION__, IPFW_HOOK_IN, "$Id$");
629 my_mod_register(moddesc_ipfw, "ipfw", 1);
630 my_mod_register(moddesc_dummynet, "dummynet", 2);
636 #else /* linux hook */
637 /* sockopt register, in order to talk with user space */
638 ret = nf_register_sockopt(&ipfw_sockopts);
640 printf("error %d in nf_register_sockopt\n", ret);
644 /* queue handler registration, in order to get network
645 * packet under a private queue */
646 ret = nf_register_queue_handler(PF_INET, REG_QH_ARG(ipfw2_queue_handler) );
647 if (ret < 0) /* queue busy */
648 goto unregister_sockopt;
650 ret = nf_register_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
652 goto unregister_sockopt;
654 printf("%s loaded\n", __FUNCTION__);
658 /* handle errors on load */
660 nf_unregister_queue_handler(PF_INET UNREG_QH_ARG(ipfw2_queue_handler) );
661 nf_unregister_sockopt(&ipfw_sockopts);
665 printf("%s error\n", __FUNCTION__);
671 /* module shutdown */
673 ipfw_module_exit(void)
676 #else /* linux hook */
677 nf_unregister_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
678 /* maybe drain the queue before unregistering ? */
679 nf_unregister_queue_handler(PF_INET UNREG_QH_ARG(ipfw2_queue_handler) );
680 nf_unregister_sockopt(&ipfw_sockopts);
685 printf("%s unloaded\n", __FUNCTION__);
689 module_init(ipfw_module_init)
690 module_exit(ipfw_module_exit)
691 MODULE_LICENSE("Dual BSD/GPL"); /* the code here is all BSD. */