xt_multiport.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
  3. ports are in the same place so we can treat them as equal. */
  4. /* (C) 1999-2001 Paul `Rusty' Russell
  5. * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  6. */
  7. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8. #include <linux/module.h>
  9. #include <linux/types.h>
  10. #include <linux/udp.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/in.h>
  13. #include <linux/netfilter/xt_multiport.h>
  14. #include <linux/netfilter/x_tables.h>
  15. #include <linux/netfilter_ipv4/ip_tables.h>
  16. #include <linux/netfilter_ipv6/ip6_tables.h>
  17. MODULE_LICENSE("GPL");
  18. MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  19. MODULE_DESCRIPTION("Xtables: multiple port matching for TCP, UDP, UDP-Lite, SCTP and DCCP");
  20. MODULE_ALIAS("ipt_multiport");
  21. MODULE_ALIAS("ip6t_multiport");
  22. /* Returns 1 if the port is matched by the test, 0 otherwise. */
  23. static inline bool
  24. ports_match_v1(const struct xt_multiport_v1 *minfo,
  25. u_int16_t src, u_int16_t dst)
  26. {
  27. unsigned int i;
  28. u_int16_t s, e;
  29. for (i = 0; i < minfo->count; i++) {
  30. s = minfo->ports[i];
  31. if (minfo->pflags[i]) {
  32. /* range port matching */
  33. e = minfo->ports[++i];
  34. pr_debug("src or dst matches with %d-%d?\n", s, e);
  35. switch (minfo->flags) {
  36. case XT_MULTIPORT_SOURCE:
  37. if (src >= s && src <= e)
  38. return true ^ minfo->invert;
  39. break;
  40. case XT_MULTIPORT_DESTINATION:
  41. if (dst >= s && dst <= e)
  42. return true ^ minfo->invert;
  43. break;
  44. case XT_MULTIPORT_EITHER:
  45. if ((dst >= s && dst <= e) ||
  46. (src >= s && src <= e))
  47. return true ^ minfo->invert;
  48. break;
  49. default:
  50. break;
  51. }
  52. } else {
  53. /* exact port matching */
  54. pr_debug("src or dst matches with %d?\n", s);
  55. switch (minfo->flags) {
  56. case XT_MULTIPORT_SOURCE:
  57. if (src == s)
  58. return true ^ minfo->invert;
  59. break;
  60. case XT_MULTIPORT_DESTINATION:
  61. if (dst == s)
  62. return true ^ minfo->invert;
  63. break;
  64. case XT_MULTIPORT_EITHER:
  65. if (src == s || dst == s)
  66. return true ^ minfo->invert;
  67. break;
  68. default:
  69. break;
  70. }
  71. }
  72. }
  73. return minfo->invert;
  74. }
  75. static bool
  76. multiport_mt(const struct sk_buff *skb, struct xt_action_param *par)
  77. {
  78. const __be16 *pptr;
  79. __be16 _ports[2];
  80. const struct xt_multiport_v1 *multiinfo = par->matchinfo;
  81. if (par->fragoff != 0)
  82. return false;
  83. pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
  84. if (pptr == NULL) {
  85. /* We've been asked to examine this packet, and we
  86. * can't. Hence, no choice but to drop.
  87. */
  88. pr_debug("Dropping evil offset=0 tinygram.\n");
  89. par->hotdrop = true;
  90. return false;
  91. }
  92. return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
  93. }
  94. static inline bool
  95. check(u_int16_t proto,
  96. u_int8_t ip_invflags,
  97. u_int8_t match_flags,
  98. u_int8_t count)
  99. {
  100. /* Must specify supported protocol, no unknown flags or bad count */
  101. return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
  102. || proto == IPPROTO_UDPLITE
  103. || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
  104. && !(ip_invflags & XT_INV_PROTO)
  105. && (match_flags == XT_MULTIPORT_SOURCE
  106. || match_flags == XT_MULTIPORT_DESTINATION
  107. || match_flags == XT_MULTIPORT_EITHER)
  108. && count <= XT_MULTI_PORTS;
  109. }
  110. static int multiport_mt_check(const struct xt_mtchk_param *par)
  111. {
  112. const struct ipt_ip *ip = par->entryinfo;
  113. const struct xt_multiport_v1 *multiinfo = par->matchinfo;
  114. return check(ip->proto, ip->invflags, multiinfo->flags,
  115. multiinfo->count) ? 0 : -EINVAL;
  116. }
  117. static int multiport_mt6_check(const struct xt_mtchk_param *par)
  118. {
  119. const struct ip6t_ip6 *ip = par->entryinfo;
  120. const struct xt_multiport_v1 *multiinfo = par->matchinfo;
  121. return check(ip->proto, ip->invflags, multiinfo->flags,
  122. multiinfo->count) ? 0 : -EINVAL;
  123. }
  124. static struct xt_match multiport_mt_reg[] __read_mostly = {
  125. {
  126. .name = "multiport",
  127. .family = NFPROTO_IPV4,
  128. .revision = 1,
  129. .checkentry = multiport_mt_check,
  130. .match = multiport_mt,
  131. .matchsize = sizeof(struct xt_multiport_v1),
  132. .me = THIS_MODULE,
  133. },
  134. {
  135. .name = "multiport",
  136. .family = NFPROTO_IPV6,
  137. .revision = 1,
  138. .checkentry = multiport_mt6_check,
  139. .match = multiport_mt,
  140. .matchsize = sizeof(struct xt_multiport_v1),
  141. .me = THIS_MODULE,
  142. },
  143. };
  144. static int __init multiport_mt_init(void)
  145. {
  146. return xt_register_matches(multiport_mt_reg,
  147. ARRAY_SIZE(multiport_mt_reg));
  148. }
  149. static void __exit multiport_mt_exit(void)
  150. {
  151. xt_unregister_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
  152. }
  153. module_init(multiport_mt_init);
  154. module_exit(multiport_mt_exit);