1 #include <linux/module.h>
2 #include <linux/skbuff.h>
4 #include <linux/sctp.h>
6 #include <linux/netfilter_ipv4/ip_tables.h>
7 #include <linux/netfilter_ipv4/ipt_sctp.h>
10 #define duprintf(format, args...) printk(format , ## args)
12 #define duprintf(format, args...)
15 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
16 || (!!((invflag) & (option)) ^ (cond)))
19 match_flags(const struct ipt_sctp_flag_info *flag_info,
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;
36 match_packet(const struct sk_buff *skb,
37 const u_int32_t *chunkmap,
39 const struct ipt_sctp_flag_info *flag_info,
44 u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
45 sctp_chunkhdr_t _sch, *sch;
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);
57 sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
59 duprintf("Dropping invalid SCTP packet.\n");
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)) {
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);
87 case SCTP_CHUNK_MATCH_ONLY:
88 if (!match_flags(flag_info, flag_count,
89 sch->type, sch->flags)) {
95 switch (chunk_match_type) {
96 case SCTP_CHUNK_MATCH_ONLY:
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:
107 case SCTP_CHUNK_MATCH_ONLY:
111 /* This will never be reached, but required to stop compiler whine */
116 match(const struct sk_buff *skb,
117 const struct net_device *in,
118 const struct net_device *out,
119 const void *matchinfo,
123 const struct ipt_sctp_info *info;
124 sctp_sctphdr_t _sh, *sh;
126 info = (const struct ipt_sctp_info *)matchinfo;
129 duprintf("Dropping non-first fragment.. FIXME\n");
133 sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
135 duprintf("Dropping evil TCP offset=0 tinygram.\n");
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,
150 IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
154 checkentry(const char *tablename,
155 const struct ipt_ip *ip,
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},
182 .checkentry = &checkentry,
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);
200 MODULE_LICENSE("GPL");
201 MODULE_AUTHOR("Kiran Kumar Immidi");
202 MODULE_DESCRIPTION("Match for SCTP protocol packets");