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
27 * $Id: ipfw2_mod.c 12501 2014-01-10 01:09:14Z luigi $
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 #define ND(fmt, ...) do {} while (0)
54 #define D1(fmt, ...) do {} while (0)
55 #define D(fmt, ...) printf("%-10s " fmt "\n", \
56 __FUNCTION__, ## __VA_ARGS__)
60 #include <linux/module.h>
61 #include <linux/kernel.h>
63 #ifndef CONFIG_NETFILTER
64 #error should configure netfilter (broken on 2.6.26 and below ?)
67 #include <linux/netfilter.h>
68 #include <linux/netfilter_ipv4.h> /* NF_IP_PRI_FILTER */
70 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
71 #include <net/netfilter/nf_queue.h> /* nf_queue */
74 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
78 #endif /* !__linux__ */
80 #include <netinet/in.h> /* in_addr */
81 #include <netinet/ip_fw.h> /* ip_fw_ctl_t, ip_fw_chk_t */
82 #include <netinet/ipfw/ip_fw_private.h> /* ip_fw_ctl_t, ip_fw_chk_t */
83 #include <netinet/ip_dummynet.h> /* ip_dn_ctl_t, ip_dn_io_t */
84 #include <net/pfil.h> /* PFIL_IN, PFIL_OUT */
88 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
89 /* XXX was < 2.6.0: inet_hashtables.h is introduced in 2.6.14 */
90 // #warning --- inet_hashtables not present on 2.4
91 #include <linux/tcp.h>
92 #include <net/route.h>
94 static inline int inet_iif(const struct sk_buff *skb)
96 return ((struct rtable *)skb->dst)->rt_iif;
100 #include <net/inet_hashtables.h> /* inet_lookup */
102 #endif /* __linux__ */
104 #include <net/route.h> /* inet_iif */
107 * Here we allocate some global variables used in the firewall.
109 //ip_dn_ctl_t *ip_dn_ctl_ptr;
110 int (*ip_dn_ctl_ptr)(struct sockopt *);
112 ip_fw_ctl_t *ip_fw_ctl_ptr;
114 int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
115 ip_fw_chk_t *ip_fw_chk_ptr;
117 void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
120 void (*ip_divert_ptr)(struct mbuf *m, int incoming);
123 ng_ipfw_input_t *ng_ipfw_input_p = NULL;
126 * Glue code to implement the registration of children with the parent.
127 * Each child should call my_mod_register() when linking, so that
128 * module_init() and module_exit() can call init_children() and
129 * fini_children() to provide the necessary initialization.
130 * We use the same mechanism for MODULE_ and SYSINIT_.
131 * The former only get a pointer to the moduledata,
132 * the latter have two function pointers (init/uninit)
134 #include <sys/module.h>
138 struct moduledata *mod;
139 void (*init)(void), (*uninit)(void);
142 static unsigned int mod_idx;
143 static struct mod_args mods[10]; /* hard limit to 10 modules */
146 my_mod_register(const char *name, int order,
147 struct moduledata *mod, void *init, void *uninit);
149 * my_mod_register should be called automatically as the init
150 * functions in the submodules. Unfortunately this compiler/linker
151 * trick is not supported yet so we call it manually.
154 my_mod_register(const char *name, int order,
155 struct moduledata *mod, void *init, void *uninit)
165 printf("%s %s called\n", __FUNCTION__, name);
166 if (mod_idx < sizeof(mods) / sizeof(mods[0]))
176 /* Call the functions registered at init time. */
177 printf("%s mod_idx value %d\n", __FUNCTION__, mod_idx);
178 for (i = 0; i < mod_idx; i++) {
179 struct mod_args *m = &mods[i];
180 printf("+++ start module %d %s %s at %p order 0x%x\n",
181 i, m->name, m->mod ? m->mod->name : "SYSINIT",
183 if (m->mod && m->mod->evhand)
184 m->mod->evhand(NULL, MOD_LOAD, m->mod->priv);
195 /* Call the functions registered at init time. */
196 for (i = mod_idx - 1; i >= 0; i--) {
197 struct mod_args *m = &mods[i];
198 printf("+++ end module %d %s %s at %p order 0x%x\n",
199 i, m->name, m->mod ? m->mod->name : "SYSINIT",
201 if (m->mod && m->mod->evhand)
202 m->mod->evhand(NULL, MOD_UNLOAD, m->mod->priv);
207 /*--- end of module binding helper functions ---*/
211 * ipfw_ctl_h() is a wrapper for linux to FreeBSD sockopt call convention.
212 * then call the ipfw handler in order to manage requests.
213 * In turn this is called by the linux set/get handlers.
216 ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user)
221 memset(s, 0, sizeof(*s));
224 s->sopt_valsize = len;
227 /* sopt_td is not used but it is referenced */
228 memset(&t, 0, sizeof(t));
231 //printf("%s called with cmd %d len %d sopt %p user %p\n", __FUNCTION__, cmd, len, s, user);
233 if (ip_fw_ctl_ptr && cmd != IP_DUMMYNET3 && (cmd == IP_FW3 ||
234 cmd < IP_DUMMYNET_CONFIGURE))
235 ret = ip_fw_ctl_ptr(s);
236 else if (ip_dn_ctl_ptr && (cmd == IP_DUMMYNET3 ||
237 cmd >= IP_DUMMYNET_CONFIGURE))
238 ret = ip_dn_ctl_ptr(s);
240 return -ret; /* errors are < 0 on linux */
245 * Convert an mbuf into an skbuff
246 * At the moment this only works for ip packets fully contained
247 * in a single mbuf. We assume that on entry ip_len and ip_off are
248 * in host format, and the ip checksum is not computed.
250 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* check boundary */
251 int dst_output(struct skbuff *s)
257 mbuf2skbuff(struct mbuf* m)
263 mbuf2skbuff(struct mbuf* m)
266 size_t len = m->m_pkthdr.len;
268 /* used to lookup the routing table */
271 int ret = 0; /* success for ip_route_output_key() */
273 struct ip *ip = mtod(m, struct ip *);
275 /* XXX ip_output has ip_len and ip_off in network format,
276 * linux expects host format */
277 ip->ip_len = ntohs(ip->ip_len);
278 ip->ip_off = ntohs(ip->ip_off);
281 ip->ip_sum = in_cksum(m, ip->ip_hl<<2);
283 /* fill flowi struct, we need just the dst addr, see XXX */
284 bzero(&fl, sizeof(fl));
285 flow_daddr.daddr = ip->ip_dst.s_addr;
288 * ip_route_output_key() should increment
289 * r->u.dst.__use and call a dst_hold(dst)
290 * XXX verify how we release the resources.
292 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,38) /* check boundary */
293 r = ip_route_output_key(&init_net, &fl.u.ip4);
294 #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) /* check boundary */
295 ret = ip_route_output_key(&init_net, &r, &fl);
297 ret = ip_route_output_key(&r, &fl);
299 if (ret != 0 || r == NULL ) {
300 printf("NO ROUTE FOUND\n");
304 /* allocate the skbuff and the data */
305 skb = alloc_skb(len + sizeof(struct ethhdr), GFP_ATOMIC);
307 printf("%s: can not allocate SKB buffers.\n", __FUNCTION__);
311 skb->protocol = htons(ETH_P_IP); // XXX 8 or 16 bit ?
312 /* sk_dst_set XXX take the lock (?) */
313 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
314 skb_dst_set(skb, &r->u.dst);
316 skb_dst_set(skb, &r->dst);
318 skb->dev = skb_dst(skb)->dev;
320 /* reserve space for ethernet header */
321 skb_reserve(skb, sizeof(struct ethhdr));
323 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
324 skb_reset_network_header(skb); // skb->network_header = skb->data - skb->head
326 skb->nh.raw = skb->data;
328 /* set skbuff tail pointers and copy content */
330 memcpy(skb->data, m->m_data, len);
334 #endif /* linux 2.6+ */
339 * This function is called to reinject packets to the
340 * kernel stack within the linux netfilter system
341 * or to send a new created mbuf.
342 * In the first case we have a valid sk_buff pointer
343 * encapsulated within the fake mbuf, so we can call
344 * the reinject function trough netisr_dispatch.
345 * In the last case we need to build a sk_buff from scratch,
346 * before sending out the packet.
349 ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
350 struct ip_moptions *imo, struct inpcb *inp)
352 (void)opt; (void)ro; (void)flags; (void)imo; (void)inp; /* UNUSED */
353 if ( m->m_skb != NULL ) { /* reinjected packet, just call dispatch */
355 netisr_dispatch(0, m);
357 /* self-generated packet, wrap as appropriate and send */
359 struct sk_buff *skb = mbuf2skbuff(m);
372 * setsockopt hook has no return value other than the error code.
375 do_ipfw_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
377 struct sockopt s; /* pass arguments */
378 (void)sk; /* UNUSED */
379 return ipfw_ctl_h(&s, cmd, SOPT_SET, len, user);
383 * getsockopt can can return a block of data in response.
386 do_ipfw_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
388 struct sockopt s; /* pass arguments */
389 int ret = ipfw_ctl_h(&s, cmd, SOPT_GET, *len, user);
391 (void)sk; /* UNUSED */
392 *len = s.sopt_valsize; /* return length back to the caller */
399 * declare our [get|set]sockopt hooks
401 static struct nf_sockopt_ops ipfw_sockopts = {
403 .set_optmin = _IPFW_SOCKOPT_BASE,
404 .set_optmax = _IPFW_SOCKOPT_END,
405 .set = do_ipfw_set_ctl,
406 .get_optmin = _IPFW_SOCKOPT_BASE,
407 .get_optmax = _IPFW_SOCKOPT_END,
408 .get = do_ipfw_get_ctl,
409 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
410 .owner = THIS_MODULE,
415 * We need a number of macros to adapt to the various APIs in
416 * different linux versions. Among them:
418 * - the hook names change between macros (NF_IP*) and enum NF_INET_*
420 * - the second argument to the netfilter hook is
421 * struct sk_buff ** in kernels <= 2.6.22
422 * struct sk_buff * in kernels > 2.6.22
424 * - NF_STOP is not defined before 2.6 so we remap it to NF_ACCEPT
426 * - the packet descriptor passed to the queue handler is
427 * struct nf_info in kernels <= 2.6.24
428 * struct nf_queue_entry in kernels <= 2.6.24
430 * - the arguments to the queue handler also change;
434 * declare hook to grab packets from the netfilter interface.
435 * The NF_* names change in different versions of linux, in some
436 * cases they are #defines, in others they are enum, so we
439 #ifndef NF_IP_PRE_ROUTING
440 #define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
442 #ifndef NF_IP_POST_ROUTING
443 #define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
447 * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains.
448 * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and
449 * POST_ROUTING chains, so if we want to use that information we
450 * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING.
451 * However at the moment the skb_tag info is not reliable so
452 * we stay with the standard hooks.
454 #if 0 // defined(IPFW_PLANETLAB)
455 #define IPFW_HOOK_IN NF_IP_LOCAL_IN
457 #define IPFW_HOOK_IN NF_IP_PRE_ROUTING
461 * The main netfilter hook.
462 * To make life simple, we queue everything and then do all the
463 * decision in the queue handler.
465 * XXX note that in 2.4 and up to 2.6.22 the skbuf is passed as sk_buff**
466 * so we have an #ifdef to set the proper argument type.
470 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
471 unsigned int hooknum,
473 const struct nf_hook_ops *hooknum,
476 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) // in 2.6.22 we have **
477 struct sk_buff **skb,
481 const struct net_device *in, const struct net_device *out,
482 int (*okfn)(struct sk_buff *))
484 (void)hooknum; (void)skb; (void)in; (void)out; (void)okfn; /* UNUSED */
488 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) /* XXX was 2.6.0 */
489 #define NF_STOP NF_ACCEPT
492 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
495 * nf_queue_entry is a recent addition, in previous versions
496 * of the code the struct is called nf_info.
498 #define nf_queue_entry nf_info /* for simplicity */
500 /* also, 2.4 and perhaps something else have different arguments */
501 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* XXX unsure */
502 /* on 2.4 we use nf_info */
503 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, void *data
504 #else /* 2.6.14. 2.6.24 */
505 #define QH_ARGS struct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data
508 #define DEFINE_SKB /* nothing, already an argument */
509 #define REINJECT(_inf, _verd) nf_reinject(skb, _inf, _verd)
511 #else /* 2.6.25 and above */
513 #define QH_ARGS struct nf_queue_entry *info, unsigned int queuenum
514 #define DEFINE_SKB struct sk_buff *skb = info->skb;
515 #define REINJECT(_inf, _verd) nf_reinject(_inf, _verd)
519 * used by dummynet when dropping packets
520 * XXX use dummynet_send()
523 reinject_drop(struct mbuf* m)
525 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) /* unsure on the exact boundary */
526 struct sk_buff *skb = (struct sk_buff *)m;
528 REINJECT(m->queue_entry, NF_DROP);
532 * The real call to the firewall. nf_queue_entry points to the skbuf,
533 * and eventually we need to return both through nf_reinject().
536 ipfw2_queue_handler(QH_ARGS)
538 DEFINE_SKB /* no semicolon here, goes in the macro */
539 int ret = 0; /* return value */
542 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
543 if (skb->nh.iph == NULL) {
544 printf("null dp, len %d reinject now\n", skb->len);
545 REINJECT(info, NF_ACCEPT);
549 m = malloc(sizeof(*m), 0, 0);
551 printf("malloc fail, len %d reinject now\n", skb->len);
552 REINJECT(info, NF_ACCEPT);
557 m->m_len = skb->len; /* len from ip header to end */
558 m->m_pkthdr.len = skb->len; /* total packet len */
559 m->m_pkthdr.rcvif = info->indev;
560 m->queue_entry = info;
561 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) /* XXX was 2.6.0 */
562 m->m_data = (char *)skb->nh.iph;
564 m->m_data = (char *)skb_network_header(skb); // XXX unsigned ? */
567 /* XXX add the interface */
568 if (info->hook == IPFW_HOOK_IN) {
569 ret = ipfw_check_hook(NULL, &m, info->indev, PFIL_IN, NULL);
571 ret = ipfw_check_hook(NULL, &m, info->outdev, PFIL_OUT, NULL);
574 if (m != NULL) { /* Accept. reinject and free the mbuf */
575 REINJECT(info, NF_ACCEPT);
577 } else if (ret == 0) {
578 /* dummynet has kept the packet, will reinject later. */
581 * Packet dropped by ipfw or dummynet. Nothing to do as
582 * FREE_PKT already did a reinject as NF_DROP
592 /* XXX should include prototypes for netisr_dispatch and ip_output */
594 * The reinjection routine after a packet comes out from dummynet.
595 * We must update the skb timestamp so ping reports the right time.
596 * This routine is also used (with num == -1) as FREE_PKT. XXX
599 netisr_dispatch(int num, struct mbuf *m)
601 struct nf_queue_entry *info = m->queue_entry;
602 struct sk_buff *skb = m->m_skb; /* always used */
605 * This function can be called by the FREE_PKT()
606 * used when ipfw generate their own mbuf packets
607 * or by the mbuf2skbuff() function.
612 * info is null in the case of a real mbuf
613 * (one created by the ipfw code without a
614 * valid sk_buff pointer
619 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) // XXX above 2.6.x ?
620 __net_timestamp(skb); /* update timestamp */
623 /* XXX to obey one-pass, possibly call the queue handler here */
624 REINJECT(info, ((num == -1)?NF_DROP:NF_STOP)); /* accept but no more firewall */
628 * socket lookup function for linux.
629 * This code is used to associate uid, gid, jail/xid to packets,
630 * and store the info in a cache *ugp where they can be accessed quickly.
631 * The function returns 1 if the info is found, -1 otherwise.
633 * We do this only on selected protocols: TCP, ...
635 * The chain is the following
636 * sk_buff* sock* socket* file*
637 * skb -> sk ->sk_socket->file ->f_owner ->pid
638 * skb -> sk ->sk_socket->file ->f_uid (direct)
639 * skb -> sk ->sk_socket->file ->f_cred->fsuid (2.6.29+)
642 * linux/skbuff.h struct skbuff
643 * net/sock.h struct sock
644 * linux/net.h struct socket
645 * linux/fs.h struct file
647 * With vserver we may have sk->sk_xid and sk->sk_nid that
648 * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2]
651 * Note- for locally generated, outgoing packets we should not need
652 * need a lookup because the sk_buff already points to the socket where
655 extern struct inet_hashinfo tcp_hashinfo;
657 linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
658 const __be32 daddr, const __be16 dport,
659 struct sk_buff *skb, int dir, struct bsd_ucred *u)
661 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) /* XXX was 2.6.0 */
665 int ret = -1; /* default return value */
666 int st = -1; /* state */
669 if (proto != IPPROTO_TCP) /* XXX extend for UDP */
672 if ((dir ? (void *)skb_dst(skb) : (void *)skb->dev) == NULL) {
673 panic(" -- this should not happen\n");
681 * Try a lookup. On a match, sk has a refcount that we must
682 * release on exit (we know it because skb->sk = NULL).
684 * inet_lookup above 2.6.24 has an additional 'net' parameter
685 * so we use a macro to conditionally supply it.
686 * swap dst and src depending on the direction.
688 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
691 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
692 /* there is no dev_net() on 2.6.25 */
693 #define _OPT_NET_ARG (skb->dev->nd_net),
694 #else /* 2.6.26 and above */
695 #define _OPT_NET_ARG dev_net(skb->dev),
698 sk = (dir) ? /* dir != 0 on output */
699 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
700 daddr, dport, saddr, sport, // match outgoing
702 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
703 saddr, sport, daddr, dport, // match incoming
707 if (sk == NULL) /* no match, nothing to be done */
710 ret = 1; /* retrying won't make things better */
712 #ifdef CONFIG_VSERVER
719 * Exclude tcp states where sk points to a inet_timewait_sock which
720 * has no sk_socket field (surely TCP_TIME_WAIT, perhaps more).
721 * To be safe, use a whitelist and not a blacklist.
722 * Before dereferencing sk_socket grab a lock on sk_callback_lock.
724 * Once again we need conditional code because the UID and GID
725 * location changes between kernels.
727 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
728 /* use the current's real uid/gid */
729 #define _CURR_UID f_uid
730 #define _CURR_GID f_gid
731 #else /* 2.6.29 and above */
732 /* use the current's file access real uid/gid */
733 #define _CURR_UID f_cred->fsuid
734 #define _CURR_GID f_cred->fsgid
737 #define GOOD_STATES ( \
738 (1<<TCP_LISTEN) | (1<<TCP_SYN_RECV) | (1<<TCP_SYN_SENT) | \
739 (1<<TCP_ESTABLISHED) | (1<<TCP_FIN_WAIT1) | (1<<TCP_FIN_WAIT2) )
740 // surely exclude TCP_CLOSE, TCP_TIME_WAIT, TCP_LAST_ACK
741 // uncertain TCP_CLOSE_WAIT and TCP_CLOSING
743 if ((1<<st) & GOOD_STATES) {
744 read_lock_bh(&sk->sk_callback_lock);
745 if (sk->sk_socket && sk->sk_socket->file) {
746 //u->uid = sk->sk_socket->file->_CURR_UID;
747 //u->gid = sk->sk_socket->file->_CURR_GID;
749 read_unlock_bh(&sk->sk_callback_lock);
753 if (!skb->sk) /* return the reference that came from the lookup */
760 #endif /* LINUX > 2.4 */
764 * Now prepare to hook the various functions.
765 * Linux 2.4 has a different API so we need some adaptation
766 * for register and unregister hooks
768 * the unregister function changed arguments between 2.6.22 and 2.6.24
770 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
771 struct nf_queue_handler ipfw2_queue_handler_desc = {
772 .outfn = ipfw2_queue_handler,
773 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)
774 .name = "ipfw2 dummynet queue",
777 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)
778 #define REG_QH_ARG(pf, fn) pf, &(fn ## _desc)
780 #define REG_QH_ARG(pf, fn) &(fn ## _desc)
784 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) /* XXX was 2.6.0 */
786 nf_register_hooks(struct nf_hook_ops *ops, int n)
789 for (i = 0; i < n; i++) {
790 ret = nf_register_hook(ops + i);
798 nf_unregister_hooks(struct nf_hook_ops *ops, int n)
801 for (i = 0; i < n; i++) {
802 nf_unregister_hook(ops + i);
805 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) /* XXX was 2.6.0 */
806 #define REG_QH_ARG(pf, fn) pf, fn, NULL
808 #define UNREG_QH_ARG(pf, fn) //fn /* argument for nf_[un]register_queue_handler */
809 #define SET_MOD_OWNER
811 #else /* linux > 2.6.17 */
813 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
814 #define UNREG_QH_ARG(pf, fn) //fn
815 #elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)
816 #define UNREG_QH_ARG(pf, fn) pf, &(fn ## _desc)
818 #define UNREG_QH_ARG(pf, fn)
819 #endif /* 2.6.0 < LINUX > 2.6.24 */
821 #define SET_MOD_OWNER .owner = THIS_MODULE,
823 #endif /* !LINUX < 2.6.0 */
825 static struct nf_hook_ops ipfw_ops[] __read_mostly = {
829 .hooknum = IPFW_HOOK_IN,
830 .priority = NF_IP_PRI_FILTER,
836 .hooknum = NF_IP_POST_ROUTING,
837 .priority = NF_IP_PRI_FILTER,
841 #endif /* __linux__ */
843 /* descriptors for the children, until i find a way for the
844 * linker to produce them
846 extern moduledata_t *moddesc_ipfw;
847 extern moduledata_t *moddesc_dummynet;
848 extern moduledata_t *moddesc_dn_fifo;
849 extern moduledata_t *moddesc_dn_wf2qp;
850 extern moduledata_t *moddesc_dn_rr;
851 extern moduledata_t *moddesc_dn_qfq;
852 extern moduledata_t *moddesc_dn_prio;
853 extern void *sysinit_ipfw_init;
854 extern void *sysuninit_ipfw_destroy;
855 extern void *sysinit_vnet_ipfw_init;
856 extern void *sysuninit_vnet_ipfw_uninit;
859 * Module glue - init and exit function.
862 ipfw_module_init(void)
866 unsigned long resolution;
870 my_mod_register("ipfw", 1, moddesc_ipfw, NULL, NULL);
871 my_mod_register("sy_ipfw", 2, NULL,
872 sysinit_ipfw_init, sysuninit_ipfw_destroy);
873 my_mod_register("sy_Vnet_ipfw", 3, NULL,
874 sysinit_vnet_ipfw_init, sysuninit_vnet_ipfw_uninit);
875 my_mod_register("dummynet", 4, moddesc_dummynet, NULL, NULL);
876 my_mod_register("dn_fifo", 5, moddesc_dn_fifo, NULL, NULL);
877 my_mod_register("dn_wf2qp", 6, moddesc_dn_wf2qp, NULL, NULL);
878 my_mod_register("dn_rr", 7, moddesc_dn_rr, NULL, NULL);
879 my_mod_register("dn_qfq", 8, moddesc_dn_qfq, NULL, NULL);
880 my_mod_register("dn_prio", 9, moddesc_dn_prio, NULL, NULL);
884 resolution = ExSetTimerResolution(1, TRUE);
885 printf("*** ExSetTimerResolution: resolution set to %d n-sec ***\n",resolution);
887 #ifdef EMULATE_SYSCTL
892 /* sockopt register, in order to talk with user space */
893 ret = nf_register_sockopt(&ipfw_sockopts);
895 printf("error %d in nf_register_sockopt\n", ret);
899 /* queue handler registration, in order to get network
900 * packet under a private queue */
901 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,2)
904 nf_register_queue_handler(REG_QH_ARG(PF_INET, ipfw2_queue_handler) );
905 if (ret < 0) /* queue busy */
906 goto unregister_sockopt;
908 ret = nf_register_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
910 goto unregister_sockopt;
912 printf("%s loaded\n", __FUNCTION__);
916 /* handle errors on load */
918 nf_unregister_queue_handler(UNREG_QH_ARG(PF_INET, ipfw2_queue_handler) );
919 nf_unregister_sockopt(&ipfw_sockopts);
923 printf("%s error\n", __FUNCTION__);
925 #endif /* __linux__ */
929 /* module shutdown */
931 ipfw_module_exit(void)
933 #ifdef EMULATE_SYSCTL
937 ExSetTimerResolution(0,FALSE);
939 #else /* linux hook */
940 nf_unregister_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
941 /* maybe drain the queue before unregistering ? */
942 nf_unregister_queue_handler(UNREG_QH_ARG(PF_INET, ipfw2_queue_handler) );
943 nf_unregister_sockopt(&ipfw_sockopts);
944 #endif /* __linux__ */
948 printf("%s unloaded\n", __FUNCTION__);
952 module_init(ipfw_module_init)
953 module_exit(ipfw_module_exit)
954 MODULE_LICENSE("Dual BSD/GPL"); /* the code here is all BSD. */