www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ipt_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
4 /* (C) 1999-2001 Paul `Rusty' Russell
5  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/module.h>
13 #include <linux/types.h>
14 #include <linux/udp.h>
15 #include <linux/skbuff.h>
16
17 #include <linux/netfilter_ipv4/ipt_multiport.h>
18 #include <linux/netfilter_ipv4/ip_tables.h>
19
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
22 MODULE_DESCRIPTION("iptables multiple port match module");
23
24 #if 0
25 #define duprintf(format, args...) printk(format , ## args)
26 #else
27 #define duprintf(format, args...)
28 #endif
29
30 /* Returns 1 if the port is matched by the test, 0 otherwise. */
31 static inline int
32 ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
33             u_int8_t count, u_int16_t src, u_int16_t dst)
34 {
35         unsigned int i;
36         for (i=0; i<count; i++) {
37                 if (flags != IPT_MULTIPORT_DESTINATION
38                     && portlist[i] == src)
39                         return 1;
40
41                 if (flags != IPT_MULTIPORT_SOURCE
42                     && portlist[i] == dst)
43                         return 1;
44         }
45
46         return 0;
47 }
48
49 static int
50 match(const struct sk_buff *skb,
51       const struct net_device *in,
52       const struct net_device *out,
53       const void *matchinfo,
54       int offset,
55       int *hotdrop)
56 {
57         u16 ports[2];
58         const struct ipt_multiport *multiinfo = matchinfo;
59
60         /* Must not be a fragment. */
61         if (offset)
62                 return 0;
63
64         /* Must be big enough to read ports (both UDP and TCP have
65            them at the start). */
66         if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
67                 /* We've been asked to examine this packet, and we
68                    can't.  Hence, no choice but to drop. */
69                         duprintf("ipt_multiport:"
70                                  " Dropping evil offset=0 tinygram.\n");
71                         *hotdrop = 1;
72                         return 0;
73         }
74
75         return ports_match(multiinfo->ports,
76                            multiinfo->flags, multiinfo->count,
77                            ntohs(ports[0]), ntohs(ports[1]));
78 }
79
80 /* Called when user tries to insert an entry of this type. */
81 static int
82 checkentry(const char *tablename,
83            const struct ipt_ip *ip,
84            void *matchinfo,
85            unsigned int matchsize,
86            unsigned int hook_mask)
87 {
88         const struct ipt_multiport *multiinfo = matchinfo;
89
90         if (matchsize != IPT_ALIGN(sizeof(struct ipt_multiport)))
91                 return 0;
92
93         /* Must specify proto == TCP/UDP, no unknown flags or bad count */
94         return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
95                 && !(ip->invflags & IPT_INV_PROTO)
96                 && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport))
97                 && (multiinfo->flags == IPT_MULTIPORT_SOURCE
98                     || multiinfo->flags == IPT_MULTIPORT_DESTINATION
99                     || multiinfo->flags == IPT_MULTIPORT_EITHER)
100                 && multiinfo->count <= IPT_MULTI_PORTS;
101 }
102
103 static struct ipt_match multiport_match = {
104         .name           = "multiport",
105         .match          = &match,
106         .checkentry     = &checkentry,
107         .me             = THIS_MODULE,
108 };
109
110 static int __init init(void)
111 {
112         return ipt_register_match(&multiport_match);
113 }
114
115 static void __exit fini(void)
116 {
117         ipt_unregister_match(&multiport_match);
118 }
119
120 module_init(init);
121 module_exit(fini);