import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / net / ipv6 / netfilter / ip6t_multiport.c
1 /* Kernel module to match one of a list of TCP/UDP ports: ports are in
2    the same place so we can treat them as equal. */
3 #include <linux/module.h>
4 #include <linux/types.h>
5 #include <linux/udp.h>
6 #include <linux/skbuff.h>
7 #include <linux/in.h>
8
9 #include <linux/netfilter_ipv6/ip6t_multiport.h>
10 #include <linux/netfilter_ipv6/ip6_tables.h>
11
12 #if 0
13 #define duprintf(format, args...) printk(format , ## args)
14 #else
15 #define duprintf(format, args...)
16 #endif
17
18 /* Returns 1 if the port is matched by the test, 0 otherwise. */
19 static inline int
20 ports_match(const u_int16_t *portlist, enum ip6t_multiport_flags flags,
21             u_int8_t count, u_int16_t src, u_int16_t dst)
22 {
23         unsigned int i;
24         for (i=0; i<count; i++) {
25                 if (flags != IP6T_MULTIPORT_DESTINATION
26                     && portlist[i] == src)
27                         return 1;
28
29                 if (flags != IP6T_MULTIPORT_SOURCE
30                     && portlist[i] == dst)
31                         return 1;
32         }
33
34         return 0;
35 }
36
37 static int
38 match(const struct sk_buff *skb,
39       const struct net_device *in,
40       const struct net_device *out,
41       const void *matchinfo,
42       int offset,
43       const void *hdr,
44       u_int16_t datalen,
45       int *hotdrop)
46 {
47         const struct udphdr *udp = hdr;
48         const struct ip6t_multiport *multiinfo = matchinfo;
49
50         /* Must be big enough to read ports. */
51         if (offset == 0 && datalen < sizeof(struct udphdr)) {
52                 /* We've been asked to examine this packet, and we
53                    can't.  Hence, no choice but to drop. */
54                         duprintf("ip6t_multiport:"
55                                  " Dropping evil offset=0 tinygram.\n");
56                         *hotdrop = 1;
57                         return 0;
58         }
59
60         /* Must not be a fragment. */
61         return !offset
62                 && ports_match(multiinfo->ports,
63                                multiinfo->flags, multiinfo->count,
64                                ntohs(udp->source), ntohs(udp->dest));
65 }
66
67 /* Called when user tries to insert an entry of this type. */
68 static int
69 checkentry(const char *tablename,
70            const struct ip6t_ip6 *ip,
71            void *matchinfo,
72            unsigned int matchsize,
73            unsigned int hook_mask)
74 {
75         const struct ip6t_multiport *multiinfo = matchinfo;
76
77         /* Must specify proto == TCP/UDP, no unknown flags or bad count */
78         return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
79                 && !(ip->flags & IP6T_INV_PROTO)
80                 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
81                 && (multiinfo->flags == IP6T_MULTIPORT_SOURCE
82                     || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
83                     || multiinfo->flags == IP6T_MULTIPORT_EITHER)
84                 && multiinfo->count <= IP6T_MULTI_PORTS;
85 }
86
87 static struct ip6t_match multiport_match
88 = { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
89
90 static int __init init(void)
91 {
92         return ip6t_register_match(&multiport_match);
93 }
94
95 static void __exit fini(void)
96 {
97         ip6t_unregister_match(&multiport_match);
98 }
99
100 module_init(init);
101 module_exit(fini);