xt_sctp.c 5.0 KB

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