Blame view
net/netfilter/xt_dccp.c
4.44 KB
1d3de414e [NETFILTER]: New ... |
1 2 3 4 5 6 7 8 9 10 11 12 |
/* * iptables module for DCCP protocol header matching * * (C) 2005 by Harald Welte <laforge@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/skbuff.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
1d3de414e [NETFILTER]: New ... |
14 15 16 |
#include <linux/spinlock.h> #include <net/ip.h> #include <linux/dccp.h> |
2e4e6a17a [NETFILTER] x_tab... |
17 18 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_dccp.h> |
1d3de414e [NETFILTER]: New ... |
19 |
#include <linux/netfilter_ipv4/ip_tables.h> |
2e4e6a17a [NETFILTER] x_tab... |
20 21 22 23 |
#include <linux/netfilter_ipv6/ip6_tables.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
2ae15b64e [NETFILTER]: Upda... |
24 |
MODULE_DESCRIPTION("Xtables: DCCP protocol packet match"); |
2e4e6a17a [NETFILTER] x_tab... |
25 |
MODULE_ALIAS("ipt_dccp"); |
73aaf9355 [NETFILTER]: x_ta... |
26 |
MODULE_ALIAS("ip6t_dccp"); |
1d3de414e [NETFILTER]: New ... |
27 28 |
#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ |
601e68e10 [NETFILTER]: Fix ... |
29 |
|| (!!((invflag) & (option)) ^ (cond))) |
1d3de414e [NETFILTER]: New ... |
30 31 32 |
static unsigned char *dccp_optbuf; static DEFINE_SPINLOCK(dccp_buflock); |
1d93a9cba [NETFILTER]: x_ta... |
33 |
static inline bool |
1d3de414e [NETFILTER]: New ... |
34 35 |
dccp_find_option(u_int8_t option, const struct sk_buff *skb, |
2e4e6a17a [NETFILTER] x_tab... |
36 |
unsigned int protoff, |
1d3de414e [NETFILTER]: New ... |
37 |
const struct dccp_hdr *dh, |
cff533ac1 [NETFILTER]: x_ta... |
38 |
bool *hotdrop) |
1d3de414e [NETFILTER]: New ... |
39 40 |
{ /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ |
a47362a22 [NETFILTER]: add ... |
41 |
const unsigned char *op; |
1d3de414e [NETFILTER]: New ... |
42 43 44 |
unsigned int optoff = __dccp_hdr_len(dh); unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh); unsigned int i; |
79f55f11a nf/dccp: merge er... |
45 46 |
if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) goto invalid; |
1d3de414e [NETFILTER]: New ... |
47 48 |
if (!optlen) |
1d93a9cba [NETFILTER]: x_ta... |
49 |
return false; |
1d3de414e [NETFILTER]: New ... |
50 51 |
spin_lock_bh(&dccp_buflock); |
2e4e6a17a [NETFILTER] x_tab... |
52 |
op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf); |
1d3de414e [NETFILTER]: New ... |
53 54 |
if (op == NULL) { /* If we don't have the whole header, drop packet. */ |
79f55f11a nf/dccp: merge er... |
55 |
goto partial; |
1d3de414e [NETFILTER]: New ... |
56 57 58 59 60 |
} for (i = 0; i < optlen; ) { if (op[i] == option) { spin_unlock_bh(&dccp_buflock); |
1d93a9cba [NETFILTER]: x_ta... |
61 |
return true; |
1d3de414e [NETFILTER]: New ... |
62 |
} |
601e68e10 [NETFILTER]: Fix ... |
63 |
if (op[i] < 2) |
1d3de414e [NETFILTER]: New ... |
64 |
i++; |
601e68e10 [NETFILTER]: Fix ... |
65 |
else |
1d3de414e [NETFILTER]: New ... |
66 67 68 69 |
i += op[i+1]?:1; } spin_unlock_bh(&dccp_buflock); |
1d93a9cba [NETFILTER]: x_ta... |
70 |
return false; |
79f55f11a nf/dccp: merge er... |
71 72 73 74 75 76 |
partial: spin_unlock_bh(&dccp_buflock); invalid: *hotdrop = true; return false; |
1d3de414e [NETFILTER]: New ... |
77 |
} |
1d93a9cba [NETFILTER]: x_ta... |
78 |
static inline bool |
1d3de414e [NETFILTER]: New ... |
79 80 |
match_types(const struct dccp_hdr *dh, u_int16_t typemask) { |
7c4e36bc1 [NETFILTER]: Remo... |
81 |
return typemask & (1 << dh->dccph_type); |
1d3de414e [NETFILTER]: New ... |
82 |
} |
1d93a9cba [NETFILTER]: x_ta... |
83 |
static inline bool |
2e4e6a17a [NETFILTER] x_tab... |
84 |
match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, |
cff533ac1 [NETFILTER]: x_ta... |
85 |
const struct dccp_hdr *dh, bool *hotdrop) |
1d3de414e [NETFILTER]: New ... |
86 |
{ |
2e4e6a17a [NETFILTER] x_tab... |
87 |
return dccp_find_option(option, skb, protoff, dh, hotdrop); |
1d3de414e [NETFILTER]: New ... |
88 |
} |
1d93a9cba [NETFILTER]: x_ta... |
89 |
static bool |
62fc80510 netfilter: xtable... |
90 |
dccp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
1d3de414e [NETFILTER]: New ... |
91 |
{ |
f7108a20d netfilter: xtable... |
92 |
const struct xt_dccp_info *info = par->matchinfo; |
3cf93c96a [NETFILTER]: anno... |
93 94 |
const struct dccp_hdr *dh; struct dccp_hdr _dh; |
1d3de414e [NETFILTER]: New ... |
95 |
|
f7108a20d netfilter: xtable... |
96 |
if (par->fragoff != 0) |
1d93a9cba [NETFILTER]: x_ta... |
97 |
return false; |
601e68e10 [NETFILTER]: Fix ... |
98 |
|
f7108a20d netfilter: xtable... |
99 |
dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh); |
1d3de414e [NETFILTER]: New ... |
100 |
if (dh == NULL) { |
b4ba26119 netfilter: xtable... |
101 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
102 |
return false; |
601e68e10 [NETFILTER]: Fix ... |
103 |
} |
1d3de414e [NETFILTER]: New ... |
104 |
|
7c4e36bc1 [NETFILTER]: Remo... |
105 106 |
return DCCHECK(ntohs(dh->dccph_sport) >= info->spts[0] && ntohs(dh->dccph_sport) <= info->spts[1], |
601e68e10 [NETFILTER]: Fix ... |
107 |
XT_DCCP_SRC_PORTS, info->flags, info->invflags) |
7c4e36bc1 [NETFILTER]: Remo... |
108 109 |
&& DCCHECK(ntohs(dh->dccph_dport) >= info->dpts[0] && ntohs(dh->dccph_dport) <= info->dpts[1], |
2e4e6a17a [NETFILTER] x_tab... |
110 |
XT_DCCP_DEST_PORTS, info->flags, info->invflags) |
1d3de414e [NETFILTER]: New ... |
111 |
&& DCCHECK(match_types(dh, info->typemask), |
2e4e6a17a [NETFILTER] x_tab... |
112 |
XT_DCCP_TYPE, info->flags, info->invflags) |
f7108a20d netfilter: xtable... |
113 |
&& DCCHECK(match_option(info->option, skb, par->thoff, dh, |
b4ba26119 netfilter: xtable... |
114 |
&par->hotdrop), |
2e4e6a17a [NETFILTER] x_tab... |
115 |
XT_DCCP_OPTION, info->flags, info->invflags); |
1d3de414e [NETFILTER]: New ... |
116 |
} |
b0f38452f netfilter: xtable... |
117 |
static int dccp_mt_check(const struct xt_mtchk_param *par) |
1d3de414e [NETFILTER]: New ... |
118 |
{ |
9b4fce7a3 netfilter: xtable... |
119 |
const struct xt_dccp_info *info = par->matchinfo; |
1d3de414e [NETFILTER]: New ... |
120 |
|
9f5673174 netfilter: xtable... |
121 |
if (info->flags & ~XT_DCCP_VALID_FLAGS) |
bd414ee60 netfilter: xtable... |
122 |
return -EINVAL; |
9f5673174 netfilter: xtable... |
123 |
if (info->invflags & ~XT_DCCP_VALID_FLAGS) |
bd414ee60 netfilter: xtable... |
124 |
return -EINVAL; |
9f5673174 netfilter: xtable... |
125 |
if (info->invflags & ~info->flags) |
bd414ee60 netfilter: xtable... |
126 127 |
return -EINVAL; return 0; |
2e4e6a17a [NETFILTER] x_tab... |
128 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
129 |
static struct xt_match dccp_mt_reg[] __read_mostly = { |
4470bbc74 [NETFILTER]: x_ta... |
130 131 |
{ .name = "dccp", |
ee999d8b9 netfilter: x_tabl... |
132 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
133 134 |
.checkentry = dccp_mt_check, .match = dccp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
135 136 137 138 139 140 |
.matchsize = sizeof(struct xt_dccp_info), .proto = IPPROTO_DCCP, .me = THIS_MODULE, }, { .name = "dccp", |
ee999d8b9 netfilter: x_tabl... |
141 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
142 143 |
.checkentry = dccp_mt_check, .match = dccp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
144 145 146 147 |
.matchsize = sizeof(struct xt_dccp_info), .proto = IPPROTO_DCCP, .me = THIS_MODULE, }, |
1d3de414e [NETFILTER]: New ... |
148 |
}; |
d3c5ee6d5 [NETFILTER]: x_ta... |
149 |
static int __init dccp_mt_init(void) |
1d3de414e [NETFILTER]: New ... |
150 151 152 153 154 155 156 157 158 |
{ int ret; /* doff is 8 bits, so the maximum option size is (4*256). Don't put * this in BSS since DaveM is worried about locked TLB's for kernel * BSS. */ dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); if (!dccp_optbuf) return -ENOMEM; |
d3c5ee6d5 [NETFILTER]: x_ta... |
159 |
ret = xt_register_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg)); |
1d3de414e [NETFILTER]: New ... |
160 |
if (ret) |
2e4e6a17a [NETFILTER] x_tab... |
161 |
goto out_kfree; |
2e4e6a17a [NETFILTER] x_tab... |
162 |
return ret; |
2e4e6a17a [NETFILTER] x_tab... |
163 164 |
out_kfree: kfree(dccp_optbuf); |
1d3de414e [NETFILTER]: New ... |
165 166 |
return ret; } |
d3c5ee6d5 [NETFILTER]: x_ta... |
167 |
static void __exit dccp_mt_exit(void) |
1d3de414e [NETFILTER]: New ... |
168 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
169 |
xt_unregister_matches(dccp_mt_reg, ARRAY_SIZE(dccp_mt_reg)); |
1d3de414e [NETFILTER]: New ... |
170 171 |
kfree(dccp_optbuf); } |
d3c5ee6d5 [NETFILTER]: x_ta... |
172 173 |
module_init(dccp_mt_init); module_exit(dccp_mt_exit); |