Commit a89ecb6a2ef732d04058d87801e2b6bd7e5c7089
Committed by
David S. Miller
1 parent
dc5ab2faec
Exists in
master
and in
7 other branches
[NETFILTER]: x_tables: unify IPv4/IPv6 multiport match
This unifies ipt_multiport and ip6t_multiport to xt_multiport. As a result, this addes support for inversion and port range match to IPv6 packets. Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 12 changed files with 372 additions and 381 deletions Side-by-side Diff
- include/linux/netfilter/xt_multiport.h
- include/linux/netfilter_ipv4/ipt_multiport.h
- include/linux/netfilter_ipv6/ip6t_multiport.h
- net/ipv4/netfilter/Kconfig
- net/ipv4/netfilter/Makefile
- net/ipv4/netfilter/ipt_multiport.c
- net/ipv6/netfilter/Kconfig
- net/ipv6/netfilter/Makefile
- net/ipv6/netfilter/ip6t_multiport.c
- net/netfilter/Kconfig
- net/netfilter/Makefile
- net/netfilter/xt_multiport.c
include/linux/netfilter/xt_multiport.h
1 | +#ifndef _XT_MULTIPORT_H | |
2 | +#define _XT_MULTIPORT_H | |
3 | + | |
4 | +enum xt_multiport_flags | |
5 | +{ | |
6 | + XT_MULTIPORT_SOURCE, | |
7 | + XT_MULTIPORT_DESTINATION, | |
8 | + XT_MULTIPORT_EITHER | |
9 | +}; | |
10 | + | |
11 | +#define XT_MULTI_PORTS 15 | |
12 | + | |
13 | +/* Must fit inside union xt_matchinfo: 16 bytes */ | |
14 | +struct xt_multiport | |
15 | +{ | |
16 | + u_int8_t flags; /* Type of comparison */ | |
17 | + u_int8_t count; /* Number of ports */ | |
18 | + u_int16_t ports[XT_MULTI_PORTS]; /* Ports */ | |
19 | +}; | |
20 | + | |
21 | +struct xt_multiport_v1 | |
22 | +{ | |
23 | + u_int8_t flags; /* Type of comparison */ | |
24 | + u_int8_t count; /* Number of ports */ | |
25 | + u_int16_t ports[XT_MULTI_PORTS]; /* Ports */ | |
26 | + u_int8_t pflags[XT_MULTI_PORTS]; /* Port flags */ | |
27 | + u_int8_t invert; /* Invert flag */ | |
28 | +}; | |
29 | + | |
30 | +#endif /*_XT_MULTIPORT_H*/ |
include/linux/netfilter_ipv4/ipt_multiport.h
1 | 1 | #ifndef _IPT_MULTIPORT_H |
2 | 2 | #define _IPT_MULTIPORT_H |
3 | -#include <linux/netfilter_ipv4/ip_tables.h> | |
4 | 3 | |
5 | -enum ipt_multiport_flags | |
6 | -{ | |
7 | - IPT_MULTIPORT_SOURCE, | |
8 | - IPT_MULTIPORT_DESTINATION, | |
9 | - IPT_MULTIPORT_EITHER | |
10 | -}; | |
4 | +#include <linux/netfilter/xt_multiport.h> | |
11 | 5 | |
12 | -#define IPT_MULTI_PORTS 15 | |
6 | +#define IPT_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE | |
7 | +#define IPT_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION | |
8 | +#define IPT_MULTIPORT_EITHER XT_MULTIPORT_EITHER | |
13 | 9 | |
14 | -/* Must fit inside union ipt_matchinfo: 16 bytes */ | |
15 | -struct ipt_multiport | |
16 | -{ | |
17 | - u_int8_t flags; /* Type of comparison */ | |
18 | - u_int8_t count; /* Number of ports */ | |
19 | - u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ | |
20 | -}; | |
10 | +#define IPT_MULTI_PORTS XT_MULTI_PORTS | |
21 | 11 | |
22 | -struct ipt_multiport_v1 | |
23 | -{ | |
24 | - u_int8_t flags; /* Type of comparison */ | |
25 | - u_int8_t count; /* Number of ports */ | |
26 | - u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ | |
27 | - u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */ | |
28 | - u_int8_t invert; /* Invert flag */ | |
29 | -}; | |
12 | +#define ipt_multiport xt_multiport | |
13 | +#define ipt_multiport_v1 xt_multiport_v1 | |
14 | + | |
30 | 15 | #endif /*_IPT_MULTIPORT_H*/ |
include/linux/netfilter_ipv6/ip6t_multiport.h
1 | 1 | #ifndef _IP6T_MULTIPORT_H |
2 | 2 | #define _IP6T_MULTIPORT_H |
3 | -#include <linux/netfilter_ipv6/ip6_tables.h> | |
4 | 3 | |
5 | -enum ip6t_multiport_flags | |
6 | -{ | |
7 | - IP6T_MULTIPORT_SOURCE, | |
8 | - IP6T_MULTIPORT_DESTINATION, | |
9 | - IP6T_MULTIPORT_EITHER | |
10 | -}; | |
4 | +#include <linux/netfilter/xt_multiport.h> | |
11 | 5 | |
12 | -#define IP6T_MULTI_PORTS 15 | |
6 | +#define IP6T_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE | |
7 | +#define IP6T_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION | |
8 | +#define IP6T_MULTIPORT_EITHER XT_MULTIPORT_EITHER | |
13 | 9 | |
14 | -/* Must fit inside union ip6t_matchinfo: 16 bytes */ | |
15 | -struct ip6t_multiport | |
16 | -{ | |
17 | - u_int8_t flags; /* Type of comparison */ | |
18 | - u_int8_t count; /* Number of ports */ | |
19 | - u_int16_t ports[IP6T_MULTI_PORTS]; /* Ports */ | |
20 | -}; | |
21 | -#endif /*_IPT_MULTIPORT_H*/ | |
10 | +#define IP6T_MULTI_PORTS XT_MULTI_PORTS | |
11 | + | |
12 | +#define ip6t_multiport xt_multiport | |
13 | + | |
14 | +#endif /*_IP6T_MULTIPORT_H*/ |
net/ipv4/netfilter/Kconfig
... | ... | @@ -221,16 +221,6 @@ |
221 | 221 | |
222 | 222 | To compile it as a module, choose M here. If unsure, say N. |
223 | 223 | |
224 | -config IP_NF_MATCH_MULTIPORT | |
225 | - tristate "Multiple port match support" | |
226 | - depends on IP_NF_IPTABLES | |
227 | - help | |
228 | - Multiport matching allows you to match TCP or UDP packets based on | |
229 | - a series of source or destination ports: normally a rule can only | |
230 | - match a single range of ports. | |
231 | - | |
232 | - To compile it as a module, choose M here. If unsure, say N. | |
233 | - | |
234 | 224 | config IP_NF_MATCH_TOS |
235 | 225 | tristate "TOS match support" |
236 | 226 | depends on IP_NF_IPTABLES |
net/ipv4/netfilter/Makefile
... | ... | @@ -53,7 +53,6 @@ |
53 | 53 | # matches |
54 | 54 | obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o |
55 | 55 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o |
56 | -obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o | |
57 | 56 | obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o |
58 | 57 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o |
59 | 58 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o |
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 | -/* Returns 1 if the port is matched by the test, 0 otherwise. */ | |
50 | -static inline int | |
51 | -ports_match_v1(const struct ipt_multiport_v1 *minfo, | |
52 | - u_int16_t src, u_int16_t dst) | |
53 | -{ | |
54 | - unsigned int i; | |
55 | - u_int16_t s, e; | |
56 | - | |
57 | - for (i=0; i < minfo->count; i++) { | |
58 | - s = minfo->ports[i]; | |
59 | - | |
60 | - if (minfo->pflags[i]) { | |
61 | - /* range port matching */ | |
62 | - e = minfo->ports[++i]; | |
63 | - duprintf("src or dst matches with %d-%d?\n", s, e); | |
64 | - | |
65 | - if (minfo->flags == IPT_MULTIPORT_SOURCE | |
66 | - && src >= s && src <= e) | |
67 | - return 1 ^ minfo->invert; | |
68 | - if (minfo->flags == IPT_MULTIPORT_DESTINATION | |
69 | - && dst >= s && dst <= e) | |
70 | - return 1 ^ minfo->invert; | |
71 | - if (minfo->flags == IPT_MULTIPORT_EITHER | |
72 | - && ((dst >= s && dst <= e) | |
73 | - || (src >= s && src <= e))) | |
74 | - return 1 ^ minfo->invert; | |
75 | - } else { | |
76 | - /* exact port matching */ | |
77 | - duprintf("src or dst matches with %d?\n", s); | |
78 | - | |
79 | - if (minfo->flags == IPT_MULTIPORT_SOURCE | |
80 | - && src == s) | |
81 | - return 1 ^ minfo->invert; | |
82 | - if (minfo->flags == IPT_MULTIPORT_DESTINATION | |
83 | - && dst == s) | |
84 | - return 1 ^ minfo->invert; | |
85 | - if (minfo->flags == IPT_MULTIPORT_EITHER | |
86 | - && (src == s || dst == s)) | |
87 | - return 1 ^ minfo->invert; | |
88 | - } | |
89 | - } | |
90 | - | |
91 | - return minfo->invert; | |
92 | -} | |
93 | - | |
94 | -static int | |
95 | -match(const struct sk_buff *skb, | |
96 | - const struct net_device *in, | |
97 | - const struct net_device *out, | |
98 | - const struct xt_match *match, | |
99 | - const void *matchinfo, | |
100 | - int offset, | |
101 | - unsigned int protoff, | |
102 | - int *hotdrop) | |
103 | -{ | |
104 | - u16 _ports[2], *pptr; | |
105 | - const struct ipt_multiport *multiinfo = matchinfo; | |
106 | - | |
107 | - if (offset) | |
108 | - return 0; | |
109 | - | |
110 | - pptr = skb_header_pointer(skb, protoff, | |
111 | - sizeof(_ports), _ports); | |
112 | - if (pptr == NULL) { | |
113 | - /* We've been asked to examine this packet, and we | |
114 | - * can't. Hence, no choice but to drop. | |
115 | - */ | |
116 | - duprintf("ipt_multiport:" | |
117 | - " Dropping evil offset=0 tinygram.\n"); | |
118 | - *hotdrop = 1; | |
119 | - return 0; | |
120 | - } | |
121 | - | |
122 | - return ports_match(multiinfo->ports, | |
123 | - multiinfo->flags, multiinfo->count, | |
124 | - ntohs(pptr[0]), ntohs(pptr[1])); | |
125 | -} | |
126 | - | |
127 | -static int | |
128 | -match_v1(const struct sk_buff *skb, | |
129 | - const struct net_device *in, | |
130 | - const struct net_device *out, | |
131 | - const struct xt_match *match, | |
132 | - const void *matchinfo, | |
133 | - int offset, | |
134 | - unsigned int protoff, | |
135 | - int *hotdrop) | |
136 | -{ | |
137 | - u16 _ports[2], *pptr; | |
138 | - const struct ipt_multiport_v1 *multiinfo = matchinfo; | |
139 | - | |
140 | - if (offset) | |
141 | - return 0; | |
142 | - | |
143 | - pptr = skb_header_pointer(skb, protoff, | |
144 | - sizeof(_ports), _ports); | |
145 | - if (pptr == NULL) { | |
146 | - /* We've been asked to examine this packet, and we | |
147 | - * can't. Hence, no choice but to drop. | |
148 | - */ | |
149 | - duprintf("ipt_multiport:" | |
150 | - " Dropping evil offset=0 tinygram.\n"); | |
151 | - *hotdrop = 1; | |
152 | - return 0; | |
153 | - } | |
154 | - | |
155 | - return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); | |
156 | -} | |
157 | - | |
158 | -static struct ipt_match multiport_match = { | |
159 | - .name = "multiport", | |
160 | - .revision = 0, | |
161 | - .match = match, | |
162 | - .matchsize = sizeof(struct ipt_multiport), | |
163 | - .me = THIS_MODULE, | |
164 | -}; | |
165 | - | |
166 | -static struct ipt_match multiport_match_v1 = { | |
167 | - .name = "multiport", | |
168 | - .revision = 1, | |
169 | - .match = match_v1, | |
170 | - .matchsize = sizeof(struct ipt_multiport_v1), | |
171 | - .me = THIS_MODULE, | |
172 | -}; | |
173 | - | |
174 | -static int __init ipt_multiport_init(void) | |
175 | -{ | |
176 | - int err; | |
177 | - | |
178 | - err = ipt_register_match(&multiport_match); | |
179 | - if (!err) { | |
180 | - err = ipt_register_match(&multiport_match_v1); | |
181 | - if (err) | |
182 | - ipt_unregister_match(&multiport_match); | |
183 | - } | |
184 | - | |
185 | - return err; | |
186 | -} | |
187 | - | |
188 | -static void __exit ipt_multiport_fini(void) | |
189 | -{ | |
190 | - ipt_unregister_match(&multiport_match); | |
191 | - ipt_unregister_match(&multiport_match_v1); | |
192 | -} | |
193 | - | |
194 | -module_init(ipt_multiport_init); | |
195 | -module_exit(ipt_multiport_fini); |
net/ipv6/netfilter/Kconfig
... | ... | @@ -87,16 +87,6 @@ |
87 | 87 | |
88 | 88 | To compile it as a module, choose M here. If unsure, say N. |
89 | 89 | |
90 | -config IP6_NF_MATCH_MULTIPORT | |
91 | - tristate "Multiple port match support" | |
92 | - depends on IP6_NF_IPTABLES | |
93 | - help | |
94 | - Multiport matching allows you to match TCP or UDP packets based on | |
95 | - a series of source or destination ports: normally a rule can only | |
96 | - match a single range of ports. | |
97 | - | |
98 | - To compile it as a module, choose M here. If unsure, say N. | |
99 | - | |
100 | 90 | config IP6_NF_MATCH_OWNER |
101 | 91 | tristate "Owner match support" |
102 | 92 | depends on IP6_NF_IPTABLES |
net/ipv6/netfilter/Makefile
... | ... | @@ -10,7 +10,6 @@ |
10 | 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
11 | 11 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
12 | 12 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
13 | -obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o | |
14 | 13 | obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o |
15 | 14 | obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o |
16 | 15 | obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o |
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 | - | |
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 | -#include <linux/in.h> | |
17 | - | |
18 | -#include <linux/netfilter_ipv6/ip6t_multiport.h> | |
19 | -#include <linux/netfilter_ipv6/ip6_tables.h> | |
20 | - | |
21 | -MODULE_LICENSE("GPL"); | |
22 | -MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | |
23 | -MODULE_DESCRIPTION("ip6tables match for multiple ports"); | |
24 | - | |
25 | -#if 0 | |
26 | -#define duprintf(format, args...) printk(format , ## args) | |
27 | -#else | |
28 | -#define duprintf(format, args...) | |
29 | -#endif | |
30 | - | |
31 | -/* Returns 1 if the port is matched by the test, 0 otherwise. */ | |
32 | -static inline int | |
33 | -ports_match(const u_int16_t *portlist, enum ip6t_multiport_flags flags, | |
34 | - u_int8_t count, u_int16_t src, u_int16_t dst) | |
35 | -{ | |
36 | - unsigned int i; | |
37 | - for (i=0; i<count; i++) { | |
38 | - if (flags != IP6T_MULTIPORT_DESTINATION | |
39 | - && portlist[i] == src) | |
40 | - return 1; | |
41 | - | |
42 | - if (flags != IP6T_MULTIPORT_SOURCE | |
43 | - && portlist[i] == dst) | |
44 | - return 1; | |
45 | - } | |
46 | - | |
47 | - return 0; | |
48 | -} | |
49 | - | |
50 | -static int | |
51 | -match(const struct sk_buff *skb, | |
52 | - const struct net_device *in, | |
53 | - const struct net_device *out, | |
54 | - const struct xt_match *match, | |
55 | - const void *matchinfo, | |
56 | - int offset, | |
57 | - unsigned int protoff, | |
58 | - int *hotdrop) | |
59 | -{ | |
60 | - u16 _ports[2], *pptr; | |
61 | - const struct ip6t_multiport *multiinfo = matchinfo; | |
62 | - | |
63 | - /* Must not be a fragment. */ | |
64 | - if (offset) | |
65 | - return 0; | |
66 | - | |
67 | - /* Must be big enough to read ports (both UDP and TCP have | |
68 | - them at the start). */ | |
69 | - pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]); | |
70 | - if (pptr == NULL) { | |
71 | - /* We've been asked to examine this packet, and we | |
72 | - * can't. Hence, no choice but to drop. | |
73 | - */ | |
74 | - duprintf("ip6t_multiport:" | |
75 | - " Dropping evil offset=0 tinygram.\n"); | |
76 | - *hotdrop = 1; | |
77 | - return 0; | |
78 | - } | |
79 | - | |
80 | - return ports_match(multiinfo->ports, | |
81 | - multiinfo->flags, multiinfo->count, | |
82 | - ntohs(pptr[0]), ntohs(pptr[1])); | |
83 | -} | |
84 | - | |
85 | -/* Called when user tries to insert an entry of this type. */ | |
86 | -static int | |
87 | -checkentry(const char *tablename, | |
88 | - const void *info, | |
89 | - const struct xt_match *match, | |
90 | - void *matchinfo, | |
91 | - unsigned int matchsize, | |
92 | - unsigned int hook_mask) | |
93 | -{ | |
94 | - const struct ip6t_ip6 *ip = info; | |
95 | - const struct ip6t_multiport *multiinfo = matchinfo; | |
96 | - | |
97 | - /* Must specify proto == TCP/UDP, no unknown flags or bad count */ | |
98 | - return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) | |
99 | - && !(ip->invflags & IP6T_INV_PROTO) | |
100 | - && (multiinfo->flags == IP6T_MULTIPORT_SOURCE | |
101 | - || multiinfo->flags == IP6T_MULTIPORT_DESTINATION | |
102 | - || multiinfo->flags == IP6T_MULTIPORT_EITHER) | |
103 | - && multiinfo->count <= IP6T_MULTI_PORTS; | |
104 | -} | |
105 | - | |
106 | -static struct ip6t_match multiport_match = { | |
107 | - .name = "multiport", | |
108 | - .match = match, | |
109 | - .matchsize = sizeof(struct ip6t_multiport), | |
110 | - .checkentry = checkentry, | |
111 | - .me = THIS_MODULE, | |
112 | -}; | |
113 | - | |
114 | -static int __init ip6t_multiport_init(void) | |
115 | -{ | |
116 | - return ip6t_register_match(&multiport_match); | |
117 | -} | |
118 | - | |
119 | -static void __exit ip6t_multiport_fini(void) | |
120 | -{ | |
121 | - ip6t_unregister_match(&multiport_match); | |
122 | -} | |
123 | - | |
124 | -module_init(ip6t_multiport_init); | |
125 | -module_exit(ip6t_multiport_fini); |
net/netfilter/Kconfig
... | ... | @@ -298,6 +298,16 @@ |
298 | 298 | |
299 | 299 | To compile it as a module, choose M here. If unsure, say N. |
300 | 300 | |
301 | +config NETFILTER_XT_MATCH_MULTIPORT | |
302 | + tristate "Multiple port match support" | |
303 | + depends on NETFILTER_XTABLES | |
304 | + help | |
305 | + Multiport matching allows you to match TCP or UDP packets based on | |
306 | + a series of source or destination ports: normally a rule can only | |
307 | + match a single range of ports. | |
308 | + | |
309 | + To compile it as a module, choose M here. If unsure, say N. | |
310 | + | |
301 | 311 | config NETFILTER_XT_MATCH_PHYSDEV |
302 | 312 | tristate '"physdev" match support' |
303 | 313 | depends on NETFILTER_XTABLES && BRIDGE_NETFILTER |
net/netfilter/Makefile
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
42 | 42 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o |
43 | 43 | obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o |
44 | +obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o | |
44 | 45 | obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o |
45 | 46 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o |
46 | 47 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o |
net/netfilter/xt_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 | +#include <linux/in.h> | |
17 | + | |
18 | +#include <linux/netfilter/xt_multiport.h> | |
19 | +#include <linux/netfilter/x_tables.h> | |
20 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
21 | +#include <linux/netfilter_ipv6/ip6_tables.h> | |
22 | + | |
23 | +MODULE_LICENSE("GPL"); | |
24 | +MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | |
25 | +MODULE_DESCRIPTION("x_tables multiple port match module"); | |
26 | +MODULE_ALIAS("ipt_multiport"); | |
27 | +MODULE_ALIAS("ip6t_multiport"); | |
28 | + | |
29 | +#if 0 | |
30 | +#define duprintf(format, args...) printk(format , ## args) | |
31 | +#else | |
32 | +#define duprintf(format, args...) | |
33 | +#endif | |
34 | + | |
35 | +/* Returns 1 if the port is matched by the test, 0 otherwise. */ | |
36 | +static inline int | |
37 | +ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags, | |
38 | + u_int8_t count, u_int16_t src, u_int16_t dst) | |
39 | +{ | |
40 | + unsigned int i; | |
41 | + for (i = 0; i < count; i++) { | |
42 | + if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src) | |
43 | + return 1; | |
44 | + | |
45 | + if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst) | |
46 | + return 1; | |
47 | + } | |
48 | + | |
49 | + return 0; | |
50 | +} | |
51 | + | |
52 | +/* Returns 1 if the port is matched by the test, 0 otherwise. */ | |
53 | +static inline int | |
54 | +ports_match_v1(const struct xt_multiport_v1 *minfo, | |
55 | + u_int16_t src, u_int16_t dst) | |
56 | +{ | |
57 | + unsigned int i; | |
58 | + u_int16_t s, e; | |
59 | + | |
60 | + for (i = 0; i < minfo->count; i++) { | |
61 | + s = minfo->ports[i]; | |
62 | + | |
63 | + if (minfo->pflags[i]) { | |
64 | + /* range port matching */ | |
65 | + e = minfo->ports[++i]; | |
66 | + duprintf("src or dst matches with %d-%d?\n", s, e); | |
67 | + | |
68 | + if (minfo->flags == XT_MULTIPORT_SOURCE | |
69 | + && src >= s && src <= e) | |
70 | + return 1 ^ minfo->invert; | |
71 | + if (minfo->flags == XT_MULTIPORT_DESTINATION | |
72 | + && dst >= s && dst <= e) | |
73 | + return 1 ^ minfo->invert; | |
74 | + if (minfo->flags == XT_MULTIPORT_EITHER | |
75 | + && ((dst >= s && dst <= e) | |
76 | + || (src >= s && src <= e))) | |
77 | + return 1 ^ minfo->invert; | |
78 | + } else { | |
79 | + /* exact port matching */ | |
80 | + duprintf("src or dst matches with %d?\n", s); | |
81 | + | |
82 | + if (minfo->flags == XT_MULTIPORT_SOURCE | |
83 | + && src == s) | |
84 | + return 1 ^ minfo->invert; | |
85 | + if (minfo->flags == XT_MULTIPORT_DESTINATION | |
86 | + && dst == s) | |
87 | + return 1 ^ minfo->invert; | |
88 | + if (minfo->flags == XT_MULTIPORT_EITHER | |
89 | + && (src == s || dst == s)) | |
90 | + return 1 ^ minfo->invert; | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + return minfo->invert; | |
95 | +} | |
96 | + | |
97 | +static int | |
98 | +match(const struct sk_buff *skb, | |
99 | + const struct net_device *in, | |
100 | + const struct net_device *out, | |
101 | + const struct xt_match *match, | |
102 | + const void *matchinfo, | |
103 | + int offset, | |
104 | + unsigned int protoff, | |
105 | + int *hotdrop) | |
106 | +{ | |
107 | + u16 _ports[2], *pptr; | |
108 | + const struct xt_multiport *multiinfo = matchinfo; | |
109 | + | |
110 | + if (offset) | |
111 | + return 0; | |
112 | + | |
113 | + pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports); | |
114 | + if (pptr == NULL) { | |
115 | + /* We've been asked to examine this packet, and we | |
116 | + * can't. Hence, no choice but to drop. | |
117 | + */ | |
118 | + duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); | |
119 | + *hotdrop = 1; | |
120 | + return 0; | |
121 | + } | |
122 | + | |
123 | + return ports_match(multiinfo->ports, | |
124 | + multiinfo->flags, multiinfo->count, | |
125 | + ntohs(pptr[0]), ntohs(pptr[1])); | |
126 | +} | |
127 | + | |
128 | +static int | |
129 | +match_v1(const struct sk_buff *skb, | |
130 | + const struct net_device *in, | |
131 | + const struct net_device *out, | |
132 | + const struct xt_match *match, | |
133 | + const void *matchinfo, | |
134 | + int offset, | |
135 | + unsigned int protoff, | |
136 | + int *hotdrop) | |
137 | +{ | |
138 | + u16 _ports[2], *pptr; | |
139 | + const struct xt_multiport_v1 *multiinfo = matchinfo; | |
140 | + | |
141 | + if (offset) | |
142 | + return 0; | |
143 | + | |
144 | + pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports); | |
145 | + if (pptr == NULL) { | |
146 | + /* We've been asked to examine this packet, and we | |
147 | + * can't. Hence, no choice but to drop. | |
148 | + */ | |
149 | + duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); | |
150 | + *hotdrop = 1; | |
151 | + return 0; | |
152 | + } | |
153 | + | |
154 | + return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); | |
155 | +} | |
156 | + | |
157 | +static inline int | |
158 | +check(u_int16_t proto, | |
159 | + u_int8_t ip_invflags, | |
160 | + u_int8_t match_flags, | |
161 | + u_int8_t count) | |
162 | +{ | |
163 | + /* Must specify proto == TCP/UDP, no unknown flags or bad count */ | |
164 | + return (proto == IPPROTO_TCP || proto == IPPROTO_UDP) | |
165 | + && !(ip_invflags & XT_INV_PROTO) | |
166 | + && (match_flags == XT_MULTIPORT_SOURCE | |
167 | + || match_flags == XT_MULTIPORT_DESTINATION | |
168 | + || match_flags == XT_MULTIPORT_EITHER) | |
169 | + && count <= XT_MULTI_PORTS; | |
170 | +} | |
171 | + | |
172 | +/* Called when user tries to insert an entry of this type. */ | |
173 | +static int | |
174 | +checkentry(const char *tablename, | |
175 | + const void *info, | |
176 | + const struct xt_match *match, | |
177 | + void *matchinfo, | |
178 | + unsigned int matchsize, | |
179 | + unsigned int hook_mask) | |
180 | +{ | |
181 | + const struct ipt_ip *ip = info; | |
182 | + const struct xt_multiport *multiinfo = matchinfo; | |
183 | + | |
184 | + return check(ip->proto, ip->invflags, multiinfo->flags, | |
185 | + multiinfo->count); | |
186 | +} | |
187 | + | |
188 | +static int | |
189 | +checkentry_v1(const char *tablename, | |
190 | + const void *info, | |
191 | + const struct xt_match *match, | |
192 | + void *matchinfo, | |
193 | + unsigned int matchsize, | |
194 | + unsigned int hook_mask) | |
195 | +{ | |
196 | + const struct ipt_ip *ip = info; | |
197 | + const struct xt_multiport_v1 *multiinfo = matchinfo; | |
198 | + | |
199 | + return check(ip->proto, ip->invflags, multiinfo->flags, | |
200 | + multiinfo->count); | |
201 | +} | |
202 | + | |
203 | +static int | |
204 | +checkentry6(const char *tablename, | |
205 | + const void *info, | |
206 | + const struct xt_match *match, | |
207 | + void *matchinfo, | |
208 | + unsigned int matchsize, | |
209 | + unsigned int hook_mask) | |
210 | +{ | |
211 | + const struct ip6t_ip6 *ip = info; | |
212 | + const struct xt_multiport *multiinfo = matchinfo; | |
213 | + | |
214 | + return check(ip->proto, ip->invflags, multiinfo->flags, | |
215 | + multiinfo->count); | |
216 | +} | |
217 | + | |
218 | +static int | |
219 | +checkentry6_v1(const char *tablename, | |
220 | + const void *info, | |
221 | + const struct xt_match *match, | |
222 | + void *matchinfo, | |
223 | + unsigned int matchsize, | |
224 | + unsigned int hook_mask) | |
225 | +{ | |
226 | + const struct ip6t_ip6 *ip = info; | |
227 | + const struct xt_multiport_v1 *multiinfo = matchinfo; | |
228 | + | |
229 | + return check(ip->proto, ip->invflags, multiinfo->flags, | |
230 | + multiinfo->count); | |
231 | +} | |
232 | + | |
233 | +static struct xt_match multiport_match = { | |
234 | + .name = "multiport", | |
235 | + .revision = 0, | |
236 | + .matchsize = sizeof(struct xt_multiport), | |
237 | + .match = &match, | |
238 | + .checkentry = &checkentry, | |
239 | + .family = AF_INET, | |
240 | + .me = THIS_MODULE, | |
241 | +}; | |
242 | + | |
243 | +static struct xt_match multiport_match_v1 = { | |
244 | + .name = "multiport", | |
245 | + .revision = 1, | |
246 | + .matchsize = sizeof(struct xt_multiport_v1), | |
247 | + .match = &match_v1, | |
248 | + .checkentry = &checkentry_v1, | |
249 | + .family = AF_INET, | |
250 | + .me = THIS_MODULE, | |
251 | +}; | |
252 | + | |
253 | +static struct xt_match multiport6_match = { | |
254 | + .name = "multiport", | |
255 | + .revision = 0, | |
256 | + .matchsize = sizeof(struct xt_multiport), | |
257 | + .match = &match, | |
258 | + .checkentry = &checkentry6, | |
259 | + .family = AF_INET6, | |
260 | + .me = THIS_MODULE, | |
261 | +}; | |
262 | + | |
263 | +static struct xt_match multiport6_match_v1 = { | |
264 | + .name = "multiport", | |
265 | + .revision = 1, | |
266 | + .matchsize = sizeof(struct xt_multiport_v1), | |
267 | + .match = &match_v1, | |
268 | + .checkentry = &checkentry6_v1, | |
269 | + .family = AF_INET6, | |
270 | + .me = THIS_MODULE, | |
271 | +}; | |
272 | + | |
273 | +static int __init xt_multiport_init(void) | |
274 | +{ | |
275 | + int ret; | |
276 | + | |
277 | + ret = xt_register_match(&multiport_match); | |
278 | + if (ret) | |
279 | + goto out; | |
280 | + | |
281 | + ret = xt_register_match(&multiport_match_v1); | |
282 | + if (ret) | |
283 | + goto out_unreg_multi_v0; | |
284 | + | |
285 | + ret = xt_register_match(&multiport6_match); | |
286 | + if (ret) | |
287 | + goto out_unreg_multi_v1; | |
288 | + | |
289 | + ret = xt_register_match(&multiport6_match_v1); | |
290 | + if (ret) | |
291 | + goto out_unreg_multi6_v0; | |
292 | + | |
293 | + return ret; | |
294 | + | |
295 | +out_unreg_multi6_v0: | |
296 | + xt_unregister_match(&multiport6_match); | |
297 | +out_unreg_multi_v1: | |
298 | + xt_unregister_match(&multiport_match_v1); | |
299 | +out_unreg_multi_v0: | |
300 | + xt_unregister_match(&multiport_match); | |
301 | +out: | |
302 | + return ret; | |
303 | +} | |
304 | + | |
305 | +static void __exit xt_multiport_fini(void) | |
306 | +{ | |
307 | + xt_unregister_match(&multiport_match); | |
308 | + xt_unregister_match(&multiport_match_v1); | |
309 | + xt_unregister_match(&multiport6_match); | |
310 | + xt_unregister_match(&multiport6_match_v1); | |
311 | +} | |
312 | + | |
313 | +module_init(xt_multiport_init); | |
314 | +module_exit(xt_multiport_fini); |