xt_dccp.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * iptables module for DCCP protocol header matching
  3. *
  4. * (C) 2005 by Harald Welte <laforge@netfilter.org>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/spinlock.h>
  13. #include <net/ip.h>
  14. #include <linux/dccp.h>
  15. #include <linux/netfilter/x_tables.h>
  16. #include <linux/netfilter/xt_dccp.h>
  17. #include <linux/netfilter_ipv4/ip_tables.h>
  18. #include <linux/netfilter_ipv6/ip6_tables.h>
  19. MODULE_LICENSE("GPL");
  20. MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  21. MODULE_DESCRIPTION("Match for DCCP protocol packets");
  22. MODULE_ALIAS("ipt_dccp");
  23. #define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
  24. || (!!((invflag) & (option)) ^ (cond)))
  25. static unsigned char *dccp_optbuf;
  26. static DEFINE_SPINLOCK(dccp_buflock);
  27. static inline int
  28. dccp_find_option(u_int8_t option,
  29. const struct sk_buff *skb,
  30. unsigned int protoff,
  31. const struct dccp_hdr *dh,
  32. int *hotdrop)
  33. {
  34. /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
  35. unsigned char *op;
  36. unsigned int optoff = __dccp_hdr_len(dh);
  37. unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
  38. unsigned int i;
  39. if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
  40. *hotdrop = 1;
  41. return 0;
  42. }
  43. if (!optlen)
  44. return 0;
  45. spin_lock_bh(&dccp_buflock);
  46. op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
  47. if (op == NULL) {
  48. /* If we don't have the whole header, drop packet. */
  49. spin_unlock_bh(&dccp_buflock);
  50. *hotdrop = 1;
  51. return 0;
  52. }
  53. for (i = 0; i < optlen; ) {
  54. if (op[i] == option) {
  55. spin_unlock_bh(&dccp_buflock);
  56. return 1;
  57. }
  58. if (op[i] < 2)
  59. i++;
  60. else
  61. i += op[i+1]?:1;
  62. }
  63. spin_unlock_bh(&dccp_buflock);
  64. return 0;
  65. }
  66. static inline int
  67. match_types(const struct dccp_hdr *dh, u_int16_t typemask)
  68. {
  69. return (typemask & (1 << dh->dccph_type));
  70. }
  71. static inline int
  72. match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
  73. const struct dccp_hdr *dh, int *hotdrop)
  74. {
  75. return dccp_find_option(option, skb, protoff, dh, hotdrop);
  76. }
  77. static int
  78. match(const struct sk_buff *skb,
  79. const struct net_device *in,
  80. const struct net_device *out,
  81. const struct xt_match *match,
  82. const void *matchinfo,
  83. int offset,
  84. unsigned int protoff,
  85. int *hotdrop)
  86. {
  87. const struct xt_dccp_info *info = matchinfo;
  88. struct dccp_hdr _dh, *dh;
  89. if (offset)
  90. return 0;
  91. dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
  92. if (dh == NULL) {
  93. *hotdrop = 1;
  94. return 0;
  95. }
  96. return DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0])
  97. && (ntohs(dh->dccph_sport) <= info->spts[1])),
  98. XT_DCCP_SRC_PORTS, info->flags, info->invflags)
  99. && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0])
  100. && (ntohs(dh->dccph_dport) <= info->dpts[1])),
  101. XT_DCCP_DEST_PORTS, info->flags, info->invflags)
  102. && DCCHECK(match_types(dh, info->typemask),
  103. XT_DCCP_TYPE, info->flags, info->invflags)
  104. && DCCHECK(match_option(info->option, skb, protoff, dh,
  105. hotdrop),
  106. XT_DCCP_OPTION, info->flags, info->invflags);
  107. }
  108. static int
  109. checkentry(const char *tablename,
  110. const void *inf,
  111. const struct xt_match *match,
  112. void *matchinfo,
  113. unsigned int hook_mask)
  114. {
  115. const struct xt_dccp_info *info = matchinfo;
  116. return !(info->flags & ~XT_DCCP_VALID_FLAGS)
  117. && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
  118. && !(info->invflags & ~info->flags);
  119. }
  120. static struct xt_match xt_dccp_match[] = {
  121. {
  122. .name = "dccp",
  123. .family = AF_INET,
  124. .checkentry = checkentry,
  125. .match = match,
  126. .matchsize = sizeof(struct xt_dccp_info),
  127. .proto = IPPROTO_DCCP,
  128. .me = THIS_MODULE,
  129. },
  130. {
  131. .name = "dccp",
  132. .family = AF_INET6,
  133. .checkentry = checkentry,
  134. .match = match,
  135. .matchsize = sizeof(struct xt_dccp_info),
  136. .proto = IPPROTO_DCCP,
  137. .me = THIS_MODULE,
  138. },
  139. };
  140. static int __init xt_dccp_init(void)
  141. {
  142. int ret;
  143. /* doff is 8 bits, so the maximum option size is (4*256). Don't put
  144. * this in BSS since DaveM is worried about locked TLB's for kernel
  145. * BSS. */
  146. dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
  147. if (!dccp_optbuf)
  148. return -ENOMEM;
  149. ret = xt_register_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match));
  150. if (ret)
  151. goto out_kfree;
  152. return ret;
  153. out_kfree:
  154. kfree(dccp_optbuf);
  155. return ret;
  156. }
  157. static void __exit xt_dccp_fini(void)
  158. {
  159. xt_unregister_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match));
  160. kfree(dccp_optbuf);
  161. }
  162. module_init(xt_dccp_init);
  163. module_exit(xt_dccp_fini);