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