diff options
-rw-r--r-- | include/linux/dccp.h | 16 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/ipt_dccp.h | 23 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 11 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_dccp.c | 176 |
5 files changed, 224 insertions, 3 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index fd1412ddb3ff..431d58923ba9 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -242,10 +242,15 @@ static inline struct dccp_hdr_ext *dccp_hdrx(const struct sk_buff *skb) | |||
242 | return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr)); | 242 | return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr)); |
243 | } | 243 | } |
244 | 244 | ||
245 | static inline unsigned int __dccp_basic_hdr_len(const struct dccp_hdr *dh) | ||
246 | { | ||
247 | return sizeof(*dh) + (dh->dccph_x ? sizeof(struct dccp_hdr_ext) : 0); | ||
248 | } | ||
249 | |||
245 | static inline unsigned int dccp_basic_hdr_len(const struct sk_buff *skb) | 250 | static inline unsigned int dccp_basic_hdr_len(const struct sk_buff *skb) |
246 | { | 251 | { |
247 | const struct dccp_hdr *dh = dccp_hdr(skb); | 252 | const struct dccp_hdr *dh = dccp_hdr(skb); |
248 | return sizeof(*dh) + (dh->dccph_x ? sizeof(struct dccp_hdr_ext) : 0); | 253 | return __dccp_basic_hdr_len(dh); |
249 | } | 254 | } |
250 | 255 | ||
251 | static inline __u64 dccp_hdr_seq(const struct sk_buff *skb) | 256 | static inline __u64 dccp_hdr_seq(const struct sk_buff *skb) |
@@ -297,10 +302,15 @@ static inline struct dccp_hdr_reset *dccp_hdr_reset(struct sk_buff *skb) | |||
297 | return (struct dccp_hdr_reset *)(skb->h.raw + dccp_basic_hdr_len(skb)); | 302 | return (struct dccp_hdr_reset *)(skb->h.raw + dccp_basic_hdr_len(skb)); |
298 | } | 303 | } |
299 | 304 | ||
305 | static inline unsigned int __dccp_hdr_len(const struct dccp_hdr *dh) | ||
306 | { | ||
307 | return __dccp_basic_hdr_len(dh) + | ||
308 | dccp_packet_hdr_len(dh->dccph_type); | ||
309 | } | ||
310 | |||
300 | static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) | 311 | static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) |
301 | { | 312 | { |
302 | return dccp_basic_hdr_len(skb) + | 313 | return __dccp_hdr_len(dccp_hdr(skb)); |
303 | dccp_packet_hdr_len(dccp_hdr(skb)->dccph_type); | ||
304 | } | 314 | } |
305 | 315 | ||
306 | 316 | ||
diff --git a/include/linux/netfilter_ipv4/ipt_dccp.h b/include/linux/netfilter_ipv4/ipt_dccp.h new file mode 100644 index 000000000000..3cb3a522e62b --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_dccp.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef _IPT_DCCP_H_ | ||
2 | #define _IPT_DCCP_H_ | ||
3 | |||
4 | #define IPT_DCCP_SRC_PORTS 0x01 | ||
5 | #define IPT_DCCP_DEST_PORTS 0x02 | ||
6 | #define IPT_DCCP_TYPE 0x04 | ||
7 | #define IPT_DCCP_OPTION 0x08 | ||
8 | |||
9 | #define IPT_DCCP_VALID_FLAGS 0x0f | ||
10 | |||
11 | struct ipt_dccp_info { | ||
12 | u_int16_t dpts[2]; /* Min, Max */ | ||
13 | u_int16_t spts[2]; /* Min, Max */ | ||
14 | |||
15 | u_int16_t flags; | ||
16 | u_int16_t invflags; | ||
17 | |||
18 | u_int16_t typemask; | ||
19 | u_int8_t option; | ||
20 | }; | ||
21 | |||
22 | #endif /* _IPT_DCCP_H_ */ | ||
23 | |||
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 2fa26a41fa47..9f5e1d769b5f 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -354,6 +354,17 @@ config IP_NF_MATCH_SCTP | |||
354 | If you want to compile it as a module, say M here and read | 354 | If you want to compile it as a module, say M here and read |
355 | <file:Documentation/modules.txt>. If unsure, say `N'. | 355 | <file:Documentation/modules.txt>. If unsure, say `N'. |
356 | 356 | ||
357 | config IP_NF_MATCH_DCCP | ||
358 | tristate 'DCCP protocol match support' | ||
359 | depends on IP_NF_IPTABLES | ||
360 | help | ||
361 | With this option enabled, you will be able to use the iptables | ||
362 | `dccp' match in order to match on DCCP source/destination ports | ||
363 | and DCCP flags. | ||
364 | |||
365 | If you want to compile it as a module, say M here and read | ||
366 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
367 | |||
357 | config IP_NF_MATCH_COMMENT | 368 | config IP_NF_MATCH_COMMENT |
358 | tristate 'comment match support' | 369 | tristate 'comment match support' |
359 | depends on IP_NF_IPTABLES | 370 | depends on IP_NF_IPTABLES |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index c2ae663b723f..58aa7c616e1f 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -42,6 +42,7 @@ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o | |||
42 | obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o | 42 | obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o |
43 | obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o | 43 | obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o |
44 | obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o | 44 | obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o |
45 | obj-$(CONFIG_IP_NF_MATCH_DCCP) += ipt_dccp.o | ||
45 | obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o | 46 | obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o |
46 | obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o | 47 | obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o |
47 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o | 48 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o |
diff --git a/net/ipv4/netfilter/ipt_dccp.c b/net/ipv4/netfilter/ipt_dccp.c new file mode 100644 index 000000000000..ad3278bba6c1 --- /dev/null +++ b/net/ipv4/netfilter/ipt_dccp.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * iptables module for DCCP protocol header matching | ||
3 | * | ||
4 | * (C) 2005 by Harald Welte <laforge@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <net/ip.h> | ||
15 | #include <linux/dccp.h> | ||
16 | |||
17 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
18 | #include <linux/netfilter_ipv4/ipt_dccp.h> | ||
19 | |||
20 | #define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ | ||
21 | || (!!((invflag) & (option)) ^ (cond))) | ||
22 | |||
23 | static unsigned char *dccp_optbuf; | ||
24 | static DEFINE_SPINLOCK(dccp_buflock); | ||
25 | |||
26 | static inline int | ||
27 | dccp_find_option(u_int8_t option, | ||
28 | const struct sk_buff *skb, | ||
29 | const struct dccp_hdr *dh, | ||
30 | int *hotdrop) | ||
31 | { | ||
32 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ | ||
33 | unsigned char *op; | ||
34 | unsigned int optoff = __dccp_hdr_len(dh); | ||
35 | unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh); | ||
36 | unsigned int i; | ||
37 | |||
38 | if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) { | ||
39 | *hotdrop = 1; | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | if (!optlen) | ||
44 | return 0; | ||
45 | |||
46 | spin_lock_bh(&dccp_buflock); | ||
47 | op = skb_header_pointer(skb, | ||
48 | skb->nh.iph->ihl*4 + optoff, | ||
49 | optlen, dccp_optbuf); | ||
50 | if (op == NULL) { | ||
51 | /* If we don't have the whole header, drop packet. */ | ||
52 | spin_unlock_bh(&dccp_buflock); | ||
53 | *hotdrop = 1; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | for (i = 0; i < optlen; ) { | ||
58 | if (op[i] == option) { | ||
59 | spin_unlock_bh(&dccp_buflock); | ||
60 | return 1; | ||
61 | } | ||
62 | |||
63 | if (op[i] < 2) | ||
64 | i++; | ||
65 | else | ||
66 | i += op[i+1]?:1; | ||
67 | } | ||
68 | |||
69 | spin_unlock_bh(&dccp_buflock); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | |||
74 | static inline int | ||
75 | match_types(const struct dccp_hdr *dh, u_int16_t typemask) | ||
76 | { | ||
77 | return (typemask & (1 << dh->dccph_type)); | ||
78 | } | ||
79 | |||
80 | static inline int | ||
81 | match_option(u_int8_t option, const struct sk_buff *skb, | ||
82 | const struct dccp_hdr *dh, int *hotdrop) | ||
83 | { | ||
84 | return dccp_find_option(option, skb, dh, hotdrop); | ||
85 | } | ||
86 | |||
87 | static int | ||
88 | match(const struct sk_buff *skb, | ||
89 | const struct net_device *in, | ||
90 | const struct net_device *out, | ||
91 | const void *matchinfo, | ||
92 | int offset, | ||
93 | int *hotdrop) | ||
94 | { | ||
95 | const struct ipt_dccp_info *info = | ||
96 | (const struct ipt_dccp_info *)matchinfo; | ||
97 | struct dccp_hdr _dh, *dh; | ||
98 | |||
99 | if (offset) | ||
100 | return 0; | ||
101 | |||
102 | dh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_dh), &_dh); | ||
103 | if (dh == NULL) { | ||
104 | *hotdrop = 1; | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | return DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) | ||
109 | && (ntohs(dh->dccph_sport) <= info->spts[1])), | ||
110 | IPT_DCCP_SRC_PORTS, info->flags, info->invflags) | ||
111 | && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) | ||
112 | && (ntohs(dh->dccph_dport) <= info->dpts[1])), | ||
113 | IPT_DCCP_DEST_PORTS, info->flags, info->invflags) | ||
114 | && DCCHECK(match_types(dh, info->typemask), | ||
115 | IPT_DCCP_TYPE, info->flags, info->invflags) | ||
116 | && DCCHECK(match_option(info->option, skb, dh, hotdrop), | ||
117 | IPT_DCCP_OPTION, info->flags, info->invflags); | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | checkentry(const char *tablename, | ||
122 | const struct ipt_ip *ip, | ||
123 | void *matchinfo, | ||
124 | unsigned int matchsize, | ||
125 | unsigned int hook_mask) | ||
126 | { | ||
127 | const struct ipt_dccp_info *info; | ||
128 | |||
129 | info = (const struct ipt_dccp_info *)matchinfo; | ||
130 | |||
131 | return ip->proto == IPPROTO_DCCP | ||
132 | && !(ip->invflags & IPT_INV_PROTO) | ||
133 | && matchsize == IPT_ALIGN(sizeof(struct ipt_dccp_info)) | ||
134 | && !(info->flags & ~IPT_DCCP_VALID_FLAGS) | ||
135 | && !(info->invflags & ~IPT_DCCP_VALID_FLAGS) | ||
136 | && !(info->invflags & ~info->flags); | ||
137 | } | ||
138 | |||
139 | static struct ipt_match dccp_match = | ||
140 | { | ||
141 | .name = "dccp", | ||
142 | .match = &match, | ||
143 | .checkentry = &checkentry, | ||
144 | .me = THIS_MODULE, | ||
145 | }; | ||
146 | |||
147 | static int __init init(void) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | /* doff is 8 bits, so the maximum option size is (4*256). Don't put | ||
152 | * this in BSS since DaveM is worried about locked TLB's for kernel | ||
153 | * BSS. */ | ||
154 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); | ||
155 | if (!dccp_optbuf) | ||
156 | return -ENOMEM; | ||
157 | ret = ipt_register_match(&dccp_match); | ||
158 | if (ret) | ||
159 | kfree(dccp_optbuf); | ||
160 | |||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | static void __exit fini(void) | ||
165 | { | ||
166 | ipt_unregister_match(&dccp_match); | ||
167 | kfree(dccp_optbuf); | ||
168 | } | ||
169 | |||
170 | module_init(init); | ||
171 | module_exit(fini); | ||
172 | |||
173 | MODULE_LICENSE("GPL"); | ||
174 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
175 | MODULE_DESCRIPTION("Match for DCCP protocol packets"); | ||
176 | |||