Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / ipv4 / netfilter / ipt_sctp.c
blobfe2b327bcaa495dce12552505a27a9f1955ca4c1
1 #include <linux/module.h>
2 #include <linux/skbuff.h>
3 #include <net/ip.h>
4 #include <linux/sctp.h>
6 #include <linux/netfilter_ipv4/ip_tables.h>
7 #include <linux/netfilter_ipv4/ipt_sctp.h>
9 #ifdef DEBUG_SCTP
10 #define duprintf(format, args...) printk(format , ## args)
11 #else
12 #define duprintf(format, args...)
13 #endif
15 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
16 || (!!((invflag) & (option)) ^ (cond)))
18 static int
19 match_flags(const struct ipt_sctp_flag_info *flag_info,
20 const int flag_count,
21 u_int8_t chunktype,
22 u_int8_t chunkflags)
24 int i;
26 for (i = 0; i < flag_count; i++) {
27 if (flag_info[i].chunktype == chunktype) {
28 return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
32 return 1;
35 static int
36 match_packet(const struct sk_buff *skb,
37 const u_int32_t *chunkmap,
38 int chunk_match_type,
39 const struct ipt_sctp_flag_info *flag_info,
40 const int flag_count,
41 int *hotdrop)
43 int offset;
44 u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
45 sctp_chunkhdr_t _sch, *sch;
47 #ifdef DEBUG_SCTP
48 int i = 0;
49 #endif
51 if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
52 SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
55 offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
56 do {
57 sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
58 if (sch == NULL) {
59 duprintf("Dropping invalid SCTP packet.\n");
60 *hotdrop = 1;
61 return 0;
64 duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
65 ++i, offset, sch->type, htons(sch->length), sch->flags);
67 offset += (htons(sch->length) + 3) & ~3;
69 duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
71 if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
72 switch (chunk_match_type) {
73 case SCTP_CHUNK_MATCH_ANY:
74 if (match_flags(flag_info, flag_count,
75 sch->type, sch->flags)) {
76 return 1;
78 break;
80 case SCTP_CHUNK_MATCH_ALL:
81 if (match_flags(flag_info, flag_count,
82 sch->type, sch->flags)) {
83 SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
85 break;
87 case SCTP_CHUNK_MATCH_ONLY:
88 if (!match_flags(flag_info, flag_count,
89 sch->type, sch->flags)) {
90 return 0;
92 break;
94 } else {
95 switch (chunk_match_type) {
96 case SCTP_CHUNK_MATCH_ONLY:
97 return 0;
100 } while (offset < skb->len);
102 switch (chunk_match_type) {
103 case SCTP_CHUNK_MATCH_ALL:
104 return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
105 case SCTP_CHUNK_MATCH_ANY:
106 return 0;
107 case SCTP_CHUNK_MATCH_ONLY:
108 return 1;
111 /* This will never be reached, but required to stop compiler whine */
112 return 0;
115 static int
116 match(const struct sk_buff *skb,
117 const struct net_device *in,
118 const struct net_device *out,
119 const void *matchinfo,
120 int offset,
121 int *hotdrop)
123 const struct ipt_sctp_info *info;
124 sctp_sctphdr_t _sh, *sh;
126 info = (const struct ipt_sctp_info *)matchinfo;
128 if (offset) {
129 duprintf("Dropping non-first fragment.. FIXME\n");
130 return 0;
133 sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
134 if (sh == NULL) {
135 duprintf("Dropping evil TCP offset=0 tinygram.\n");
136 *hotdrop = 1;
137 return 0;
139 duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
141 return SCCHECK(((ntohs(sh->source) >= info->spts[0])
142 && (ntohs(sh->source) <= info->spts[1])),
143 IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
144 && SCCHECK(((ntohs(sh->dest) >= info->dpts[0])
145 && (ntohs(sh->dest) <= info->dpts[1])),
146 IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
147 && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
148 info->flag_info, info->flag_count,
149 hotdrop),
150 IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
153 static int
154 checkentry(const char *tablename,
155 const struct ipt_ip *ip,
156 void *matchinfo,
157 unsigned int matchsize,
158 unsigned int hook_mask)
160 const struct ipt_sctp_info *info;
162 info = (const struct ipt_sctp_info *)matchinfo;
164 return ip->proto == IPPROTO_SCTP
165 && !(ip->invflags & IPT_INV_PROTO)
166 && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
167 && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
168 && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
169 && !(info->invflags & ~info->flags)
170 && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) ||
171 (info->chunk_match_type &
172 (SCTP_CHUNK_MATCH_ALL
173 | SCTP_CHUNK_MATCH_ANY
174 | SCTP_CHUNK_MATCH_ONLY)));
177 static struct ipt_match sctp_match =
179 .list = { NULL, NULL},
180 .name = "sctp",
181 .match = &match,
182 .checkentry = &checkentry,
183 .destroy = NULL,
184 .me = THIS_MODULE
187 static int __init init(void)
189 return ipt_register_match(&sctp_match);
192 static void __exit fini(void)
194 ipt_unregister_match(&sctp_match);
197 module_init(init);
198 module_exit(fini);
200 MODULE_LICENSE("GPL");
201 MODULE_AUTHOR("Kiran Kumar Immidi");
202 MODULE_DESCRIPTION("Match for SCTP protocol packets");