xt_sctp.c 5.0 KB

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