xt_multiport.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* Kernel module to match one of a list of TCP/UDP(-Lite)/SCTP/DCCP ports:
  2. ports are in the same place so we can treat them as equal. */
  3. /* (C) 1999-2001 Paul `Rusty' Russell
  4. * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
  12. #include <linux/udp.h>
  13. #include <linux/skbuff.h>
  14. #include <linux/in.h>
  15. #include <linux/netfilter/xt_multiport.h>
  16. #include <linux/netfilter/x_tables.h>
  17. #include <linux/netfilter_ipv4/ip_tables.h>
  18. #include <linux/netfilter_ipv6/ip6_tables.h>
  19. MODULE_LICENSE("GPL");
  20. MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  21. MODULE_DESCRIPTION("x_tables multiple port match module");
  22. MODULE_ALIAS("ipt_multiport");
  23. MODULE_ALIAS("ip6t_multiport");
  24. #if 0
  25. #define duprintf(format, args...) printk(format , ## args)
  26. #else
  27. #define duprintf(format, args...)
  28. #endif
  29. /* Returns 1 if the port is matched by the test, 0 otherwise. */
  30. static inline int
  31. ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags,
  32. u_int8_t count, u_int16_t src, u_int16_t dst)
  33. {
  34. unsigned int i;
  35. for (i = 0; i < count; i++) {
  36. if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
  37. return 1;
  38. if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
  39. return 1;
  40. }
  41. return 0;
  42. }
  43. /* Returns 1 if the port is matched by the test, 0 otherwise. */
  44. static inline int
  45. ports_match_v1(const struct xt_multiport_v1 *minfo,
  46. u_int16_t src, u_int16_t dst)
  47. {
  48. unsigned int i;
  49. u_int16_t s, e;
  50. for (i = 0; i < minfo->count; i++) {
  51. s = minfo->ports[i];
  52. if (minfo->pflags[i]) {
  53. /* range port matching */
  54. e = minfo->ports[++i];
  55. duprintf("src or dst matches with %d-%d?\n", s, e);
  56. if (minfo->flags == XT_MULTIPORT_SOURCE
  57. && src >= s && src <= e)
  58. return 1 ^ minfo->invert;
  59. if (minfo->flags == XT_MULTIPORT_DESTINATION
  60. && dst >= s && dst <= e)
  61. return 1 ^ minfo->invert;
  62. if (minfo->flags == XT_MULTIPORT_EITHER
  63. && ((dst >= s && dst <= e)
  64. || (src >= s && src <= e)))
  65. return 1 ^ minfo->invert;
  66. } else {
  67. /* exact port matching */
  68. duprintf("src or dst matches with %d?\n", s);
  69. if (minfo->flags == XT_MULTIPORT_SOURCE
  70. && src == s)
  71. return 1 ^ minfo->invert;
  72. if (minfo->flags == XT_MULTIPORT_DESTINATION
  73. && dst == s)
  74. return 1 ^ minfo->invert;
  75. if (minfo->flags == XT_MULTIPORT_EITHER
  76. && (src == s || dst == s))
  77. return 1 ^ minfo->invert;
  78. }
  79. }
  80. return minfo->invert;
  81. }
  82. static int
  83. match(const struct sk_buff *skb,
  84. const struct net_device *in,
  85. const struct net_device *out,
  86. const struct xt_match *match,
  87. const void *matchinfo,
  88. int offset,
  89. unsigned int protoff,
  90. int *hotdrop)
  91. {
  92. __be16 _ports[2], *pptr;
  93. const struct xt_multiport *multiinfo = matchinfo;
  94. if (offset)
  95. return 0;
  96. pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
  97. if (pptr == NULL) {
  98. /* We've been asked to examine this packet, and we
  99. * can't. Hence, no choice but to drop.
  100. */
  101. duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
  102. *hotdrop = 1;
  103. return 0;
  104. }
  105. return ports_match(multiinfo->ports,
  106. multiinfo->flags, multiinfo->count,
  107. ntohs(pptr[0]), ntohs(pptr[1]));
  108. }
  109. static int
  110. match_v1(const struct sk_buff *skb,
  111. const struct net_device *in,
  112. const struct net_device *out,
  113. const struct xt_match *match,
  114. const void *matchinfo,
  115. int offset,
  116. unsigned int protoff,
  117. int *hotdrop)
  118. {
  119. __be16 _ports[2], *pptr;
  120. const struct xt_multiport_v1 *multiinfo = matchinfo;
  121. if (offset)
  122. return 0;
  123. pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
  124. if (pptr == NULL) {
  125. /* We've been asked to examine this packet, and we
  126. * can't. Hence, no choice but to drop.
  127. */
  128. duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
  129. *hotdrop = 1;
  130. return 0;
  131. }
  132. return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
  133. }
  134. static inline int
  135. check(u_int16_t proto,
  136. u_int8_t ip_invflags,
  137. u_int8_t match_flags,
  138. u_int8_t count)
  139. {
  140. /* Must specify supported protocol, no unknown flags or bad count */
  141. return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
  142. || proto == IPPROTO_UDPLITE
  143. || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
  144. && !(ip_invflags & XT_INV_PROTO)
  145. && (match_flags == XT_MULTIPORT_SOURCE
  146. || match_flags == XT_MULTIPORT_DESTINATION
  147. || match_flags == XT_MULTIPORT_EITHER)
  148. && count <= XT_MULTI_PORTS;
  149. }
  150. /* Called when user tries to insert an entry of this type. */
  151. static int
  152. checkentry(const char *tablename,
  153. const void *info,
  154. const struct xt_match *match,
  155. void *matchinfo,
  156. unsigned int hook_mask)
  157. {
  158. const struct ipt_ip *ip = info;
  159. const struct xt_multiport *multiinfo = matchinfo;
  160. return check(ip->proto, ip->invflags, multiinfo->flags,
  161. multiinfo->count);
  162. }
  163. static int
  164. checkentry_v1(const char *tablename,
  165. const void *info,
  166. const struct xt_match *match,
  167. void *matchinfo,
  168. unsigned int hook_mask)
  169. {
  170. const struct ipt_ip *ip = info;
  171. const struct xt_multiport_v1 *multiinfo = matchinfo;
  172. return check(ip->proto, ip->invflags, multiinfo->flags,
  173. multiinfo->count);
  174. }
  175. static int
  176. checkentry6(const char *tablename,
  177. const void *info,
  178. const struct xt_match *match,
  179. void *matchinfo,
  180. unsigned int hook_mask)
  181. {
  182. const struct ip6t_ip6 *ip = info;
  183. const struct xt_multiport *multiinfo = matchinfo;
  184. return check(ip->proto, ip->invflags, multiinfo->flags,
  185. multiinfo->count);
  186. }
  187. static int
  188. checkentry6_v1(const char *tablename,
  189. const void *info,
  190. const struct xt_match *match,
  191. void *matchinfo,
  192. unsigned int hook_mask)
  193. {
  194. const struct ip6t_ip6 *ip = info;
  195. const struct xt_multiport_v1 *multiinfo = matchinfo;
  196. return check(ip->proto, ip->invflags, multiinfo->flags,
  197. multiinfo->count);
  198. }
  199. static struct xt_match xt_multiport_match[] = {
  200. {
  201. .name = "multiport",
  202. .family = AF_INET,
  203. .revision = 0,
  204. .checkentry = checkentry,
  205. .match = match,
  206. .matchsize = sizeof(struct xt_multiport),
  207. .me = THIS_MODULE,
  208. },
  209. {
  210. .name = "multiport",
  211. .family = AF_INET,
  212. .revision = 1,
  213. .checkentry = checkentry_v1,
  214. .match = match_v1,
  215. .matchsize = sizeof(struct xt_multiport_v1),
  216. .me = THIS_MODULE,
  217. },
  218. {
  219. .name = "multiport",
  220. .family = AF_INET6,
  221. .revision = 0,
  222. .checkentry = checkentry6,
  223. .match = match,
  224. .matchsize = sizeof(struct xt_multiport),
  225. .me = THIS_MODULE,
  226. },
  227. {
  228. .name = "multiport",
  229. .family = AF_INET6,
  230. .revision = 1,
  231. .checkentry = checkentry6_v1,
  232. .match = match_v1,
  233. .matchsize = sizeof(struct xt_multiport_v1),
  234. .me = THIS_MODULE,
  235. },
  236. };
  237. static int __init xt_multiport_init(void)
  238. {
  239. return xt_register_matches(xt_multiport_match,
  240. ARRAY_SIZE(xt_multiport_match));
  241. }
  242. static void __exit xt_multiport_fini(void)
  243. {
  244. xt_unregister_matches(xt_multiport_match,
  245. ARRAY_SIZE(xt_multiport_match));
  246. }
  247. module_init(xt_multiport_init);
  248. module_exit(xt_multiport_fini);