1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2 #include <linux/module.h>
3 #include <linux/skbuff.h>
6 #include <net/sctp/sctp.h>
7 #include <linux/sctp.h>
9 #include <linux/netfilter/x_tables.h>
10 #include <linux/netfilter/xt_sctp.h>
11 #include <linux/netfilter_ipv4/ip_tables.h>
12 #include <linux/netfilter_ipv6/ip6_tables.h>
14 MODULE_LICENSE("GPL");
15 MODULE_AUTHOR("Kiran Kumar Immidi");
16 MODULE_DESCRIPTION("Xtables: SCTP protocol packet match");
17 MODULE_ALIAS("ipt_sctp");
18 MODULE_ALIAS("ip6t_sctp");
20 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
21 || (!!((invflag) & (option)) ^ (cond)))
24 match_flags(const struct xt_sctp_flag_info
*flag_info
,
31 for (i
= 0; i
< flag_count
; i
++)
32 if (flag_info
[i
].chunktype
== chunktype
)
33 return (chunkflags
& flag_info
[i
].flag_mask
) == flag_info
[i
].flag
;
39 match_packet(const struct sk_buff
*skb
,
41 const struct xt_sctp_info
*info
,
44 u_int32_t chunkmapcopy
[256 / sizeof (u_int32_t
)];
45 const sctp_chunkhdr_t
*sch
;
47 int chunk_match_type
= info
->chunk_match_type
;
48 const struct xt_sctp_flag_info
*flag_info
= info
->flag_info
;
49 int flag_count
= info
->flag_count
;
55 if (chunk_match_type
== SCTP_CHUNK_MATCH_ALL
)
56 SCTP_CHUNKMAP_COPY(chunkmapcopy
, info
->chunkmap
);
59 sch
= skb_header_pointer(skb
, offset
, sizeof(_sch
), &_sch
);
60 if (sch
== NULL
|| sch
->length
== 0) {
61 pr_debug("Dropping invalid SCTP packet.\n");
66 pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d"
68 ++i
, offset
, sch
->type
, htons(sch
->length
),
71 offset
+= SCTP_PAD4(ntohs(sch
->length
));
73 pr_debug("skb->len: %d\toffset: %d\n", skb
->len
, offset
);
75 if (SCTP_CHUNKMAP_IS_SET(info
->chunkmap
, sch
->type
)) {
76 switch (chunk_match_type
) {
77 case SCTP_CHUNK_MATCH_ANY
:
78 if (match_flags(flag_info
, flag_count
,
79 sch
->type
, sch
->flags
)) {
84 case SCTP_CHUNK_MATCH_ALL
:
85 if (match_flags(flag_info
, flag_count
,
86 sch
->type
, sch
->flags
))
87 SCTP_CHUNKMAP_CLEAR(chunkmapcopy
, sch
->type
);
90 case SCTP_CHUNK_MATCH_ONLY
:
91 if (!match_flags(flag_info
, flag_count
,
92 sch
->type
, sch
->flags
))
97 switch (chunk_match_type
) {
98 case SCTP_CHUNK_MATCH_ONLY
:
102 } while (offset
< skb
->len
);
104 switch (chunk_match_type
) {
105 case SCTP_CHUNK_MATCH_ALL
:
106 return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy
);
107 case SCTP_CHUNK_MATCH_ANY
:
109 case SCTP_CHUNK_MATCH_ONLY
:
113 /* This will never be reached, but required to stop compiler whine */
118 sctp_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
120 const struct xt_sctp_info
*info
= par
->matchinfo
;
121 const sctp_sctphdr_t
*sh
;
124 if (par
->fragoff
!= 0) {
125 pr_debug("Dropping non-first fragment.. FIXME\n");
129 sh
= skb_header_pointer(skb
, par
->thoff
, sizeof(_sh
), &_sh
);
131 pr_debug("Dropping evil TCP offset=0 tinygram.\n");
135 pr_debug("spt: %d\tdpt: %d\n", ntohs(sh
->source
), ntohs(sh
->dest
));
137 return SCCHECK(ntohs(sh
->source
) >= info
->spts
[0]
138 && ntohs(sh
->source
) <= info
->spts
[1],
139 XT_SCTP_SRC_PORTS
, info
->flags
, info
->invflags
)
140 && SCCHECK(ntohs(sh
->dest
) >= info
->dpts
[0]
141 && ntohs(sh
->dest
) <= info
->dpts
[1],
142 XT_SCTP_DEST_PORTS
, info
->flags
, info
->invflags
)
143 && SCCHECK(match_packet(skb
, par
->thoff
+ sizeof(sctp_sctphdr_t
),
144 info
, &par
->hotdrop
),
145 XT_SCTP_CHUNK_TYPES
, info
->flags
, info
->invflags
);
148 static int sctp_mt_check(const struct xt_mtchk_param
*par
)
150 const struct xt_sctp_info
*info
= par
->matchinfo
;
152 if (info
->flags
& ~XT_SCTP_VALID_FLAGS
)
154 if (info
->invflags
& ~XT_SCTP_VALID_FLAGS
)
156 if (info
->invflags
& ~info
->flags
)
158 if (!(info
->flags
& XT_SCTP_CHUNK_TYPES
))
160 if (info
->chunk_match_type
& (SCTP_CHUNK_MATCH_ALL
|
161 SCTP_CHUNK_MATCH_ANY
| SCTP_CHUNK_MATCH_ONLY
))
166 static struct xt_match sctp_mt_reg
[] __read_mostly
= {
169 .family
= NFPROTO_IPV4
,
170 .checkentry
= sctp_mt_check
,
172 .matchsize
= sizeof(struct xt_sctp_info
),
173 .proto
= IPPROTO_SCTP
,
178 .family
= NFPROTO_IPV6
,
179 .checkentry
= sctp_mt_check
,
181 .matchsize
= sizeof(struct xt_sctp_info
),
182 .proto
= IPPROTO_SCTP
,
187 static int __init
sctp_mt_init(void)
189 return xt_register_matches(sctp_mt_reg
, ARRAY_SIZE(sctp_mt_reg
));
192 static void __exit
sctp_mt_exit(void)
194 xt_unregister_matches(sctp_mt_reg
, ARRAY_SIZE(sctp_mt_reg
));
197 module_init(sctp_mt_init
);
198 module_exit(sctp_mt_exit
);