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