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