Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0003 #include <linux/module.h>
0004 #include <linux/skbuff.h>
0005 #include <net/ip.h>
0006 #include <net/ipv6.h>
0007 #include <net/sctp/sctp.h>
0008 #include <linux/sctp.h>
0009 
0010 #include <linux/netfilter/x_tables.h>
0011 #include <linux/netfilter/xt_sctp.h>
0012 #include <linux/netfilter_ipv4/ip_tables.h>
0013 #include <linux/netfilter_ipv6/ip6_tables.h>
0014 
0015 MODULE_LICENSE("GPL");
0016 MODULE_AUTHOR("Kiran Kumar Immidi");
0017 MODULE_DESCRIPTION("Xtables: SCTP protocol packet match");
0018 MODULE_ALIAS("ipt_sctp");
0019 MODULE_ALIAS("ip6t_sctp");
0020 
0021 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
0022                           || (!!((invflag) & (option)) ^ (cond)))
0023 
0024 static bool
0025 match_flags(const struct xt_sctp_flag_info *flag_info,
0026         const int flag_count,
0027         u_int8_t chunktype,
0028         u_int8_t chunkflags)
0029 {
0030     int i;
0031 
0032     for (i = 0; i < flag_count; i++)
0033         if (flag_info[i].chunktype == chunktype)
0034             return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
0035 
0036     return true;
0037 }
0038 
0039 static inline bool
0040 match_packet(const struct sk_buff *skb,
0041          unsigned int offset,
0042          const struct xt_sctp_info *info,
0043          bool *hotdrop)
0044 {
0045     u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
0046     const struct sctp_chunkhdr *sch;
0047     struct sctp_chunkhdr _sch;
0048     int chunk_match_type = info->chunk_match_type;
0049     const struct xt_sctp_flag_info *flag_info = info->flag_info;
0050     int flag_count = info->flag_count;
0051 
0052 #ifdef DEBUG
0053     int i = 0;
0054 #endif
0055 
0056     if (chunk_match_type == SCTP_CHUNK_MATCH_ALL)
0057         SCTP_CHUNKMAP_COPY(chunkmapcopy, info->chunkmap);
0058 
0059     do {
0060         sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
0061         if (sch == NULL || sch->length == 0) {
0062             pr_debug("Dropping invalid SCTP packet.\n");
0063             *hotdrop = true;
0064             return false;
0065         }
0066 #ifdef DEBUG
0067         pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d"
0068              "\tflags: %x\n",
0069              ++i, offset, sch->type, htons(sch->length),
0070              sch->flags);
0071 #endif
0072         offset += SCTP_PAD4(ntohs(sch->length));
0073 
0074         pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset);
0075 
0076         if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) {
0077             switch (chunk_match_type) {
0078             case SCTP_CHUNK_MATCH_ANY:
0079                 if (match_flags(flag_info, flag_count,
0080                     sch->type, sch->flags)) {
0081                     return true;
0082                 }
0083                 break;
0084 
0085             case SCTP_CHUNK_MATCH_ALL:
0086                 if (match_flags(flag_info, flag_count,
0087                     sch->type, sch->flags))
0088                     SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
0089                 break;
0090 
0091             case SCTP_CHUNK_MATCH_ONLY:
0092                 if (!match_flags(flag_info, flag_count,
0093                     sch->type, sch->flags))
0094                     return false;
0095                 break;
0096             }
0097         } else {
0098             switch (chunk_match_type) {
0099             case SCTP_CHUNK_MATCH_ONLY:
0100                 return false;
0101             }
0102         }
0103     } while (offset < skb->len);
0104 
0105     switch (chunk_match_type) {
0106     case SCTP_CHUNK_MATCH_ALL:
0107         return SCTP_CHUNKMAP_IS_CLEAR(chunkmapcopy);
0108     case SCTP_CHUNK_MATCH_ANY:
0109         return false;
0110     case SCTP_CHUNK_MATCH_ONLY:
0111         return true;
0112     }
0113 
0114     /* This will never be reached, but required to stop compiler whine */
0115     return false;
0116 }
0117 
0118 static bool
0119 sctp_mt(const struct sk_buff *skb, struct xt_action_param *par)
0120 {
0121     const struct xt_sctp_info *info = par->matchinfo;
0122     const struct sctphdr *sh;
0123     struct sctphdr _sh;
0124 
0125     if (par->fragoff != 0) {
0126         pr_debug("Dropping non-first fragment.. FIXME\n");
0127         return false;
0128     }
0129 
0130     sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh);
0131     if (sh == NULL) {
0132         pr_debug("Dropping evil TCP offset=0 tinygram.\n");
0133         par->hotdrop = true;
0134         return false;
0135     }
0136     pr_debug("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
0137 
0138     return  SCCHECK(ntohs(sh->source) >= info->spts[0]
0139             && ntohs(sh->source) <= info->spts[1],
0140             XT_SCTP_SRC_PORTS, info->flags, info->invflags) &&
0141         SCCHECK(ntohs(sh->dest) >= info->dpts[0]
0142             && ntohs(sh->dest) <= info->dpts[1],
0143             XT_SCTP_DEST_PORTS, info->flags, info->invflags) &&
0144         SCCHECK(match_packet(skb, par->thoff + sizeof(_sh),
0145                      info, &par->hotdrop),
0146             XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
0147 }
0148 
0149 static int sctp_mt_check(const struct xt_mtchk_param *par)
0150 {
0151     const struct xt_sctp_info *info = par->matchinfo;
0152 
0153     if (info->flags & ~XT_SCTP_VALID_FLAGS)
0154         return -EINVAL;
0155     if (info->invflags & ~XT_SCTP_VALID_FLAGS)
0156         return -EINVAL;
0157     if (info->invflags & ~info->flags)
0158         return -EINVAL;
0159     if (!(info->flags & XT_SCTP_CHUNK_TYPES))
0160         return 0;
0161     if (info->chunk_match_type & (SCTP_CHUNK_MATCH_ALL |
0162         SCTP_CHUNK_MATCH_ANY | SCTP_CHUNK_MATCH_ONLY))
0163         return 0;
0164     return -EINVAL;
0165 }
0166 
0167 static struct xt_match sctp_mt_reg[] __read_mostly = {
0168     {
0169         .name       = "sctp",
0170         .family     = NFPROTO_IPV4,
0171         .checkentry = sctp_mt_check,
0172         .match      = sctp_mt,
0173         .matchsize  = sizeof(struct xt_sctp_info),
0174         .proto      = IPPROTO_SCTP,
0175         .me     = THIS_MODULE
0176     },
0177     {
0178         .name       = "sctp",
0179         .family     = NFPROTO_IPV6,
0180         .checkentry = sctp_mt_check,
0181         .match      = sctp_mt,
0182         .matchsize  = sizeof(struct xt_sctp_info),
0183         .proto      = IPPROTO_SCTP,
0184         .me     = THIS_MODULE
0185     },
0186 };
0187 
0188 static int __init sctp_mt_init(void)
0189 {
0190     return xt_register_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg));
0191 }
0192 
0193 static void __exit sctp_mt_exit(void)
0194 {
0195     xt_unregister_matches(sctp_mt_reg, ARRAY_SIZE(sctp_mt_reg));
0196 }
0197 
0198 module_init(sctp_mt_init);
0199 module_exit(sctp_mt_exit);