Blame view
net/netfilter/xt_sctp.c
4.97 KB
be91fd5e3 netfilter: xtable... |
1 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 |
#include <linux/module.h> #include <linux/skbuff.h> #include <net/ip.h> |
2e4e6a17a [NETFILTER] x_tab... |
5 |
#include <net/ipv6.h> |
2bf074825 netfilter: xt_sct... |
6 |
#include <net/sctp/sctp.h> |
1da177e4c Linux-2.6.12-rc2 |
7 |
#include <linux/sctp.h> |
2e4e6a17a [NETFILTER] x_tab... |
8 9 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_sctp.h> |
1da177e4c Linux-2.6.12-rc2 |
10 |
#include <linux/netfilter_ipv4/ip_tables.h> |
2e4e6a17a [NETFILTER] x_tab... |
11 12 13 14 |
#include <linux/netfilter_ipv6/ip6_tables.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kiran Kumar Immidi"); |
2ae15b64e [NETFILTER]: Upda... |
15 |
MODULE_DESCRIPTION("Xtables: SCTP protocol packet match"); |
2e4e6a17a [NETFILTER] x_tab... |
16 |
MODULE_ALIAS("ipt_sctp"); |
73aaf9355 [NETFILTER]: x_ta... |
17 |
MODULE_ALIAS("ip6t_sctp"); |
1da177e4c Linux-2.6.12-rc2 |
18 |
|
1da177e4c Linux-2.6.12-rc2 |
19 20 |
#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ || (!!((invflag) & (option)) ^ (cond))) |
1d93a9cba [NETFILTER]: x_ta... |
21 |
static bool |
2e4e6a17a [NETFILTER] x_tab... |
22 |
match_flags(const struct xt_sctp_flag_info *flag_info, |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 |
const int flag_count, u_int8_t chunktype, u_int8_t chunkflags) { int i; |
7c4e36bc1 [NETFILTER]: Remo... |
28 29 |
for (i = 0; i < flag_count; i++) if (flag_info[i].chunktype == chunktype) |
1da177e4c Linux-2.6.12-rc2 |
30 |
return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag; |
1da177e4c Linux-2.6.12-rc2 |
31 |
|
1d93a9cba [NETFILTER]: x_ta... |
32 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
33 |
} |
1d93a9cba [NETFILTER]: x_ta... |
34 |
static inline bool |
1da177e4c Linux-2.6.12-rc2 |
35 |
match_packet(const struct sk_buff *skb, |
2e4e6a17a [NETFILTER] x_tab... |
36 |
unsigned int offset, |
009e8c965 [NETFILTER]: xt_s... |
37 |
const struct xt_sctp_info *info, |
cff533ac1 [NETFILTER]: x_ta... |
38 |
bool *hotdrop) |
1da177e4c Linux-2.6.12-rc2 |
39 |
{ |
1da177e4c Linux-2.6.12-rc2 |
40 |
u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; |
3cf93c96a [NETFILTER]: anno... |
41 42 |
const sctp_chunkhdr_t *sch; sctp_chunkhdr_t _sch; |
009e8c965 [NETFILTER]: xt_s... |
43 44 45 |
int chunk_match_type = info->chunk_match_type; const struct xt_sctp_flag_info *flag_info = info->flag_info; int flag_count = info->flag_count; |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
be91fd5e3 netfilter: xtable... |
47 |
#ifdef DEBUG |
1da177e4c Linux-2.6.12-rc2 |
48 49 |
int i = 0; #endif |
7c4e36bc1 [NETFILTER]: Remo... |
50 |
if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) |
009e8c965 [NETFILTER]: xt_s... |
51 |
SCTP_CHUNKMAP_COPY(chunkmapcopy, info->chunkmap); |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
1da177e4c Linux-2.6.12-rc2 |
53 54 |
do { sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); |
d3dcd4efe [NETFILTER]: xt_s... |
55 |
if (sch == NULL || sch->length == 0) { |
be91fd5e3 netfilter: xtable... |
56 57 |
pr_debug("Dropping invalid SCTP packet. "); |
cff533ac1 [NETFILTER]: x_ta... |
58 |
*hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
59 |
return false; |
601e68e10 [NETFILTER]: Fix ... |
60 |
} |
be91fd5e3 netfilter: xtable... |
61 62 63 64 65 66 67 |
#ifdef DEBUG pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d" "\tflags: %x ", ++i, offset, sch->type, htons(sch->length), sch->flags); #endif |
2bf074825 netfilter: xt_sct... |
68 |
offset += WORD_ROUND(ntohs(sch->length)); |
1da177e4c Linux-2.6.12-rc2 |
69 |
|
be91fd5e3 netfilter: xtable... |
70 71 |
pr_debug("skb->len: %d\toffset: %d ", skb->len, offset); |
1da177e4c Linux-2.6.12-rc2 |
72 |
|
009e8c965 [NETFILTER]: xt_s... |
73 |
if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) { |
1da177e4c Linux-2.6.12-rc2 |
74 75 |
switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ANY: |
601e68e10 [NETFILTER]: Fix ... |
76 |
if (match_flags(flag_info, flag_count, |
1da177e4c Linux-2.6.12-rc2 |
77 |
sch->type, sch->flags)) { |
1d93a9cba [NETFILTER]: x_ta... |
78 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
79 80 81 82 |
} break; case SCTP_CHUNK_MATCH_ALL: |
601e68e10 [NETFILTER]: Fix ... |
83 |
if (match_flags(flag_info, flag_count, |
7c4e36bc1 [NETFILTER]: Remo... |
84 |
sch->type, sch->flags)) |
1da177e4c Linux-2.6.12-rc2 |
85 |
SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type); |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 |
break; case SCTP_CHUNK_MATCH_ONLY: |
601e68e10 [NETFILTER]: Fix ... |
89 |
if (!match_flags(flag_info, flag_count, |
7c4e36bc1 [NETFILTER]: Remo... |
90 |
sch->type, sch->flags)) |
1d93a9cba [NETFILTER]: x_ta... |
91 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 95 96 |
break; } } else { switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ONLY: |
1d93a9cba [NETFILTER]: x_ta... |
97 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
98 99 100 101 102 103 |
} } } while (offset < skb->len); switch (chunk_match_type) { case SCTP_CHUNK_MATCH_ALL: |
d4e2675a6 netfilter: xt_sct... |
104 |
return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy); |
1da177e4c Linux-2.6.12-rc2 |
105 |
case SCTP_CHUNK_MATCH_ANY: |
1d93a9cba [NETFILTER]: x_ta... |
106 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
107 |
case SCTP_CHUNK_MATCH_ONLY: |
1d93a9cba [NETFILTER]: x_ta... |
108 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
109 110 111 |
} /* This will never be reached, but required to stop compiler whine */ |
1d93a9cba [NETFILTER]: x_ta... |
112 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
113 |
} |
1d93a9cba [NETFILTER]: x_ta... |
114 |
static bool |
62fc80510 netfilter: xtable... |
115 |
sctp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4c Linux-2.6.12-rc2 |
116 |
{ |
f7108a20d netfilter: xtable... |
117 |
const struct xt_sctp_info *info = par->matchinfo; |
3cf93c96a [NETFILTER]: anno... |
118 119 |
const sctp_sctphdr_t *sh; sctp_sctphdr_t _sh; |
1da177e4c Linux-2.6.12-rc2 |
120 |
|
f7108a20d netfilter: xtable... |
121 |
if (par->fragoff != 0) { |
be91fd5e3 netfilter: xtable... |
122 123 |
pr_debug("Dropping non-first fragment.. FIXME "); |
1d93a9cba [NETFILTER]: x_ta... |
124 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
125 |
} |
601e68e10 [NETFILTER]: Fix ... |
126 |
|
f7108a20d netfilter: xtable... |
127 |
sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh); |
1da177e4c Linux-2.6.12-rc2 |
128 |
if (sh == NULL) { |
be91fd5e3 netfilter: xtable... |
129 130 |
pr_debug("Dropping evil TCP offset=0 tinygram. "); |
b4ba26119 netfilter: xtable... |
131 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
132 |
return false; |
601e68e10 [NETFILTER]: Fix ... |
133 |
} |
be91fd5e3 netfilter: xtable... |
134 135 |
pr_debug("spt: %d\tdpt: %d ", ntohs(sh->source), ntohs(sh->dest)); |
1da177e4c Linux-2.6.12-rc2 |
136 |
|
7c4e36bc1 [NETFILTER]: Remo... |
137 138 |
return SCCHECK(ntohs(sh->source) >= info->spts[0] && ntohs(sh->source) <= info->spts[1], |
601e68e10 [NETFILTER]: Fix ... |
139 |
XT_SCTP_SRC_PORTS, info->flags, info->invflags) |
7c4e36bc1 [NETFILTER]: Remo... |
140 141 |
&& SCCHECK(ntohs(sh->dest) >= info->dpts[0] && ntohs(sh->dest) <= info->dpts[1], |
2e4e6a17a [NETFILTER] x_tab... |
142 |
XT_SCTP_DEST_PORTS, info->flags, info->invflags) |
f7108a20d netfilter: xtable... |
143 |
&& SCCHECK(match_packet(skb, par->thoff + sizeof(sctp_sctphdr_t), |
b4ba26119 netfilter: xtable... |
144 |
info, &par->hotdrop), |
2e4e6a17a [NETFILTER] x_tab... |
145 |
XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); |
1da177e4c Linux-2.6.12-rc2 |
146 |
} |
b0f38452f netfilter: xtable... |
147 |
static int sctp_mt_check(const struct xt_mtchk_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
148 |
{ |
9b4fce7a3 netfilter: xtable... |
149 |
const struct xt_sctp_info *info = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
150 |
|
9f5673174 netfilter: xtable... |
151 |
if (info->flags & ~XT_SCTP_VALID_FLAGS) |
bd414ee60 netfilter: xtable... |
152 |
return -EINVAL; |
9f5673174 netfilter: xtable... |
153 |
if (info->invflags & ~XT_SCTP_VALID_FLAGS) |
bd414ee60 netfilter: xtable... |
154 |
return -EINVAL; |
9f5673174 netfilter: xtable... |
155 |
if (info->invflags & ~info->flags) |
bd414ee60 netfilter: xtable... |
156 |
return -EINVAL; |
9f5673174 netfilter: xtable... |
157 |
if (!(info->flags & XT_SCTP_CHUNK_TYPES)) |
bd414ee60 netfilter: xtable... |
158 |
return 0; |
9f5673174 netfilter: xtable... |
159 160 |
if (info->chunk_match_type & (SCTP_CHUNK_MATCH_ALL | SCTP_CHUNK_MATCH_ANY | SCTP_CHUNK_MATCH_ONLY)) |
bd414ee60 netfilter: xtable... |
161 162 |
return 0; return -EINVAL; |
2e4e6a17a [NETFILTER] x_tab... |
163 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
164 |
static struct xt_match sctp_mt_reg[] __read_mostly = { |
4470bbc74 [NETFILTER]: x_ta... |
165 166 |
{ .name = "sctp", |
ee999d8b9 netfilter: x_tabl... |
167 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
168 169 |
.checkentry = sctp_mt_check, .match = sctp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
170 171 172 173 174 175 |
.matchsize = sizeof(struct xt_sctp_info), .proto = IPPROTO_SCTP, .me = THIS_MODULE }, { .name = "sctp", |
ee999d8b9 netfilter: x_tabl... |
176 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
177 178 |
.checkentry = sctp_mt_check, .match = sctp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
179 180 181 182 |
.matchsize = sizeof(struct xt_sctp_info), .proto = IPPROTO_SCTP, .me = THIS_MODULE }, |
5d04bff09 [NETFILTER]: Conv... |
183 |
}; |
2e4e6a17a [NETFILTER] x_tab... |
184 |
|
d3c5ee6d5 [NETFILTER]: x_ta... |
185 |
static int __init sctp_mt_init(void) |
1da177e4c Linux-2.6.12-rc2 |
186 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
187 |
return xt_register_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg)); |
1da177e4c Linux-2.6.12-rc2 |
188 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
189 |
static void __exit sctp_mt_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
190 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
191 |
xt_unregister_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg)); |
1da177e4c Linux-2.6.12-rc2 |
192 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
193 194 |
module_init(sctp_mt_init); module_exit(sctp_mt_exit); |