Major changes:
[ipfw.git] / dummynet / ipfw2_mod.c
1 /*
2  * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * $Id$
28  *
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).
32  *
33  * The control interface uses the sockopt mechanism
34  * on a socket(AF_INET, SOCK_RAW, IPPROTO_RAW).
35  *
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.
40  *
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.
46  */
47
48 #include <sys/cdefs.h>
49 #include <sys/mbuf.h>                   /* sizeof struct mbuf */
50 #include <sys/param.h>                  /* NGROUPS */
51
52 #ifdef __linux__
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 */
57
58 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
59 #include <net/netfilter/nf_queue.h>     /* nf_queue */
60 #endif
61
62 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
63 #define __read_mostly
64 #endif
65
66 #endif /* !__linux__ */
67
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 */
74
75 /*
76  * Here we allocate some global variables used in the firewall.
77  */
78 ip_dn_ctl_t    *ip_dn_ctl_ptr;
79 ip_fw_ctl_t    *ip_fw_ctl_ptr;
80
81 ip_dn_io_t     *ip_dn_io_ptr;
82 ip_fw_chk_t    *ip_fw_chk_ptr;
83
84 void            (*bridge_dn_p)(struct mbuf *, struct ifnet *);
85
86 /*---
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.
91  */
92 #include <sys/module.h>
93 struct mod_args {
94         struct moduledata *mod;
95         const char *name;
96         int order;
97 };
98
99 static unsigned int mod_idx;
100 static struct mod_args mods[10];        /* hard limit to 10 modules */
101
102 /*
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
106  * a firewall rule.
107  */
108 struct ip_fw_ugid {
109         gid_t           fw_groups[NGROUPS];
110         int             fw_ngroups;
111         uid_t           fw_uid;
112         int             fw_prid;
113 };
114
115 /*
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.
119  */
120 int
121 my_mod_register(struct moduledata *mod, const char *name, int order)
122 {
123         struct mod_args m = { mod, name, order };
124
125         printf("%s %s called\n", __FUNCTION__, name);
126         if (mod_idx < sizeof(mods) / sizeof(mods[0]))
127                 mods[mod_idx++] = m;
128         return 0;
129 }
130
131 static void
132 init_children(void)
133 {
134         unsigned int i;
135
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);
143         }
144 }
145
146 static void
147 fini_children(void)
148 {
149         int i;
150
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);
157         }
158 }
159 /*--- end of module bindinghelper functions ---*/
160
161 /*---
162  * Control hooks:
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.
166  */
167 static int
168 ipfw_ctl_h(struct sockopt *s, int cmd, int dir, int len, void __user *user)
169 {
170         struct thread t;
171         int ret = EINVAL;
172
173         memset(s, 0, sizeof(s));
174         s->sopt_name = cmd;
175         s->sopt_dir = dir;
176         s->sopt_valsize = len;
177         s->sopt_val = user;
178
179         /* sopt_td is not used but it is referenced */
180         memset(&t, 0, sizeof(t));
181         s->sopt_td = &t;
182         
183         // printf("%s called with cmd %d len %d\n", __FUNCTION__, cmd, len);
184
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);
189
190         return -ret;    /* errors are < 0 on linux */
191 }
192
193 #ifdef _WIN32
194
195 void
196 netisr_dispatch(int __unused num, struct mbuf *m)
197 {
198 }
199
200 int
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)
204 {
205         netisr_dispatch(0, m);
206         return 0;
207 }
208
209 #else /* this is the linux glue */
210 /*
211  * setsockopt hook has no return value other than the error code.
212  */
213 static int
214 do_ipfw_set_ctl(struct sock __unused *sk, int cmd,
215         void __user *user, unsigned int len)
216 {
217         struct sockopt s;       /* pass arguments */
218
219         return ipfw_ctl_h(&s, cmd, SOPT_SET, len, user);
220 }
221
222 /*
223  * getsockopt can can return a block of data in response.
224  */
225 static int
226 do_ipfw_get_ctl(struct sock __unused *sk,
227         int cmd, void __user *user, int *len)
228 {
229         struct sockopt s;       /* pass arguments */
230         int ret = ipfw_ctl_h(&s, cmd, SOPT_GET, *len, user);
231
232         *len = s.sopt_valsize;  /* return lenght back to the caller */
233         return ret;
234 }
235
236 /*
237  * declare our [get|set]sockopt hooks
238  */
239 static struct nf_sockopt_ops ipfw_sockopts = {
240         .pf             = PF_INET,
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,
249 #endif
250 };
251
252 /*----
253  * We need a number of macros to adapt to the various APIs in
254  * different linux versions. Among them:
255  *
256  * - the hook names change between macros (NF_IP*) and enum NF_INET_*
257  *
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
261  *
262  * - NF_STOP is not defined before 2.6 so we remap it to NF_ACCEPT
263  *
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
267  *
268  * - the arguments to the queue handler also change;
269  */
270  
271 /*
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
275  * need to adapt.
276  */
277 #ifndef NF_IP_PRE_ROUTING
278 #define NF_IP_PRE_ROUTING       NF_INET_PRE_ROUTING
279 #endif
280 #ifndef NF_IP_POST_ROUTING
281 #define NF_IP_POST_ROUTING      NF_INET_POST_ROUTING
282 #endif
283
284 /*
285  * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains.
286  * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and
287  * POST_ROUTING chains, so if we want to use that information we
288  * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING.
289  * However at the moment the skb_tag info is not reliable so
290  * we stay with the standard hooks.
291  */
292 #if 0 // defined(IPFW_PLANETLAB)
293 #define IPFW_HOOK_IN NF_IP_LOCAL_IN
294 #else
295 #define IPFW_HOOK_IN NF_IP_PRE_ROUTING
296 #endif
297
298 /*
299  * The main netfilter hook.
300  * To make life simple, we queue everything and then do all the
301  * decision in the queue handler.
302  *
303  * XXX note that in 2.4 and up to 2.6.22 the skbuf is passed as sk_buff**
304  * so we have an #ifdef to set the proper argument type.
305  */
306 static unsigned int
307 call_ipfw(unsigned int __unused hooknum,
308 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) // in 2.6.22 we have **
309         struct sk_buff  __unused **skb,
310 #else
311         struct sk_buff  __unused *skb,
312 #endif
313         const struct net_device  __unused *in,
314         const struct net_device  __unused *out,
315         int __unused (*okfn)(struct sk_buff *))
316 {
317         return NF_QUEUE;
318 }
319
320 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
321 #define NF_STOP         NF_ACCEPT
322 #endif
323
324 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
325
326 /*
327  * nf_queue_entry is a recent addition, in previous versions
328  * of the code the struct is called nf_info.
329  */
330 #define nf_queue_entry  nf_info /* for simplicity */
331
332 /* also, 2.4 and perhaps something else have different arguments */
333 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)  /* unsure on the exact boundary */
334 /* on 2.4 we use nf_info */
335 #define QH_ARGS         struct sk_buff *skb, struct nf_info *info, void *data
336 #else   /* 2.6.1.. 2.6.24 */
337 #define QH_ARGS         struct sk_buff *skb, struct nf_info *info, unsigned int qnum, void *data
338 #endif
339
340 #define DEFINE_SKB      /* nothing, already an argument */
341 #define REINJECT(_inf, _verd)   nf_reinject(skb, _inf, _verd)
342
343 #else   /* 2.6.25 and above */
344
345 #define QH_ARGS         struct nf_queue_entry *info, unsigned int queuenum
346 #define DEFINE_SKB      struct sk_buff *skb = info->skb;
347 #define REINJECT(_inf, _verd)   nf_reinject(_inf, _verd)
348 #endif
349
350 /*
351  * used by dummynet when dropping packets
352  * XXX use dummynet_send()
353  */
354 void
355 reinject_drop(struct mbuf* m)
356 {
357 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) /* unsure on the exact boundary */
358         struct sk_buff *skb = (struct sk_buff *)m;
359 #endif
360         REINJECT(m->queue_entry, NF_DROP);
361 }
362
363 /*
364  * The real call to the firewall. nf_queue_entry points to the skbuf,
365  * and eventually we need to return both through nf_reinject().
366  */
367 static int
368 ipfw2_queue_handler(QH_ARGS)
369 {
370         DEFINE_SKB      /* no semicolon here, goes in the macro */
371         int ret = 0;    /* return value */
372         struct mbuf *m;
373
374 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
375         if (skb->nh.iph == NULL) {
376                 printf("null dp, len %d reinject now\n", skb->len);
377                 REINJECT(info, NF_ACCEPT);
378                 return 0;
379         }
380 #endif
381         m = malloc(sizeof(*m), 0, 0);
382         if (m == NULL) {
383                 printf("malloc fail, len %d reinject now\n", skb->len);
384                 REINJECT(info, NF_ACCEPT);
385                 return 0;
386         }
387
388         m->m_skb = skb;
389         m->m_len = skb->len;            /* len in this skbuf */
390         m->m_pkthdr.len = skb->len;     /* total packet len */
391         m->m_pkthdr.rcvif = info->indev;
392         m->queue_entry = info;
393 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
394         m->m_data = skb->nh.iph;
395 #else
396         m->m_data = skb_network_header(skb);
397 #endif
398
399         /* XXX add the interface */
400         if (info->hook == IPFW_HOOK_IN) {
401                 ret = ipfw_check_in(NULL, &m, info->indev, PFIL_IN, NULL);
402         } else {
403                 ret = ipfw_check_out(NULL, &m, info->outdev, PFIL_OUT, NULL);
404         }
405
406         if (m != NULL) {        /* Accept. reinject and free the mbuf */
407                 REINJECT(info, NF_STOP);
408                 m_freem(m);
409         } else if (ret == 0) {
410                 /* dummynet has kept the packet, will reinject later. */
411         } else {
412                 /*
413                  * Packet dropped by ipfw or dummynet, reinject as NF_DROP
414                  * mbuf already released by ipfw itself
415                  */
416                 REINJECT(info, NF_DROP);
417         }
418         return 0;
419 }
420
421 struct route;
422 struct ip_moptions;
423 struct inpcb;
424
425
426 /* XXX should include prototypes for netisr_dispatch and ip_output */
427 /*
428  * The reinjection routine after a packet comes out from dummynet.
429  * We must update the skb timestamp so ping reports the right time.
430  */
431 void
432 netisr_dispatch(int num, struct mbuf *m)
433 {
434         struct nf_queue_entry *info = m->queue_entry;
435         struct sk_buff *skb = m->m_skb; /* always used */
436
437         m_freem(m);
438
439         KASSERT((info != NULL), ("%s info null!\n", __FUNCTION__));
440 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)        // XXX above 2.6.x ?
441         __net_timestamp(skb);   /* update timestamp */
442 #endif
443
444         /* XXX to obey one-pass, possibly call the queue handler here */
445         REINJECT(info, ((num == -1)?NF_DROP:NF_STOP));  /* accept but no more firewall */
446 }
447
448 int
449 ip_output(struct mbuf *m, struct mbuf __unused *opt,
450         struct route __unused *ro, int __unused flags,
451     struct ip_moptions __unused *imo, struct inpcb __unused *inp)
452 {
453         netisr_dispatch(0, m);
454         return 0;
455 }
456
457 /*
458  * socket lookup function for linux.
459  * This code is used to associate uid, gid, jail/xid to packets,
460  * and store the info in a cache *ugp where they can be accessed quickly.
461  * The function returns 1 if the info is found, -1 otherwise.
462  *
463  * We do this only on selected protocols: TCP, ...
464  *
465  * The chain is the following
466  *   sk_buff*  sock*  socket*    file*
467  *     skb  ->  sk ->sk_socket->file ->f_owner    ->pid
468  *     skb  ->  sk ->sk_socket->file ->f_uid (direct)
469  *     skb  ->  sk ->sk_socket->file ->f_cred->fsuid (2.6.29+)
470  *
471  * Related headers:
472  * linux/skbuff.h      struct skbuff
473  * net/sock.h          struct sock
474  * linux/net.h         struct socket
475  * linux/fs.h          struct file
476  *
477  * With vserver we may have sk->sk_xid and sk->sk_nid that
478  * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2]
479  * (no matches yet)
480  *
481  * Note- for locally generated, outgoing packets we should not need
482  * need a lookup because the sk_buff already points to the socket where
483  * the info is.
484  */
485 extern struct inet_hashinfo tcp_hashinfo;
486 int
487 linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
488                 const __be32 daddr, const __be16 dport,
489                 struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp)
490 {
491         struct sock *sk;
492         int ret = -1;   /* default return value */
493         int uid = -1;   /* user id */
494         int st = -1;    /* state */
495
496         if (proto != IPPROTO_TCP)
497                 return -1;
498
499         if ((dir ? (void *)skb->dst : (void *)skb->dev) == NULL) {
500                 panic(" -- this should not happen\n");
501                 return -1;
502         }
503
504         /*
505          * inet_lookup above 2.6.24 has an additional 'net' parameter
506          * so we use a macro to conditionally supply it.
507          * Also we need to switch dst and src depending on the direction.
508          */
509 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
510 #define _OPT_NET_ARG
511 #else
512 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
513 /* there is no dev_net() on 2.6.25 */
514 #define _OPT_NET_ARG (skb->dev->nd_net),
515 #else  /* 2.6.26 and above */
516 #define _OPT_NET_ARG dev_net(skb->dev),
517 #endif
518 #endif
519
520         if (0 && skb->sk) {
521                 sk=skb->sk;
522         } else {
523         sk =  (dir) ?
524                 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
525                         daddr, dport, saddr, sport,     // matches outgoing for server sockets
526                         inet_iif(skb)) :
527                 inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
528                         saddr, sport, daddr, dport,     // matches incoming for server sockets
529                         skb->dev->ifindex);
530         }
531
532 #undef _OPT_NET_ARG
533         /* no match, nothing to be done */
534         if (sk == NULL)
535                 return -1;
536
537         /*
538          * On a match, sk is returned with a refcount.
539          * In tcp some states reference a valid struct sock
540          * which is what we want, otherwise the struct sock
541          * referenced can be invalid, as in the case of the
542          * TCP_TIME_WAIT state, when it references a
543          * struct inet_timewait_sock which does not point to credentials.
544          * To be safe we exclude TCP_CLOSE and TCP_LAST_ACK states too.
545          *
546          * Once again we need conditional code because the UID and GID
547          * location changes between the two kernels.
548          */
549 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
550 /* use the current's real uid/gid */
551 #define _CURR_UID f_uid
552 #define _CURR_GID f_gid
553 #else /* 2.6.29 and above */
554 /* use the current's file access real uid/gid */
555 #define _CURR_UID f_cred->fsuid
556 #define _CURR_GID f_cred->fsgid
557 #endif
558         st = sk->sk_state;
559         if (st != TCP_TIME_WAIT && st != TCP_CLOSE && st != TCP_LAST_ACK &&
560                         sk->sk_socket && sk->sk_socket->file) {
561                 ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
562                 uid = ugp->fw_uid;
563                 ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID;
564 #ifdef CONFIG_VSERVER
565                 ugp->fw_groups[1] = sk->sk_xid;
566                 ugp->fw_groups[2] = sk->sk_nid;
567 #endif
568                 ret = 1;
569         }
570         if (1 && !skb->sk) /* the reference came from the lookup */
571                 sock_put(sk);
572 #undef _CURR_UID
573 #undef _CURR_GID
574
575         //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);
576         return ret;
577 }
578
579 /*
580  * Now prepare to hook the various functions.
581  * Linux 2.4 has a different API so we need some adaptation
582  * for register and unregister hooks
583  *
584  * the unregister function changed arguments between 2.6.22 and 2.6.24
585  */
586 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
587 static int
588 nf_register_hooks(struct nf_hook_ops *ops, int n)
589 {
590         int i, ret = 0;
591         for (i = 0; i < n; i++) {
592                 ret = nf_register_hook(ops + i);
593                 if (ret < 0)
594                         break;
595         }
596         return ret;
597 }
598
599 static void
600 nf_unregister_hooks(struct nf_hook_ops *ops, int n)
601 {
602         int i;
603         for (i = 0; i < n; i++) {
604                 nf_unregister_hook(ops + i);
605         }
606 }
607 #define REG_QH_ARG(fn)  fn, NULL        /* argument for nf_[un]register_queue_handler */
608 #define UNREG_QH_ARG(fn) //fn   /* argument for nf_[un]register_queue_handler */
609 #define SET_MOD_OWNER
610
611 #else /* linux >= 2.6.0 */
612
613 struct nf_queue_handler ipfw2_queue_handler_desc = {
614         .outfn = ipfw2_queue_handler,
615         .name = "ipfw2 dummynet queue",
616 };
617 #define REG_QH_ARG(fn)  &(fn ## _desc)
618
619 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
620 #define UNREG_QH_ARG(fn) //fn   /* argument for nf_[un]register_queue_handler */
621 #else
622 #define UNREG_QH_ARG(fn)        , &(fn ## _desc)
623 #endif /* 2.6.0 < LINUX > 2.6.24 */
624
625 #define SET_MOD_OWNER   .owner = THIS_MODULE,
626
627 #endif  /* !LINUX < 2.6.0 */
628
629 static struct nf_hook_ops ipfw_ops[] __read_mostly = {
630         {
631                 .hook           = call_ipfw,
632                 .pf             = PF_INET,
633                 .hooknum        = IPFW_HOOK_IN,
634                 .priority       = NF_IP_PRI_FILTER,
635                 SET_MOD_OWNER
636         },
637         {
638                 .hook           = call_ipfw,
639                 .pf             = PF_INET,
640                 .hooknum        = NF_IP_POST_ROUTING,
641                 .priority       = NF_IP_PRI_FILTER,
642                 SET_MOD_OWNER
643         },
644 };
645 #endif /* !__linux__ */
646
647 /* descriptors for the children */
648 extern moduledata_t *moddesc_ipfw;
649 extern moduledata_t *moddesc_dummynet;
650
651 /*
652  * Module glue - init and exit function.
653  */
654 static int __init
655 ipfw_module_init(void)
656 {
657         int ret = 0;
658
659         printf("%s in-hook %d svn id %s\n", __FUNCTION__, IPFW_HOOK_IN, "$Id$");
660
661         my_mod_register(moddesc_ipfw, "ipfw",  1);
662         my_mod_register(moddesc_dummynet, "dummynet",  2);
663         init_children();
664
665 #ifdef _WIN32
666         return ret;
667
668 #else  /* linux hook */
669         /* sockopt register, in order to talk with user space */
670         ret = nf_register_sockopt(&ipfw_sockopts);
671         if (ret < 0) {
672                 printf("error %d in nf_register_sockopt\n", ret);
673                 goto clean_modules;
674         }
675
676         /* queue handler registration, in order to get network
677          * packet under a private queue */
678         ret = nf_register_queue_handler(PF_INET, REG_QH_ARG(ipfw2_queue_handler) );
679         if (ret < 0)    /* queue busy */
680                 goto unregister_sockopt;
681
682         ret = nf_register_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
683         if (ret < 0)
684                 goto unregister_sockopt;
685
686         printf("%s loaded\n", __FUNCTION__);
687         return 0;
688
689
690 /* handle errors on load */
691 unregister_sockopt:
692         nf_unregister_queue_handler(PF_INET  UNREG_QH_ARG(ipfw2_queue_handler) );
693         nf_unregister_sockopt(&ipfw_sockopts);
694
695 clean_modules:
696         fini_children();
697         printf("%s error\n", __FUNCTION__);
698
699         return ret;
700 #endif  /* linux */
701 }
702
703 /* module shutdown */
704 static void __exit
705 ipfw_module_exit(void)
706 {
707 #ifdef _WIN32
708 #else  /* linux hook */
709         nf_unregister_hooks(ipfw_ops, ARRAY_SIZE(ipfw_ops));
710         /* maybe drain the queue before unregistering ? */
711         nf_unregister_queue_handler(PF_INET  UNREG_QH_ARG(ipfw2_queue_handler) );
712         nf_unregister_sockopt(&ipfw_sockopts);
713 #endif  /* linux */
714
715         fini_children();
716
717         printf("%s unloaded\n", __FUNCTION__);
718 }
719
720 #ifdef __linux__
721 module_init(ipfw_module_init)
722 module_exit(ipfw_module_exit)
723 MODULE_LICENSE("Dual BSD/GPL"); /* the code here is all BSD. */
724 #endif