xt_socket.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Transparent proxy support for Linux/iptables
  4. *
  5. * Copyright (C) 2007-2008 BalaBit IT Ltd.
  6. * Author: Krisztian Kovacs
  7. */
  8. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  9. #include <linux/module.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/netfilter/x_tables.h>
  12. #include <linux/netfilter_ipv4/ip_tables.h>
  13. #include <net/tcp.h>
  14. #include <net/udp.h>
  15. #include <net/icmp.h>
  16. #include <net/sock.h>
  17. #include <net/inet_sock.h>
  18. #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
  19. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  20. #include <linux/netfilter_ipv6/ip6_tables.h>
  21. #include <net/inet6_hashtables.h>
  22. #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  23. #endif
  24. #include <net/netfilter/nf_socket.h>
  25. #include <linux/netfilter/xt_socket.h>
  26. /* "socket" match based redirection (no specific rule)
  27. * ===================================================
  28. *
  29. * There are connections with dynamic endpoints (e.g. FTP data
  30. * connection) that the user is unable to add explicit rules
  31. * for. These are taken care of by a generic "socket" rule. It is
  32. * assumed that the proxy application is trusted to open such
  33. * connections without explicit iptables rule (except of course the
  34. * generic 'socket' rule). In this case the following sockets are
  35. * matched in preference order:
  36. *
  37. * - match: if there's a fully established connection matching the
  38. * _packet_ tuple
  39. *
  40. * - match: if there's a non-zero bound listener (possibly with a
  41. * non-local address) We don't accept zero-bound listeners, since
  42. * then local services could intercept traffic going through the
  43. * box.
  44. */
  45. static bool
  46. socket_match(const struct sk_buff *skb, struct xt_action_param *par,
  47. const struct xt_socket_mtinfo1 *info)
  48. {
  49. struct sk_buff *pskb = (struct sk_buff *)skb;
  50. struct sock *sk = skb->sk;
  51. if (sk && !net_eq(xt_net(par), sock_net(sk)))
  52. sk = NULL;
  53. if (!sk)
  54. sk = nf_sk_lookup_slow_v4(xt_net(par), skb, xt_in(par));
  55. if (sk) {
  56. bool wildcard;
  57. bool transparent = true;
  58. /* Ignore sockets listening on INADDR_ANY,
  59. * unless XT_SOCKET_NOWILDCARD is set
  60. */
  61. wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
  62. sk_fullsock(sk) &&
  63. inet_sk(sk)->inet_rcv_saddr == 0);
  64. /* Ignore non-transparent sockets,
  65. * if XT_SOCKET_TRANSPARENT is used
  66. */
  67. if (info->flags & XT_SOCKET_TRANSPARENT)
  68. transparent = inet_sk_transparent(sk);
  69. if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
  70. transparent && sk_fullsock(sk))
  71. pskb->mark = sk->sk_mark;
  72. if (sk != skb->sk)
  73. sock_gen_put(sk);
  74. if (wildcard || !transparent)
  75. sk = NULL;
  76. }
  77. return sk != NULL;
  78. }
  79. static bool
  80. socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
  81. {
  82. static struct xt_socket_mtinfo1 xt_info_v0 = {
  83. .flags = 0,
  84. };
  85. return socket_match(skb, par, &xt_info_v0);
  86. }
  87. static bool
  88. socket_mt4_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
  89. {
  90. return socket_match(skb, par, par->matchinfo);
  91. }
  92. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  93. static bool
  94. socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
  95. {
  96. const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
  97. struct sk_buff *pskb = (struct sk_buff *)skb;
  98. struct sock *sk = skb->sk;
  99. if (sk && !net_eq(xt_net(par), sock_net(sk)))
  100. sk = NULL;
  101. if (!sk)
  102. sk = nf_sk_lookup_slow_v6(xt_net(par), skb, xt_in(par));
  103. if (sk) {
  104. bool wildcard;
  105. bool transparent = true;
  106. /* Ignore sockets listening on INADDR_ANY
  107. * unless XT_SOCKET_NOWILDCARD is set
  108. */
  109. wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
  110. sk_fullsock(sk) &&
  111. ipv6_addr_any(&sk->sk_v6_rcv_saddr));
  112. /* Ignore non-transparent sockets,
  113. * if XT_SOCKET_TRANSPARENT is used
  114. */
  115. if (info->flags & XT_SOCKET_TRANSPARENT)
  116. transparent = inet_sk_transparent(sk);
  117. if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
  118. transparent && sk_fullsock(sk))
  119. pskb->mark = sk->sk_mark;
  120. if (sk != skb->sk)
  121. sock_gen_put(sk);
  122. if (wildcard || !transparent)
  123. sk = NULL;
  124. }
  125. return sk != NULL;
  126. }
  127. #endif
  128. static int socket_mt_enable_defrag(struct net *net, int family)
  129. {
  130. switch (family) {
  131. case NFPROTO_IPV4:
  132. return nf_defrag_ipv4_enable(net);
  133. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  134. case NFPROTO_IPV6:
  135. return nf_defrag_ipv6_enable(net);
  136. #endif
  137. }
  138. WARN_ONCE(1, "Unknown family %d\n", family);
  139. return 0;
  140. }
  141. static int socket_mt_v1_check(const struct xt_mtchk_param *par)
  142. {
  143. const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
  144. int err;
  145. err = socket_mt_enable_defrag(par->net, par->family);
  146. if (err)
  147. return err;
  148. if (info->flags & ~XT_SOCKET_FLAGS_V1) {
  149. pr_info_ratelimited("unknown flags 0x%x\n",
  150. info->flags & ~XT_SOCKET_FLAGS_V1);
  151. return -EINVAL;
  152. }
  153. return 0;
  154. }
  155. static int socket_mt_v2_check(const struct xt_mtchk_param *par)
  156. {
  157. const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;
  158. int err;
  159. err = socket_mt_enable_defrag(par->net, par->family);
  160. if (err)
  161. return err;
  162. if (info->flags & ~XT_SOCKET_FLAGS_V2) {
  163. pr_info_ratelimited("unknown flags 0x%x\n",
  164. info->flags & ~XT_SOCKET_FLAGS_V2);
  165. return -EINVAL;
  166. }
  167. return 0;
  168. }
  169. static int socket_mt_v3_check(const struct xt_mtchk_param *par)
  170. {
  171. const struct xt_socket_mtinfo3 *info =
  172. (struct xt_socket_mtinfo3 *)par->matchinfo;
  173. int err;
  174. err = socket_mt_enable_defrag(par->net, par->family);
  175. if (err)
  176. return err;
  177. if (info->flags & ~XT_SOCKET_FLAGS_V3) {
  178. pr_info_ratelimited("unknown flags 0x%x\n",
  179. info->flags & ~XT_SOCKET_FLAGS_V3);
  180. return -EINVAL;
  181. }
  182. return 0;
  183. }
  184. static struct xt_match socket_mt_reg[] __read_mostly = {
  185. {
  186. .name = "socket",
  187. .revision = 0,
  188. .family = NFPROTO_IPV4,
  189. .match = socket_mt4_v0,
  190. .hooks = (1 << NF_INET_PRE_ROUTING) |
  191. (1 << NF_INET_LOCAL_IN),
  192. .me = THIS_MODULE,
  193. },
  194. {
  195. .name = "socket",
  196. .revision = 1,
  197. .family = NFPROTO_IPV4,
  198. .match = socket_mt4_v1_v2_v3,
  199. .checkentry = socket_mt_v1_check,
  200. .matchsize = sizeof(struct xt_socket_mtinfo1),
  201. .hooks = (1 << NF_INET_PRE_ROUTING) |
  202. (1 << NF_INET_LOCAL_IN),
  203. .me = THIS_MODULE,
  204. },
  205. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  206. {
  207. .name = "socket",
  208. .revision = 1,
  209. .family = NFPROTO_IPV6,
  210. .match = socket_mt6_v1_v2_v3,
  211. .checkentry = socket_mt_v1_check,
  212. .matchsize = sizeof(struct xt_socket_mtinfo1),
  213. .hooks = (1 << NF_INET_PRE_ROUTING) |
  214. (1 << NF_INET_LOCAL_IN),
  215. .me = THIS_MODULE,
  216. },
  217. #endif
  218. {
  219. .name = "socket",
  220. .revision = 2,
  221. .family = NFPROTO_IPV4,
  222. .match = socket_mt4_v1_v2_v3,
  223. .checkentry = socket_mt_v2_check,
  224. .matchsize = sizeof(struct xt_socket_mtinfo1),
  225. .hooks = (1 << NF_INET_PRE_ROUTING) |
  226. (1 << NF_INET_LOCAL_IN),
  227. .me = THIS_MODULE,
  228. },
  229. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  230. {
  231. .name = "socket",
  232. .revision = 2,
  233. .family = NFPROTO_IPV6,
  234. .match = socket_mt6_v1_v2_v3,
  235. .checkentry = socket_mt_v2_check,
  236. .matchsize = sizeof(struct xt_socket_mtinfo1),
  237. .hooks = (1 << NF_INET_PRE_ROUTING) |
  238. (1 << NF_INET_LOCAL_IN),
  239. .me = THIS_MODULE,
  240. },
  241. #endif
  242. {
  243. .name = "socket",
  244. .revision = 3,
  245. .family = NFPROTO_IPV4,
  246. .match = socket_mt4_v1_v2_v3,
  247. .checkentry = socket_mt_v3_check,
  248. .matchsize = sizeof(struct xt_socket_mtinfo1),
  249. .hooks = (1 << NF_INET_PRE_ROUTING) |
  250. (1 << NF_INET_LOCAL_IN),
  251. .me = THIS_MODULE,
  252. },
  253. #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  254. {
  255. .name = "socket",
  256. .revision = 3,
  257. .family = NFPROTO_IPV6,
  258. .match = socket_mt6_v1_v2_v3,
  259. .checkentry = socket_mt_v3_check,
  260. .matchsize = sizeof(struct xt_socket_mtinfo1),
  261. .hooks = (1 << NF_INET_PRE_ROUTING) |
  262. (1 << NF_INET_LOCAL_IN),
  263. .me = THIS_MODULE,
  264. },
  265. #endif
  266. };
  267. static int __init socket_mt_init(void)
  268. {
  269. return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
  270. }
  271. static void __exit socket_mt_exit(void)
  272. {
  273. xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
  274. }
  275. module_init(socket_mt_init);
  276. module_exit(socket_mt_exit);
  277. MODULE_LICENSE("GPL");
  278. MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
  279. MODULE_DESCRIPTION("x_tables socket match module");
  280. MODULE_ALIAS("ipt_socket");
  281. MODULE_ALIAS("ip6t_socket");