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