1 #include <linux/module.h>
2 #include <linux/skbuff.h>
5 #include <linux/sctp.h>
7 #include <linux/netfilter/x_tables.h>
8 #include <linux/netfilter/xt_sctp.h>
9 #include <linux/netfilter_ipv4/ip_tables.h>
10 #include <linux/netfilter_ipv6/ip6_tables.h>
12 MODULE_LICENSE("GPL");
13 MODULE_AUTHOR("Kiran Kumar Immidi");
14 MODULE_DESCRIPTION("Match for SCTP protocol packets");
15 MODULE_ALIAS("ipt_sctp");
18 #define duprintf(format, args...) printk(format , ## args)
20 #define duprintf(format, args...)
23 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
24 || (!!((invflag) & (option)) ^ (cond)))
27 match_flags(const struct xt_sctp_flag_info
*flag_info
,
34 for (i
= 0; i
< flag_count
; i
++) {
35 if (flag_info
[i
].chunktype
== chunktype
) {
36 return (chunkflags
& flag_info
[i
].flag_mask
) == flag_info
[i
].flag
;
44 match_packet(const struct sk_buff
*skb
,
46 const u_int32_t
*chunkmap
,
48 const struct xt_sctp_flag_info
*flag_info
,
52 u_int32_t chunkmapcopy
[256 / sizeof (u_int32_t
)];
53 sctp_chunkhdr_t _sch
, *sch
;
59 if (chunk_match_type
== SCTP_CHUNK_MATCH_ALL
) {
60 SCTP_CHUNKMAP_COPY(chunkmapcopy
, chunkmap
);
64 sch
= skb_header_pointer(skb
, offset
, sizeof(_sch
), &_sch
);
66 duprintf("Dropping invalid SCTP packet.\n");
71 duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
72 ++i
, offset
, sch
->type
, htons(sch
->length
), sch
->flags
);
74 offset
+= (htons(sch
->length
) + 3) & ~3;
76 duprintf("skb->len: %d\toffset: %d\n", skb
->len
, offset
);
78 if (SCTP_CHUNKMAP_IS_SET(chunkmap
, sch
->type
)) {
79 switch (chunk_match_type
) {
80 case SCTP_CHUNK_MATCH_ANY
:
81 if (match_flags(flag_info
, flag_count
,
82 sch
->type
, sch
->flags
)) {
87 case SCTP_CHUNK_MATCH_ALL
:
88 if (match_flags(flag_info
, flag_count
,
89 sch
->type
, sch
->flags
)) {
90 SCTP_CHUNKMAP_CLEAR(chunkmapcopy
, sch
->type
);
94 case SCTP_CHUNK_MATCH_ONLY
:
95 if (!match_flags(flag_info
, flag_count
,
96 sch
->type
, sch
->flags
)) {
102 switch (chunk_match_type
) {
103 case SCTP_CHUNK_MATCH_ONLY
:
107 } while (offset
< skb
->len
);
109 switch (chunk_match_type
) {
110 case SCTP_CHUNK_MATCH_ALL
:
111 return SCTP_CHUNKMAP_IS_CLEAR(chunkmap
);
112 case SCTP_CHUNK_MATCH_ANY
:
114 case SCTP_CHUNK_MATCH_ONLY
:
118 /* This will never be reached, but required to stop compiler whine */
123 match(const struct sk_buff
*skb
,
124 const struct net_device
*in
,
125 const struct net_device
*out
,
126 const void *matchinfo
,
128 unsigned int protoff
,
131 const struct xt_sctp_info
*info
;
132 sctp_sctphdr_t _sh
, *sh
;
134 info
= (const struct xt_sctp_info
*)matchinfo
;
137 duprintf("Dropping non-first fragment.. FIXME\n");
141 sh
= skb_header_pointer(skb
, protoff
, sizeof(_sh
), &_sh
);
143 duprintf("Dropping evil TCP offset=0 tinygram.\n");
147 duprintf("spt: %d\tdpt: %d\n", ntohs(sh
->source
), ntohs(sh
->dest
));
149 return SCCHECK(((ntohs(sh
->source
) >= info
->spts
[0])
150 && (ntohs(sh
->source
) <= info
->spts
[1])),
151 XT_SCTP_SRC_PORTS
, info
->flags
, info
->invflags
)
152 && SCCHECK(((ntohs(sh
->dest
) >= info
->dpts
[0])
153 && (ntohs(sh
->dest
) <= info
->dpts
[1])),
154 XT_SCTP_DEST_PORTS
, info
->flags
, info
->invflags
)
155 && SCCHECK(match_packet(skb
, protoff
,
156 info
->chunkmap
, info
->chunk_match_type
,
157 info
->flag_info
, info
->flag_count
,
159 XT_SCTP_CHUNK_TYPES
, info
->flags
, info
->invflags
);
163 checkentry(const char *tablename
,
166 unsigned int matchsize
,
167 unsigned int hook_mask
)
169 const struct xt_sctp_info
*info
;
170 const struct ipt_ip
*ip
= inf
;
172 info
= (const struct xt_sctp_info
*)matchinfo
;
174 return ip
->proto
== IPPROTO_SCTP
175 && !(ip
->invflags
& XT_INV_PROTO
)
176 && matchsize
== XT_ALIGN(sizeof(struct xt_sctp_info
))
177 && !(info
->flags
& ~XT_SCTP_VALID_FLAGS
)
178 && !(info
->invflags
& ~XT_SCTP_VALID_FLAGS
)
179 && !(info
->invflags
& ~info
->flags
)
180 && ((!(info
->flags
& XT_SCTP_CHUNK_TYPES
)) ||
181 (info
->chunk_match_type
&
182 (SCTP_CHUNK_MATCH_ALL
183 | SCTP_CHUNK_MATCH_ANY
184 | SCTP_CHUNK_MATCH_ONLY
)));
188 checkentry6(const char *tablename
,
191 unsigned int matchsize
,
192 unsigned int hook_mask
)
194 const struct xt_sctp_info
*info
;
195 const struct ip6t_ip6
*ip
= inf
;
197 info
= (const struct xt_sctp_info
*)matchinfo
;
199 return ip
->proto
== IPPROTO_SCTP
200 && !(ip
->invflags
& XT_INV_PROTO
)
201 && matchsize
== XT_ALIGN(sizeof(struct xt_sctp_info
))
202 && !(info
->flags
& ~XT_SCTP_VALID_FLAGS
)
203 && !(info
->invflags
& ~XT_SCTP_VALID_FLAGS
)
204 && !(info
->invflags
& ~info
->flags
)
205 && ((!(info
->flags
& XT_SCTP_CHUNK_TYPES
)) ||
206 (info
->chunk_match_type
&
207 (SCTP_CHUNK_MATCH_ALL
208 | SCTP_CHUNK_MATCH_ANY
209 | SCTP_CHUNK_MATCH_ONLY
)));
213 static struct xt_match sctp_match
=
217 .checkentry
= &checkentry
,
220 static struct xt_match sctp6_match
=
224 .checkentry
= &checkentry6
,
229 static int __init
init(void)
232 ret
= xt_register_match(AF_INET
, &sctp_match
);
236 ret
= xt_register_match(AF_INET6
, &sctp6_match
);
238 xt_unregister_match(AF_INET
, &sctp_match
);
243 static void __exit
fini(void)
245 xt_unregister_match(AF_INET6
, &sctp6_match
);
246 xt_unregister_match(AF_INET
, &sctp_match
);