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